1. 先想清楚一件事:你真的需要多Agent吗
先说个实在的判断标准。我见过太多人一听说"多Agent"这个词,就觉得单Agent不够高级,恨不得把手里所有任务都拆给好几个大模型,结果做出来的东西不但没有变强,反而更慢、更贵、更不可控。所以这篇博文的第一件事,不是讲怎么搭多Agent,而是帮你判断该不该用多Agent。
多Agent本质上解决的是单Agent的三个硬瓶颈。
第一个瓶颈是上下文窗口。单个Agent能承载的上下文始终有限,你要让同一个模型既做全局规划、又读大量资料、还要输出精细结果,很快就会把上下文塞满,然后开始"忘事"或者胡说八道。把不同职责拆给不同Agent,每个Agent各自维护自己相关的上下文,表面上看起来是多了几个"人",实际上是把一个"撑爆的脑子"拆成了几个"分工明确的脑子"。
第二个瓶颈是角色冲突。一个Agent同时扮演执行者和质检者,或者同时做信息搜集与最终决策,它很难诚实地批评自己。就好像一个人写代码又自己给自己做Code Review,往往会越看越顺眼。把监督、批判、执行拆给不同Agent,让它们互相审视,反而能逼出更高的准确率。
第三个瓶颈是并行与等待。单Agent只能串行思考,多Agent可以让信息搜集、草案生成、数据分析同时进行,在任务拆解合理的前提下,整体耗时有明显下降。这个在"需要汇总多路信息"的场景里尤其值钱。
那什么样的场景不该用多Agent呢?我建议你先对照这张表做一次冷静评估:
| 场景特点 | 建议方案 |
|---|---|
| 任务步骤固定、输入输出简单 | 单Agent加提示词模板就够了 |
| 需要大量背景知识才能回答的问题 | 优先做检索增强,而不是拆多Agent |
| 强依赖全局一致性,不允许各说各话 | 慎用多Agent,除非设计严格的共享状态 |
| 预算非常敏感,每次调用都嫌贵 | 先算账,多Agent通常意味着更多轮模型调用 |
| 任务天然可分、分头处理再汇总 | 这是多Agent的主场,可以上 |
判断的核心原则只有一个:多Agent是架构手段,不是目标。如果你的问题没有"可拆分性"和"角色冲突",上多Agent只会徒增复杂度。
顺带说一句适用人群。这篇内容适合正在做Agent应用的开发者、技术负责人,以及想从单Agent往协作式架构迁移的团队。如果你只是刚接触大模型,建议先把单Agent的提示工程和工具调用跑熟,再回来看这篇会比较轻松。
2. 架构设计:先把"人"和组织架构定下来
很多新手犯的第一个错误,就是一上来就写代码,想着"我创建三个Agent,一个做A,一个做B,一个做C",然后让它们自由对话。这样做的结果是:Agent之间互相扯皮、反复确认、不断偏题,跑出来的东西和预期完全不是一回事。
好的多Agent设计,80%的工作发生在写代码之前。你要先把自己当成一家公司的架构师,设计好这家公司的岗位、汇报关系、协作规则,然后才轮到Agent上场。
2.1 角色定义是第一步
角色不是随便起的名字,它决定了三个关键要素:职责边界、可用工具、输出契约。我习惯用一张角色卡片来定义每一个Agent:
| 字段 | 含义 | 示例 |
|---|---|---|
| 角色名称 | 一句话说明身份 | 需求分析师 |
| 核心职责 | 必须完成的任务列表 | 拆解用户需求、输出任务清单、识别缺失信息 |
| 输入来源 | 它读取谁的消息 | 上游Planner、用户消息 |
| 输出对象 | 它的产物交给谁 | 下游执行Agent、评审Agent |
| 可用工具 | 允许调用哪些外部能力 | 搜索引擎、代码解释器、向量数据库 |
| 输出契约 | 必须遵循的格式模板 | 返回结构化JSON,字段包括task_id、描述、优先级 |
| 禁止事项 | 不允许做什么 | 不可以直接生成最终回复、不可以越过Router联系其他Agent |
举一个我实际用过的例子。做一个"市场分析报告生成系统"(我这里只说方案,不涉具体客户信息),我定义了四个角色:
- Planner:负责把用户的宽泛问题拆成"市场概况、竞品动态、用户反馈、风险建议"四块,并生成任务卡。
- Researcher:负责按任务卡分头检索信息,输出带来源标注的事实清单。
- Analyst:负责对事实清单做交叉分析、提炼结论,输出图表数据。
- Critic:负责审查Analyst的分析是否逻辑自洽、是否有数据支持、有没有遗漏关键角度。
这四个角色的设计逻辑是:信息搜集归信息搜集,分析归分析,审查归审查。任何一个角色跟我说"我要做所有事情",我都会直接砍掉,因为那又回到了单Agent。
2.2 四种编排模式与选择
角色定下来之后,还要决定它们之间怎么"协作"。我把常见模式归纳为四类:
串行流水线式,A做完交给B,B做完交给C,适合步骤固定、依赖明确的流程。优点是简单可控,缺点是一旦中间某个环节出错,后面全跟着错,而且整体耗时是所有环节之和。
并行扇出式,一个Router把任务拆给多个同质Agent分头处理,最后再汇总。适合"同一任务多路信息源"的场景,比如同时读多份文档、同时调研多个方向。这种模式之所以常见,是因为它能显著缩短耗时,但汇总环节容易成为瓶颈,需要设计好合并策略。
主管-下属式,一个Supervisor Agent负责任务分配、结果验收、决定谁下一步行动,下属Agent只负责执行。这种模式适合任务复杂度高、需要动态决策的流程。它是目前多Agent系统里稳定性最好的形态之一,因为决策权和执行权分离了,不容易出现"群龙无首"的场面。
黑板式,所有Agent共享一块"公共黑板"(共享状态区),谁有产出就往上写,谁需要信息就来读。这种模式适合创新探索类任务,比如头脑风暴、多方案对比,但缺点也明显:全局状态很容易冲突,需要花大力气做并发控制和版本管理。
我在实际项目中的选择偏好比较明确:能串行就不并行,能主管-下属就不让Agent自由聊天。因为模型不是人,自由聊天意味着大量无意义的寒暄和确认,而主管-下属式至少还有一个人盯着全局。
2.3 一个经过验证的最小可用拓扑
如果你刚起步,我建议直接照搬这个最小拓扑,不要自己发挥:
用户消息 └──> Router(意图识别 + 任务拆解) ├──> Worker A(执行任务块1,可用工具:检索) ├──> Worker B(执行任务块2,可用工具:代码解释器) ├──> Worker C(执行任务块3,可用工具:数据查询) └──> 结果送入 Merger(合并子结果,生成统一格式) └──> Critic(质检,通过则输出,不通过则退回对应Worker)Router、Worker、Merger、Critic,四个角色就够。这个拓扑的好处是:引入角色少,通信路径短,每一环都有明确的输入输出。我最早自己做的系统是6个Agent乱聊,后来全部推翻,改成这个结构之后才跑稳。
提示:Agent数量不是越多越好。我的经验是,核心执行角色控制在3到5个以内,超过8个,通信和调试成本会急剧上升,收益反而递减。所谓"人多力量大",在Agent协作里并不成立。
2.4 先画协作拓扑图,再写代码
这个方法论值得多说一句。写代码之前,我会先在白板上画一张协作拓扑图:每个Agent是一个节点,每条通信是一条边,边上标注传递的"消息类型"和"触发条件"。
这张图至少能回答三个问题:消息会不会出现环(A依赖B,B又依赖A)?有没有角色接收到的信息超过它能处理的量?哪个Agent是单点故障(它挂了全链停摆)?这些问题在代码里发现再去改架构,代价很大;在图上发现,几分钟就能调整。
3. 通信协议与共享状态:多Agent的"信息总线"
说完角色和流程,接下来是很多人最容易糊弄的部分:Agent之间到底怎么说话、怎么传递状态。不少团队的做法是"让大模型自然语言聊呗",结果聊着聊着就聊飞了。
你以为多Agent是几个聪明人在开研讨会,实际上一旦没有强约束,它更像一群人在没主持人的会议室里各说各话,而且每句话还要收一次钱。所以通信协议必须设计得具体、沉重,而不是自由发挥。
3.1 消息格式:别整散文,要整结构
我要求所有Agent之间的通信,一律使用结构化JSON消息。以一条任务分配消息为例:
{ "message_id": "msg_20240101_001", "msg_type": "task_assign", "sender": "Router", "receiver": "Worker_A", "timestamp": "2024-01-01T10:00:00Z", "payload": { "task_id": "task_json_001", "task_description": "抽取用户需求中的关键实体与关系", "input_refs": ["context://user_request"], "output_refs": ["context://entity_graph"], "priority": 1, "deadline_tokens": 2000, "constraints": ["必须使用提供的抽取模板", "输出字段必须包含entity_name"], "tools_allowed": ["http_client", "code_interpreter"], "reject_policy": "如果需求描述不完整,返回need_more_info" } }看到没有,一条消息里明确定义了:这条任务是什么、输入去哪里取、产出去哪里写、能用哪些工具、token限制是多少、什么条件可以拒绝执行。
我特别想让新手重视的是"output_refs"这个字段。它表示"你的产出写到哪个上下文槽位",而不是让Agent把结果直接发给另一个人。这样做的好处是,Agent不需要在消息里携带大量正文,只需要带上引用地址,需要的时候去读,这能省大量token。
3.2 上下文的分层管理
多Agent系统里,上下文如果全部共享,那必然是灾难。每个Agent都会往里面塞东西,最后谁看到的状态都是半新不旧的,还会互相覆盖。我用的是三层上下文模型:
全局上下文:系统级信息,比如用户原始需求、全局约束、时间截止,所有Agent都可读,但只有Router有写权限。
任务上下文:每个任务单独立一份,包含该任务的目标、输入引用、中间产出。任务上下文默认只有执行该任务的Agent和它的直接主管可读写。
私有上下文:某个Agent的思考过程、临时笔记、个人偏好,只对本人可见,不允许其他Agent读取。
这三层隔离在我做过的项目里非常关键。尤其是私有上下文,它的存在让Agent敢在内部先"打草稿",不需要把不成熟的中间想法暴露给全系统,最终输出的质量明显更稳。
3.3 上下文预算:给每个Agent发"钱"
大模型的上下文长度是成本的核心变量,多Agent系统如果不做预算管理,很容易出现"对话轮数没多少,花费却翻了很多倍"的情况。我的做法是给每个Agent分配明确的token预算。
Router在每轮任务开始时会做一个预算表:
| Agent | 输入上下文预算 | 输出token上限 | 说明 |
|---|---|---|---|
| Router | 4000 | 1500 | 只做拆解和决策,不承载长文本 |
| Worker A | 6000 | 2000 | 读取检索结果,做信息抽取 |
| Worker B | 8000 | 3000 | 生成大段分析内容 |
| Critic | 3000 | 1000 | 只看关键结论,不读全文 |
超过预算的Worker,系统会强制截断或要求其先做摘要再继续。这听起来粗暴,但实测下来能有效抑制"Agent越聊越长、越聊越偏"的通病。模型没有危机意识,你不替它做资源控制,它就替你失控。
3.4 同步与异步通信怎么选
在通信时机上,我的经验是:任务链里的关键节点用同步,普通消息传递用异步。同步调用意味着"我把消息发给你,然后在那里等你的结果",适合上游需要下游产出才能继续的情况;异步意味着"我把消息放进你的信箱,你去处理别的事",适合互不依赖的分头执行。
多Agent系统里最常见的性能瓶颈,就是所有通信都用同步,导致系统变成了"排队等答复"的串行流程。我见过一个项目,明明拆了5个Agent做并行,但因为通信设计全是同步,实际耗时比串行还长。后来我把每个Worker内部处理改成异步轮询,工作流的整体耗时降了40%以上。
4. 任务编排与执行细节:让Agent真正跑起来
光有架构和通信还不够,落地执行的时候,任务编排的质量直接决定了系统能不能稳定运转。这个环节我踩过的坑最多,也是我认为整个多Agent设计里最见功力的地方。
4.1 任务卡:最小可用字段
所谓编排,本质上就是把大目标拆成小任务,然后按依赖关系调度。我给每个任务设计了一套"任务卡"模板,核心字段包括:任务目的、输入数据、输出数据、验收标准、依赖任务、尝试次数上限、可调用工具、超时策略。
其中验收标准这个字段最容易被省略,但它恰恰最重要。没有验收标准,Agent做完一个任务,你根本不知道该不该放行它进入下一个环节。我通常会要求任务卡里至少写两个可验证的验收条件,比如"输出必须包含超过3个有效来源链接""结论必须引用了输入摘要中的至少两个数据点"。
4.2 调度与重试机制
任务跑起来之后,会遇到各种意外:某个Worker超时、某个工具返回异常、某个模型输出格式不对。如果整个系统没有重试与熔断机制,一次小失败就会拖垮整条链路。
我的调度器逻辑一般长这样:
async def dispatch_task(task_card, agent): max_retries = task_card.max_retries # 默认2次 for attempt in range(max_retries): try: result = await agent.run(task_card) if validate_result(result, task_card.acceptance_criteria): return result else: log_failure(attempt, reason="验收未通过") except ToolException as e: log_failure(attempt, reason=f"工具异常: {e}") except TimeoutError: log_failure(attempt, reason="任务超时") # 重试仍然失败,走降级策略 return degrade_task(task_card)这里说几个关键点:
重试不是无脑重跑。如果Agent上一次已经给出了接近合格的答案,重试时应把上一次输出连同失败原因一起塞进提示词,让它"基于上次的未通过原因进行修订"。纯重跑大概率还会犯同样的错。
失败降级要有兜底策略。如果Worker A彻底失败,至少要有一个预设的Plan B,比如改用更简单的方法生成结果、或者把该子任务标记为跳过并在最终输出中明确提示缺失。绝不能假装没发生过。
日志里要同时记录成功和失败路径。这为后续调优提供了非常重要的依据。我后面会详细说怎么基于日志迭代。
注意:多Agent系统里出错的往往不是大模型"笨",而是你给它的任务本身就含混不清。排查问题时,先把任务卡里的描述和验收标准重新读一遍,大概率能找到根源。
4.3 工具使用与权限边界
每个Agent能调什么工具,必须白名单化,这既是安全需要,也是成本控制手段。我见过一个系统,所有Agent共用所有工具,结果一个负责文案的Agent闲着没事调了三次数据接口,账单直接翻倍。
工具权限设计至少要考虑三个维度:只读还是可写、数据导出范围、调用频次限制。Router可以有全局权限,Worker一般只有只读和检索权限,只有特定执行Agent(比如写文件、发请求的)才开放写权限。
4.4 人工介入与断点续跑
多Agent系统再复杂,也不能是"全自动黑箱"。我强烈建议在流程里预留几个"人工检查点",尤其是在以下场景:
- 最终输出要直接对外的(比如生成合同、发邮件),必须加人工审核。
- 任务链超过5个节点时,在中间节点加一个Human-in-the-loop确认,避免错误一路传导到末端。
- 涉及外部真实操作的(扣款、发消息、改数据),必须双人复核或至少二次授权。
断点续跑是另一个容易被忽略的细节。系统执行到一半失败时,不应该从头再跑一遍,而应该能恢复上次的上下文,从失败节点继续。我在设计调度器时,会在每个任务完成时把任务上下文和产出物持久化下来,重跑时直接加载最近的持久化状态,而不是重新让Router再拆一遍。
5. 记忆机制设计:不是所有东西都要塞进上下文
多Agent系统跑久了,会出现一类共性症状:Agent"忘记"了项目早期的需求约束,或者某条结论被反复重新争论。这个问题本质上就是记忆机制没设计好。
大模型本身没有记忆,所有"记忆"都是你主动写进上下文的东西。所以记忆机制设计得好不好,决定了系统是越来越聪明,还是原地打转。
5.1 三种记忆类型分别管理
我把多Agent的记忆分成三类,分开存储、分开读写。
短期工作记忆:当前任务链开始后产生的事实和中间结论,任务结束就清空。它对应前面说过的任务上下文。
长期档案记忆:关于用户偏好、项目背景、领域术语、历史决策的记录。比如"用户不喜欢过于夸张的措辞""这个项目的目标受众是技术决策者"。这类记忆要持久化,由Router在每次任务初始化时决定要加载哪些相关档案。
共享项目知识:所有Agent共同积累的事实库,比如已经验证过的数据结论、已经否决过的方案。这是多Agent系统最值得投资的部分,因为它能让不同Agent在关键事实上达成共识,避免互相矛盾。
5.2 写入与召回机制
记忆写入不能靠模型自动写,那样会写进很多垃圾。我的做法是设置一个"记忆管理Agent",在关键节点(新结论产生、需求变更、用户反馈)触发写入,而且写入前要过一遍格式校验:
哪些事实值得写入长期记忆,我会看三个指标:这个事实会不会影响后续决策?会不会被多个Agent重复引用?会不会被时间快速淘汰?三个条件至少满足两个,才允许写入。
召回策略上,按需召回比全量加载划算得多。每个新任务初始化时,Router从长期档案里做一次相似度检索,选出与当前任务最相关的记忆片段,塞进相关Agent的上下文,再通过向量数据库存储记忆。
我推荐用一个简易的向量数据库或索引结构来管理长期记忆,这样召回时能按相关性排序,让每个Agent看到的是它最需要的那一小块,而不是整个项目历史。
5.3 防止记忆污染
记忆污染是多Agent系统里最隐蔽的坑。某个Agent在某一次任务中得出一个错误结论,如果没有经过验证就被写入共享知识库,之后所有Agent都会被这个错误污染,而且污染还会自我强化(因为多个Agent引用同一个错误来源,看起来就像"多方交叉验证"了)。
我在实践中总结出几个防污染规则:
- 结论型记忆必须经过Critic或人工审核才能入库。
- 记忆里注明来源和时间,设置有效期。过期的共享结论要自动降权。
- 支持记忆版本回滚,一旦发现某条记忆导致了下游任务失败,能快速定位并删除。
这个部分文字不多,但值得花大量时间打磨。记忆系统做得好,多Agent才有"成长"的可能,而不仅仅是"每次重新思考"。
6. 评估体系:怎么证明你的多Agent系统是有效的
这是很多做多Agent的团队跳过去的一步,也是最危险的一步。没有评估体系,你根本不知道改动是变好了还是变差了,只能靠"感觉更像人了"这种玄学判断。
6.1 离线评估三板斧
我每次调优之前,都会先固定一组评估指标,至少覆盖三个维度:
任务完成质量:最终输出是否满足用户的原始意图?这里可以用人工打分,也可以用一组预设的验证用例来跑"端到端通过率"。
协作效率:整个系统跑完花了多少时间、调用了多少次模型、消耗了多少token。多Agent系统最大的风险是"协作成本吞噬收益",所以这个指标必须记账。
失败模式分布:统计运行日志中各种失败原因的出现次数,比如"任务描述不清晰""工具超时""验收不通过""上下文超预算"。这个分布能直接告诉你系统最弱的环节在哪。
6.2 用模拟场景做压力测试
我会准备一组标准测试用例,每个用例覆盖一种典型场景:
- 单轮简单任务,多Agent系统不能比单Agent慢太多、贵太多。
- 多路信息汇总任务,测试并行分头处理和汇总质量。
- 带明确约束的复杂任务(如"不能超出预算""输出格式必须符合API规范"),测试约束传递能力。
- 歧义输入(用户需求没说清楚),测试Agent识别缺失信息并及时追问的能力。
每一次架构调整,都跑同一组用例,对比前后指标。没有这套压测基线,你有任何改动心里都没底。
提示:评估用例不要只用你自己手写的那三五条,尽量收集真实用户问题去扩充。真实问题里才有各种你意想不到的边界条件和表达方式。
6.3 迭代调优:先看失败模式,再看模型
调优顺序上,我的经验是"先改架构和提示词,再换模型"。多数失败并非模型能力不足,而是任务卡描述不清、上下文引用错误、工具权限管太死。直接把锅甩给模型换一个更强的,既贵又未必见效。
具体的调优循环是:收集失败样本,归类失败模式,针对高频失败点做修正(可能是改任务卡、改验收标准、加工具、调记忆),再用标准测试用例回归。这个循环走三四轮之后,系统往往会稳定很多。
有些团队会做自动评估器(用一个大模型评估另一个大模型的输出),我试过,能跑但不可全信,尤其是涉及事实准确性和逻辑严谨性时,自动评估器也会犯迷糊。建议关键指标保留人工抽检,自动评估只用来做粗筛。
7. 常见问题与排查技巧实录
最后这部分,我整理一下多Agent系统落地时最常遇到的几类问题,以及我实际排查时的做法。这份"速查表"能帮你省很多弯路。
7.1 高频问题速查表
| 现象 | 典型原因 | 排查方向 |
|---|---|---|
| Agent互相甩锅或无限对话 | 通信协议缺少终止条件,角色边界不清 | 检查消息格式是否有"最终回复"标记,收紧角色禁止事项 |
| 多Agent输出比单Agent还差 | 拆解过度,子任务之间信息断层 | 检查任务卡的input_refs是否完整,Merger是否拿到全部关键结果 |
| 上下文越来越大,token消耗暴涨 | 没有做上下文预算和记忆隔离 | 给每个Agent设token上限,改用引用而非正文传递 |
| 分工了但还是串行跑 | 同步通信用得太多,弱化了并行 | 检查调度器是否等待了不需要等待的依赖 |
| 中间结论与最终输出矛盾 | 关键约束信息在链路中丢失 | 把全局约束写进每个Agent的system prompt,而不是只在开头给一次 |
| 某个Agent死活不按格式输出 | 提示词里的格式说明太靠后,模型注意不到 | 把格式要求放到提示词最前部,并且给出一个完整示例 |
| 重试后结果更差 | 无脑重跑,没有带上历史失败原因 | 改造成将上次结果与失败原因一并作为上下文再尝试 |
| 记忆被污染,系统越来越糊涂 | 未经验证就写入共享记忆库 | 加上写入审核、来源标注、有效期与版本回滚 |
7.2 排查方法论:从哪个环节先查
遇到系统行为不对,我建议按这个顺序排查:
第一,看任务卡和验收标准。多数"Agent不听话"其实是任务编得含糊。第二,看消息传递记录。从Router到Worker的每一条实际消息,对比任务卡和最终产出,看信息在哪一环丢失或变形。第三,看上下文内容。把执行Agent的最终输入上下文完整打印出来,人工读一遍,很多时候一眼就能看出"该有的信息压根没给它"。
如果这三步走完还没有头绪,再考虑换模型或者调参数。我一直认为多Agent系统的调试,本质上是"信息流追踪",而不是"玄学调参"。
7.3 三个亲测有效的优化技巧
最后分享三个我在实际项目中反复验证过的小技巧。
第一,给关键Agent加"节流阀"。当一个Agent需要更新共享状态时,不要直接写入,而是先生成一个"变更提案",等Router或Critic确认后再正式写入。这能明显减少共享状态的混乱和覆盖。
第二,在每个Agent的system prompt里固定一段"开场白模板"。让Agent在开始执行前先复述一遍它理解的任务目标、约束条件和预期输出。这个"复述-对齐"的过程只需要额外消耗一点点token,却能把大量因为误会需求而失败的案例扼杀在摇篮里。
第三,设置"最低质量线"。在Merger合成最终结果之前,先让Critic做一次快速检查,不合格的直接打回对应Worker,而不是把不合格的内容送到用户面前。打回时附上明确修改意见比只说"不合格,重做"有效得多。
踩过几次坑之后,我的体会是:多Agent没有银弹,但那些"该有的笨功夫"——清晰的角色定义、结构化的消息、分层的上下文、严格的验收标准、持续的压测回归——一个都不能少。把这些基本功做到位,多Agent才能真正发挥协作的价值,而不是变成一堆聊天的模型来回消耗你的预算。
最后再分享一个小技巧:刚开始做多Agent时,别急着追求超大系统,先把一个最小闭环跑通,比如Router加两个Worker加Critic。等这个闭环稳定了,再往里加Agent、加工具、加记忆,会从容得多。好的多Agent系统不是设计出来的,是一轮一轮跑出来、改出来的。