先交代前提:这篇东西不是论文,也不是产品文档,更像是我自己从单体 Agent 一路折腾到 Multi-Agent 框架之后的复盘笔记。如果你正在用单体 Agent 做稍微复杂一点的业务,比如多步工具调用、多角色协作、长流程执行,大概率迟早会撞上那面墙。我撞过一次之后,才真正理解那句“复杂任务必然走向 Multi-Agent”并不是在追技术时髦,而是在解一道工程题。
1. 从一次失败的 Agent 调试说起
1.1 我原来的架构:所有能力塞进一个 Agent
我这个项目起初的目标是一个“工作流Agent”,负责处理用户从需求描述到最终交付的全流程。比如用户说“帮我把这批客服工单做分类、提取要点、再生成一份周报草稿”,我希望 Agent 自己完成意图理解、数据读取、分类执行、摘要生成、表格输出,全程不需要人工介入。
所以我一开始的设计特别简单粗暴:一个 Agent,三个工具(读工单、写临时文件、调LLM做摘要),再加上一个系统提示词,把所有要求都写进去——你要什么时候调用工具、输出格式是什么、遇到模糊表述怎么处理、多轮修正怎么回到主干。技术栈选的也是一个开源的思考模式框架,支持 ReAct 式的思考-行动循环。
这个方案在演示阶段非常顺。简单的工单,比如“退货流程太慢”“物流信息不更新”,Agent 能准确读取数据、输出分类结果和摘要。但一旦上了真实业务,问题就来了。
1.2 第一个翻车现场:上下文污染和工具误调用
我记得特别清楚的一条线上真实工单:用户先是投诉物流,然后又在后续补充里提到了退款金额和发票问题。整个上下文包含多轮对话、历史工单详情、外部知识库片段。我的单体 Agent 在处理到中途时,突然做了一件事——它把一个无关工单里的客户姓氏当成了当前投诉人,直接在摘要里写错了人。
调日志的时候我发现,Agent 在执行一次工具返回后,把返回内容原封不动塞回了对话历史,然后又基于这段历史继续推理。一个人的对话轮次有限,但工具返回的数据量和上下文长度是动态涨的。单一模型面对几百条历史记录加多个大段JSON时,注意力全部散掉,早期指令的遵循度肉眼可见地下降,工具调用也开始“手滑”。
更让人崩溃的是,Agent 在角色上是“全能的”,它没有某个独立模块来专门负责校验输出和纠正错误。它判断“自己错了”只能靠重新推理,推理错了那就整个流程崩掉。这让我意识到,单体 Agent 遇到复杂任务,问题不是模型不够聪明,而是“一个脑子干三个流程”这件事本身就不合理。
2. 单体 Agent 的天花板到底在哪
2.1 上下文窗口不等于有效注意力
很多人一看模型支持 200K token,就觉得单体 Agent 可以无限塞信息。但实操下来我最大的体会是:上下文长度是容量,不是质量。当上下文里面混杂了系统指令、用户诉求、工具返回、历史修正记录、临时思考过程,模型真正能稳定依赖的其实就是最近的几万 token。超过这个范围,它可能出现两类问题:一是遗忘早期关键约束,比如“只允许调用白名单内的工具”;二是被中段某个明显无关的信息带偏,输出幻觉内容。
我在一段专门做的对比实验里,把同样一个分类任务分别放在 20K 和 80K 的上下文里跑,前者的准确率波动在 3% 以内,后者则出现了接近 10% 的随机波动。这个波动不是模型能力差异,而是注意力分布导致的“决策不稳定”。单体 Agent 在复杂任务里要保留大量中间状态,这必然挤压有效注意力空间。与其指望模型扛住,不如从架构上把上下文拆开。
2.2 工具越多,权限与边界越难管
单体 Agent 的第二个问题,是工具边界模糊。当我给一个 Agent 同时挂上“读取数据库”“发送邮件”“修改工单状态”“调用支付接口”这些工具时,它实际上拥有的是一个全局权限。哪怕在提示词里反复强调“只有用户明确要求才能调用写操作”,它依然会在某些模糊场景下做出过度操作。
我做了个测试:让 Agent 在处理售后需求时,主动调用了支付接口查询用户历史订单。这在功能上不算错误,但业务上越权了。单体 Agent 没有天然的“最小权限原则”,所有工具对它来说都是平等的。而 Multi-Agent 系统里,“付款相关Agent”和“物流查询Agent”是分开的,前者根本没有读取物流信息的工具权限,越权行为在结构上就不可能发生。
2.3 记忆与长期任务的漂移问题
单体 Agent 还有个大坑,就是长时间执行后“人格漂移”。它原本被设定成严谨审慎的风格,但执行几十步工具调用之后,回答问题开始变得简略、口语化,甚至忘记自己最初的角色设定。这是因为系统提示词被淹没在巨大的对话历史里。
为了对抗这个问题,我试过把系统提示词重复塞进上下文,也试过定期压缩历史。但一切都是打补丁,不能根治。根本原因在于单体架构只有一个记忆容器,不管是长短期记忆都要在这个容器里读写。而 Multi-Agent 天然把“哪个角色负责什么、记忆归属于谁”做了划分。比如分析 Agent 只需要保留分析上下文,报告 Agent 只需要接收结构化结果。记忆被分区,漂移概率大幅下降。
3. 复杂任务拆解:Multi-Agent 不是噱头
3.1 任务分解是根,角色划分是果
我后来重新设计了系统。第一步不是立刻写 Multi-Agent 代码,而是把业务任务做完整拆解。以“客服工单处理”为例,我的拆法是这样的:意图识别与分类是一个阶段,信息抽取是一个阶段,分析决策是一个阶段,最终报告生成又是一个阶段。
每个阶段天然对应一个子 Agent,它有自己独立的系统提示词、工具集和输入输出协议。我管这种结构叫“流水线式职责划分”。这样做的好处第一是提示词可以写得非常聚焦,比如分类 Agent 只需要遵循一个分类体系,完全不需要知道报告长什么样;第二是每一个 Agent 的上下文都很干净,输入是上一级 Agent 吐出的结构化结果,不包含整个工单的原始内容。
更关键的是,任何一个子 Agent 出错,修复成本都极低。原来单体 Agent 出错了,我得猜是哪个步骤逻辑有误;现在出错,直接定位到对应 Agent,改它的提示词或工具逻辑,其他环节完全不受影响。
3.2 协作协议:从“单脑子”到“小组开会”
Multi-Agent 不是简单地把代码拆成多个函数,它真正的核心是协作协议。我自己早期犯过一个错误:让多个 Agent 直接传自然语言文本,结果信息传递不完整,下游 Agent 不得不反复回头问问题,效率反而比单体还差。
后来我改成了结构化的协作协议,每个 Agent 的输出都必须遵守一个DAG(有向无环图)上下文模型,比如分类 Agent 只输出 JSON 字段order_id, category, confidence, reason,下一个分析 Agent 只读取这些字段,不再处理原始文本。
协作协议里还需要定义三种基本交互模式:串行(A完成后B再开始)、并行(多个 Agent 同时处理不同子任务)、主从(一个 Planner Agent 下发任务,多个 Worker Agent 并行执行并把结果汇总回 Planner)。我实际项目里用得最多的是主从模式,因为大部分复杂任务都可以拆成“规划-拆解-并行执行-汇总决策”四步,这个模式天然适合人工介入监督。
4. 落地实现:从单体到 Multi-Agent 的实战迁移
4.1 基础设施:模型、框架与消息总线
这块大家最关心的就是技术选型。我用过几种路线:直接用 LangChain 的 AgentExecutor 搭多智能体,也试过 AutoGen 的双人对话模式,最后我的生产环境是自己封装的一层轻量消息总线。
核心组件分四块:任务入口(接收用户请求)、Planner(负责拆解任务并生成执行计划)、Worker 池(每个 Worker 是独立 Agent,负责具体子任务)、汇总器(收集所有结果,做结构化和冲突检测)。这四块通过一个消息队列通信,消息格式统一用 JSON。
实现消息总线的时候,我重点解决两个问题:一是消息的幂等性,同一个请求不能被重复执行;二是任务的依赖关系。最开始我用简单的队列,结果并行 Worker 都把结果写回汇总器,汇总器不知道先处理谁的结果。后来参考了工作流引擎的思路,给每条消息加message_id和depends_on字段,做一个轻量的调度判断,问题就解决了。
代码示例我这里给个参考:
# 简化的消息结构 class AgentMessage: def __init__(self, msg_id, sender, recipients, payload, depends_on=None): self.msg_id = msg_id self.sender = sender self.recipients = recipients self.payload = payload self.depends_on = depends_on4.2 一个可复用的 Multi-Agent 实测示例
我用一个具体的例子说明完整流程:假设我现在要让系统自动处理一批工商投诉,诉求是“分类 + 风险评级 + 周报生成”。
第一步,Planner Agent 接受到原始请求后,把任务拆成三个子任务:任务A是对投诉内容做分类(消费纠纷、合同违约、售后服务);任务B是对每一条投诉做风险评级(高、中、低);任务C是把分类和评级结果制作成一份 Markdown 周报。
第二步,任务A和任务B之间其实是并行的,因为它们都只需要原始文本输入,互相不依赖。两个 Worker 同时开工,各自只处理分给自己的那部分内容。任务C 要等A和B都完成才开始。
第三步,风险评级的 Worker 在输出结果时,额外抛出了一个“高风险工单”的信号,按照协作协议它会生成一条只发给汇总器的消息,提示要对某条工单做额外复核。这个场景里,单体 Agent 要做到这个逻辑,需要写复杂的分支处理和状态判断,而 Multi-Agent 架构下,这是天然的消息路由。
我强烈建议做迁移的朋友,不要一上来就套用复杂框架,先手动定义好你项目的 Agent 之间收什么消息、发什么消息,用一个脚本模拟一遍,再上框架。这套流程走通了,比直接调库结实得多。
4.3 编排模式:串行、并行与层级
编排模式决定了一个 Multi-Agent 系统的复杂度和稳定性。我按实战经验总结一下:
串行模式适合有严格先后顺序的阶段任务,比如“先提取,再分类,最后生成报告”。这个模式结构最简单,缺点是慢,因为每个环节都要等前一个完成。并行模式适合互不依赖的独立子任务,比如同时分析多个渠道的反馈。我一般用concurrent.futures或 asyncio 做并行调度,能把总体耗时从“所有任务之和”降成“最重任务的耗时”。
层级模式是现在主流,也就是 Planner 负责拆解和调度,中间可以再有一层 GroupLeader,下面挂多个 Worker。层级的好处是每个节点的职责都清晰可查,而且可以部分重试。比如某个 Worker 执行失败了,Planner 只需要单独重新分发这个子任务,而不需要整个流程重来。这一点在生产环境的运营压力下非常值钱。
5. 避坑实录:Multi-Agent 不是银弹
5.1 我踩过的 6 个大坑
先说结论:Multi-Agent 的复杂度是真实存在的,用不好反而比单体更难维护。
第一个是消息爆炸。每个 Agent 都可能给其他 Agent 发消息,当 Agent 数量从3个涨到8个时,系统里的消息路径不是线性增长,而是平方级增长。这时候没有消息协议和过滤机制,整个系统会变成一群人在会议室里各说各话。
第二个是“级联幻觉”。单体 Agent 产生幻觉,影响只限于一次输出;Multi-Agent 系统里,一个 Agent 的幻觉会沿着消息链路传到下一个 Agent,下一层基于错误数据继续生成,问题被放大。我现在强制所有跨 Agent 的消息携带confidence字段,低置信度的信息必须触发复核节点。
第三个是死锁。两个 Agent 循环等待对方的情况,在任务依赖关系复杂时很容易发生。我用了带超时机制的消息总线,每条消息在指定时间没收到响应就触发 Plan B,避免整个流程挂死。
第四个是角色重叠。如果两个 Agent 的职责边界不够清晰,比如分类 Agent 和意图识别 Agent 都能处理“判断用户想干什么”,就会产生结果冲突。我最后用了一个简单的权责表,把每个 Agent 能处理的意图和能调用的工具全部显式列出来,不允许交叉。
第五个是调试难。单体 Agent 出问题,看一遍日志基本就能定位;Multi-Agent 出问题,经常是消息链路里的某个中间状态不对。我后来的做法是把所有 Agent 之间的消息都录制下来,用一个可视化的时间线工具回放,这样排查效率高很多。
5.2 什么场景下真的不建议上 Multi-Agent
实话说,做了这么久 Multi-Agent,我也学会了一个道理:很多任务根本不该用 Multi-Agent。
比方说单轮问答、简单的信息抽取、格式转换、一次性的文本改写,这些用一个高情商单体 Agent 完全能解决。你硬拆成多智能体,反而要把大量时间花在消息结构设计和错误处理上,还要忍受额外的 token 开销和延迟。
我自己的经验是,要不要上 Multi-Agent,先看两个指标:第一个是任务是否需要多个阶段或多种角色来协同,第二个是单个 Agent 的上下文是否能覆盖完整流程且保持稳定。如果两个答案都是否,那就继续用单体,别给自己找不痛快。工具还是服务于业务的,架构只是手段,不是目的。
6. 最后的几句经验心得
我个人的体会是,单体 Agent 没有死,它依然是最快落地、最适合简单场景的形态。但如果你要做复杂的业务系统,Multi-Agent 不仅仅是一个选项,而是迟早要面对的方向。它解决的核心不是“让模型更聪明”,而是让系统可控、可观测、可优雅地失败。
最后再分享一个小建议:你想从单体迁移到 Multi-Agent,不用一上来就重写系统。先把你当前单体 Agent 的日志翻出来,找到最频繁出错的 3 类问题,看看这些错误是不是因为“职责混乱”或“上下文超载”导致的。如果是,那就把对应的环节切出来独立成一个子 Agent,逐块迁移,比一次性推翻整个架构要稳得多。成功案例不是堆出来的,是改出来的。