1. 从单Agent到多Agent为什么一个全能助手的路线走不通我最早接触Agent开发的时候和大多数人一样脑子里想的是造一个什么都能干的超级助手。给它挂上搜索、代码执行、文件读写、浏览器操作再配一个足够长的系统提示词理论上它就能处理所有任务。这个思路在Demo阶段非常爽一个Agent跑通全流程演示效果拉满。但一旦往生产环境推问题就集中爆发了。最典型的症状是上下文污染。一个Agent既要记住用户的原始意图又要记住中间调用了哪些工具、返回了什么结果、当前进行到哪一步还要在每一轮对话里保持人设和格式约束。当任务链路超过七八步之后提示词里塞进去的历史信息开始互相干扰模型会忘记早期的关键约束或者把某个工具的返回结果误当成用户指令。我实测过一个客服场景单Agent在处理退款换货查询物流三件事混在一起时错误率比拆成三个专职Agent高了将近40%。第二个症状是能力耦合导致的调试地狱。当搜索、计算、写文件全在一个Agent里一旦输出格式出错你根本不知道是提示词的问题、工具描述的问题还是模型在某一步推理跑偏了。每次改一处提示词可能把另一个本来正常的流程搞崩。这种牵一发动全身的体验做过复杂Prompt工程的人都懂。多智能体系统Multi-Agent System的核心思路就是把一个全能选手拆成一支分工明确的团队。每个Agent只负责一个相对窄的领域有自己的系统提示词、自己的工具集、自己的输出格式约束。Agent之间通过编排器Orchestrator来协调谁先干、谁后干、结果怎么传递全部显式定义。这样做的好处是每个Agent的上下文窗口更干净职责边界清晰出问题能快速定位到具体是哪个环节。但这里有个常见的误解需要先澄清多Agent不等于多个模型实例。很多人以为多Agent就是开三个GPT-4的API并行跑其实不是。多Agent的本质是角色分离与流程编排底层可以是同一个模型甚至可以是不同厂商、不同规模的模型混用。一个负责意图识别的Agent可以用小模型负责复杂推理的Agent用大模型负责格式校验的Agent甚至可以用规则引擎代替。这种异构组合才是多Agent架构真正的成本优势所在。提示如果你现在的单Agent系统已经出现改A坏B、上下文越堆越长、错误无法归因的情况那就是该考虑多Agent拆分的信号了。不要等到系统彻底不可维护才动手。2. 编排器到底在编排什么三种主流协作拓扑的取舍编排器Orchestrator是多智能体系统的大脑它决定了Agent之间怎么协作。市面上常见的协作拓扑大致分三类我按实际落地难度和适用场景逐个拆解。2.1 流水线式Pipeline最稳但最不灵活流水线式就是A做完交给BB做完交给C像工厂装配线一样。每个Agent的输入是上一个Agent的输出职责极其清晰。这种拓扑的优点是可预测性极强每一步的输入输出都能打日志、做校验出问题一眼就能定位。缺点是无法处理需要回退或分支的任务。比如用户问帮我查一下上周的订单如果还没发货就取消流水线式就很难处理如果这个条件分支。我一般建议新手从流水线式入手因为它最容易调试。你可以先把一个复杂任务拆成固定的N步每步一个Agent跑通之后再考虑引入分支。2.2 主管-工人式Supervisor-Worker灵活但有调度开销这种拓扑里有一个主管Agent负责理解任务、拆解子任务、分派给不同的工人Agent最后汇总结果。主管Agent本质上是一个路由器加协调者。它的优势是能处理动态任务——用户的需求千变万化主管可以实时决定调用哪些工人。但这里有个坑主管Agent本身也会犯错。如果主管把任务分错了后面的工人再努力也是白搭。我踩过一次坑主管Agent把查询账户余额的任务分给了负责发送邮件的工人结果工人拿着查询请求去调邮件API直接报错。后来我在主管的提示词里加了强约束每个工人Agent必须有一段明确的能力描述主管只能从能力描述里选不能自由发挥。2.3 黑板式Blackboard适合复杂协作但实现成本高黑板式是指所有Agent共享一块黑板通常是一个共享的内存或数据库每个Agent都可以读写黑板上的信息根据黑板状态决定自己要不要行动。这种模式适合需要多轮协商、信息共享的场景比如多个Agent共同分析一份财报各自贡献不同维度的分析最后汇总。但黑板式的实现复杂度最高因为你要处理并发读写冲突和状态一致性。多个Agent同时往黑板上写谁先谁后、冲突怎么解决都需要额外设计。我个人的经验是除非任务真的需要多Agent反复协商否则不要轻易上黑板式维护成本会让你怀疑人生。拓扑类型适用场景实现难度调试难度我的推荐指数流水线式步骤固定的任务如文档处理、数据清洗低低新手首选主管-工人式需求动态变化如客服、任务分派中中生产环境主流黑板式多轮协商、联合分析高高按需使用选拓扑的核心原则是能用流水线就别用主管-工人能用主管-工人就别用黑板。每增加一层灵活性就多一层不确定性和调试成本。很多团队一上来就搞最复杂的架构结果连最基本的流程都跑不稳。3. Agent之间的通信协议消息传递里藏着最多的坑多Agent系统里Agent之间怎么说话是决定系统稳定性的关键。我见过太多项目Agent单独跑都没问题一串联就各种格式错乱、信息丢失。问题基本都出在通信协议上。3.1 结构化消息是底线自由文本是灾难最原始的做法是让Agent直接输出自然语言下一个Agent去解析。这种做法在Demo里能跑在生产里必崩。因为自然语言有歧义A Agent说订单已处理B Agent可能理解成已发货也可能理解成已取消。正确的做法是强制结构化输出。每个Agent的输出必须是一个JSON对象包含固定的字段比如{ task_id: order_123, status: completed, result: { action: cancel_order, reason: not_shipped, confidence: 0.95 }, next_agent: notification_agent }这样下一个Agent拿到的是明确的字段而不是一段需要猜的自然语言。我在项目里强制要求所有Agent的输出必须通过JSON Schema校验校验不通过就重试重试三次还不行就报错。这个约束看起来死板但把线上事故率降了一个数量级。3.2 上下文传递传什么、不传什么Agent之间传递上下文时最容易犯的错误是把整个对话历史全传下去。这样做的后果是上下文窗口迅速膨胀后面的Agent被无关信息干扰。正确的做法是只传必要信息。我通常会把上下文分成三层任务层当前任务的ID、目标、约束条件这些必须传。结果层上一个Agent的输出结果按需传。历史层之前的交互记录默认不传除非当前Agent明确需要。举个例子用户问帮我订一张明天去北京的机票要靠窗。意图识别Agent输出{intent: book_flight, destination: 北京, date: 明天, preference: 靠窗}。订票Agent只需要这些字段不需要知道用户之前还问过天气。如果把完整对话历史传过去订票Agent可能会被天气这个无关词干扰。3.3 错误传递与重试机制多Agent系统里一个Agent失败会级联影响后面的Agent。所以必须设计错误传递协议。我的做法是每个Agent的输出里都带一个status字段取值success、retry、fail。如果上游Agent返回retry编排器就重新调用它如果返回fail编排器要么走降级流程要么直接终止并通知用户。这里有个细节重试不能无脑重试。如果Agent是因为输入格式错误而失败重试一百次也没用。所以我在重试逻辑里加了判断如果是格式错误先让一个修复Agent尝试修正输入如果是超时或临时故障才直接重试。注意Agent之间的通信协议一定要在项目初期就定死不要等到系统跑起来再改。改通信协议等于把所有Agent的提示词和解析逻辑全部重写成本极高。4. 并发与状态管理多Agent系统最容易翻车的地方单Agent系统基本不涉及并发问题但多Agent系统一旦上生产并发就是绕不开的坎。我见过一个团队Demo阶段用单线程跑得好好的一上线遇到十个用户同时请求系统直接雪崩。问题就出在状态管理和并发控制上。4.1 无状态Agent与有状态编排一个重要的设计原则是Agent本身尽量无状态状态由编排器统一管理。Agent每次被调用时输入是完整的上下文输出是结果它自己不保存任何跨请求的状态。这样做的好处是Agent可以水平扩展十个请求可以分给十个Agent实例并行处理。但编排器必须是有状态的它要记住每个任务的进度、当前走到哪一步、下一步该调谁。编排器的状态通常存在数据库或Redis里key是任务IDvalue是当前状态。这样即使编排器重启任务也能从断点恢复。4.2 并发冲突同一个任务被重复处理最常见的并发问题是同一个任务被多个编排器实例同时处理。比如用户点了两次提交或者消息队列重复投递导致同一个任务ID被处理了两遍。如果这个任务是扣款那就出大事了。解决办法是加锁。编排器在处理任务前先尝试获取任务ID对应的分布式锁拿到锁才处理处理完释放锁。拿不到锁说明已经有实例在处理了直接跳过。这个锁的粒度要细锁的是单个任务不是整个系统。4.3 超时与死锁Agent卡住了怎么办Agent调用外部API时可能超时如果编排器没有超时机制整个任务就会一直挂着。我的做法是给每个Agent调用设置硬超时比如30秒。超时后编排器记录日志然后决定是重试还是走降级流程。还有一种更隐蔽的问题是死锁。比如Agent A等Agent B的结果Agent B又等Agent A的结果两个都卡住。这种情况通常出现在黑板式架构里。避免死锁的方法是设计单向依赖A依赖BB就不能依赖A。如果业务上确实需要双向依赖就拆成两个阶段第一阶段A产出第二阶段B产出不要在同一阶段互相等待。并发问题典型表现解决方案任务重复处理同一任务被执行多次分布式锁 幂等设计Agent超时任务长时间挂起硬超时 重试/降级循环等待多个Agent互相等待单向依赖 分阶段设计状态不一致编排器状态与实际不符状态机 定期对账4.4 幂等性让重复执行不出错幂等性是并发场景下的保命符。所谓幂等就是同一个操作执行一次和执行多次结果一样。比如查询余额天然幂等扣款就不幂等。对于不幂等的操作要在执行前检查是否已经执行过。我的做法是在数据库里建一张操作记录表每次执行前先查这个操作ID是否已存在存在就直接返回上次的结果。5. 记忆与上下文工程多Agent系统的共享大脑怎么建多Agent系统里记忆管理比单Agent复杂得多。单Agent只需要维护一份对话历史多Agent则要处理哪些记忆共享、哪些记忆私有、记忆怎么在Agent之间传递的问题。5.1 短期记忆与长期记忆的分层我把记忆分成两层短期记忆是当前任务执行过程中的临时信息任务结束就丢弃长期记忆是跨任务需要保留的信息比如用户偏好、历史交互记录。短期记忆通常放在编排器的内存或Redis里key是任务ID。每个Agent执行时编排器把相关的短期记忆注入到它的上下文里。长期记忆则存在向量数据库里需要时通过语义检索召回。这里有个关键决策哪些信息进长期记忆。我的原则是只存对未来任务有用的信息。比如用户说我不喜欢靠过道的座位这个偏好值得存用户说今天天气不错这个就不用存。判断标准是如果下次用户再来这条信息能不能帮我更好地服务他。5.2 记忆的写入时机与冲突处理记忆写入最容易出的问题是冲突。比如用户上次说我喜欢靠窗这次说我喜欢靠过道两条记忆冲突了怎么办。我的做法是给每条记忆加时间戳和置信度检索时优先返回最新的、置信度最高的。如果两条记忆明显矛盾就在注入上下文时都带上让Agent自己判断或者直接问用户确认。另一个坑是记忆污染。如果Agent把错误的信息写进了长期记忆后面所有任务都会受影响。所以我在写入长期记忆前加了一道校验只有置信度超过阈值的记忆才允许写入低置信度的先放短期记忆等确认后再转长期。5.3 上下文窗口的预算管理每个Agent的上下文窗口是有限的多Agent系统里上下文要在多个Agent之间分配。我的做法是给每个Agent设定上下文预算比如意图识别Agent只给2000 token复杂推理Agent给8000 token。编排器在注入上下文时按预算裁剪优先保留任务相关的信息历史信息按时间倒序保留。这个预算管理听起来简单但实际做起来很考验对业务的理解。你得知道每个Agent真正需要什么信息才能合理分配。我一般会先让Agent跑一段时间统计它实际用到的上下文比例再反过来调整预算。6. 落地实战从零搭一个可用的多Agent系统前面讲的都是原理和设计这一节讲具体怎么落地。我以一个智能客服工单处理场景为例完整走一遍搭建流程。6.1 场景拆解与Agent划分假设需求是用户提交工单系统自动分类、自动处理简单问题、复杂问题转人工。我把它拆成四个Agent分类Agent读取工单内容判断是退款、换货还是咨询。信息提取Agent从工单里提取订单号、用户ID、问题描述等结构化信息。处理Agent根据分类结果调用对应的业务API处理。回复Agent生成给用户的回复文案。编排器负责按顺序调用这四个Agent并在处理Agent失败时决定是否转人工。6.2 每个Agent的提示词设计要点分类Agent的提示词要窄而明确只让它做分类不要让它顺便提取信息。我见过有人把分类和信息提取塞进一个Agent结果分类准确率下降。原因是模型在同时做两件事时注意力被分散了。信息提取Agent的提示词要给出明确的字段定义和示例。比如订单号格式为ORD开头加8位数字这样模型提取时有个参照。不给示例的话模型可能把用户随口说的数字当成订单号。处理Agent的提示词要强调工具调用的前置条件。比如调用退款API前必须先确认订单状态为已支付。这个约束能避免很多无效调用。回复Agent的提示词要控制语气和格式。我一般会给出几个正例和反例让模型模仿正例的语气。6.3 编排器的状态机设计编排器本质上是一个状态机。我用的是最朴素的状态机每个任务有一个状态字段取值classifying、extracting、processing、replying、done、failed。编排器根据当前状态决定调哪个AgentAgent返回后更新状态。状态机的转移规则要写死不要让模型来决定下一步。模型只负责在当前Agent内部做决策跨Agent的流程由代码控制。这样能保证流程的确定性。6.4 日志与可观测性多Agent系统没有日志就是瞎子。我在每个Agent的输入输出都打了日志包括任务ID、Agent名称、输入上下文、输出结果、耗时、token消耗。这些日志存在Elasticsearch里出问题时能快速检索。除了日志我还加了链路追踪。每个任务有一个trace_id所有Agent的调用都带上这个ID这样能在追踪系统里看到完整的调用链路一眼看出是哪一步慢、哪一步错。提示可观测性不是上线后才补的要在开发阶段就建好。我一般会在第一个Agent跑通后就把日志和追踪加上后面每加一个Agent都自动接入。7. 踩过的坑与性能优化让系统真正扛住生产流量系统能跑通和能扛住生产流量是两回事。这一节分享几个我在生产环境踩过的坑和对应的优化手段。7.1 模型调用延迟并行化能省一半时间多Agent系统里模型调用是最大的延迟来源。如果四个Agent串行调用每个平均2秒总延迟就是8秒。用户等8秒基本就流失了。优化的关键是找出可以并行的步骤。比如分类Agent和信息提取Agent其实可以并行因为它们都只依赖原始工单内容互不依赖。并行之后这两个步骤的延迟从4秒降到2秒。处理Agent和回复Agent有依赖关系必须串行但回复Agent可以在处理Agent返回后立即开始不用等日志写完。我实测下来合理的并行化能把端到端延迟降低40%到60%。但并行化也有代价并发调用会增加API的QPS压力如果用的是有速率限制的API可能触发限流。所以并行度要根据API的限额来定不能无脑并行。7.2 缓存哪些结果可以复用有些Agent的输出是可以缓存的。比如分类Agent如果两个工单内容完全一样分类结果肯定一样没必要重复调用。我在分类Agent前面加了一层缓存key是工单内容的哈希命中缓存直接返回。但缓存要小心时效性。比如查询订单状态这种Agent结果随时会变不能缓存。我一般只缓存那些输入相同则输出稳定的Agent比如分类、信息提取、格式转换。7.3 降级策略模型挂了怎么办生产环境必须考虑模型服务不可用的情况。我的降级策略分三级一级降级切换到备用模型。比如主用大模型备用小模型虽然效果差一点但能保证服务不中断。二级降级走规则引擎。对于分类这种任务如果模型不可用可以用关键词匹配兜底。三级降级转人工。如果前两级都不可用直接把任务转给人工客服并给用户一个明确的提示。降级策略要提前设计好不能等故障发生了再临时想。我一般会在系统里加一个开关运维可以手动切换降级级别。7.4 成本控制不是所有Agent都需要大模型多Agent系统的一个隐性成本是token消耗。如果每个Agent都用最贵的模型成本会高得吓人。我的做法是按任务复杂度分配模型Agent类型任务特点推荐模型成本占比分类/提取简单判断输出结构化小模型低推理/决策复杂逻辑需要理解大模型高格式转换机械转换规则引擎极低回复生成需要自然语言中等模型中这样分配下来整体成本能比全用大模型降低60%以上而效果下降不明显。关键是要对每个Agent的任务难度有准确判断不能一刀切。8. 多Agent系统的安全边界与权限隔离多Agent系统里Agent能调用的工具越多风险越大。一个被恶意输入操控的Agent可能调用它本不该调用的工具。所以权限隔离是多Agent系统必须做的功课。8.1 最小权限原则每个Agent只给必要的工具我在设计Agent时严格遵循最小权限原则。分类Agent只给文本分类工具不给任何写操作的工具。处理Agent才给业务API的调用权限而且只给当前任务需要的API。比如退款Agent只给退款API不给转账API。这样做的好处是即使某个Agent被提示词注入攻击它能造成的破坏也有限。我见过一个案例一个Agent被用户输入诱导调用了删除数据的API就是因为那个Agent的权限给太大了。8.2 工具调用的二次确认对于高风险操作比如退款、删除、修改用户信息我在编排器层面加了二次确认。Agent调用这类工具时编排器先拦截检查是否满足预设条件比如金额是否超过阈值、是否已经确认过满足才放行。这个二次确认不是让用户确认而是系统内部的校验。比如退款金额超过1000元编排器就要求处理Agent提供额外的确认信息否则拒绝执行。8.3 输入输出的安全过滤Agent的输入可能包含恶意内容输出可能包含敏感信息。我在编排器的入口和出口都加了过滤。入口过滤是检测提示词注入的常见模式比如忽略之前的指令这类话术。出口过滤是检测输出里是否包含手机号、身份证号等敏感信息包含就脱敏。这些过滤规则不可能覆盖所有情况但能挡住大部分低级攻击。安全是个持续对抗的过程规则要定期更新。9. 写在最后一些不那么技术但很重要的经验做多Agent系统这一年多技术上的坑踩了不少但真正让我印象深刻的是一些非技术层面的经验。第一不要为了多Agent而多Agent。我见过一些团队明明一个Agent加几个工具就能解决的问题非要拆成五个Agent结果复杂度上去了效果反而下降。多Agent的价值在于职责分离和流程可控如果一个任务本身很简单单Agent完全够用就别折腾。第二Agent的粒度要反复调。拆得太粗等于没拆拆得太细Agent之间通信开销比干活还大。我一般会先粗拆跑一段时间看哪些Agent经常一起被调用就把它们合并哪些Agent内部逻辑太复杂就再拆。这个粒度不是一次定死的要迭代。第三提示词版本管理很重要。多Agent系统里每个Agent的提示词都是一份配置。改提示词等于改代码必须版本化。我用Git管理所有Agent的提示词每次改动都记录原因和效果出问题能快速回滚。第四测试要覆盖Agent之间的交互。单Agent测试只能保证单个Agent正常多Agent系统的bug往往出在交互上。我专门写了一套集成测试模拟完整的任务流程覆盖各种异常情况比如某个Agent超时、返回格式错误、返回空结果等。第五别忽视人工兜底。再好的多Agent系统也有搞不定的情况。我在每个关键节点都留了转人工的入口用户不满意可以随时转人工Agent处理不了的也自动转人工。人工兜底不是失败而是系统成熟度的体现。最后分享一个我常用的调试技巧当多Agent系统出问题时我会把整个调用链路的输入输出打印出来按时间顺序排列然后从最后一个出错的Agent往前倒推看是哪一步的输入不对。这个方法看起来笨但比盲目改提示词有效得多。多Agent系统的调试本质上就是沿着数据流找断点找到断点问题就解决了一半。
阅读完成 · 觉得有帮助?