遥望星星
发布于 2026-09-08 / 13 阅读
0

朋友问我“为什么要用 9 个 Agent”,我愣了一下

朋友问我"为什么要用 9 个 Agent",我愣了一下

离职之后时间归自己,接了朋友那边一个活:给他们的客服系统加一层 AI。

两周前他过来看进展,我打开架构图讲了二十分钟。他盯着那张图看了一会儿,问了一句:

"为什么要用九个?一个不行吗?"

我张嘴就想解释,然后发现自己说不出一句完整的话。

不是没理由,是理由太多、太碎,而且没有一条是当初决定要拆九个时想过的。实际情况是:路由太乱,拆一个;上下文太长,拆一个;输出什么话都敢说,加一个审核;转人工时上下文丢了,加一个工单生成……九个是长出来的,不是设计出来的。

那天下班我把这个问题重新想了一遍。这篇是复盘,写给同样在搭 Agent 系统的人,也写给我自己——下次再被问,我不想再愣。

先说结论

多 Agent 和单 Agent 的区别不在"能力",在"工程"。 九个 Agent 不会让系统变得更聪明,它让系统更容易改、更容易测、更容易定位问题。代价是编排复杂度和延迟。

拆分 Agent 的依据不是功能模块的数量,是失败域:两件事会不会在同一个上下文里互相污染?其中一个挂了会不会拖垮另一个?它们的权限等级是不是一样?

按这个标准,我那九个里有三个其实可以合并。我没合,原因后面会说——那个原因本身也挺说明问题的。

一、单 Agent 到底卡在哪

先把问题问反:不用多 Agent 会怎样。

假设一个 Agent 处理完整的客服流程,prompt 里写完所有业务规则,挂上全部二十来个工具。它会在下面五个地方依次出问题。

1. 上下文污染

这是最要命的一个,也是多 Agent 最大的收益来源。

一个用户会话里,前几轮查订单的返回、中间知识库检索的片段、后面情绪判断的分析,全都堆在同一条 message list 里。到第十轮,模型要在几千 token 里翻找有用信息——它能翻到,但注意力是被稀释的。

更麻烦的是跨任务串味。举个实际会发生的:

用户:你们退货政策是什么?
(知识库返回:7 天无理由,需保持包装完好)
用户:那我这个订单能退吗?

模型很容易直接把上一轮的知识库结论套到这个具体订单上,跳过实际校验——订单是不是超过 7 天、是不是特价商品、是不是已经用过优惠券。它答得太顺了,顺到根本不会去调订单接口。

这类错误的恶心之处在于它不是答错,是答得太自信。单 Agent 里,前面任务的中间结论会被后面的推理当成"已知事实"直接引用,而这个引用过程你是看不到的。

2. 工具越多,选得越不准

这条有公开的基准数据,不是体感。

LangChain 在 2025 年 2 月发过一个 ReAct 基准测试:同一个日历调度任务,在只有一个业务域时 o1 拿到 71%、o3-mini 68%;把域数扩到七个以上(每个域只有两三个工具),o1 基本没掉,o3-mini 大幅下滑,GPT-4o 掉到 2%,Llama-3.3-70B 直接 0%——它干脆不再调用 send_email 了。

注意这个实验的设计:工具总数并不夸张,变的是干扰项的数量。模型不是能力不够,是选择空间把它淹没了。

另一篇论文《少即是多》(Less is More)给出了更直接的对照:Llama 3.1 8B 面对 46 个工具时基准测试失败,把工具集减到 19 个就通过了。作者的结论是,症结在 context confusion(上下文混淆),不在于上下文窗口的大小——也就是说,你换 200K 上下文的模型也解决不了这个问题。该团队后来加了一层"工具推荐器",先用 LLM 挑出相关子集再交给执行模型,BFCL 上性能提升了 44%。

业界比较一致的经验阈值是单次请求暴露的工具控制在 20 个以内。超过之后函数调用准确率会明显下滑,而且这些失败里的大头不是"选错工具",是"工具选对了、参数填错了"——有统计说参数类错误能占到失败的六到七成。

回到客服场景:查订单、查物流、查历史订单、查退款进度、查优惠券——这五个在模型眼里的语义距离,比你设计的近得多。

3. 权限没法分级

客服系统里的工具,危险等级差得很远:

  • 查订单:只读,随便调
  • 改收货地址:写操作,得验证身份
  • 发起退款:涉及钱,必须有明确的用户意图 + 二次确认
  • 查用户手机号:PII,得脱敏

单 Agent 里这些工具是平铺的,模型"想调就调"。你当然可以在每个工具内部做校验,但有个隐藏问题:模型知道自己有这个能力。当系统提示里写着"你可以发起退款",它在组织回复时的语气、承诺的分寸,会不一样。

权限不只是执行时的拦截,还影响模型的行为边界。

4. 出 bug 定位不到

单 Agent 的失败是"整体失败"。

用户投诉说 AI 胡说八道,你打开日志,看到的是一长串 message、几次工具调用、一段最终输出。你说不清是检索召回错了、工具参数填错了、还是推理跑偏了。更糟的是,很可能是三个都有一点。

能定位的问题才是能修的问题。定位不了,就只能改 prompt 碰运气——改完也不知道是不是真的好了。

5. 改一处动全身

业务规则变了,要改"退货政策"这块。但你的 prompt 里,退货政策、物流查询、投诉安抚三块规则是写在一起的,彼此之间还有交叉引用。改完你不敢只测退货,得把所有场景过一遍。

这已经是微服务讲过一遍的故事了,只不过在 Agent 系统里,耦合发生在自然语言里,比代码耦合更隐蔽。代码耦合编译器会告诉你,prompt 耦合不会。

二、那 9 个是怎么分的

下面是我现在的分工。需要说明的是:这张表是事后整理的,不是一开始就设计好的。

# Agent 干什么 挂什么工具 为什么必须单独
1 Router 意图分类 + 分流 无(纯分类) 它要的是快和准,不能带业务上下文
2 SlotFiller 多轮追问,收齐必要信息 无 拿半个订单号去查是个高频 bug
3 Knowledge 产品/政策问答 向量检索 检索片段要隔离,不能污染决策
4 OrderQuery 订单/物流查询 订单 API(只读) 只读,权限等级最低
5 AfterSales 退货退款处理 售后 API(写) 写操作,必须单独限权
6 Complaint 情绪识别 + 安抚 + 升级判断 无 回复风格和其他场景完全不同
7 Ticket 转人工时生成结构化工单 工单 API 输出是给人看的,格式要求不同
8 Guardrail 输出前合规审核 敏感词/PII 规则 必须独立于生成过程
9 Responder 汇总各路结果,生成最终回复 无 隔离"事实"和"表达"

其中我觉得拆分理由最硬的是这四个:

Router 必须独立。 路由是每一轮都要跑的,对延迟最敏感。它应该是纯分类,系统提示短、不带业务知识、用便宜的小模型。如果你让主 Agent 顺带做路由,那每一次路由都在为用不上的上下文付费。

Guardrail 必须独立。 审核逻辑如果和生成逻辑在同一个 Agent 里,等于让一个人既写又审。不是说他一定会包庇自己,而是他在生成的时候就已经知道要通过什么标准了——这会影响他的措辞。独立出来,它是一个不知道生成过程的第三方。

OrderQuery 和 AfterSales 必须分开。 因为它们权限等级不同。读和写放在一个 Agent 里,你没法在 Agent 层面说"这个会话只能读"。分开之后,路由到 AfterSales 之前可以强制插入身份校验,这是架构级的保证,不是 prompt 级的请求。

Knowledge 必须独立。 就是前面说的串味问题。检索回来的片段只应该存在于 Knowledge Agent 的上下文里,它输出的是"基于资料,政策是 X",而不是把三段原文塞进主上下文让后面的推理自己去读。

三、多 Agent 带来的真实收益

按我觉得的重要性排个序。注意排第一的不是"能力"。

1. 上下文隔离(最大收益)
每个 Agent 只在自己的小上下文里工作。Knowledge 的检索片段不会跑进 AfterSales 的决策里,上一轮的情绪分析不会污染这一轮的订单查询。串味问题从根上被削弱了。

2. 权限分级
可以在 Agent 层做权限,而不是在工具层。路由到写操作 Agent 之前插一道身份校验,这是架构保证的,不是求模型别乱来。

3. 每个 Agent 的工具集变小了
这是上一个问题的直接解。拆完之后,OrderQuery 只挂订单相关的三四个工具,AfterSales 只挂售后的两三个。单个 Agent 面对的工具数降到个位数,选择准确率自然上去。这比"在一个大 Agent 里写更好的工具描述"有效得多——你是在减少干扰项,不是在优化描述。

4. 可测试
每个 Agent 可以单独跑评测集。Knowledge 的召回准确率、Router 的分类准确率、Guardrail 的拦截率,各测各的。出了问题能定位到单个 Agent。这一条我认为是多 Agent 最被低估的价值——它把"端到端效果不好"这个模糊问题,拆成了几个可以分别测量的具体问题。

5. 可观测
每个 Agent 单独打点:耗时、token、失败率、重试次数。你能看到"最近售后场景变慢了",而不是"系统变慢了"。

6. 可替换
某个 Agent 想换模型、换 prompt、换策略,影响范围是确定的。Router 换便宜模型,只影响路由准确率这一个指标。

7. 并行
几个无依赖的 Agent 可以同时跑。不过说实话,客服场景里能并行的机会不多——大部分时候下一步依赖上一步的结果。

四、代价:这部分我也确实付了

只讲收益不讲代价的文章都是软文。下面是我真实付出的东西。

编排复杂度
你得自己处理:Agent 之间传什么、失败怎么重试、超时怎么降级、结果怎么合并。Spring AI 也好、AgentScope 也好,框架给的是基础能力,编排逻辑得自己写,而且这部分代码会越来越像业务代码——也就是说,它会开始有自己的 bug。

延迟
串行调用是累加的。Router → SlotFiller → OrderQuery → Guardrail → Responder,五个 Agent 就是五次模型调用。即使每个只要 800ms,加起来也 4 秒了。

我们的做法是:能并行的一律并行,Guardrail 尽量用规则而不是再调一次模型,Responder 用小模型而不是主模型。

但不管怎么优化,多 Agent 相比单 Agent 的延迟开销是实打实的——每多一跳就多一次模型调用,这个下限省不掉,只能靠并行和小模型去摊薄。如果你的场景对首字延迟很敏感,这一条可能直接一票否决。

上下文传递的损耗
这是最隐蔽的代价。Agent A 知道的东西,Agent B 不一定知道,你得显式传递。传少了信息丢失,传多了又回到了上下文膨胀。

我现在的做法是每个 Agent 只输出结构化结果而不是自然语言,下游 Agent 拿到的是干净字段。这能解决大部分问题,但需要你为每个 Agent 定义清楚输出 schema——这本身就是工作量。

回复风格不一致
九个 Agent,九套 prompt,很容易出现"问订单一个语气,问售后另一个语气"。最后必须有一个统一的 Responder 来收口,这是为什么第 9 个 Agent 存在。

成本
多次模型调用就是多倍的 token。Router 和 Guardrail 可以用便宜的小模型顶掉一部分,但总量一定是上升的。

这笔账要算清楚:你换来的是可维护性和可测试性,付出的是真金白银的推理成本。值不值,取决于你这个系统是跑三个月还是跑三年——短期项目拆九个 Agent,大概率是亏的。

五、什么时候不该拆

这部分我觉得比前面都重要,因为大部分多 Agent 系统是不该拆的。

下面这些情况,拆了纯属自找麻烦:

  • 任务之间没有上下文污染风险。 单轮问答、输入输出都短,一个 Agent 就够了。
  • 工具少于 5 个。 工具选择准确率还没成为瓶颈。
  • 你的问题其实是"工具太多"。 这是个容易误诊的地方。工具超过 20 个导致准确率下滑,正确的第一反应不是拆 Agent,而是做 tool loadout——先用一层便宜的检索或分类挑出本次请求相关的工具子集,再交给执行模型。拆 Agent 能顺带解决工具数量问题,但如果你真正的痛点只有这一条,拆 Agent 是重药。
  • 不需要多轮。 一次调用解决问题,没有会话状态要管理。
  • 没有权限分级需求。 所有操作都是只读,拆开没有架构收益。
  • 没人维护编排层。 这个最现实。多 Agent 的复杂度是持续成本,团队里得有人能 hold 住。如果只有你一个人写,你想清楚离职之后谁接手。
  • 延迟极度敏感且无法并行。 每一步都依赖上一步,拆开就是纯加延迟。

一句话:如果你的理由只是"功能模块多",那不该拆。 功能模块多可以用一个 Agent 加工具解决。

六、现在我会怎么回答那个问题

回到开头。如果朋友现在再问我一次,我会这么说:

不是因为需要九个。是因为有六个地方,它们要么会在同一个上下文里互相污染,要么权限等级不一样必须分开限权。剩下三个——SlotFiller、Ticket、Complaint——其实可以合并回主流程,我没合是因为分开之后每个都能单独测,合并了我不知道怎么保证改动不出问题。

这个答案不漂亮,但它诚实。而且它暴露了一个真实的取舍:我把"可测试性"排在了"简洁性"前面,这是我自己的偏好,不是技术上的必然。

最后:一个能直接用的检查清单

下次你要决定某两块逻辑要不要拆成两个 Agent,问自己五个问题:

  1. 它们会在同一个上下文里互相污染吗?
  2. 其中一个失败了,另一个还能正常返回吗?
  3. 它们的权限等级一样吗?
  4. 你会想单独给其中一个换模型或换 prompt 吗?
  5. 你能单独为它写测试用例吗?

有两个以上回答"会 / 不一样 / 会 / 能",就拆。否则别拆。

这套标准的价值不在于让你拆对,在于让你能说出为什么拆。被追问的时候不愣住,这本身就是工程能力的一部分。


技术是自己的,账也是自己的。九个 Agent 是对的还是错的,我现在其实还不敢下结论——等这套系统跑满三个月,有了足够的线上数据,我再来写一篇复盘。

[]