业务Agent该怎么设计?
本文为 Anthropic 原文的阅读笔记。
原文:The anatomy of effective commerce agents
背景:Anthropic 与零售、旅行、票务、电信等企业合作落地商业业务 Agent 的经验。
1. 架构

1.1. 单 Agent 优先
一个主模型在标准 Agent Loop 中持续:理解目标 → 获取上下文 → 调工具 → 观察结果 → 澄清 → 继续行动。Anthropic 认为,传统的 Multi-Agent 架构(orchestrator + subagent)有几个劣势:
- 每次委派都会损失状态、增加 token 和秒级延迟。
- 业务域是分不清楚的,某一个 subagent 所需要的输入/上下文,可能是另外一个 subagent 的输出,subagent 之间也有重合。
- LLM 是越来越聪明的,要面向未来设计。
替代方案是 Agent Skills,把分领域的指令包成 Skill,按需加载进已经掌握全部历史的主代理。那什么情况还是适合 Subagent 的方式呢?
- 深度研究、代码执行等边界清晰、可压缩成一个结果的任务。
- 药品、金融等拥有独立合规体系,需要真正把对话控制权移交出去的场景。
1.2. System Prompt 和 Skill 的划分
如果是单 Agent 的话,我们该怎么划分什么信息该放在 System Prompt,什么该放在 Skill 里呢?Anthropic 的答案是:按照频率来。
- 约三分之一以上流量都会用到的指令,放 System Prompt。
- 长尾能力:放 Skill。
- 安全、法律、品牌规范、过敏信息等关键约束:无论频率如何都放 System Prompt。
- 如果能根据入口页面提前判断需要哪个 Skill,就由框架预加载,避免多消耗一次模型轮次。
本质是,利用业务逻辑来优化 Agent Skill loading 策略。
1.3. Tool
1.3.1. Tool 不应该重写业务逻辑
业务逻辑(商品排序、库存、促销、履约、支付等逻辑)应继续由原有系统负责。Agent Tool 只是这些系统的接口。Tool 返回值也是模型上下文,因此要:
- 只保留推理需要的字段。
- 删除无关的大字段。
- 把错误码转成可行动的提示。
- 避免让 Tool 本身逐渐堆积大量业务规则。
1.3.2. UI 组件搞成 Tool
不要让模型输出自定义 XML/标签再由前端解析。商品卡片、行程单、套餐对比、座位图等都应该是有类型约束的展示 Tool,例如:
present_products(...)
这样展示结构天然进入消息历史,用户之后说“左边第三个酒店”时,模型知道屏幕上的真实布局。
2. 优化
2.1. 减少真实任务延迟
任务完成延迟概括为:总延迟 = Σ(每轮模型生成时间 + Tool 执行时间)。
因此有三个杠杆:
- 减少轮数:
- 预加载页面上下文。
- 提高模型能力:更聪明但单轮更慢的模型,有时反而拥有更低的总延迟,因为它规划更好、调用轮数更少。
- 并行调用独立工具。
- 加速 Tool:
- 优化后端接口。
- 在参数生成完成后立即执行:单个工具调用的参数已经完整,但模型还在继续生成后续工具调用或文本时,框架就可以先执行这个工具。
- 也可以要求模型“最慢的 Tool 先输出”,这样减少整体时长。
- 加速生成:通过 Eval 能力来选择与平衡速度和效果。
2.2. 感知延迟优化
在总耗时相同的情况下:
- Tool 参数一边生成,前端一边渐进渲染组件。
- 工具执行期间展示“正在查找临水酒店”之类的进度信息。
这样用户看到的是推进过程,而不是五秒钟的加载动画。
2.3. Prompt caching 优化
推荐的上下文顺序是:
Global:全局稳定内容
Session:用户/会话内容
Volatile:当前时间、页面等易变内容
缓存是前缀匹配的。把时间戳放在 System Prompt 顶部,会导致后面的缓存全部失效。Anthropic 称其见到的优秀电商 Agent 可以达到 90%–99% 缓存命中率。
2.4. 模型选择
更大的模型:更好的理解、规划和工具调用,更高单 token 成本;生成可能更慢。
更高的 effort:更充分的推理和检查;更多推理时间和 token。
更小模型/低 effort:单次调用更快、更便宜;可能多走几轮、出错或任务失败。
2.4.1. 明确目标
先定义究竟要优化什么,以及不可突破的底线。例如购物 Agent 可以定义:
- 任务完成率 ≥ 92%。
- 商品信息有据可查率 ≥ 99%。
- 推荐相关性 ≥ 4.2/5。
- p50 总延迟 ≤ 4 秒(代表普通用户体验)。
- p99 总延迟 ≤ 15 秒(代表最慢的那部分用户体验)。
- 每个成功任务成本 ≤ 0.08 美元。
2.4.2. Sweep
其实就是模型 + effort,排列组合测试,比如:
Sonnet + low effort
Sonnet + medium effort
Sonnet + high effort
Opus + low effort
Opus + medium effort
Opus + high effort
测试样本要尽量对准线上流量分布,比如:
60% 简单商品查询;
25% 多条件推荐;
10% 售后处理;
5% 复杂购物规划。
不同模型对于不同 Prompt 的适配程度是不一样的,所以如果 prompt 不变的话,其实测的是模型能力 + Prompt 与该模型的适配程度。
Anthropic 建议流程是这样:
- 先用相同基线 Prompt 跑 Sweep。
- 查看每个候选模型的失败案例。
- 针对明显的 Prompt 不适配做几轮有限迭代。
- 再进行比较。
- 记录每个模型使用的 Prompt 版本。
否则很容易因为一个为 Sonnet 长期调优的 Prompt,对 Opus 或更小模型作出不公平判断。
2.4.3. 最终选择
选择分数高的,但是如果有分数接近的,选能力更强的配置。原因:
- 更好的复杂请求覆盖。
- 更低的长尾失败率。
- 给未来新增功能留下能力余量。
- 更少的 Prompt 特例和补丁。
- 更好的用户采用率、复用率和留存。
整体流程:
定义业务指标和硬底线
↓
用真实流量构成建立 Eval
↓
Sweep 模型 × effort
↓
分析各配置失败案例
↓
有限度地适配各自 Prompt
↓
重新测质量、任务总延迟、成功任务成本
↓
剔除不满足硬底线的配置
↓
在剩余配置中选择最佳性价比
3. 产品化
3.1. 记忆设计
3.1.1. 记忆不是完整聊天记录,是结构化事实
Anthropic 不建议把所有内容长期放在一份 Markdown 用户画像里。小规模时这样简单,但生产系统通常会遇到:
- 用户事实越来越多。
- 需要按字段查询。
- 其他业务系统也需要读取。
- 某些字段要触发确定性规则。
- 要支持权限、修改、删除和保留期限。
- 要与已有用户、门店和账号数据关联。
因此,最终应该使用业务数据库,把每条记忆保存为小型、带类型、带来源的事实记录。
3.1.2. 记忆治理
- 建立允许保存的记忆类型,并在写入路径用代码校验,比如:
ALLOWED_MEMORY_TYPES = {
"shoe_size",
"default_store",
"dietary_constraint",
"fulfillment_preference",
"preferred_report_metrics",
}
- 建议记忆必须进入数据权利流程,用户能看到系统记住了什么,也可以改正错误事实。
- 偏好会过期,几年前的鞋码、地址或常用门店可能已经失效,因此要设置更新/失效策略。
3.1.3. 记忆写入
做成异步的,比如一个工具 save_memory() 让 Agent 调用(依赖 Agent 的推理能力,可能还需要给 Agent 一个 tool output),或者固定时机保存记忆(每轮对话结束)。
并且,记忆保存工具只能读用户和助手文本,避免把 tool_result,比如商品描述,错误地存成用户偏好,更安全。

3.1.4. 记忆读取
根据频率分层,通常为 3 层:
- 每轮固定携带:适合几乎所有请求都会使用的小量事实,比如默认门店、默认配送方式、关键安全约束。
- 根据当前请求预取:根据当前页面、请求类型或预加载的 Skill,提前查询相关事实,比如:
用户搜索鞋子
→ 预取鞋码、常购品牌、宽脚偏好
- 通过 Tool 按需查找:低频、数量较多、当前是否需要无法提前判断的事实,通过
lookup_memory()工具实现。
3.2. 安全设计
Prompt 负责表达规则,Harness 负责强制规则。
3.2.1. 关键动作,模型不能直接提交
比如广告的下单,Agent 最好从根本上不要有这个工具,而是让用户点击按钮来调用后端接口。
3.2.2. 通过 harness 来维护一个可访问资源
Harness 维护一个本会话允许访问的 ID 集合:
allowed_product_ids
allowed_order_ids
allowed_campaign_ids
allowed_change_ids
写操作和展示操作只接受这些 ID。
3.2.3. UI 展示也只接收 ID
展示工具不应该让模型直接传完整的商品或订单对象,因为可能会有幻觉。
bad case:
{
"name": "某商品",
"price": "1 元",
"availability": "现货"
}
good case:
{
"product_ids": ["p_123", "p_456"]
}
然后服务器自行补全。
3.2.4. 第三方信息消毒
如果要用到外部信息(评论、弹幕、商品描述、竞品网页等),需要对内容进行消毒(Sanitize),防止提示词注入攻击:
移除控制字符;
移除双向文本控制字符;
破坏伪造的消息角色和 Tool Call 格式;
防止伪造系统所使用的内容边界标记;
限制最大长度;
使用固定标签和 fence 包裹。
3.3. 评估
3.3.1. 主要评估结果,不要过度锁死调用路径
因为多个路径都可能得到正确结果。严格限制路径会导致:
- 测试非常脆弱。
- 模型升级后无意义失败。
- 阻止更高效的新策略。
- 团队开始为了通过测试而过度提示模型。
3.3.2. 不推荐用模拟用户作为主要度量
Anthropic 认为主要有几个原因:
- 用户模型是随机的。
- 被测 Agent 也是随机的。
- Judge 仍然是随机的。
- 需要更大样本才能稳定。
- 失败时不容易定位是谁造成的。
- 成本高、运行慢。
它适合:
- 探索未知失败。
- 发现 Eval 覆盖盲区。
- 做总体体验检查。
3.3.3. 正例 + 负例
Anthropic 认为,每个 should serve 都有 should refuse,每个 should ask 都有 should just do it,否则 Agent 很容易通过一种“过度保守策略”取得虚假的高分:遇到任何情况都追问或拒绝。
positive:
用户要求退款,符合条件 → 应该暂存退款
negative:
不符合条件 → 应该拒绝
缺少订单 → 应该追问
已有足够信息 → 不应该多余追问
4. 组织协作
业务 Agent 通常会涉及多个团队一起开发,每个团队都有可能改其中的组件,Agent 没有传统微服务那么强的模块隔离。所有内容最终进入同一个上下文窗口,影响同一个模型决策。Anthropic 不建议做 subagent 来隔离,原因如上。所以通过以下方式来解决。
4.1. 所有权跟随业务系统
每个 Tool 和 Skill 必须有唯一 owner,例如:
定价团队:
pricing-promotions Skill
promotion tools
客服团队:
customer-care Skill
order/return tools
库存团队:
inventory-operations Skill
inventory tools
共享 System Prompt 则分层管理:
- 通用部分由 Agent 平台团队统一拥有。
- 领域段落由对应领域团队负责。
- 最终仍要有一个平台级 owner 对整体负责。
重点是避免:
- 多个团队都能随意修改同一个 Skill。
- Tool 出问题时找不到负责人。
- Prompt 成为没有所有者的公共文档。
- 每个团队只对局部分数负责,不对整体 Agent 负责。
4.2. 每个变更必须带 Eval Case
团队提交新的 Skill 或 Tool 时,不能只交付实现,还要交付:正例、负例、边界案例、交叉案例……
本质是要写好可执行测试。
4.3. Eval 每次只跑影响范围
完整的很慢很贵、有随机性。只跑部分案例,例如:
- 修改 Skill:Skill 自身案例 + 相邻 Skill 的交叉案例。
- 修改 Tool:所有会调用该 Tool 的案例。
- 修改展示组件:相关 UI 和引用位置案例。
- 修改共享 System Prompt:完整 Eval。
- 修改安全框架:全部安全、写入、权限、注入案例。
5. 总结
四部分如何形成闭环:
用户请求
│
主 Agent 进行判断
│
┌───────────────┼────────────────┐
│ │ │
Memory 提供 Tools 连接业务 Skills 提供流程
跨会话上下文 系统能力 知识
│ │ │
└───────────────┼────────────────┘
│
Harness 强制执行
权限、ID、限额、审批、串行化
│
产生最终业务状态
│
Evals 验证结果和边界
│
CI、Canary、开关控制发布
│
生产事故沉淀为新 Eval
每层解决不同问题:
| 层 | 负责什么 | 不应该负责什么 |
|---|---|---|
| 模型 | 理解、判断、规划、选择 | 最终授权和强制安全 |
| Memory | 保存可复用的用户事实 | 无限制保存所有聊天 |
| Skill | 提供领域流程和程序性知识 | 绕过后端规则 |
| Tool | 连接现有业务能力 | 重新实现整个业务系统 |
| Harness | 权限、校验、审批、不变量 | 依赖模型自觉遵守 |
| Eval | 检测行为和业务结果 | 只测调用路径 |
| 发布流程 | 控制变更影响面 | 把 Prompt 当普通文案上线 |