
我最早对多智能体Multi-Agent开发产生兴趣并不是因为看了什么框架宣传而是被一个非常实际的问题逼的单个大模型Agent根本撑不住复杂长任务。去年我在搭一个自动生成行业分析报告的工具最开始只有一个Agent给它配了检索、统计、写作几把工具结果惨不忍睹——它会把从网上抓来的数据和正文里的结论混在一起写到一半忘记自己前面定的章节结构面对互相冲突的数据时也不会主动判断只会把两段话硬拼到一起。后来我把这个单Agent拆成五个各司其职的智能体协作跑起来之后问题反而迎刃而解。也是从那以后我才算真正摸到了多智能体开发的门道。这篇文章会从为什么需要多智能体、主流协作模式、框架选型、实战代码、常见坑和完整排查案例这几个角度展开。不管你是刚接触Agent开发的新手还是已经在用LangChain、AutoGen只要你想把“多个大模型角色协同工作”这件事做得稳定、可控、可维护这篇文章应该都能给你一些参考。1. 为什么非要拆成多个智能体单Agent的上限与多Agent的边界1.1 单Agent做长任务问题出在“上下文污染”和“角色矛盾”很多人一开始都在单Agent里塞角色描述比如写一段长长的System Prompt“你是一名研究员、分析师、编辑、写作专家、审稿人……”这确实能跑通一些简单任务但只要任务一复杂立刻露馅。原因有两个。第一是上下文污染。一个Agent在同一个上下文窗口里既要看检索结果又要回忆大纲又要组织语言写正文还要检查错误。不同性质的信息互相干扰模型很容易把工具返回的原始文本直接抄进正文。第二是角色矛盾。你让同一个模型既“客观检索、不带预设”又“给出鲜明观点、做出判断”这两个要求在同一个注意力范围里是互相竞争的。我实测下来这种模式下生成的报告经常出现一种很典型的问题开头说“市场增长乏力”结论却写“建议激进扩张”前后逻辑完全对不上。多智能体的核心价值就在这里把一个大而全的角色拆成几个小而专的角色每个智能体只维护自己那份上下文只对自己的任务负责。就像开餐厅一个厨师要同时管切菜、炒菜、摆盘、算账肯定手忙脚乱但你把它拆成墩子、炉头、传菜员每个人专注一件事整体效率反而更高。1.2 多Agent协作的三种主流模式编排、会议、流水线多智能体不是简单地把几个Agent丢在一起它们之间的组织方式决定了整个系统的成败。我在实践中归纳出三种最常用的模式。编排者-执行者模式Orchestrator-Workers一个主控Agent负责任务分解把大任务拆成子任务分发给执行Agent再汇总结果。适合任务边界清晰的场景比如“先检索行业规模再分析竞争格局最后写市场前景”。会议/评审模式GroupChat多个Agent在同一个对话组里轮流发言互相补充、互相质疑最后达成共识。适合需要多角度讨论的场景比如产品方案评审、报告审校。但代价是token消耗高且容易陷入无休止的客套。流水线/图模式Pipeline/Graph严格按照节点顺序执行可以带条件分支和循环。适合步骤明确、需要强控制的场景比如“检索 → 数据分析 → 写大纲 → 写初稿 → 审核 → 修改”。三种模式不是对立的实际项目里往往混合使用。比如我的报告生成系统主体用的是流水线模式但在最后的审校节点用了局部会议模式——让评审Agent和写作Agent针对修改意见进行最多两轮交互既保住了整体流程可控又获得了讨论带来的质量提升。我用一张表来对比三种模式的维度差异模式控制力灵活性成本最适合的场景编排者-执行者中高中任务可分解需要动态规划会议/评审低很高很高头脑风暴、方案评审、多角度审校流水线/图很高中较低业务流程固定、步骤清晰我的建议是能用流水线解决的不要上会议能用编排解决的不要上自由讨论。多一个智能体就多一层不确定系统越开放越难调试。1.3 什么时候不要用多智能体多智能体不是银弹。我自己在几个项目里踩过坑之后总结了几条“别用”的判断标准。任务太简单别用。翻译、摘要、关键词提取这种单轮任务一个Agent做得又快又好拆成多Agent纯属浪费token。角色边界不清晰别用。如果两个Agent的职责高度重叠比如“研究助理”和“信息收集员”模型根本分不清谁该干什么最后就是互相抢活或者互相推诿。对延迟和成本极度敏感别用。每次Agent之间的交接都意味着一次完整的模型调用多Agent系统的token消耗通常是一个同能力单Agent的3到10倍。如果产品对响应时间有硬性要求多Agent方案可能一开始就不成立。没有日志和评测体系别用。多Agent的失败模式比单Agent多得多如果没有完整的运行日志、中间状态记录出问题的时候你连定位都做不到。我看到太多人连单Agent的Prompt都没调明白就一头扎进多Agent最后变成“公开debug”现场。记住这句话多智能体的本质是用更多模型调用换取更强的任务处理能力是一种资源换效果的策略不是越多越好。2. 框架选型与架构设计AutoGen、LangGraph、CrewAI怎么选2.1 三个框架的核心设计思路目前最常被提到的多智能体开发框架有三个AutoGen、LangGraph、CrewAI。很多人都问我该学哪个我的回答是别急着学先搞清楚它们的设计哲学。AutoGen是某大厂开源的智能体框架核心概念是ConversableAgent可对话智能体和GroupChat群聊。它的思路是把多个Agent放进一个聊天组让它们像真人开会一样轮流发言再通过人类或代码检查来终止对话。优点是思想直观、代码量极小特别适合快速验证“多Agent能不能解决我的问题”。缺点是流程控制很弱你很难精确告诉它“先做A再做B除非遇到C才做D”一切靠Agent自主发挥状态管理也偏弱。LangGraph走的是另一条路它把多Agent流程建模成一张图——节点是Agent或工具边是流转条件全局有一个State状态对象在节点间传递。它的设计哲学是“可控优先”。你可以精确控制每个节点的输入输出可以实现条件分支、循环、断点续跑。代价是学习曲线比较陡你得花时间理解StateGraph、Node、Edge这些概念代码量也明显更大。CrewAI是三者中上手最快的它的核心概念是Agent、Role角色、Task任务三件套。你只需要声明式地定义“角色是什么、任务是什么、工具是什么”框架就会自动编排执行。问题在于灵活度低遇到非标准流程时需要写很多hack复杂项目里后期维护会比较痛苦。2.2 我用的选型标准与结论我自己的选型标准就三条流程控制够不够强、状态可不可观测、能不能断点续跑。流程控制意味着我们能不能强制Agent按既定步骤走而不是靠它“自觉”状态可观测意味着运行到一半出问题时我们能从日志里看到每个节点的输入输出断点续跑意味着某个Agent崩了之后我们可以从失败节点恢复而不是整个任务从头再来。按这个标准复杂业务系统我优先选择LangGraph或同类图编排方案。AutoGen适合做原型验证和探索性任务比如“我想看看三个Agent互相讨论能不能产生更好的结果”它的低代码优势会非常明显。CrewAI则适合没有强流程要求的团队内部工具几天就能跑出可用版本。我把差异整理成一张参考表评估维度AutoGenLangGraphCrewAI上手速度快慢最快流程控制力弱强中状态可观测性中强弱复杂分支支持弱强中典型使用场景会议式协作、原型验证业务流程、状态机控制快速演示、简单RPA一句话总结如果你心里已经清楚流程长什么样用LangGraph这类图框架把流程固化成代码如果你还不清楚流程用AutoGen快速探索。我在模拟项目X里最终选择了图编排方案后面的实战拆解也基于它。3. 实战搭建行业分析报告自动生成系统的完整拆解模拟项目X3.1 角色定义与边界设计我做的这个模拟项目X目标是给定一个行业主题自动产出一份结构完整、数据支撑充分的分析报告。整个系统由五个智能体组成每个角色只干一件事角色核心职责可调用工具输出研究员Researcher检索行业背景、市场数据、政策信息网络搜索、网页读取facts列表数据分析师Analyst根据facts输出统计口径、趋势判断本地数据计算脚本数据分析结论主编Editor制定报告大纲分配章节任务无纯LLM推理章节目录撰稿人Writer按大纲和facts撰写初稿无纯LLM推理各章节正文评审员Reviewer审校初稿提出修改意见无纯LLM推理修改意见列表这个角色设计的核心是“责任边界清晰”。每个Agent的输出结构都不同任何一个环节出问题你都能立刻定位是哪一步。比如facts摘录错了问题只可能出在研究员大纲逻辑不对问题只可能出在主编。如果我把这些角色揉成一个Agent出了问题你根本不知道是哪个环节背锅。还有一个很重要的细节工具权限要严格隔离。数据分析师不能调网络搜索研究员不能直接生成最终结论撰稿人不能修改数据。多Agent系统里Agent会主动越权去调用它能调的所有工具尤其是当模型觉得“数据不够”的时候。所以权限控制要在工具层做而不是仅仅在Prompt里口头要求。3.2 基于图编排的实现与核心代码我以LangGraph风格的状态图来演示整个流程代码做了简化重点看结构。from typing import TypedDict, List class ReportState(TypedDict): topic: str facts: List[str] # 研究员收集的事实 analysis: str # 分析师的数据结论 outline: str # 主编定的大纲 draft: str # 撰稿人的初稿 review_comments: str # 评审员的意见 final_report: str # 终稿 def researcher_node(state: ReportState) - dict: 检索并整理事实写入 facts # 实际调用网络搜索然后让LLM浓缩成结构化条目 raw_pages search(state[topic]) facts llm_condense(raw_pages, max_items30) return {facts: facts} def analyst_node(state: ReportState) - dict: 根据 facts 做数据分析和趋势判断 analysis llm_analyze(state[facts]) return {analysis: analysis} def editor_node(state: ReportState) - dict: 根据 facts analysis 制定大纲 outline llm_make_outline(state[topic], state[facts], state[analysis]) return {outline: outline} def writer_node(state: ReportState) - dict: 按大纲撰写正文 draft llm_write(state[outline], state[facts], state[analysis]) return {draft: draft} def reviewer_node(state: ReportState) - dict: 审核初稿返回修改意见 comments llm_review(state[draft], state[facts]) return {review_comments: comments} def should_revise(state: ReportState) - str: # 如果评审意见里有“必须修改”类的问题返回 revise否则 accept return revise if must_fix in state[review_comments] else accept # 构建状态图 graph StateGraph(ReportState) graph.add_node(researcher, researcher_node) graph.add_node(analyst, analyst_node) graph.add_node(editor, editor_node) graph.add_node(writer, writer_node) graph.add_node(reviewer, reviewer_node) graph.set_entry_point(researcher) graph.add_edge(researcher, analyst) graph.add_edge(analyst, editor) graph.add_edge(editor, writer) graph.add_edge(writer, reviewer) graph.add_conditional_edges( reviewer, should_revise, {revise: writer, accept: finish} ) graph.add_node(finish, lambda state: {final_report: state[draft]}) graph.add_edge(finish, END)这段代码看起来简单但包含了一个很重要的设计条件循环。撰稿人和评审员形成一个“修改回路”最多可以执行N轮这是靠外部代码控制的。我看到很多人直接用“让评审员自己决定要不要返回给撰稿人”结果就是两个Agent陷入无限互相客套的循环。我的做法是顶层定义一个循环次数上限比如max_review_rounds 3超过就直接走终稿节点宁可接受一个仍有小瑕疵的报告也不能让任务无限运行下去。每个节点的内部逻辑本质都是“把特定上下文拼成Prompt → 调用大模型 → 解析结果写入State”。其中研究员节点最复杂它需要维护一个内部循环检索 → 阅读 → 决定是否补充检索 → 再检索……这个循环同样有次数上限我在后面排查案例里会详细讲这里出的问题。3.3 共享记忆与状态设计最容易崩的地方多Agent系统有一个非常容易被忽略的关键点每个Agent每次调用模型时模型本身是无状态的。大家共享的唯一“记忆”就是你定义的那个State对象。这意味着State字段设计得不好整个系统都会受影响。我在模拟项目X里总结了几条状态设计原则。第一字段最小化。State里只放“下一步必须用到的信息”不要把所有中间过程都塞进去。比如研究员只把“浓缩后的30条facts”写入State而不是把30个网页原文塞进去。这一步直接让整条链路的token消耗降低了至少一个数量级。第二长内容用摘要替代全文。如果跨节点需要传递长文档不要传原文传摘要。我在项目里设置了一条硬性规则任何节点往State里写入的内容超过2000字必须先让LLM做一次压缩摘要。第三结构化优于自由文本。facts用列表大纲用Markdown层级修改意见用“问题级别原文引用修改建议”的结构化格式而不是一大段自然语言。结构化输出方便下游节点解析也能减少模型输出格式漂移。第四可见性隔离。不是所有上下文都要给所有Agent看。编辑不需要读30条facts原文它只需要分析师给它的最终结论评审员可以看facts原文来核对数据但不需要看检索过程中的原始URL列表。我在实现时给每个节点配了独立的提示词模板只从State里挑它需要的字段注入而不是每次都把所有字段拼进去。这四套原则做下来系统的稳定性和成本控制都会有质的提升。多Agent开发大部分“看起来很难”的问题其实都是状态设计偷懒导致的。4. 多Agent协作中最容易踩的四个坑4.1 上下文爆炸token开销失控多Agent系统跑一段时间后最常见的问题就是token开销激增。根因很简单每个Agent的上下文不是独立维护的而是沿着图节点不断累积的。尤其是会议式协作模式每个Agent都能看到其他所有人的发言于是每多一个Agent每个人的上下文都要膨胀一圈。到了第5轮讨论可能每个Agent的上下文里都躺着前面所有Agent全部的聊天记录而真正有用的信息只占其中的一两个片段。我控制上下文爆炸的手段有三个一是全流程使用“摘要传递”每个Agent输出后先浓缩再进State二是在Agent调用模型时只注入与当前任务直接相关的字段三是设立单节点上下文上限超过上限就自动触发摘要压缩。这招很有效但必须在系统初期就设计好而不是等token账单炸了再补救。4.2 角色越权Agent会“顺手”干了不该它干的事多Agent开发里一个非常反直觉的现象是只要工具权限不收紧Agent一定会越权。研究员明明只需要检索但当它看见自己的工具列表里有“生成图表”工具时它可能会顺手调用来生成图表因为它觉得这张图对后续任务有帮助。越权带来的问题比想象中严重。首先它会改变State内容下游节点本来预期输入是一组facts文本结果进来一张图的路径解析直接失败。其次越权调用消耗了额外的token和工具资源还会污染日志让你排查问题时多一层干扰。我的做法是“工具权限白名单制”每个Agent在定义时显式声明可调用工具运行时在工具调度层再做一次校验。校验不通过直接拦截并返回错误信息让Agent知道“这个工具你无权调用”。不要指望模型靠自觉遵守规则代码层的硬控制永远比提示词可靠。4.3 死循环与重复工具调用多Agent系统跑久了另一个高频事故是死循环或重复调用。表现形式很典型Agent反复调用同一个工具得到相同的结果然后又调用一次或者评审Agent和撰稿Agent对同一句话来回修改每一轮都变一点但总体没有进展。根因通常有三个。一是缺少“已完成记录”上下文里没有标记这个动作已经做过模型不知道它正在重复劳动。二是终止条件太弱Agent之间的循环靠“一方觉得满意”来结束但模型往往倾向于“再改一改”。三是工具调用没有幂等性同一个检索请求每次返回结果都被当作新信息写入State。我的对策是“外部强控”每个工具调用记录带时间戳和参数哈希写入日志同一个哈希值短时间内不允许重复调用每个Agent的工具调用次数用计数器硬限制达到上限就自动跳转下一节点关键死循环靠超时强制退出。所有“停止”逻辑一律放在图编排层而不是让Agent自己决定。4.4 结果不一致与不可复现多Agent系统还有一种让人抓狂的问题同一个任务跑三次三次结果都不一样甚至有两次完全跑不通。这主要是因为大模型采样有随机性加上多Agent链路长任何一步输出的微小波动都会被下游放大。我提高可复现性的手段包括在模型服务端支持时把temperature固定为0或较低值用JSON Schema强制输出格式避免模型飘把关键决策点如报告大纲在前序节点生成后就固化到State下游只能微调不能推翻重写建立回归测试集每次修改完Prompt都跑同一组用例对比输出质量和运行日志。我的回归测试集只有10个主题样例规模不大但足以在每次改动后快速暴露死循环、格式解析错误、token暴增等问题。这套回归体系后来帮我省下的调试时间远超建它花的时间。5. 一次完整的问题排查实录研究员Agent重复检索引发token暴涨5.1 现象与初步怀疑有一次压测模拟项目X我拿一个信息密度比较高的行业主题做压力测试结果吓一跳单次任务耗时从平时的2分钟飙升到14分钟token消耗翻了大几十倍。打开运行日志一看发现“researcher”节点的工具调用记录里同一个关键词组合被检索了37次而正常情况下这个节点最多调用5次。我的第一反应是“重复检索”。但问题在于为什么Agent要反复检索同一个东西是网络搜索返回内容为空还是状态写入失败了还是提示词里有什么东西诱导它不断补充信息带着这三个猜测我开始了逐层定位。5.2 定位链路日志、状态快照、代码逐层查我先查日志中的工具调用序列发现每次检索后研究员Agent都往State里写了一轮新文本但文本内容几乎一样唯一区别是措辞微调。这说明它每次都能真的拿到数据数据也被写入了State不是写入失败。接着我查了State在两次检索之间的快照。发现一个关键细节研究员Agent内部有一个“是否信息充分”的判断逻辑它的判断依据不是“已经收集了多少条facts”而是“我在当前对话历史里看到的信息是否足够”。因为研究员每读取一个新页面后会把页面原文加进自己的对话上下文但State里的facts却在每次调用后被覆盖写成了“前一次的浓缩结果”。也就是说研究员在下一轮对话里看到的是“历史上下文中的原始网页 最新State里的浓缩结果”它总觉得最新那版不够完整于是继续检索。最后查代码问题彻底清楚了。我的研究员节点实现里有一个bug每轮循环结束时都会用最新一次的结果覆盖state[facts]而不是追加。正常逻辑应该是把新的facts条目追加到已有列表里覆盖写导致前几轮的有效信息在下一次循环开始时就“看不见”了模型误以为前面收集的信息全丢了只能重新检索。这个问题的隐蔽性在于它不是一个会崩溃的bug而是一个“看似在运行、实际在空转”的逻辑错误。如果系统没有结构化的State日志只看最终输出你只会觉得“这次任务慢了点”很难想到是状态覆盖导致的重复劳动。5.3 修复方案与验证定位到根因后我做了四处修改。第一修State写入逻辑facts从覆盖改为追加并添加去重逻辑用“规范化后的文本片段”做去重主键相似度超过阈值的条目自动合并。第二给检索工具加内存缓存相同参数组合在短时间内的重复调用直接返回缓存结果不真正执行网络请求。第三在研究员节点外层加“最大工具调用次数5”的硬限制超限直接构造结论并跳转到分析师节点不再给模型自我循环的空间。第四在提示词里明确告诉研究员“每完成一次有效检索就往facts里追加条目你不需要为了确认信息充足而重复检索后续节点会基于facts判断。”修复后我用同一个测试用例做验证工具调用次数从37次降到5次单次任务耗时从14分钟回落到3分钟token消耗下降约七成当天压测的另外两个主题也都通过了。更让我意外的是报告质量反而提升了因为追加后的facts列表信息量更加完整撰稿人拿到的事实依据更丰富正文数据缺失的问题也减少了。这次排查给我的教训是多Agent系统里任何“循环节点”都必须一眼能看出“它往全局State里写了什么、写了多少次、什么时候停”。如果State结构不清晰、日志不全这类性能问题会伪装成随机卡顿排查起来非常痛苦。所以我在后来所有项目里都坚持节点必须单数入、单数出能纯函数化就纯函数化。6. 成本评测与上线经验让多Agent系统稳定跑起来的几个关键6.1 成本控制从“事后看账单”到“事前定预算”多Agent系统的成本不透明是劝退很多人的主要原因。我现在的做法是给每个任务设定一个“token预算帽”超帽直接中断或降级到简化流程。这个预算不是拍脑袋定的而是基于历史运行数据的统计。以模拟项目X为例一个中等复杂度的行业主题原先的无约束运行成本很高拆解下来大头是“研究员”和“评审员”两个节点它们分别占据了总token的40%和25%。研究员是因为重复检索评审员是因为要反复阅读全文。针对这两个大头做裁剪后整体成本降到了可接受范围。成本控制的核心手段可以归纳为四句话能传摘要的不传原文能缓存的不重复算能早终止的不多跑一轮能白名单控制的不开放全部工具。6.2 评测怎么做别只看“感觉效果变好了”多Agent系统上线前一定要有自己的评测集和评测指标。我的评测体系分三层。第一层是运行态指标包括任务完成率有结果输出且没触发死循环、平均工具调用次数、单任务总token、最长运行时长、节点失败率。这些指标不需要人工直接靠日志自动统计。第二层是内容质量指标包括报告章节完整性、事实一致性抽取报告中的关键数字和研究员facts列表对比是否一致、格式合规率。第三层是主观评分让真人按1到5分对报告的可读性、逻辑性、结论合理性打分。我建议每周跑一次全量回归每次改Prompt或改代码之后至少把评测集完整跑一遍。没有评测体系的多Agent系统改进基本靠运气有了评测体系你每次改动都能看到量化结果才不会在“好像变好了”和“好像变差了”之间反复横跳。6.3 上线后的灰度与可观测性最后说上线经验。多Agent系统和生产环境单接口最大的区别是一个任务可能调用模型几十次持续几分钟甚至十几分钟任何一个中间环节失败都可能影响最终结果。所以上线时必须做两件事。第一结构化日志。每条日志除了时间、节点名之外还要记录“该节点的输入摘要、输出摘要、调用工具列表、耗时、token数、错误码”。这样出问题时可以直接按运行ID拉出整条链路。第二单节点failover。研究员节点检索失败不能整个任务崩溃应该允许它用已有facts生成报告并在日志里标记数据覆盖度较低评审员节点超时则默认通过并记录日志。系统能降级运行才算真正具备上线条件。我在模拟项目X里还做了一项灰度验证先在测试环境跑真实用户过去的数据确认稳定性后才切一部分真实流量进来。结果果然在灰度阶段又发现了一个新问题——几个Agent在超长主题上会出现互相等待的情况因为某个节点把输入字段设成了“依赖上一节点返回”而上一节点却在等待它的确认。这类问题只有在真实数据流下才会暴露所以千万别跳过灰度。最后再分享一个小技巧评审Agent的提示词里务必加一句“只提必须修改的硬伤不要为了体现专业度而堆叠风格类意见”。不加这句话评审员会花好几轮去改撰稿人的用词风格两个Agent在“连词是否恰当”这种问题上无限拉扯。加了之后评审意见的可用率明显提升修改轮次也稳定降到了1到2轮。这个细节很小但对多Agent系统的稳定性影响很大尤其是在长流程任务里。