1. 为什么偏偏是编排:Agent 数量上来之后的那道坎
1.1 从单 Agent 到多 Agent,复杂度不是线性增长
我第一次真正意识到编排问题,是在做一个内部知识库问答系统的时候。最初只有一个 Agent,用户提问,Agent 检索,生成回答,整个流程简单到用几十行代码就能跑完。后来需求变成了要接入实时库存、要做多轮追问、要调用三四个外部工具,还要让一个"主管"Agent 去判断该把问题转给哪个子 Agent。那一瞬间,代码开始失控。
如果把一个 Agent 想象成一个人,单 Agent 工作就像是个人单打独斗,你只需要管好他自己的待办清单。但多个 Agent 一起干活,就变成了一支团队,团队里有人做前端接待,有人查数据库,有人做质检,还有人负责最后签字。此时你真正要管的不是每个人怎么干活,而是他们之间怎么交接、按什么顺序配合、出了问题谁来兜底——这就是编排。换句话说,编排解决的不是"每个 Agent 多聪明",而是"一帮 Agent 合在一起能不能像一个靠谱的组织一样运转"。
这个复杂度不是线性增长的。两个 Agent 之间只需要一种协作关系,五个 Agent 之间潜在的交互路径就已经是十种以上。而且 Agent 本身有随机性:同样的问题,语言模型的输出可能每次都不一样。没有编排约束的时候,整个系统的行为就像一场没有导演的即兴剧,今天能跑通,明天换个措辞就卡死在某一步。所以编排不是锦上添花,而是多 Agent 系统从 demo 走向生产之间必须补上的一课。
1.2 编排到底在编排什么:任务拆分、状态流转与工具调度
很多人一说编排就想到搭一个流程图,把几个节点连起来。但真正做下来你会发现,编排至少有四层事情要做。
第一层是任务拆分:一个复杂目标怎么切成足够小、足够明确的子任务。例如"整理本月销售报告"这个目标,在单 Agent 场景里可能是直接写提示词,但在多 Agent 场景里需要拆成"拉数据""分析异常""生成图表""撰写结论"四步,再决定每一步由谁执行。拆分得越清晰,后面对话和纠错越容易。
第二层是状态流转:所有 Agent 共享的上下文、中间结果、进度标记如何在步骤之间传递。这里最容易踩坑——每个 Agent 如果只看到局部消息而不了解全局状态,就会出现"铁路警察各管一段"式的混乱:销售 Agent 认为价格已经算过折扣,财务 Agent 却不知道折扣系数从哪来的。
第三层是工具调度:哪个 Agent 在什么条件下可以调用哪个外部接口、调用权限和频率怎么管控。不做好这层,Agent 可能会乱调工具,或者某个冷门接口被高频请求打爆。
第四层是异常处理:超时、重试、降级、失败转移、人工介入。很多人做完前三层就上线,结果一个外部服务的偶发超时就让整条链路卡住,这就是把编排想浅了的表现。我的经验是,一个真正能落地的编排系统,异常处理占的代码量往往比正常路径还多。
2. 编排的七种常见模式:从串行到事件驱动的取舍
多 Agent 编排没有银弹,不同的协作关系对应不同的模式。这些年我陆续在几个项目里实践过七种模式,按适用场景从简单到复杂给你捋一遍,每种模式都有它自己的脾气。
2.1 串行管道模式
这是最基础的一种:A 的输出直接作为 B 的输入,像工厂流水线一样,一个工序接着一个工序。适合那些目标明确、顺序固定的任务,比如"先提取关键词,再搜索资料,最后写摘要"。
串行模式的优点是好理解、好调试,任何一个环节出问题都能直接定位。缺点也很明显:整条链路的延迟等于所有环节延迟之和,而且一旦前面的 Agent 给出低质量输出,后面的 Agent 会基于错误继续加工,错误被逐级放大。
我建议在串行模式下,每个环节都要显式校验上一轮的输出格式和关键字段,如果不符合要求,宁可重试也不要硬着头皮往下传。
2.2 并行扇出/聚合模式
当一个任务可以拆成互不依赖的多个子任务时,就让多个 Agent 同时开工,最后再把结果汇总。典型场景是市场调研:同时让几个 Agent 分别去分析竞品、用户评论、行业报告,最后汇总成一份报告。
扇出模式能大幅缩短耗时,但聚合阶段是个难点。各个子任务的返回格式可能不一致,甚至内容相互矛盾。你需要设计一个聚合 Agent,或者用规则把结果合并。我踩过的坑是:并行子任务都拿同一个系统提示词生成,结果它们回传的报告结构高度雷同,聚合价值大打折扣。实际上应该让每个子 Agent 的提示词和输出模板明确差异化,聚合时才不会像在玩连连看。
2.3 路由与条件分支模式
路由模式是指一个主管/分发 Agent 先理解用户意图,再把请求转给对应的子 Agent。比如客服系统里,先判断用户是想退货还是想查物流,分别转到售后 Agent 和物流 Agent。
路由的核心在于分类准确率。分类错了,后面全白搭。我通常会在路由 Agent 后面加一个置信度阈值,低于阈值的请求直接转人工,而不是硬交给某个子 Agent。另一个细节是路由结果要进入日志,方便日后分析意图分布,反过来优化路由 Prompt。
2.4 协商/投票模式
让多个 Agent 各自提出方案,然后通过投票或辩论达成一致。这种模式在创意生成、代码评审、复杂决策里很有用。例如让三个 Agent 分别扮演架构师、运维和业务方,对一个技术方案发表意见,再让一个主持人 Agent 汇总并权衡。
协商模式最怕的是"集体迷失":大家都顺着第一个发言的结论跑,投票变成走过场。解决办法是让每个参与 Agent 先独立思考并输出理由,再汇聚到主持人那里,主持人必须明确记录分歧点,而不是简单取多数。
2.5 计划-执行模式
这种模式把编排分成两步:Planner Agent 先根据目标生成一个多步计划,然后由 Executor Agent 逐步执行,必要时 Planner 会根据中间结果调整后续计划。它适合目标开放、步骤不明确的场景,比如"帮我策划一场线下活动"。
计划-执行模式的难度在于计划的可执行性。我曾经遇到过 Planner 制定了一个非常漂亮的五步计划,但第二步就涉及一个根本不存在的内部接口,执行 Agent 直接卡死。后来我在计划阶段加了一个"工具清单检查"约束,让 Planner 在输出计划时必须对照当前可用的工具和权限清单逐条打勾,这种低级错误就基本消失了。
2.6 人机协同模式
有些决策风险太高,不能让 Agent 自己拍板,需要在流程里留一个"人工确认"节点。比如 Agent 自动写好了群发邮件,发送前需要负责人点一下确认。这类模式经常用在财务、法务、对外发布等场景。
人机协同要注意的是人工节点的触发时机和超时处理。我的经验是:把人工确认设计成队列中的一个特殊任务,如果人在规定时间内没有响应,系统可以自动降级为"不执行"或"延迟执行",并在日志里标记。这里最忌讳的是把人工节点挂在异步流程里但没有超时机制,结果整个流程等人等到天荒地老。
2.7 事件驱动与消息总线模式
当 Agent 数量再多一些,硬编码的流程就不够用了。事件驱动模式让每个 Agent 监听自己关心的事件,收到触发后执行任务并发布新事件,完成的 Agent 之间通过消息总线解耦。比如库存变化事件会同时触发补货 Agent、通知 Agent 和数据报表 Agent 并行工作。
这种模式扩展性最强,但可观测性和调试难度也最大。你不再有一条清晰的"主流程",所有事情都是异步发生的。如果没有良好的追踪体系,出了 bug 只能靠日志大海捞针。所以除非你的系统真有动态扩展需求,否则不要轻易上事件驱动,它是七种模式里运维成本最高的。
3. 手写编排 vs 编排框架:我为什么最终选了后者
3.1 第一个可运行的版本:用代码硬编
在了解各种编排框架之前,我第一版多 Agent 系统是纯手写的:每步就是一段 Python 代码,调用一下模型接口,处理返回结果,再决定下一步调用哪个函数。硬编码的好处是毫无学习成本,逻辑完全在自己手里,出了问题也能快速加日志排查。
但很快问题就来了。首先是状态管理:我需要同时维护多个中间变量、步骤状态和上下文历史,代码里到处都是if step == "xxx"和global_state这种写法,改一个流程要动很多处。其次是重试逻辑:每个工具调用我都要自己写try-except和重试退避,代码重复率极高。最痛苦的是可视化需求——业务方想看"这个 Agent 系统内部到底怎么跑的",我对着代码讲了一个小时,他们还是摇摇头。
其实手写编排在 Agent 只有两三个、流程几乎没有分支的情况下是完全可行的,甚至比引入框架更划算。但一旦流程分支多、需要人机确认、需要失败重试,纯手写就会变成维护负担。这个分界线大概在"流程节点超过十个"或者"存在两种以上并行关系"时会出现。
3.2 状态管理、重试与可视化的三重压力
手写方案撑不住,主要是被三座山压垮的。
第一座是状态管理。多 Agent 协作最需要的是全局共享的上下文,但不同 Agent 只能看到自己被授权的部分。手写时我得自己实现一套"状态作用域"机制,还要考虑状态如何持久化——系统重启后中间状态丢了怎么办?这已经很接近一个工作流引擎的功能了,自己从零写属于重复造轮子。
第二座是重试和补偿。真实生产环境里,模型接口的限流、数据库的超时、第三方 API 的抖动,都是家常便饭。正确的做法是区分"可重试"和"不可重试"的错误,设计指数退避和熔断策略。手写这套逻辑不仅工作量巨大,而且容易有遗漏,往往会漏掉某些节点。
第三座是可视化。说白了,业务方、老板、甚至我自己都希望一眼看清 Agent 流程跑到哪一步了。手写代码很难呈现这种视图,而编排框架天然内置了图形化的执行图,可以实时显示每个节点的状态。后来我直接给同事看框架的执行面板,他们说"这才叫流程"。
3.3 主流编排框架的真实对比
市面上号称能做 Agent 编排的工具不少,但定位差异很大,选错了等于自找麻烦。我拿自己实测过的几类给你对比一下。
第一类是图编排型框架,比如 LangGraph 这类。它的核心是把流程定义成一张图,节点是 Agent 或工具函数,边是流转关系,支持条件分支和循环,还内置对话状态管理。它比较适合在语言模型工作流里做精细的流程控制,社区里参考案例也比较多。
第二类是协作型框架,比如 AutoGen 和 CrewAI 这波讨论度较高的项目。它们强调"多 Agent 对话协作",Agent 之间像开会议一样你来我往。好处是能处理一些非结构化协作,坏处是流程不可控性增加,跑出来的结果可能不稳定,需要比较强的 Prompt 调教能力。
第三类是通用工作流 / 任务队列引擎,比如 Airflow、Temporal 这类。严格来说不是给 Agent 设计的,但如果你已经有了完整的技术栈,它们也能扛住任务编排、重试、超时和分布式执行。缺点是要自己接入模型调用,Agent 相关的状态管理要自己做。
我最终的选择是,核心生产链路用图编排型框架,外围的定时任务、长耗时流程用工作流引擎,而协作型框架只用来做头脑风暴和探索性任务。每一类工具都有它的舒适区,硬把一个框架用到所有场景,结局大概率是事倍功半。
4. 一次真实的多 Agent 客服系统编排复盘
4.1 场景与约束
为了不让你觉得上面都在讲抽象概念,我分享一个实际项目:某电商平台的智能客服系统。这个项目一开始只有一个问答机器人,后来接到需求,要让它能处理售前咨询、订单查询、物流进度、退货退款四类业务,并且一些高风险操作需要人工复核。
技术选型上,我知道不能全指望一个大模型 Agent 一把抓,因为业务方对每个模块的答复口径有强约束,模糊的指挥会让系统说出不合适的承诺。于是我们把任务定义成四类专用 Agent,外加一个调度 Agent、一个质检 Agent 和一个工单 Agent。调度 Agent 做意图识别和路由,四个业务 Agent 分别处理具体业务,质检 Agent 对即将返回用户的答案做合规检查,工单 Agent 负责在必要时创建转人工工单。
这个系统要跑在生产环境,约束条件包括:每个会话必须在 5 秒内响应用户,库存、订单接口的调用频次受限,超过一万种商品信息不能全量放进上下文,而且所有对外回复必须经过口径校验,不能由模型自由发挥。
4.2 编排流程设计
整个流程我设计成了三条主线。
第一条是常规问答线:用户消息进来,先由调度 Agent 判断业务类型,如果置信度较高,就分发到对应的业务 Agent;业务 Agent 产出草稿后进入质检 Agent 检查,质检通过就直接回复,不通过就退回重写或转人工。
第二条是订单查询线:这一步要实时调用订单系统,所以我在业务 Agent 之前加了一个"参数提取 Agent",先让模型把用户问题里的订单号、手机号后四位等结构化信息提取出来,再用规则校验这些字段的合法性。校验不过就直接向用户索要正确信息,校验通过才真正调用订单接口。这个设计避免了大模型凭空编造查询参数。
第三条是退货退款人工线:当质检 Agent 判断请求超出自动处理范围(比如退货金额超过阈值),就触发工单 Agent,创建一个待人工处理的任务,同时给人任务分配超时。工单 Agent 不直接回答用户,而是告知"我们已生成人工工单,请留意电话回访",并在超时后自动给处理人发提醒。
流程跑起来之后,调度准确率初始只有 87%,主要误判发生在"退货规则咨询"和"订单查询"之间。后来我在调度 Agent 的 Prompt 里加入了一个少样本示例,把两种意图的边界案例写清楚,准确率超过了 95%。
4.3 踩坑记录与解决
这个项目里踩了一批很有代表性的坑,挑几个给你说。
第一个坑是质检 Agent 和业务 Agent 互相甩锅。业务 Agent 生成的回答经常被质检 Agent 以"违反口径"为由打回,导致用户等了几秒才收到回复。后来我检查日志发现,质检 Agent 的检查标准其实比业务 Agent 的提示词描述更严格。解决办法是,把质检规则也注入到业务 Agent 的系统提示词里,让它在生成阶段就主动避开口径问题,而不是等事后拦截。
第二个坑是订单接口的并发限流。促销期间用户咨询量暴增,大量 Agent 同时调用订单接口,触发了订单系统的限流保护。我们原本没有做并发控制,结果越多请求越超时,用户体验更加差。后来加了一层信号量限流,同时把请求排队做成异步,高峰期主动在回复里告知用户"当前查询人数较多",反而把接口压力控制住了。
第三个坑是状态丢失。由于每个业务 Agent 被设计成无状态,用户的连续追问(比如先查订单号 A,再追问"那运费呢")会让业务 Agent 丢失上文。我们最终在上下文里引入了一个"会话摘要"结构,每轮对话后由摘要 Agent 生成简短记忆,下一轮请求时带上。这个机制后来也变成了系统的核心模块之一。
5. 编排中的隐藏细节:状态、超时、幂等、可观测性
5.1 上下文状态的作用域与传递
已经不止一次提到状态了,但状态这个问题值得单独拎出来说。在实际编排系统里,状态至少分两层:流程状态和上下文状态。流程状态记录了当前执行到哪个节点、已完成哪些步骤,这是引擎帮你管理的;上下文状态则记录了业务数据,比如订单号、用户 ID、临时结果。上下文状态最容易出错的地方是作用域——某个中间变量到底只在一个子流程内可见,还是全链路共享?
我的建议是设计时明确三类作用域:局部于单个 Agent 调用、局部于单个会话、全局共享。凡是涉及外部系统返回的敏感字段,尽量只保留在局部,必须传递时脱敏,避免日志和上下文里堆积无关数据。实际项目中,我们曾把外部接口的完整响应串进了下一个小模型的 Prompt,结果上下文塞得满满的,响应慢且费用暴涨。后来只在状态里存"摘要后的关键字段",问题立刻缓解。
5.2 超时、重试与退避策略
模型接口调用不是传统函数调用,它可能很慢,也可能报错。编排系统里如果没有全局超时策略,一个慢请求就能阻塞整条链路。我常用的做法是分级超时:模型生成调用设 30 秒超时,外部 API 调用设 10 秒超时,内部函数调用设 5 秒超时。超时后先判断错误类型,可重试的(如 429 限流、503 过载)做指数退避重试,第一次 1 秒、第二次 2 秒、第三次 4 秒,最多三次;不可重试的(如 400 参数错误)直接进入失败分支,交由上层的异常处理模块处理。
这里有一个很多人忽略的点:重试次数和退避上限要根据用户可感知等待时间来确定。客服系统等不起 1+2+4=7 秒的重试,所以我给模型调用设定的是最多重试 2 次,总耗时控制在 10 秒内。而离线报表任务则可以放宽到 5 次重试,因为没人等着它实时响应。
5.3 幂等性与补偿
编排系统里每个节点都可能失败,但失败后重试会带来一个隐患——重复执行。以"下单后发短信通知"为例,消息队列可能在发完短信后还没确认就宕机了,消息重投后就会给用户发两条一模一样的短信。解决办法是给每个有副作用的操作定义一个幂等键,比如订单号+通知类型的组合。执行前先查一下是否已经处理过,处理过就直接返回成功,不再重复触发外部动作。
补偿则是更进一步的保障。如果流程中间某一步成功、后一步失败,你需要把前面已经做出的修改回滚。比如一个退款流程,先调用支付平台退款成功,再更新本地订单状态失败,如果不做补偿,就会出现"钱退了但系统显示未退"的脏数据。我们设计的补偿策略是:记录每步的执行结果到一张审计表,失败时反向执行补偿动作,并标记补偿是否成功。补偿本身也必须幂等。
5.4 日志追踪与可观测性
多 Agent 系统最大的可观测性挑战是:一个用户请求会触发多个 Agent 接力,每个 Agent 内部又有若干模型调用和工具调用。没有统一追踪,你根本不知道回答到底是谁生成的、中间经历了什么。我们项目里最终接入了链路追踪体系,为每个用户请求生成唯一 trace ID,所有日志、模型调用记录、外部 API 调用都带上这个 ID。这样排查问题时,可以通过 trace ID 把整条链路拉出来,逐节点看耗时和输出。
另外,我会为每个 Agent 节点记录输入输出摘要、模型消耗的 token 数、延迟和重试次数,汇总成每日报表。这些数据不仅是排查问题的基础,更是后续优化 Prompt 和拆分 Agent 的重要依据。不要等到线上出了问题才想到埋点,从第一天跑通 Demo 时就要把可观测性做上,这是我可以给你的最诚恳的建议。
6. 给后来者的编排检查清单
6.1 设计阶段先回答的六个问题
如果你正准备做一个多 Agent 系统,先不要急着写代码。停下来把下面六个问题在白板上写清楚,再动手:
- 这个流程是固定顺序,还是需要动态决策?固定顺序用串行或并行就够了,动态决策需要引入路由或计划-执行模式。
- 各 Agent 之间是资源竞争还是明确分工?明确分工更适合图编排,资源竞争则要考虑并发控制。
- 失败的影响面有多大?如果一个环节失败会让整个任务作废,还是只需要局部重试?这决定了你要不要引入补偿机制。
- 用户能等多久?实时场景必须严格控制超时与重试次数,异步场景则可以使用更重的重试策略。
- 每个 Agent 的输入输出是否符合统一接口规范?如果各 Agent 的数据格式五花八门,最后聚合会崩溃,不如提前定义好统一的消息契约。
- 谁有最终解释权?当多个 Agent 的结论冲突时,是投票、是规则、还是人工?这个问题不回答,生产环境就会随机给你一个烂结果。
6.2 落地阶段的八个检查项
设计定了之后,落地阶段对照下面这些检查项逐条过一遍:
- 每个 Agent 的调用是否有超时设置?没有就默认为无限等待,这是故障放大器。
- 是否对模型输出做了结构校验?如果期望 JSON 却可能收到 Markdown,解析前先做校验和清洗。
- 是否记录了 trace ID?没有 trace ID,线上问题排查等于黑夜摸鱼。
- 是否处理了重试幂等?重复调用外部接口会造成生产事故,这条必须确认。
- 是否有熔断机制?当外部 API 连续失败时,直接切换到降级话术,而不是继续疯狂重试。
- 是否有人工介入通道?至少在高风险操作上,要能随时中止自动流程转人工。
- 上下文是否做过长度审计?每轮对话后检查上下文占用,防止 token 膨胀拖垮模型调用。
- 是否做了金丝雀发布?新编排版本先对 5% 流量生效,观察一段时间再全量,多 Agent 系统的行为比较难预测,全量切换容易直接翻车。
6.3 什么时候不要用编排
最后也是一个反直觉的提醒:不是所有多 Agent 场景都需要编排。如果你的 Agent 之间只是简单的"调用一个再调用一个",而且不存在失败恢复需求,那直接用代码串起来可能更简单。还有,一个 Agent 如果通过精心设计的工具调用链能解决所有问题,就不要硬拆成五个 Agent——Agent 越多,通信成本、token 消耗和出错的概率都会上升。
编排的本质是用额外的计算和管理开销换取可控性和扩展性。当单 Agent 已经足够搞定任务,强行编排只会把简单问题复杂化。我在实际项目中见过原本 50 行代码能完成的功能,被人为拆成 4 个 Agent 协作,结果每次回复都要多花 3 倍时间和 4 倍 token。这个教训说明,编排是工具,不是目的。好的系统设计者应该知道什么时候加编排,更要知道什么时候不加。
回到文章开头那句话:Agent 编排的功夫,全在把"一群各有想法的模型"管成"一支步调一致的服务团队"。它考验的不只是对某个框架的熟练度,更是对状态、异常、契约和可观测性的综合把控。希望这篇梳理能帮你在自己的 Agent 系统里少走一段弯路。