多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

多Agent系统设计实战:从角色定义到编排、消息协议与落地避坑

多Agent系统设计实战:从角色定义到编排、消息协议与落地避坑 先说个我在不少团队里看到的通病大家一听说多Agent就想着把十个八个大模型角色扔进同一个聊天群里让它们互相来去以为这样就能涌现出超级智能。结果往往是上下文乱成一锅粥Token费用翻了好几倍最后产出的东西还不如一个老老实实写好提示词的单Agent靠谱。多Agent不是把多个提示词拼在一起它本质上是一个系统工程问题——你要设计的是协作机制、信息流动的边界、任务的拆分与验收方式而不是设计一堆会说话的角色。这篇文章我打算把多Agent设计这件事掰开揉碎从要不要用多Agent的判断标准到角色定义、拓扑结构、消息协议、编排方式再到落地实现时的上下文管理、工具权限、并发控制最后聊聊我实测中踩过的失败模式和调试思路。内容偏实战适合已经跑通单Agent、正准备往多Agent架构迈一步的工程师也适合正在被“用了多Agent就一定更强”这种幻觉困扰的架构师。1. 先想清楚你真的需要多Agent还是一个复杂Agent很多多Agent项目失败的根源不是实现得不够好而是起点就错了——团队在需求分析阶段把“多Agent”当成了默认答案。我个人的判断标准很朴素能用一个复杂Agent解决的问题绝不用两个简单Agent。多Agent架构天然带来三笔额外成本Token消耗增加、延迟变长、错误的传播路径变多。如果这些成本换不来对应的收益就不值得上。什么样的任务才适合多Agent我总结了三个比较硬的判断条件。第一任务内部存在明显不同的专业视角而且这些视角需要的知识边界和上下文内容差异足够大。比如医疗场景里的分诊、用药审核、病历归档或者金融场景里的信息采集、风险评估、合规审查每个环节关注的数据维度完全不同。混在一个Agent里要么提示词撑爆要么输出互相干扰。第二子任务之间可以定义清晰的输入输出契约。多Agent协作本质上是一个流水线或一张图每个节点必须能回答三件事你接收什么格式的数据你产出什么格式的数据你怎么让别人验证你是对的如果任务连清晰的边界都划不出来那说明它在认知上还是一个整体硬拆只会让信息在传递过程中不断损耗。第三某些子任务天然需要并行执行单Agent串行会显著拖慢流程。比如做行业调研你需要同时查政策、查市场数据、查竞品动态且这三者互不依赖用并行Agent就能把耗时从串行的十分钟压到两分钟。但注意并行意味着要处理结果汇总和冲突消解这也是额外的设计负担。反过来什么样的任务不要用多Agent最典型的是线性创作类任务。比如“写一篇品牌故事”你就算把它拆成“构思—拟大纲—写初稿—润色”这四个阶段在真正写的时候是互相纠缠的硬拆成四个Agent反而会丢掉整体连贯性。一个带记忆、带工具、有清晰写作流程的复杂Agent会做得更好。另一个要避开的场景是只有一个大模型可用且效果还凑合的场景多Agent不会让模型本身变聪明它只是把同一个模型用在了多个职责位上模型如果本身能力不足拆得越细死得越快。所以我给团队的建议通常是先拿一个复杂Agent跑通最小闭环把任务的瓶颈找出来。如果瓶颈是上下文太长、工具太多、职责太杂导致的互相干扰再考虑拆成多Agent如果瓶颈是模型推理能力本身拆多Agent几乎没用换个更强的模型才是正路。2. 设计多Agent要先画四张蓝图角色、拓扑、通信与编排当你确认了任务确实适合多Agent下一步不是写代码而是先画蓝图。我把整个过程收敛成四张必须画出来的设计图每一张都对应一个具体的决策维度。2.1 第一张图角色定义要从“人设”升级成“岗位说明书”多数人定义Agent角色就是一句“你是一位资深的营销专家”然后没了。这充其量算人设不算是设计。我推荐把每个角色写成一份岗位说明书至少包含六项内容职责边界、输入模式、输出模式、成功标准、可用工具、负向约束。职责边界要说清楚这个Agent负责什么更重要的是不负责什么。比如“检索Agent只负责收集和结构化信息不负责判断信息对错”——判断是分析Agent的事。没有边界Agent之间就会抢活、甩锅产出大量无关对话。输入输出模式是契约的基础要做成结构化的模式不能是散文。输出不能只给一段自然语言还要给出结构化字段。比如检索Agent输出至少应该包含来源标题、URL、概述、关键词、可信度评分。这样下游Agent才能稳定消费。成功标准要让Agent自己知道“我的活干完了”。比如合规审查Agent的成功标准是“检查清单所有项全部通过并且未标记项数为零”。没有成功标准Agent经常给出一个半成品就宣布完成。可用工具直接决定了Agent的能力边界。检索Agent可以调搜索引擎和网页提取器但绝对不能调代码执行器数据分析Agent可以调脚本执行器但绝对不能调外部API写操作。工具权限本质上就是职责边界在系统层面的强制落实。负向约束值得单独拎出来写。比如“不要在回答中直接给出数值结论只描述数据分布特征”以及“当你发现输入数据不完整时标记缺失项并继续不要自行假设”。大部分人设计角色时只写正向指令忘记写负向指令结果就是Agent发挥不稳定有时候好用有时候乱来。2.2 第二张图拓扑结构决定了Agent之间如何排列拓扑是多Agent系统的骨架。我见过的基本就四种星型、流水线型、网状型、分层型。它们各有适用场景没有绝对好坏但有明显的倾向性。星型拓扑有一个中心协调员所有Agent都只跟协调员通信彼此不直接对话。协调员负责拆任务、派任务、收结果、做下一步决策。这种结构最好控制错误传播路径最短也很容易加日志和权限控制。代价是协调员容易成为单点瓶颈所有消息都要过它一遍Token开销不小。适合任务边界清楚、需要强管控的场景。流水线拓扑就是一条单向链路Agent A的输出是Agent B的输入依次往下走。比如“数据采集→数据清洗→分析→报告生成”。它的优点是角色间耦合度低每段都可以独立测试、独立替换非常适合流程稳定的场景。缺点是整条链路的耗时取决于最慢的节点而且一旦中间某个节点出错下游会直接拿到脏数据。网状拓扑是理论上最灵活、实际上最难用的方案每个Agent都能跟其他Agent自由对话像一群专家在圆桌讨论。看着很美好现实里经常出现对话发散、互相重复追问、没人拍板、上下文爆炸等问题。我的态度很明确除非你在做生物学仿真之类的开放式研究否则别在生产环境用纯网状。如果你确实需要讨论机制可以用“有限网状”——规定每轮最多三条消息且必须由协调员做最后决策这其实是带约束的星型变种。分层拓扑则更接近现实组织架构有管理层和执行层。比如有一个项目经理Agent它不直接干活只负责把任务拆成了模块分给三个执行Agent然后自己汇总。执行Agent如果遇到自己搞不定的子问题还可以向下再委派一层。这种结构好处是层级间的上下文可以隔离上层只看摘要下层看细节坏处是深度多了延迟很高而且责任链太长时错误难追踪。适合天然有层级结构的复杂业务比如供应链管理。2.3 第三张图消息协议不是传字符串而是封信封多Agent系统里Agent之间传递的每一份消息都应该是一个结构化信封而不是一段裸的自然语言字符串。没有结构下游Agent就得靠阅读理解去解析解析错了就是一次隐性的错误传播。我常用的信封格式大概长这样。用JSON做一个示意{ message_id: msg_8f2a1c, trace_id: trace_9b3d7e, sender: search_agent, receiver: analysis_agent, task_id: task_0042, msg_type: response, intent: provide_results, schema_version: 1.0, payload: { items: [ {title: ..., url: ..., summary: ..., score: 0.87} ] }, created_at: 2025-06-12T10:30:00Z }字段里有几个容易被忽略但实际很关键的点。trace_id是整个业务流程的追踪串一次用户请求从开始到结束所有Agent的消息都会带上同一个trace_id。没有它多Agent系统一旦出问题你根本不知道消息在哪一环丢了、在哪一环重复了。msg_type区分“请求”“响应”“通知”“审批”这决定了接收方要不要阻塞等待要不要触发后续动作。比如“审批”类型消息发过来协调员就必须停下来做决定而不是顺手转发。intent描述的是这条消息希望接收方“做什么”比如“provide_results”是交付数据“request_clarification”是请求澄清“request_tool_usage”是申请调用某个工具。把意图结构化之后接收Agent的决策逻辑就可以写成基于规则的分发器而不需要每次都重新读一遍全文去猜对方想要什么。2.4 第四张图编排模式决定了控制权的粒度编排是多Agent系统的“指挥系统”解决的是“接下来谁动”的问题。我实践下来纯中心化编排和纯自主协作都容易走极端真正好用的是中间态。中心化编排模式下协调员拿着完整的全局流程一步一步往下派活。优点是可预期、可控、可重试但协调员会成为所有决策的汇聚点流程一长协调员本身的提示词就变得极其复杂容易出错。自主协作模式下没有中心协调员Agent按消息内容自行决定是否响应。灵活但可控性差很难确定生产环境里某个流程为什么走到了某一步。中间态则是我踩过很多坑之后总结出来的最佳方案流程骨架固定节点逻辑分层。什么意思就是把整个业务拆成确定性的节点和发散性的节点两类。比如做一份市场分析报告流程是固定的“检索→清洗→分析→撰写→校对”但其中“分析”和“撰写”这两个节点需要模型发挥它们就是Agent节点而路由逻辑、格式转换、进度检查这些完全可以用代码写死。这就是所谓的“WorkflowAgent”混合编排确定性逻辑用代码发散性逻辑用Agent。我建议所有刚上手多Agent的团队都从这个模式开始它比纯自主协作稳得多又比纯中心化编排灵活得多。3. 从需求到架构一套可复用的多Agent设计流程说完了四张蓝图接下来是具体的操作步骤。这一节我会用一个贯穿全文的例子做一个“行业市场分析报告”的多Agent系统。需求很简单——用户给一个行业名称系统产出一份包含市场规模、竞争格局、政策环境、趋势预测的报告。3.1 第一步把任务分解成依赖图先别想Agent先把任务拆成子任务并画出它们的依赖关系。这个阶段可以用纸笔也可以用任意画图工具重点是只关注任务本身不关注用什么模型。市场分析报告这个例子的任务分解大概是这样的子任务A检索政策、市场、竞品相关信息子任务B对检索到的数据进行清洗和去重子任务C市场规模与增长趋势分析子任务D竞争格局分析子任务E政策环境梳理子任务F综合撰写报告子任务G事实核对与格式校对依赖关系也很清楚A → B →C、D、E可以并行→ F → G。这是一个典型的分层汇聚结构前段串行中段并行后段再汇总。3.2 第二步为每个子任务定义可验证的验收标准这一步是决定系统质量的关键但也是大多数团队最容易跳过的一步。每个子任务至少要定义两个东西产出的结构化格式以及人类可验证的成功标准。拿子任务B“数据清洗去重”举例。它的产出格式可以定义为“一个数组每项包含title、url、source_type、duplicate_group_id”成功标准是“数组中不含URL完全相同的重复项所有项都有source_type字段”。子任务F“综合撰写报告”的成功标准就是一层层叠加的必须引用C、D、E三个子任务的结构化结论报告结论不能超出这些结论的范围格式符合给定模板。你可能注意到了我不要求验证内容“是不是足够深刻”——那是模型的能力问题很难自动化。我验证的是结构、引用关系和格式这些是可计算、可断言、可回滚的。多Agent系统的验收逻辑就建立在这些可验证点之上。3.3 第三步确定每个节点是Agent节点还是代码节点拿到任务依赖图以后接下来是去模型化的过程。你需要在每个节点上问自己两个问题这个节点是否需要根据语义做出创造性输出它是否存在唯一正确的确定性答案如果答案是“需要创造性输出”那这个节点很可能需要Agent如果答案是“存在唯一正确答案”那写代码做正则、查表、计算会比用模型更准、更便宜、更快。还是以市场分析报告为例A检索、C分析、D分析、E梳理、F撰写、G校对都需要语义理解归为Agent节点而B数据清洗去重虽然也需要一些判断但完全可以先用规则做URL去重再用一个轻量模型做语义去重不需要独立Agent。代码节点的判定逻辑很简单100次执行中如果99次你不会接受模型输出上的随机差异那就不该让Agent干这事。多Agent系统最忌讳的就是把能用代码解决的问题强行交给Agent结果既浪费Token又引入了随机性。我在实际项目里甚至见过用Agent做JSON格式修复的这本来就是一个try...catch加json.loads就能解决的事。3.4 第四步定义消息契约和失败策略当所有节点确定后就要把节点之间的连线都变成规范化的消息契约。每个连线要定义发送方、接收方、payload字段、触发条件、超时时间、失败时重试还是降级还是熔断。我习惯把这一步写成一份配置文件作为整个系统的“宪法”。这个文件可以存成JSON或YAML由编排框架读取。我给出的这段配置更近似于一个高层设计模板实际字段需要按你选的框架去对应agents: search_agent: role: 检索Agent tools: [web_search, page_reader] llm: gpt-4o max_retries: 3 timeout_s: 120 input_contract: { topic: string, depth: string } output_contract: { items: array } analysis_agent: role: 分析Agent tools: [data_visualizer] llm: gpt-4o timeout_s: 90 output_contract: { insights: array } workflow: edges: - from: search_agent to: data_cleaner on_success: continue - from: data_cleaner to: analysis_agent - from: data_cleaner to: policy_agent policies: global_timeout_s: 600 max_parallel_agents: 3 circuit_breaker_threshold: 5有一个容易忽略的细节失败的语义不止“这步失败了”一种。你要区分“超时”Agent没回应、“格式错误”Agent回应了但没按契约出牌、“内容失败”Agent回应了、格式也对但生成内容显然不符合业务常识。这三种失败要有不同的处理策略超时就重试或换备用Agent格式错误就补丁解析或要求重发内容失败就得降级到人工审核。把失败类型分开定义排查问题的时候才知道往哪个方向看。4. 落地实现时最容易翻车的四个关键细节架构画完了流程理清了但真正动手实现多Agent系统时你还会遇到文档里很少提的四个硬问题。这些是我在多个项目里反复踩过的坑提前处理能让你少走很多弯路。4.1 共享上下文不是所有信息都要给所有Agent看多Agent系统最常见的失控原因是上下文被无差别共享。大家都在同一块黑板上面写字后写的Agent能看到前面所有Agent的思考过程——于是Token消耗暴涨而且先入为主的信息污染了下游Agent的判断。我的建议是引入基于角色的上下文视图机制。每个Agent只能看到自己职责范围内需要的那部分数据。检索Agent只能读用户输入的原始需求分析Agent只能读清洗后的结构化数据撰写Agent只能读C、D、E三个分析结论看不到检索的原始网页列表。实现上可以简单地在编排框架里为每个Agent维护一个context_slice每次调用模型时只注入该Agent的白名单字段。这不是保守而是刻意的信息隔离。分析Agent如果看到原始网页里那些互相矛盾的标题就可能被带偏撰写Agent如果看到检索Agent的失败记录就可能开始自我怀疑。多Agent系统的设计哲学是让每个Agent获得它需要的、刚好够用的信息而不是获得所有信息。4.2 工具权限全局工具池是一个等着爆的安全漏洞设计多Agent系统时一开始图省事我常常会把所有工具放一起让所有Agent都能调用。这在实际运行中会出现两类问题一是Agent A调用了一个它不理解的工具产出了误导性结果二是Agent A篡改了Agent B正在使用的中间文件导致下游拿到脏数据。现在我的做法是给工具的可见性和权限都加一层控制。每个Agent的提示词里只会注入它能调用的工具清单编排框架的代码里会在工具调用层再做一次白名单校验防止Agent越权调用。比如检索Agent只暴露web_search一个工具数据分析Agent只暴露code_interpreter和data_reader。你可能觉得冗余但这一层冗余是必要的。大模型的工具调用并不总是受提示词约束的——极端情况下它能绕过注入的工具清单直接调用你不希望它碰的底层API。所以提示词白名单只是第一道闸代码层的权限校验才是第二道闸。尤其当你的Agent要处理敏感数据或执行外部写操作时这个双闸设计是底线要求。4.3 并发控制并行不是白拿的资源是真正的瓶颈很多多Agent框架把“并行”“实时”“自动编排”当成卖点但这背后有一个很现实的瓶颈你调的是同一个大模型供应商的API并发一高限流和超时就全来了。我在实际项目中踩过一次性启动8个并发Agent结果第3个请求直接被429限流然后整条流水线等待最后因为超时报错。后来我总结了三件事。第一要设置全局的并发上限做出一个信号量或线程池守卫把同时执行的Agent数量限制在一个不会触发限流的区间。第二要给每个Agent设置独立的超时时间而且要遵守一个原则Agent调不动应该通知编排层“本节点失败”而不是无限期等待。第三要做好幂等设计。出错重试时同一个Agent不应重复产生重复的副作用——比如检索Agent重试时不能把同一条URL插入数据库两次消息去重是At Least Once投递机制的必备伙伴。4.4 可观测性没有trace_id的多Agent系统是黑盒加黑盒从单Agent过渡到多Agent时调试难度是成倍上升的。单Agent出了问题你可以把一次调用记录逐条回放多Agent出了问题你需要回答“在哪一步出错、是谁导致了这一步出错、当时它看到了什么”。没有结构化日志你根本没法回答这三个问题。我实践下来比较好用的组合是这样的。第一用trace_id贯穿所有环节从用户请求进入系统开始生成所有Agent的消息、工具调用、模型响应都带上同一个id第二每次Agent调用模型前把实际发送的prompt完整落盘这里说的“完整”包括全量上下文内容而不只是sentinal长度第三记录Agent每次对工具调用的输入输出特别情况是“Agent选择了不调用工具”——这个选择本身就是要记录的信号。有了这些数据碰到“报告里结论与数据矛盾”之类的问题你就能倒推数据是哪个Agent产出的它基于什么上下文它调用了什么工具是哪一个环节发生了偏差。在多Agent系统里调试的艺术不是猜而是把每个决策过程变成可回放的记录。5. 多Agent系统的典型失败模式与我的调试思路无论你把蓝图画得多完美真实运行的多Agent系统一定会出现设计阶段没料到的行为。这一节我整理了四个最高频的失败模式都是我自己项目里遇到过的并附上对应的排查思路。5.1 回声室效应所有Agent说的是同一个模子的话一个反直觉的事实是同一个大模型驱动的不同Agent它们的“性格差异”远没有你想象得大。当你给每个Agent同一组语料、同一套prompt结构时它们产出的结论往往高度相似这个现象在报告分析类系统里尤其致命——你明明派出去检索、分析、政策三个Agent最后它们的结论像是同一个人写的。根因在于它们共享了两样东西底层模型和上下文源。破解的办法有两个方向一个是给不同Agent注入不同的数据视角比如分析Agent多喂市场数据政策Agent多喂监管文件另一个是在prompt模板上做差异化不只是改称呼还要改输出要求——政策Agent要求引用具体条例编号数据分析Agent要求给出数值区间和置信度这样它们被迫采用不同的思考框架。此外在结论汇总时还要加一道交叉验证让汇总Agent专门检查各子报告的结论是否存在“未经数据证实的雷同表述”。5.2 重试风暴一个Agent卡住整个系统跟着自旋这是元凶级问题。场景是这样的Agent B依赖Agent A的结果A超时了B根据策略开始重试与此同时协调员发现整个流程没到预期也开始重试下游任务几轮下来同一个任务被并发执行了好几次Token烧穿日志里全是重复的trace。这种重试风暴在引入自动重试机制之后几乎必然会遇到。我的调试思路是把重试分为“任务级重试”和“消息级重试”。任务级重试由编排层决定整个子流程是否需要重新来一遍同时要提供幂等键避免重复写入。消息级重试只针对单条消息的发送和接收超时后重试间隔要指数退避。还要设置熔断器当某个Agent在5分钟内连续失败超过阈值就直接标记该节点降级不再触发后续重试。判断重试是否合理有一条简单经验重试的代价是否可能超过重新发起整个上游子流程的代价如果超过那就别重试直接失败并让人工介入。5.3 共享状态被污染某个Agent悄悄改坏了全局数据多Agent系统里如果所有Agent都往同一个全局状态对象里写东西在某个时刻一定会出现数据竞争。比并发写更隐蔽的是越权覆盖数据分析Agent为了计算方便直接改了原始数据表里的字段撰写Agent为了省字改写了一些中间结论。下游Agent看到被改过的数据做出了一系列看似合理但完全错误的后续决策。我把共享状态分成了三层每一层有严格的读写权限原始输入区只读初始化后所有Agent均只有read权限、工作区每个Agent一个私有文件夹只有自己和协调员可读写、汇总输出区只有编排层和汇总Agent可写其他Agent只能读。刚开始你会觉得约束太多、代码变慢但稳定运行几周之后就会发现这套权限分层是救命的设计。排查共享状态被污染时我的第一步就是查trace日志里谁在什么时间点对目标字段做了非授权写入。5.4 成本失控消息传递本身比模型输出贵得多多Agent的Token消耗模型和单Agent是截然不同的。单Agent的Token成本约等于“输入输出”而多Agent下还有一层“中间消息传递成本”——每个Agent发给另一个Agent的消息对接收方而言都是待处理的输入Token。如果中间消息写得冗长成本会像滚雪球一样膨胀。我做过一个测试某个协作流程如果每个Agent都发给自己专业范围内的五百字文本6个Agent一轮协作下来Token输入总量轻松破万而这个流程真正需要的信息可能只有其中的三分之一。应对手段首先是强制消息摘要发送方在信封外额外附一版摘要接收方默认只看摘要在接收方Agents的prompt中明确指示详细内容仅在被摘要引用时才展开。其次是预算硬约束我给每个Agent设了单次调用预算和整体流程预算超过预算就强制降级用更便宜的模型或直接跳过非关键环节。要衡量系统是否健康看一个指标就行有效信息Token占全部Token的比例。这个比例低于30%就意味着大量Token被无意义传递消耗了你的通信设计大概率有问题。6. 保持怀疑小步迭代多Agent系统的落地建议最后分享几条我个人在多个项目里沉淀下来的经验或者说是一些值得“反常识”的原则。第一先做2到3个Agent的最小闭环。不要一开始就设计10个Agent因为每个Agent都意味着一个额外的失败点、一部分额外的Token成本、一份额外的调试工作量。一个检索Agent加一个分析Agent加一个编排层就能验证你的任务是否适合多Agent模式。跑通这个最小闭环之后再往上下游扩展每次变化只动一个环节保持其余部分不变这样出了问题你永远知道该查谁。第二能用代码写严的配置就别用模型来“发挥”。Agent的价值在于处理需要语义理解和生成的部分而路由、幂等、重试、格式校验这些环节交给规则和代码既省钱又稳定。多Agent系统的最佳实践往往是代码管骨架、Agent管血肉。第三为每个Agent建立效能档案。我强烈建议在日常运行中记录每个Agent的各项指标平均耗时、失败率、Token消耗、返工次数。半个月后你会发现有的Agent一直表现稳定有的Agent总是在某些特定输入上翻车。针对后者不是换更大的模型就好先看它接收到的上下文是否包含了误导信息八成是因为上下文污染而不是模型能力问题。多Agent系统应该是渐进演化出来的。不要相信任何一次把所有模块一步到位设计的方案——因为系统里Agent的交互行为天生具有复杂性几乎不可能在纸面上推演清楚。让流程先短、让信息先收敛、让控制先集中再一步步放开。这个系统会越来越复杂也会越来越有价值。希望这篇基于实践经验的梳理能帮你少踩几个我踩过的坑。
返回列表