在过去一年里,我们与商业领域的各类团队合作,包括零售商、交易平台、旅游、娱乐和电信提供商,使用 Claude 构建商业智能体。
这些代理已经投入生产,企业客户在使用它们时看到了更大的购物车和更高效的卖家运营。它们也共享一种简单的架构:在一个带有一组技能、工具和强大 eval 套件的 agent loop 中运行的 Claude。
这篇文章面向正在构建这类代理(或其他面向消费者的代理)的工程师和工程负责人。第一部分介绍架构,这部分只需决定一次。第二部分介绍延迟和成本。第三部分介绍生产环境:记忆、安全、评测,以及如何在组织内扩展这项工作。
一个标准 agent loop 中的单一模型,配合用于长尾场景的 skills,以及调用你已在运行的系统的 tools。这部分只需决定一次。
我们将商业智能体定义为一种简化在线目录中买卖流程的代理。
有些代理面向消费者:它们进行搜索、比较、替代,并组装订单。可能是零售购物车、旅行行程、手机套餐变更,或为演出保留座位。有些代理面向业务:它们回答销售相关问题、执行促销和营销活动,并管理库存和定价。

上面的两个面板运行的是同一个代理,使用相同的工具和提示词;不同的只是 harness。总耗时大致相同,但用户看到结果的时间差别很大。
核心架构是在一个标准 agent loop中的模型:围绕目标进行推理,探索上下文,通过工具采取行动,通过 skills 学习流程,提出澄清性问题,并观察结果,直到目标达成。
前面没有一个意图路由器来分流对话,后面也没有一组领域专用代理。
商业智能体 需要覆盖多个类别和意图下的广泛能力,这很容易让人想为每个领域都建立一个 subagent。
但在实践中,这并不是最优解,因为一次 commerce 对话本质上是跨多个意图和轮次的紧密耦合会话,而且需要大量共享上下文。
在 subagent 架构中,orchestrator 持有购物车或已暂存的变更、用户偏好以及对话历史。
每次交接给 subagent 都是一次有状态损失的操作,这通常会影响 subagent 响应的质量,进而影响整体响应。除此之外,每次交接还可能消耗数倍 token,并增加数秒延迟。
这些领域也很少能清晰分开。一个退货流程可能需要订单历史、当前购物车和产品目录,这意味着按领域划分 subagent 的方案要么在各处重复这些访问,要么在任务中途进行交接。
随着模型越来越聪明,它们也能处理更长上下文、更多 skills 和更多 tools,因此如今放置规则背后的限制会随着每一代模型而放松。
相较之下,agent skills 能在不付出交接代价的情况下,提供类似的按领域模块化与上下文控制,因为 skill 指令会加载到已经持有完整历史记录的主代理中。
在我们对多个企业部署的对比中,带 skills 的单一代理在质量上始终优于“一个提示词包打天下”的设计和 subagent 设计,而且通常每个任务的成本和延迟也更低。
subagent 真正适合出现的场景,是 orchestrator 可以把它当作一个 tool,用于狭窄或自包含的任务,而且该任务会受益于自己独立的上下文窗口。
一个常见的生产示例是深度研究 subagent:它搜索和阅读文档、编写并运行代码、遍历数据模型,也会走进死胡同。所有工作都发生在一个或多个 subagent 内部,最后只把一个紧凑答案返回给 orchestrator。
另一个例外是那些本来就已经有专门构建的 agent 的领域。如果你的药房或金融服务体验运行的是一个拥有自己合规边界的专用代理,正确做法可能是交接,即让那个代理接管任务,并通过它自己的 loop 直接与用户协作,直到任务完成。
区别在于对话的所有权。交接会让领域代理成为用户的对话对象,而委派则保留 orchestrator,让领域代理在单轮内进出,且每次交换都会让效果变差。
决定一组指令应放入 system prompt 还是 skill 的主要因素,是代理需要它的频率。加载一个 skill 会消耗一个模型轮次,所以代理在大多数轮次都需要的内容,通常应放进 system prompt。
不过,这也取决于你的流量分布,以及 eval 显示出的代理行为。一个好的起点是:凡是与你至少三分之一流量相关的内容,无论是发布前预期的还是生产中观察到的,都放进 system prompt,其余则放进 skills。
如果某个 skill 可以由你已经拥有的信号推断出来,比如用户来自哪个页面,我们建议在第一次模型调用前由 harness 注入它,跳过额外一轮去加载该 skill。
关键指令,例如安全与法律规则、品牌约束,以及过敏史这类重要用户信息,始终放进 system prompt。
对于 商业智能体 来说,这意味着产品搜索应该放在 prompt 中,因为几乎每个会话都会涉及它,而 skills 负责覆盖长尾功能。
在我们的参考实现中,购物代理的 prompt 包含 grounding、购物车和结账语义,以及展示规则;其余部分由以下 skills 覆盖:search-discovery、purchase-research、planning-goals、customer-care 和 memory-personalization。
商家代理也按同样方式拆分,skills 分别是 performance-insights、catalog-listings、inventory-operations、pricing-promotions 和 marketing-campaigns,每个对应一个运营领域。
在 prompt 中 Shopping agent grounding、购物车和结账语义、展示规则,以及产品搜索。
Shopping skills 长尾场景 search-discovery · purchase-research · planning-goals · customer-care · memory-personalization
Merchant skills 每个运营领域一个 performance-insights · catalog-listings · inventory-operations · pricing-promotions · marketing-campaigns
我们关于为代理编写高效工具的文章已经概述了工具设计的一般原则。在 commerce 场景里,最重要的有两点:
在你的核心系统和逻辑之上构建代理工具。
一家 commerce 公司本来就已经有搜索与排序、购物车、偏好和画像存储、库存系统、促销和活动引擎、销售分析等系统;这些系统都编码了经过多年打磨的逻辑,承载着模型永远不会自行获得的信号。
代理的 tools 应该调用这些系统,而不是重新实现它们;工具边界就是这些系统逻辑结束、模型判断开始的地方。
例如,当代理调用 search_products 时,结果应当已经完成排序;代理的职责是决定哪些结果最能服务用户目标、展示多少,以及如何呈现。
工具结果就是上下文。
只返回模型推理所需的字段,删掉其余内容。每一行搜索结果里都带图片 URL,通常就是最常见的冗余来源。
需要时,在工具内部重塑原始响应,包括在数据里看不出来时补上下一步。
这在错误场景中尤其重要,因为模型更受指令而不是错误码的帮助。例如,别只返回一个通用的 403,而是添加一条错误指令:“查询库存时请包含 product ID。”
大多数 商业智能体 的响应不是散文,而是 UI 组件,比如产品轮播、行程表、座位图或图表。这意味着代理需要输出 schema,而不是纯文本。
一些团队会先通过提示模型输出自定义标签,再在客户端解析。这种方法在界面不断扩展时会失效,因为:
经实践验证的模式,是把每个 UI 组件都做成一个 tool。模型以带类型参数的方式调用 present_products、present_itinerary 或 present_plan_comparison;你的服务器对调用进行校验和增强并发出事件;客户端再进行渲染。
因为这些组件本身就是 tool call,它们已经以原生格式存在于 messages 数组中,所以在重新加载旧对话时不需要再次解析。下面以及参考仓库中都展示了一个 presentation-tool 合约示例。

上面的两个面板运行的是同一个代理,使用相同的工具和提示词;不同的只是 harness。总耗时大致相同,但用户看到结果的时间差别很大。
权衡在于流式粒度。工具调用的每个顶层参数都要先在服务器端缓冲以便校验,因此即使开启 streaming,presentation tool 的子组件也会分步骤到达。这会影响感知延迟。
如果想要 token 级流式输出,可以在工具定义中把 eager_input_streaming: 设为 true,这样就会跳过缓冲,也就失去了服务器端的 schema 保证。
在我们的 eval 中,Claude Sonnet 级别及以上模型的 schema 违规非常少,但对于少数漏网情况,仍应在调用外层加上重试。
Presentation tools 还会给代理留下“屏幕上显示了什么”的记录。当客户说“第一个酒店”或“左边往下数第三个”,布局信息就已经在 messages 数组里,位于最近一次 presentation 调用的参数中。
要让这一点生效,参数必须反映渲染后的布局,因此应当按 UI 的结构来组织,比如按顺序排列的行和轮播,而不是让客户端再去重排的扁平列表。
从端到端和感知两个方面同时攻击延迟,并让缓存承担成本。实现这一点不应消耗智能。
在 commerce 场景中,延迟很重要,而面向消费者的界面最不容忍延迟。不过,在 agentic 界面上,我们一贯看到真正推动留存、参与度和购物车规模等指标的,是结果质量。
答案是否相关、任务是否真正完成,对这些指标的重要性通常高于微小的延迟改进。
因此要从两个方面攻击延迟。通过良好的工程实践压缩端到端延迟,同时降低感知延迟,因为用户看着代理工作时,这段时间本身就像“正在前进”。
每个用户都有一个延迟预算,下面这些技巧能让代理留在预算内,而且不需要消耗额外智能。
任务完成延迟是各个模型轮次中“到最后一个 token 的时间”加上工具处理时间的总和。这给了你三个优化杠杆:更少的轮次、更快的工具和更快的 token。这些杠杆有时会相互竞争,因此真正要最小化的是它们的总和,而不是任何一个单项。
更少的轮次 预先加载可能相关的上下文,提高模型智能,并让模型并行调用彼此独立的工具。
更快的工具 优化工具自身的后端,并在参数一完成就尽早派发工具调用。
更快的 token 通过遍历 eval 套件来选择模型及其配置。
查询复杂度会增加轮次,而且通常不受你控制。模型智能和相关上下文能帮助代理用更少轮次完成任务。我们在这方面的一些关键经验包括:

上面的两个面板运行的是同一个代理,使用相同的工具和提示词;不同的只是 harness。总耗时大致相同,但用户看到结果的时间差别很大。
感知延迟指的是用户感觉屏幕开始有反应之前的时间。它在面向消费者的场景中特别关键,因为任何交易摩擦都会影响结账率和收入。有两种技术可以在不改动模型的前提下缩短它:
user_facing_message 参数工具,让模型写出这行文案。

上面的两个面板运行的是同一个代理,使用相同的工具和提示词;不同的只是 harness。总耗时大致相同,但用户看到结果的时间差别很大。
Prompt 缓存是你最大的降本候选项,而且 commerce 流量非常适合它。缓存输入 token 的读取成本只有新 token 的十分之一;虽然缓存写入大约要付出 1.25 倍的溢价,但一个缓存前缀在第二次使用时就能回本。在面向消费者、流量较大的应用中,你有独特机会利用默认的 5 分钟缓存过期时间,达到非常高的缓存命中率。
我们见过的最佳 commerce 部署,缓存命中率都能达到 90% 到 99%,而且从一开始就应该按这个范围来设计。我们的经验表明,在约 10 万 token 的规模下,缓存 token 的读取速度也大约快 1.5 到 2 倍,而且随着 token 数量增多,扩展关系相对线性。
缓存是基于前缀的。一次请求会一直从缓存中读取,直到与之前某次请求不同的第一个字节为止,所以真正重要的不只是上下文里有什么,还有它的顺序。可以把一次请求看作三个部分,按变化频率排序:

这里有两个实现细节要记住。第一,skills 应当以工具结果的形式加载,而不是追加到 system prompt 中。这样 skill 正文会落在对话前缀里,并与前缀一起被缓存。
第二,每一轮都要把 breakpoint 向前推进:一次请求允许的 breakpoint 数量有限,所以要把最新的那个移动到每个用户轮次的末尾。这样每一轮都能从缓存中读取累积历史,包括像搜索响应这样较长的工具结果。

模型大小和 effort 设置本质上是同一个权衡:智能与延迟和成本之间的取舍。你应该通过测量来同时选择它们:
衡量时要按“完成任务的成本”而不是“每次模型调用的成本”来算,因为一个更便宜但需要更多轮次、或者失败率更高的模型,并不更便宜。当结果接近、且成本符合你按任务核算的经济性和延迟要求时,优先选择智能。质量才是驱动采用和留存的关键,也能为未来 6 个月的建设留出空间,因为模型会越来越强。
记忆、安全、eval,以及如何在组织内扩展这项工作:这些决定了一个代理能否进入生产并留在生产里。
最后,我们来讲讲让代理通过生产考验并持续运行所需要的内容:记忆、安全、eval,以及如何在组织内扩展这项工作。
你与客户之间的关系和互动很重要。记忆能让代理接续上一次对话,而不是每次都从零开始。三月提到坚果过敏的购物者,不应该在六月还得再说一遍;每周一都会检查同样三个活动的商家,也不应该每次都重新报一遍名字。长期记忆,也就是那些应该跨会话保留的事实,是你需要自己构建的系统,它由三部分组成:事实如何存储、如何写入、以及如何读取。
记忆应该放在你的系统里,而不是放在模型里。
当 profile 很小,而且代理是唯一读取者时,扁平的 markdown profile 是可行的。大多数生产 商业智能体 都会超出这个范围,而现实中的替代方案就是你已经在运营的数据库。一个事实就是一条小的 typed record:一个键(如 shoe_size、default_store、preferred_report_cadence)、一个简短值、一个类别,以及它来自哪个会话。一些键你会预先决定并分配给每个用户,其余的由 extractor 发现。随着存储增长,数据库仍然可查询,允许你基于特定属性构建确定性行为,并能与你已经拥有的用户数据做关联。
对于面向商家的代理,应按“人”而不是“账号”来键控记忆。商家的登录账号经常被多个操作员共享,因此每个操作员都需要自己的 profile,而且读取时必须尊重该操作员的权限:门店经理的代理不应记起区域经理说过的事实。
在 commerce 领域,代理记忆存放的是个人数据。值得记住的那些事实,往往恰恰是监管最严格的,而不同司法辖区之间的规则也不同。要把记忆当作一个数据处理设计问题,而不仅仅是存储问题。实践中,这意味着四件事:
记忆应异步写入。每轮结束时,或者在长会话的每几轮结束时,由另一个线程或进程中的代理读取对话,并在存储中创建、更新或删除事实,同时在会话继续进行时维护自己的工作上下文。
这不会增加对话延迟,而且在我们内部的 commerce memory eval 套件中,事实召回率提高了 13%。
显而易见的替代方案,是让代理调用一个 tool 去保存事实,但对延迟敏感的 商业智能体 来说,这不是正确做法。每次保存都是一次位于用户可见轮次中的 tool call;而且除非整个存储都在上下文里,否则一次保存前通常还需要先读一次来更新或去重,这本身又是一轮。
它还会在每一轮给代理多加一个决策,而在我们的 eval 中,这种对注意力的竞争会表现为漏记忆。
把 extractor 独立出来,还能让你更精确地提示它。它只读取用户和助手的文本,从不读取工具结果,因此产品描述或评论不会变成关于用户的事实。它的 prompt 会说明什么算事实,例如明确说出的尺码、饮食限制、履约偏好、商家常用的 materialized views;也会说明什么不算,例如列表页中的任何内容或一次性的细节。

以三层方式读取记忆。
始终在上下文中 一小组固定事实会在每一轮进入上下文:几乎每个请求都会依赖的那些事实,例如购物者的默认门店和履约偏好,或操作员的门店和角色。
每轮预取 与当前请求相关的事实,会根据与预加载 skill 相同的信号按轮预取:例如鞋类搜索会拉取尺码和品牌偏好,活动问题会拉取操作员常用的指标。
放在 lookup tool 后面 其余内容都放在 lookup tool 后。
由于记忆是每个用户的上下文,它全部都应放在 session 段中,位于 global cache breakpoint 之下。
prompt 是安全行为的起点,但在 commerce 里,它不能成为安全执行的地方。失败往往意味着财务损失,而且通常不可逆;而一条 prompt 规则,只要一次注入或一次坏样本,就可能被跳过。下面每条规则都通过代码强制执行,适用于消费者代理和商家代理,并且只定义一次,确保每个运行时都共享它。
没有任何模型 tool call 会直接移动资金或改变业务。下单、支付、退款、调价和活动上线,最终都要落到由 harness 控制而不是由模型控制的动作上。
在消费者侧,这是结构性的:checkout tool 会把购物车渲染出来并带上一个下单按钮,而代理所调用的后端接口根本没有 charge 方法。
在商家侧,每个写入工具都会生成一个带服务器生成 ID 的 staged change,而 apply_change 只有在通过真实界面批准后才会成功:可以是运营门户中的一个按钮、CLI 中的一次确认,或者当代理运行在 Managed Agents 上时由平台自己的工具审批提示。
这些护栏在 apply 时会依据当前限制重新检查,而不是依据变更暂存时有效的限制。无论界面如何,形态都是一样的:模型最危险的动作只是提出建议,审批则通过你业务中用于这类变更的 maker-checker 流程进行。
harness 会为每个会话保留一份记录,记录服务器曾交给模型的每一个 ID,而这份记录是任何写入或渲染唯一接受的 key。
购物车只接受服务器向该会话返回的 product ID,商家工具只接受代理确实读到过的 listing 和 campaign ID。任何以其他方式到达的 ID,无论是模型幻觉出来的、用户粘贴的,还是评论里植入的,都会在后端看到它之前被拒绝。
同样的规则也适用于 UI。Presentation tools 接收 ID,由服务器自行填充产品、订单或变更记录,因此只有服务器自己填过的记录才会被渲染成卡片。
这也适用于 delegate:商家分析 subagent 可以读取数据,但不会把任何 ID 加入代理可写入的集合。
对于费用、披露和其他受监管内容,模型决定要披露哪个产品,而服务器提供每一个字,使用的是经过批准的文案。同样的费用字段也在商家代理的受保护列表中,因此柜台两侧都不能更改或改写它们,eval 会逐字节检查渲染出的字符串。
大多数 commerce 界面都会限制单个用户可购买某一商品的数量,例如票务配额、促销定价或反欺诈控制;而代理会以人类点击按钮不会采用的方式进行重试、改写和并行化。
因此,这个上限应当像写入后那样在线上执行,这样第二次“再加两个”就不能把数量叠加超过上限,而且同一会话的购物车写入要串行化,这样单轮中的并行 tool call 就不会合并后突破限制。
对于费用、披露信息和其他受监管内容,模型只选择要披露哪款产品,服务器则从获批文案中逐字提供全部内容。同样的费用字段也在商家代理的受保护清单上,因此交易柜台两侧的任何一方都无法更改或改写它们,评测也会逐字节检查渲染后的字符串。
大多数商业界面都会限制单个用户可购买某件商品的数量——用于门票配额、促销定价或欺诈控制——而代理会以人类点击按钮从未有过的方式重试、改写请求并并行执行。
因此,上限会在行项目层面按写入后的状态来执行,这样第二次“再加两件”就无法叠加并突破上限;同一会话中的购物车写入也会被串行化,确保单轮交互中的并行工具调用无法合并起来超过上限。
商家侧的更改也会以同样方式检查价格变动幅度、折扣深度、补货规模和活动预算的上限,以及任何更改都不得触碰的受保护字段清单。这个规则可以泛化为:对结果状态而不是请求本身执行每一项限制,并按会话串行化写入。
在商业场景中,大部分上下文都由不是你的人撰写——卖家、评论者、竞争对手——因此每一次后端读取都是不可信输入,都要经过同一个清洗器。
凡是由第三方编写的工具结果,例如商品列表、评论、政策、卖家消息和已存储记忆,都会在模型看到之前被清洗,并用固定标签包裹在围栏中。
清洗器会去除控制字符和双向文本字符,移除任何模仿围栏标记的内容,化解那些伪装成对话轮次或工具调用的文本,并限制大小;这些设计旨在阻止恶意商品列表冒充系统,或填满上下文。
提示词则承担契约的另一半:围栏中的文本是用于汇报的材料,绝不是用于执行的指令。
从一个小小的提示词改动到新增一个工具,任何变化都可能以难以预测的方式改变代理行为,而你正在发布的变更往往并不是导致回归的那个变更。评测(evals)就是让你在部署前发现这些问题的方法。我们此前关于代理评测的博客文章介绍了通用实践。本节介绍商业代理的具体做法。
评估快照,而不是对话
模型 API 是无状态的,因此代理的输出是系统提示词、工具和消息数组的函数。这意味着商业对话可达到的任何状态都可以被直接构造出来。因此,创建一个评测用例,就是构造测试状态、追加测试用户消息,然后让代理从那里开始运行。
然后对结果评分:最终状态和渲染出的回复,包括最后一次写入的参数。在大多数情况下,我们不建议对代理到达结果所走的路径本身评分,因为这类测试用例既脆弱又具有过强约束。
模拟用户评测,也就是由第二个模型扮演用户、再由裁判评估整段对话,并不是一种好的度量工具。两个非确定性系统交互需要更大的样本量、每次试验成本更高、更难评判,而且产生的失败也很难归因。它们适合用来发现覆盖缺口,也适合对代理做整体观感检查,所以可以用它们来发现用例,然后把每个用例写成快照。

大多数团队没有充分测试注入后的状态。一个用例应该编码失败的前置条件,而不只是任务本身。如果某种行为只有在第一轮繁忙交互、包含多次工具调用之后,或在会话早些时候出现矛盾之后才会显现,那么从干净状态开始的用例会在每一种配置下都通过,并且无法提供有意义的数据。
我们观察到,大多数测试套件都过度偏向这类干净状态用例,所以要确保你的用例中有一部分从冗长、混乱或相互矛盾的历史开始。
有效评估需要同时测试期望行为和非期望行为。
对每一个正向用例,都要写出它的反向对应项:每一个“应该服务”都要对应一个“应该拒绝”,每一个“应该直接执行”都要对应一个“应该追问”。缺少反向用例是我们在测试套件中最常发现的缺口。
请评估以下内容:
与能一线看到失败的主题专家合作设计测试用例,例如产品、法务、商家运营、客户服务和品类管理团队成员。真实失败是最好的评测素材,每个用户流程 50–100 个评测用例是一个不错的起点。
确保用例类型多样,如上所述。生产环境对话记录是获取新用例的绝佳来源,尤其是那些棘手用例。编码代理很擅长生成更多用例和对抗性变体。参考仓库包含一个 Claude Code 插件,其中内置了按我们推荐方法构建的评测编写技能。
在商业企业中,代理由许多工程团队共同构建。搜索、结账、定价、营销技术、客户服务和目录平台分别拥有代理所依赖的系统,各自按自己的节奏发布,也都会想要新增或修改某个工具、技能或提示词规则。
与服务不同,代理没有严格的模块边界来保护其他部分:定价团队做出的更改会与结账共享同一个上下文窗口。
诱人的修复方案是把系统拆成许多子代理,每个业务单元一个。正如第 1 部分所讨论的,出于质量原因,我们不建议这样做。相反,我们概述了降低多团队协作风险的流程:
关于这种安排中的人员协作侧,请参阅构建高效的人类—代理团队。
本文描述的大部分内容并不关于模型本身。工具调用的是你已经在运行的系统,技能编码的是你已经在遵循的流程,评测是以测试形式写成的产品需求文档,而运行框架会执行你对任何客户端都会执行的策略。模型会持续改进;当更好的模型发布时,我们描述的架构可以把它作为一次配置变更引入,并配合一轮评测扫描。其他一切都能继续工作。
同样重要的是,要思考你的产品界面路线图。这套架构会比聊天面板更持久。同一个代理可以通过语音工作,也可以在用户提出请求前主动针对票价下降采取行动。对于一个已经具备评测和工具的团队来说,这些都是表现层项目。再往后,你的店铺流量中有一部分会来自代表用户购物的代理。让你自己的代理保持边界内的同一套来源追踪、暂存和审批规则,也会让你能够安全地向这些代理开放工具。
商业一直奖励那些让购买流程尽可能顺畅的做法。代理让这件事容易得多。可以查看完整参考实现,其中包含消费者代理和商家代理,以及面向零售、旅行、电信和娱乐的可运行示例。
作者为 Matthew Koen 和 Ali Shazal。特别感谢 Michael Segner、Rodrigo Olivares、Amandeep Khurana、Aiza Usman、John Lopus 以及其他贡献者。