
做了大半年多Agent系统我越来越觉得这个方向最难的其实不是让单个Agent变聪明而是让一群Agent像一支团队那样协作干活、还不互相踩脚。这个系列前几篇聊了Harness Engineering的基础框架、工具调用、上下文管理今天这篇专门聊多Agent系统与Agent蜂群——也就是怎么把多个模型实例编排成一个作战单元而不是一群各自为战的散兵游勇。先给个结论多Agent不是银弹不能为了包装而硬上。但在任务复杂度超过单Agent能力边界、或者业务链路天然适合并行处理时蜂群模式能用可控的token消耗换到数量级上的效率提升。这篇文章适合已经在做Agent应用、踩过单Agent上下文溢出和错误累积这类坑的开发者我会把设计思路、通信机制、容错方案和实战参数都摊开来讲。1. 多Agent系统到底解决了什么问题1.1 单Agent的边界不是聪明程度而是上下文和串行很多第一次接触多Agent的开发者有个误解以为单Agent不够聪明所以需要多个Agent群策群力。实际上主流大模型本身的推理能力已经够强真正的瓶颈在别处。第一个瓶颈是上下文窗口。单Agent干活的时候所有中间结果、工具返回、思考过程都挤在一个上下文里。任务链路一长早先的关键信息就会被挤到注意力边缘。我做过一个实验让一个Agent去调研某行业的五个竞品并输出对比报告任务拆成二十多步之后它经常把第一家公司的数据记混到第三家公司身上。不是模型变笨了是信息太多太挤了。第二个瓶颈是串行效率。单Agent再强也只能一条链跑到底。整理一份包含五十个数据点的周报必须逐个查数据源串行跑可能二十分钟用多个Agent并行查五分钟就能收齐。第三个瓶颈是错误累积。单Agent链路里每一步输出都可能引入小误差误差顺着链路滚下去到了最后一步经常面目全非。多Agent系统把链路拆成多个可独立验证的环节某个环节出错可以单独重跑不用整个链路推倒重来。1.2 蜂群模式的三种典型形态我把实践中见到的多Agent编排形态归成三类编排式、协商式、流水线式。它们不是互斥的真实系统里经常混合使用。编排式是最常用的形态也叫主管-工人模式。一个主管Agent负责任务理解、拆解和派发多个工人Agent只负责执行被分配的子任务。好处是逻辑清晰、容易调试、每个子Agent的职责边界明确出问题能快速定位。坏处是主管Agent可能成为瓶颈而且如果主管拆解能力不行整个系统的上限被它卡死。协商式是让多个Agent对同一问题独立给出结论再由一个决策Agent或投票机制综合输出。典型场景是代码评审、方案选型这类没有标准答案的任务。好处是能显著降低单次判断的偏差率代价是token消耗成倍增加——N个Agent讨论同一个问题成本就是N倍起步。流水线式是把任务按阶段串成一条链路每个Agent负责一道工序前一道的输出是后一道的输入。适合流程极其固定的场景比如数据处理链路采集、清洗、分析、可视化各环节分别由不同Agent承担。好处是结构简单坏处是灵活性差改需求等于该流水线。注意判断该不该上多Agent有一个简单标准——如果单Agent把任务做砸的原因是可以归纳为具体某一步的先修那一步别急着上蜂群。如果原因分散且并发需求明显再考虑多Agent。2. 核心设计任务拆解、分配与结果聚合2.1 任务分解策略静态、动态与递归任务拆解是蜂群设计的第一个分水岭。拆得好每个子Agent只干一件明确的事输出质量自然稳定。拆得烂子任务边界模糊Agent之间互相重复劳动聚合的时候一地鸡毛。静态拆解是预案式写法。开发者在代码里写死任务流程比如调研任务固定拆成五个部分每个部分一个Agent负责。优点是完全可控运行期零决策成本适合业务规则不会频繁变化的场景。缺点是遇到没见过的任务形态就傻眼。动态拆解是让一个规划Agent在运行期根据任务内容决定怎么拆。灵活度高能应对多种任务形态但你要额外承担规划Agent本身的输出不确定性。规划错了整个蜂群在错误方向上狂奔哪怕每个子Agent都干得很完美结果也是错的。递归拆解是动态拆解的进阶版主管Agent拆出子任务后子Agent发现自己干不过来可以再往下拆一层形成树状结构。适合真正复杂的任务但必须给深度加硬限制。我在代码里默认限制拆解深度不超过3层——超过3层规划开销和通信复杂度会指数级膨胀得不偿失。实操参数上我建议控制子任务的粒度在一个子任务对应一到三次Agent调用。如果某个子任务需要Agent调用十次以上才能完成说明拆得不够细如果子任务里嵌套了三个并列目标说明拆得太粗。2.2 扇出与扇入蜂群并发的基本姿势扇出Fan-out和扇入Fan-in是蜂群并发的基本功。描述一下主管Agent收到任务后识别出可以并行的子任务一次性派发给多个Worker同时执行这叫扇出所有Worker返回结果后统一收回由汇总逻辑处理这叫扇入。实践中扇出最常栽在并发度上。我一个同事某开发者做的某跨平台项目里最初设置30个并发Worker同时调研30个数据源结果模型接口直接限流整批请求打回去重试实际完成时间反而比15并发更慢。接口能承受的并发不是越多越好你还要算上重试的概率。我现在的习惯是并发度取接口限流阈值的三分之一到二分之一宁可慢一点保证不触发批量重试。扇入的设计容易被忽略。多个Worker返回结果后你是不是简单地拼个长文本就丢给下一个Agent这样做十有八九会把汇总Agent的上下文撑爆。我通常让Worker在返回结果时附带结构化摘要字段扇入阶段先只看摘要做归类需要详细内容时再按需拉取完整结果。顺带说一句同步机制。蜂群里的并行子任务不需要像多线程那样考虑锁和竞态——每个Worker只对自己那份子任务负责天然隔离。但扇入阶段要注意乱序到达的问题尤其是子任务耗时差异明显时。解决方案是给每个子任务一个全局唯一的task_id扇入时按task_id归位而不是按返回顺序处理。2.3 结果聚合与冲突处理扇入之后棘手的问题来了多个Worker返回的结果之间出现冲突怎么办。比如三个Worker分别调研同一家公司的产品定价一个返回99元一个返回109元一个返回价格未公开。你不能简单取多数因为三个Worker的信息源可能来自不同的页面时效性不同。我常用的聚合策略有四种投票、加权、拼接、二次加工。投票适合结果可离散分类的场景加权适合各Worker可靠性可以量化评估的场景比如历史准确率高的Worker权重更大拼接适合维度互补的调研结果二次加工是让一个汇总Agent通读所有结果生成最终结论——这是最通用的也是成本最高的。冲突处理要提前设计不要等冲突发生了才想怎么办。我的做法是给每条聚合结果带上来源标记和时间戳。来源标记记录它是哪个Worker、来自哪个信息源时间戳用于判断信息的时效优先级。这样即使冲突不可调和至少能追踪到根源不至于让错误信息默默进入最终产出。注意所有Worker的输出结构最好在派发任务时就用JSON Schema约束死。模型输出解析失败是蜂群系统排名前三的故障来源与其靠运气不如在任务描述里明确规定输出格式并在聚合前设置一道轻量校验。3. 通信与状态同步蜂群设计的灵魂3.1 消息协议先定规则再放Agent跑多Agent系统里Agent之间的通信本质上是消息传递。别看每个Agent都是大模型它们之间没有心灵感应全靠消息文本互相理解。消息协议设计得差整个蜂群看起来就像一支语言不通的杂牌军。我建议至少定义一个统一的消息信封结构包含id唯一消息编号、task_id所属任务、agent_id发送方、parent_id父任务、payload具体内容、status状态。这样不管什么类型的消息都能统一追踪和管理。信封结构具体到代码里长这样{ message_id: msg_20250101_001, task_id: task_a1, agent_id: worker_research_03, parent_id: orchestrator_main, status: completed, payload: { result_type: competitor_analysis, content: ..., summary: ... } }这个设计的好处是日志系统可以根据message_id串起整条链路排查问题时一行命令搜出所有相关消息聚合阶段按task_id归位不会因为并发返回顺序乱套。协议还有一个细节容易被忽略给每条消息加schema版本号。蜂群系统迭代速度快payload结构说变就变。没有版本号旧消息和新逻辑混在一起解析报错时你根本分不清是哪个版本的格式问题。我踩过这个坑之后所有消息协议默认带version字段。3.2 状态共享能隔离就隔离能只读就只读多Agent系统里状态同步是个两难的问题。完全共享Agent之间会互相污染数据完全隔离又没法协作。我的平衡方案是共享上下文只读写操作走主管。具体来说全局共享区放的是任务目标、约束条件、统一的领域术语表这些不变量信息。所有Worker启动时读取一份干活期间不修改。Worker自己的中间结果和私有笔记放在自己的工作区只有最终结论才回传给主管。这样做能有效避免一个Worker乱改共享信息导致其他Worker输出全偏的问题。这里可以类比现实中的团队协作项目组成员共用一个需求文档但每个人自己的草稿和工作笔记是私有的交作业时只提交最终版本。如果大家同时在一个文档里改来改去到截止日期文档早就面目全非了。还有个细节全局KV或数据库作为共享状态载体时并发读没问题并发写一定要加锁或使用原子操作。虽然大模型Agent不像传统程序那样高频写状态但一旦发生并发写冲突错误极其隐蔽调试成本很高。我见过一个系统两个Worker同时往共享配置里写入不同的温度参数导致下游Agent一会儿按低温策略干活一会儿按高温策略干活输出结果忽高忽低排查了整整两天。3.3 上下文压缩蜂群能跑多远全看这步多Agent系统最大的隐性成本是上下文膨胀。每个Worker返回的结果都是大段文本几十个Worker的结果汇聚到主管或汇总Agent那里分分钟几万token打底。如果不做压缩上下文窗口再大也不够用。我常用的上下文压缩有三种手段。第一种是模型摘要让一个轻量Agent把长篇结果压缩成几百字的要点适合语义密集的内容。第二种是结构化抽取用正则或指令从结果中提取关键字段填入预设表格适合格式固定的结果。第三种是混合策略先结构化抽取关键字段再对剩余的重要段落做语义摘要最后拼接成紧凑的中间表示。实操参数上我给自己定了一条线单个Worker返回结果超过2000 token时必须触发压缩再进入上游。压缩后的摘要控制在原始长度的十分之一到五分之一。如果摘要本身还想再精简就截断并附上完整版见工作区xx号需要时按需取用。这里要强调压缩时序。我见过很多系统是在所有Worker全部返回后才开始压缩结果就是聚合阶段一次性扛下所有原始结果的内存和计算开销。正确做法是每返回一个压缩一个把压缩放到扇入管道的每个入口上而不是攒到最后一把梭。4. 容错、限流与并发控制4.1 子Agent失败重试、降级还是跳过蜂群里子Agent会失败这没什么好丢人的。模型接口超时、解析格式出错、输出内容不完整原因五花八门。设计容错策略的核心问题是子Agent失败之后对整个系统的影响有多大。我按影响程度分三级处理。第一级是可重试错误比如接口超时、临时网络抖动采用指数退避重试第一次等1秒第二次等2秒第三次等4秒最多重试三次。第二级是内容质量不合格重试大概率也是同样结果直接降级——比如让另一个思路不同的Worker重新生成一次用不同的提示词模板。第三级是子任务本身不可完成或者连续重试两次都失败跳过该子任务在最终结果里标记该部分数据缺失原因xx。关键原则是不能让一个子任务失败拖垮整个蜂群。我早期犯过一个错误某一个Worker连续失败导致整个链路抛异常其他十几个Worker辛辛苦苦算出来的结果全部作废。后来改成局部失败容忍——子任务失败只影响它自己对应的环节整条链路继续跑最终结果里如实标注缺失项。用户拿到报告时看到某数据源不可用比看到系统崩溃请重试要宽容得多。4.2 限流与成本控制先算账再开跑多Agent系统的成本控制比单Agent重要得多因为每次调度都是几十个Worker一起跑一不小心就是十万token级别的消耗。我见过有人跑一次蜂群任务烧掉上百万token结果产出内容质量还一般。成本控制第一件事是算账。做任务规划时先把预计的Agent调用次数乘上单次调用的平均token数算出一个总预算。比如50个Worker平均每个输入3000 token、输出1000 token加上主管、汇总等环节的消耗一次任务就是二十多万token。如果这个数字超过你的心理预期要么减少Worker数量要么降低任务拆解深度。第二件事是设定硬上限。代码里给每个任务配置一个最大token预算累积消耗超过预算后蜂群自动熔断不再派发新任务。宁可产出不完整也不能让成本失控。第三件事是并发限流。除了模型接口本身的限制还要考虑下游被调用的工具和数据源。比如蜂群要抓取某个网站的数据下游站点扛不住高频请求你这边并发开再高也只是徒增失败率。我现在的做法是给每类下游工具配置独立的并发配额例如外部站点抓取并发不超过3模型接口并发不超过20这样整个系统的负载曲线是平滑可控的。4.3 可观测性没有trace的蜂群就是一团乱麻单Agent调试已经够麻烦了多Agent系统的调试难度是指数级上升的。几十个Agent同时运行互相之间还有消息往来出了问题根本不知道从哪查起。所以可观测性在蜂群系统里不是加分项是必需品。我的做法是强制要求每次Agent调用都带上全局唯一的trace_id从任务启动的那一刻开始贯穿所有子Agent、工具调用和消息传递。每一份日志都记录trace_id、agent_id、当前状态、输入摘要、输出摘要和耗时。排查问题时输入一个trace_id就能捞出整条链路的所有记录。日志记录的核心字段我整理了一下字段含义示例trace_id全局追踪标识tra_20250101_abc123agent_id当前Agent标识orchestrator_mainparent_id上级Agent标识task_runnerevent事件类型task_dispatched / tool_called / result_receivedinput_summary输入摘要任务调研竞品A定价长度3200tokenoutput_summary输出摘要返回竞品A定价区间99-129元latency_ms耗时4500total_cost_tokens累计token消耗18320还有一个小技巧把任务拆解结构打成日志。主管Agent拆出了几个子任务、每个子任务分给了谁、相互之间的依赖关系是什么。这条日志在排查问题时价值极大——很多时候问题根本不在某个Worker干得不好而在任务拆解本身就拆错了。有了拆解结构你能一眼看出某个子任务是不是被重复执行了、是不是有节点被漏掉了。5. 实操案例某跨平台系统的Agent蜂群全流程5.1 需求场景与角色定义用之前同事实际做过的一个案例来讲流程。某跨平台系统需要一个竞品分析报告自动生成模块给定一个目标产品系统自动调研若干竞品从功能、定价、用户评价、近期动态四个维度做分析最终产出一份结构化对比报告。任务天然适合并行每个竞品、每个维度之间相互独立串行做太慢必须上蜂群。系统定义了六类Agent角色规划Agent负责把调研目标拆解成任务树调研Agent负责采集原始信息每个竞品配一个分析Agent负责把调研结果按维度整理成结论每个维度配一个汇总Agent负责把多维度结论整合成完整报告质控Agent负责抽查结果并标注可信度主管Agent负责整体调度和异常处理。角色拆到这一步每个Agent的职责已经足够清晰。我建议在代码里把这个角色配置表用常量定义出来标注每个角色的系统提示词、输入格式、输出格式、使用的工具集方便后续调试时单独抽某个角色出来做单元测试。5.2 调度流程与并发参数整个流程分五步走。第一步主管Agent接收任务配合规划Agent拆解任务树预计生成12到15个叶子任务。第二步调研Agent并行执行并发度设置为4不是15因为外部数据源扛不住高频访问。每个调研Agent限定最多调用20次工具防止个别Agent陷入无意义深挖。第三步分析Agent逐个处理调研结果按四个维度生成结构化分析输出JSON。第四步汇总Agent读取所有分析结果生成完整报告框架并填充内容。第五步质控Agent随机抽检30%的内容对明显矛盾或数据缺失的部分标注警告。预算分配上整个任务预估消耗token约18万其中调研阶段占大头约60%分析阶段占20%汇总和质控各占10%。遇到异常情况时无论任务是否完成总消耗超过25万token一律熔断。这里有个经验预算不能完全按预估来要留出20%左右的余量给重试和意外情况。5.3 实测结果与关键观察这个系统上线后单个竞品分析任务从原来单Agent串行的四十多分钟压缩到七分钟左右提速接近六倍。质量上由于每个Agent只处理自己负责的局部任务各环节输出的准确率反而比单Agent长链路高出不少——因为上下文短了模型注意力更集中。中间观察到一个有趣的现象限流阈值从4并发提6并发的尝试中在数据源没限流的前提下总耗时反而轻微上升。原因是几个棘手的竞品需要较长的分析时间多出来的两个并发Worker处理的是简单任务早早就跑完了对整体进度没有帮助。这个问题暴露了蜂群的一个本质特性——整体吞吐量由最慢的那个Worker决定单纯加并发不能解决长尾问题。后续优化方向是把慢Worker的任务再拆细拆分后并发度保持不变。5.4 这个方案的可持续优化空间从这套系统继续往下走还有几个明确可优化的方向。第一个是动态任务再分配。现在任务拆完就固定派发了有的Worker早早干完闲置有的Worker卡在长任务上。可以做一层轻量调度某个Worker空闲时把长任务中尚未完成的部分转移给它。这个优化预计能再压缩10%到15%的耗时。第二个是沉淀共享知识库。每轮任务里调研Agent如果发现新的数据源或新的市场信息可以写回到一个知识库中下一轮任务直接复用。这相当于给蜂群装了一个长期记忆。第三个是引入反馈闭环。质控Agent标注的问题可以回传成提示词改进建议下一轮任务自动优化各角色的系统提示词。这需要跑几轮数据后才能见效但回报非常直接——我统计过系统提示词优化两轮之后同一类型任务的返工率降低了近三成。6. 常见问题与排查技巧实录6.1 高频问题速查表实操中遇到的最典型问题按出现频率排了个序现象根本原因排查思路解决方案Worker输出JSON解析报错提示词没有约束格式模型放飞自我查看某Worker的完整输出原文系统提示词加入JSON Schema示例解析失败自动触发一次格式修复重试多个Worker输出互相矛盾信息源不一致或时效不同检查每个结果的数据来源标记汇总阶段引入投票或按时间戳加权总耗时没有随并发提升而下降长尾Worker拖慢整体进度分析各Worker耗时分布拆分慢任务配合动态任务再分配系统上下文溢出扇入前没有做压缩检查每个Worker返回消息大小在扇入管道入口强制压缩超阈值即触发摘要十几分钟后熔断结果不完整预算设置过低或有Worker陷入死循环调用工具检查工具的调用次数分布给Worker设置单任务工具调用次数上限同一任务重跑结果差异很大模型输出固有随机性对比两轮各Worker的中间结果对重要任务增加投票Agent或对输出做温度参数调低6.2 几个容易踩的深坑第一个坑是任务拆解时给Worker派发了模糊任务。比如调研竞品A的情况这个任务太大了Worker不知道要调研到多细才算完。正确拆法是把任务明确到动作级别调研竞品A的功能列表输出包含功能名称、简介、上线时间三个字段的JSON数组。任务描述越具体Worker输出越稳定。第二个坑是忽视了Worker之间的信息不对称。两个Worker分别调研不同竞品时一个可能已经发现某条通用市场信息另一个不知道导致重复劳动。轻量解决办法是在任务描述里给一个领域背景字段所有Worker启动时共享一份简短背景说明降低信息不对称带来的重复成本。第三个坑是没有给蜂群设置退出条件。有的Worker会因为任务目标太开放而一直迭代优化永远不返回。给每个Worker设置最大步骤数和时间上限很重要。我在代码里默认的最长执行时间是90秒超过直接标记为超时并返回已有中间结果至少留点东西给聚合阶段用总比毛都没有强。第四个坑也是我个人体会最深的子Agent的失败信息一定不要吞掉。系统刚上线时我在日志里只记录task failed这类笼统信息结果排查问题时完全没法定位根因。后来改成失败信息必须携带失败阶段、上游消息id、错误原文摘要排查效率提升了不止一倍。6.3 排查时推荐的工作方式如果正在调试一个蜂群任务我建议先用日志把链路画出来任务是怎么拆解的、每个Worker的耗时和结果状态、哪一步开始出现异常。绝大部分问题都能在这条链路上看出端倪。具体操作上我给日志系统加了几个查询快捷命令。输入trace_id查全链路输入task_id查询某个子任务的所有相关消息输入agent_id看某个Worker在某个时间段内干的所有事情。这套检索逻辑在排查多Agent问题时的效率比肉眼翻原始日志高好几个量级。关于Agent调试还有一个心得本地复现时把模型输出全部落盘存成文本文件不要只存在内存或数据库里。模型输出的可读性和可检索性决定了排查问题的速度。某个模型输出出了格式问题直接翻出原始文件看它究竟输出了什么比在数据库里捞字段轻松得多。最后分享一个让我获益最大的设计——给蜂群配一个死信区。所有约定了输出格式但解析失败的Worker结果不直接丢弃统一丢进一个叫dead_letter的目录。这个设计看似只是给失败结果找了个地方放实际作用远超预期定期翻死信区你能快速发现是哪类任务、哪个Agent、哪种提示词最容易产出畸形结果然后针对性修复。蜂群跑的轮次越多死信区沉淀的改进线索越厚实。我现在的习惯是每跑五十轮任务就翻一次死信区每次都能改掉一两个顽固问题这个习惯比我花大价钱调提示词模板划算得多。