把 Coding Agent 接入真实商业软件:Foundax 的架构实践
结合真实业务场景,探讨如何让 Coding Agent 参与业务系统工作。Agent 负责业务理解、探索推理与通过代码组织任务,宿主平台则负责数据授权、持久化状态管理、真实业务写入与人工协作编辑,兼顾灵活性与系统边界。
本文面向软件工程师与架构师,深度探讨如何将复杂的商业能力与创意资源重塑为 Agent 可探索的“原生工作环境”。通过剖析一个英国市场首发活动的完整生命周期,文章详细解析了渐进式披露、声明式批处理、故障修复循环、多模态视图以及上下文生命周期管理等核心架构决策,展示了如何在有限的上下文与执行预算内保障 Agent 的业务交付质量。

当我们尝试将大语言模型(LLM)引入成熟的商业软件时,最直觉的做法通常是提供两样东西:全量的开放 API 文档和一个代码执行沙盒。然而,面对真实的商业诉求——例如“为一款新商品策划英国市场首发并提供开屏优惠”——这种粗放的集成往往以失败告终。Agent 要么在庞大的 API 定义中耗尽了上下文(Context Budget),要么生成了漂亮的页面代码,却关联了错误的底层商品与促销数据。
根本原因在于:现有的系统架构是为人类操作员和确定性的前端应用设计的。要让 Agent 在不可预期的、跨领域的任务中自主推进,我们需要将业务能力和创意资源重新组织成一个可探索的工作环境(Business Environment)。
本文将以“英国市场首发”这一连续的业务挑战为主线,探讨如何设计一套让 Agent 能够发现、理解、组合并在出错时自我修复的底层架构体系。
面对首发任务,Agent 需要触及商品(Product)、促销(Promotion)、配送(Shipping)等多个领域。如果将所有领域的 Schema 一次性注入 Prompt,不仅延迟飙升,模型还会因为注意力稀释而开始“发明”不存在的字段。
初始的架构决策是引入渐进式披露(Progressive Disclosure)机制。系统提供了一个极其轻量的入口契约 client.catalog(),它仅返回领域列表、契约路径和简单的依赖图(如 dependsOn),而非具体数据。
Agent 首先通过 catalog() 建立系统拓扑认知,随后按需调用 client.read(domain) 抓取当前任务必备的数据。更重要的是,每次读取都会携带一个当前的业务版本号(revision):
const client = createBusinessClient(baseUrl);
const catalog = await client.catalog();
// Agent 根据 catalog 指引,按需读取配送策略和商品
// 每次读取独立返回数据与业务版本号,不保证跨请求是同一快照
const shippingReceipt = await client.read('shippingPolicies');
// shippingReceipt 结构为 { revision, shopId, rows }
const productReceipt = await client.read('products');这种设计下,Agent 不需要承载整个数据库的知识,而是通过短平快的 API 探明周边环境。环境是动态的,多次读取可能会观察到不同的 revision,Agent 需要在操作时声明它所基于的观察版本。
完成环境探索后,Agent 需要创建首发活动(Campaign)以及配套的促销规则。最简单的做法是开放独立的 Create API,让 Agent 依次调用。但由于网络波动或模型自身的逻辑截断,极易出现促销规则已创建、但活动创建失败的“脏数据”状态。
为了保障业务的一致性,系统引入了 client.apply(plan) 进行声明式批处理。Agent 在一个操作载荷中声明所有的创建与修改,系统通过明确的内部 ID 来处理实体间的依赖关系:
// 示例前提:系统中已存在 ID 为 'tray' 的商品和 'ie-standard' 的配送策略
const productReceipt = await client.read('products');
const plan = {
expectedRevision: productReceipt.revision,
operations: [
{
domain: 'promotions',
value: {
id: 'opening-offer',
percent: 15,
productIds: ['tray']
}
},
{
domain: 'campaigns',
value: {
id: 'quiet-mornings',
title: 'UK launch',
country: 'GB',
productIds: ['tray'],
shippingPolicyId: 'ie-standard', // 教学示例:故意引入的错误引用
promotionId: 'opening-offer'
}
}
]
};
await client.apply(plan);在这个批次中,如果候选操作的字段不合法,或者对商品与促销的引用无效(例如挂载了不存在的商品 ID),宿主系统将直接拒绝整个候选批次,确保底层核心实体的一致性。一旦校验通过,系统会递增全店统一的 revision 并落盘保存。值得注意的是,系统的保存机制容忍不完整的活动草稿——并不是所有的活动(Campaign)外部引用都必须在保存那一刻就绝对完整有效。一个活动究竟是否具备向消费者展示的资格,是由独立的 check 机制另行判断的。
落盘成功并不意味着业务有效。在这套教学参考场景中,我们可以设想一种典型的业务装配失误:Agent 构建了一个面向英国(country: 'GB')的活动,但在组合现有资源时,错误地将其指向了一个仅覆盖爱尔兰的配送策略(shippingPolicyId: 'ie-standard')。
此时,草稿已保存在环境中,但如果我们允许页面层级直接读取并渲染,就会引发灾难性的客诉。因此,系统设立了严格的屏障:
当 Agent 或外部系统调用 client.check(id) 时,引擎会返回具体的就绪差距(Readiness gaps)。在上述场景中,系统返回 shippingcoverage 错误,指出所选配送策略无法覆盖目标国家。
在修复此间隙之前,调用 client.campaign(id) 获取任务视图,或调用 client.order(input) 尝试模拟下单,都会被宿主坚决阻断。这就迫使 Agent 建立清晰的故障修复循环(Repair Loops)。不同类型的失败必须驱动不同的动作:
通过将业务校验与代码编译解耦,我们确保通过了某项检查(代码跑通了)决不代表系统可以上线。

当业务逻辑被成功修复后,Agent 的下一步是生成前端代码以展示商品。如果让前端代码(或 Agent)去对接底层的商品库、促销引擎并自行计算折后金额与库存,不仅容易出错,还会大幅消耗 Token。
架构上的应对之道是让宿主提供 campaignView(通过 client.campaign(id) 访问)。这是一个面向任务的聚合读模型,它吸收了底层多次 Join 与复杂规则计算的成本,直接吐出最终呈现所需的折后价格、退换条款和媒体素材。页面代码只需加载这个 SDK 视图即可。
然而,将数据转化为吸引人的首发页面,不仅仅是数据绑定的问题,还面临着严苛的视觉挑战。例如,某个合成商品图是一个向右延伸着长柄的马克杯,而它的托盘图片是俯视且更宽的。如果 Agent 仅仅依赖预设的、固定比例的 Bounding Box(边界框)去裁切图片,或者只是在死板的模板里替换文本,长柄就会被生生切断。
环境设计必须为创意工作留下空间。普通项目文件(React/TS/CSS)仍然是完全开放的创作表面。系统提供的模板简报(Template brief)并不限定代码死板的结构,而是沟通“购物者旅程”与“适配意图”;媒体元数据传达了图像的主体、裁剪和透明度特征。
最终的合成效果,仍然需要依靠实际的页面预览捕获(Pixel capture)反馈给 Agent。如果发现长柄被截断或元素重叠,这种视觉观察会驱动第三种修复循环:调整 CSS 布局或更换素材组合。视觉校验、业务校验、代码校验在这里各司其职,互不替代。
在这样一个反复探索、校验和修复的过程中,Agent 的上下文窗口会迅速膨胀。随着商家中途改变主意(比如将首发折扣从 15% 改为 20%),源码被更新,环境的 revision 向前推进。此时,早先读取的 API 结果和几分钟前的页面截图已经彻底失效。
将历史对话无限累加是不可持续的。一个成熟的 Agent 架构需要明确区分“可恢复的原始历史”(Raw history)与“模型当前的工作投影”(Model-facing context)。上下文生命周期管理意味着我们在每次交互前,需要自动组装出一个有界的快照,其中包含:
我们需要权衡的是:什么时候让 Agent 携带信息(消耗常驻预算),什么时候让它通过 client.read 去重新获取信息(增加请求延迟)。架构评价的终极指标不再仅仅是 Token 消耗,而是输入字节、交互轮数(Turns)、首次产生可用预览的时间,以及最终的业务、交互和视觉质量的综合考量。
为了直观地验证这些理念,Foundax 发布了一个开源的参考实现:agent-native-business-environments(Node 22+, 无第三方依赖, MIT)。
该项目包含单店铺的 Node 宿主环境、JSON 持久化层、可在 Node 或浏览器运行的 SDK,以及普通的 HTML/CSS/JS 项目文件。在代码库根目录运行 npm run demo,可以观察到一个使用合成数据的预设脚本流程:它演示了同批创建关联业务对象、通过 check 接口暴露 shippingcoverage 错误、调用 API 修复引用,并最终渲染出目标模板预览的完整过程。
在这个开源参考库中,可运行的核心部分是业务宿主、SDK、CLI 及前端模板。关于上下文生命周期管理与模型编排的具体机制,则在仓库的设计文档和伪代码中进行了详细展开,方便接入团队参考与研究。
最重要的是,通过 TASK.zh-CN.md 引导,开发者可以将自己携带了浏览器工具或视觉能力的外部 Agent 接驳到这个环境中。这种开放性的意义在于:它迫使我们证明,那些过去隐藏在人类工程师大脑中的默会知识(Implicit knowledge),已经被成功转化为一套 Agent 能够独立阅读、理解并通过契约执行的显性架构。