跳到主要内容

内容阅读

别为了多 Agent 而多 Agent:LangGraph Supervisor、Swarm 与放弃的时刻

Agent阿新聊ai

TL;DR: LangGraph 的多 agent 有两种主流拓扑:supervisor(中心调度,子 agent 当工具用)和 swarm(对等移交,谁接手谁主导)。先说结论:多 agent 不是能力升级,是用延迟和成本换上下文隔离。需要「不同工具权限、不同上下文、不同角色」三者之一才值得上;为了架构图好看而拆的多 agent,结果几乎都是更慢更贵更难调。

多 agent 是交换,不是升级

先立一个容易树错靶子的判断:多 agent 不是从单 agent「升级」来的更高级形态,它是一笔交换。你交出去的是延迟和成本,换回来的是隔离:上下文隔离、权限隔离、职责隔离。隔离是真金白银的收益,但只在你真的需要隔离时才值这个价。这个判断直接承接第 01 篇判断线的第三问,那一篇说了「多数号称需要多 agent 的需求不该拆」,本篇把「怎么拆、拆的代价、什么时候放弃」讲完。

为什么要把丑话说在前面?因为多 agent 的驱动力经常不是需求,是想象:架构图上五个框连着线,看起来比一个框专业;「每个角色专注自己的事」听起来符合管理学的分工常识。这些直觉是从人类组织借来的,而模型不关心你的组织图:它没有办公室政治,不会因为「身兼数职」而疲惫,一个配了二十个工具的单 agent 处理很多任务的效果,不比五个各配四个工具的 agent 差,还省了它们之间的沟通成本。

还有一个被低估的代价方向:故障面。单 agent 出问题,来源就那几类(模型、工具、prompt);多 agent 结构里,调度、移交、转述、合并都是新的出错点,一次任务的失败可能是三个 agent 里任何一个的锅,还可能是它们之间传递环节的锅。第 14 篇会讲调试成本,多 agent 是让调试成本翻倍的最常见单因素。故障面变大是「理由不够充分也要用多 agent」时多付的隐性保费,立项时它不写在方案里,出事时它全写在复盘里。

所以本篇的结构是:先看两种拓扑长什么样、怎么选,再把成本账算细,然后给出值得上的三个信号和该放弃的时刻。每一步都带着同一把尺子:这笔交换,你的任务买不买得起。

两种拓扑长什么样

Supervisor:hub-and-spoke。 一个调度 agent 接收任务,决定派给哪个子 agent,收结果、再调度,直到完成。子 agent 之间不直接说话,所有信息经过 supervisor 中转。适合任务可以清晰分解、有主次之分的场景,也是大多数人想象中的「多 agent」。

# pip install langgraph-supervisor
from langchain.agents import create_agent
from langgraph_supervisor import create_supervisor

researcher = create_agent(
    model, tools=[web_search],
    system_prompt="你只负责检索和整理资料",
)
writer = create_agent(
    model, tools=[write_file],
    system_prompt="你只负责根据资料写稿",
)

supervisor = create_supervisor(
    agents=[researcher, writer],
    model=model,
    prompt="把任务分给合适的助手,汇总结果",
).compile()

supervisor.invoke({"messages": [("user", "调研 LangGraph 并写一篇短文")]})

读这段代码要注意它的执行形状:这不是「一次调用跑三个角色」,而是一个循环。supervisor 看任务、决定派给 researcher,researcher 跑完返回,supervisor 重新看全局消息、决定下一步是再派 researcher 还是转 writer 还是收工。每一轮「决定」都是一次完整的模型调用,supervisor 的 prompt 和全部往返消息都要进它的上下文。子 agent 越多、轮次越多,这个循环越长。

supervisor 能派对活,靠的是它对每个子 agent 的「认知」,而这个认知完全来自你写的描述:子 agent 的名字、system prompt、它在 supervisor 视野里的工具描述。这些就是子 agent 的接口文档,写「负责检索」和写「负责网络资料检索与要点整理,不负责写作」的调度效果完全不同。supervisor 派错活的第一根源是接口文档含糊,调试调度问题时先读这几个字符串,比换模型、改图结构都优先。

Swarm:对等移交。 没有 boss,每个 agent 处理完自己的部分后,通过 Command(goto=..., graph=Command.PARENT) 把控制权直接移交给下一个。第 07 篇讲过这个机制:节点返回的 Command 指定作用域是父图,等于一个 agent 直接指挥顶层路由。适合流程天然分段、每段的专业工具完全不同的场景。典型例子是客服系统:「售前 → 下单 → 退款」三段,售前专家聊完把控制权交给下单专家,下单专家处理完交给退款专家,每一段有自己的工具、自己的 system prompt、自己的 state 视角。

swarm 里有两个设计问题要在写代码前想清楚。一是移交决策谁做:goto 的目标看起来是代码写死的,实际常由模型判断(prompt 里写清「什么时候该交给谁」),那么移交本身就是一个可能出错的模型决策。二是状态怎么跨段:移交时用 update 把必要字段写进共享 state,但写什么是接口设计,「售前聊到的需求要点」以什么结构留给下单段,是 swarm 方案里真正值得花时间的设计,比选库、画图都重要。拿售前的例子具体化:售前段产出「用户型号、预算区间、意向等级」三个字段,下单段只认这三个字段,退款段只认「订单号加原因」,每段的输出契约写进对应 agent 的 prompt 和 state 定义。契约清晰,移交才不丢话;契约含糊,用户就要在三段之间重复自述,这是 swarm 生产环境最常见的投诉形态。

Swarm:对等移交。 没有 boss,每个 agent 处理完自己的部分后,通过 Command(goto=..., graph=Command.PARENT) 把控制权直接移交给下一个。第 07 篇讲过这个机制:节点返回的 Command 指定作用域是父图,等于一个 agent 直接指挥顶层路由。适合流程天然分段、每段的专业工具完全不同的场景。典型例子是客服系统:「售前 → 下单 → 退款」三段,售前专家聊完把控制权交给下单专家,下单专家处理完交给退款专家,每一段有自己的工具、自己的 system prompt、自己的 state 视角。

选型的直觉:任务像「项目」用 supervisor,任务像「接力」用 swarm。项目的任务是发散的,谁做下一步要临场判断,中心调度看得全局;接力的任务是线性的,顺序天然固定,对等移交最省事,也省掉了 supervisor 每一轮的调度调用。接力的典型特征可以核对一下:段与段的顺序业务上就定死了(没有退款订单就没有退款环节)、每段的工具完全不重叠、段内自成闭环。三条全中,swarm 是更省的结构,少一个常驻的调度者。拿不准就 supervisor,中心调度的可观测性和可控性都更好:出问题看一个节点的决策记录就知道为什么走了这条路,swarm 的移交链要去每个 agent 的轨迹里拼。

Supervisor Swarm
控制流 中心循环调度 对等直接移交
每轮开销 supervisor 反复读全局状态 只有 agent 自己
适合的任务 发散、需临场分解 线性、天然分段
出问题时的排查 看调度记录 拼各段轨迹

表里最值得多看一眼的是「每轮开销」这行:supervisor 的调度者本身是常驻的模型调用,swarm 没有这个常驻成本,所以纯接力任务里 swarm 更便宜;而它换来的代价在最后一行,排查时没有集中的调度记录可看。便宜和好查,swarm 只能占一头。

成本账:多 agent 的代价写在调用手里

每多一个 agent 参与,就是多一轮完整的 LLM 调用,外加把必要上下文复述给它。这句话拆开是三笔账。

第一笔,调用次数。supervisor 模式下有一份持续的调度开销:每个子 agent 返回后,supervisor 都要重新看一遍全局状态再决定下一步。同样一个任务,单 agent 3 次调用能完成的,supervisor 加 writer 的结构轻松翻到 8 到 10 次:supervisor 的每轮决策一次调用,researcher 至少一两轮,writer 一两轮,中间的信息传递又是靠把消息塞进上下文完成的。把这笔账列成流水更直观:单 agent 是「思考 1 次、检索 1 次、写作 1 次」;supervisor 结构是「supervisor 分派 1 次、researcher 思考加检索 2 次、supervisor 收结果再分派 1 次、writer 写作 1 次、supervisor 验收汇总 1 次」,一共 6 到 8 次起步,任何一步不满意还会追加轮次。

第二笔,上下文复述。子 agent 之间不共享内存,A 的结论要让 B 知道,就得写进消息里让 B 重新读一遍。supervisor 的中转让这件事更贵:researcher 的结果先全文进 supervisor 的上下文,再由 supervisor 决定怎么转述给 writer。同样一万 token 的检索结果,单 agent 读一次,多 agent 结构里可能被读两三次。算一笔具体账:假设 supervisor 每轮的全局视野是两万 token,一个任务平均五轮调度,光 supervisor 的视野开销就是十万 token,这还没算子 agent 自己的消耗,而单 agent 基线整个任务可能也就五万。token 账单按倍数涨,涨的部分全是协调成本,没有任何一份花在「把任务本身做得更好」上。第 17 篇算部署成本时,这笔可以直接进对比表。

第三笔,延迟按串行链路最长的分支算。并行能压缩的只有彼此独立的分支(第 08 篇的 Send),而 supervisor 的调度循环天生是串行的:派活、等结果、再派活,一步等一步。用户感知的响应时间随着链路长度线性上涨,这通常比 token 账单更先被用户抱怨。

这三笔账加起来,就是 TL;DR 里「更慢更贵」的完整出处。更难调也顺带说清:单 agent 的一次失败,轨迹就是一条线,从头到尾顺序读;多 agent 的一次失败,轨迹是一个分叉树,supervisor 的决策、子 agent 的执行、它们之间的消息传递各有一条线,要拼起来才能还原现场。第 14 篇的观测方法能减轻这份负担,但减轻不等于消除,拓扑本身的决定已经做出了。

还有一个隐性的错误放大机制值得点名:转述是有损压缩。supervisor 转述 researcher 的结论给 writer 时,它转述的内容由模型现编,重要的限定条件可能在转述里丢掉,writer 拿到的是「经过一次耳语的结论」。单 agent 里不存在这个环节,因为理解和执行是同一个上下文。所以多 agent 结构里,子 agent 的输出格式越结构化越好,让「转述」尽量变成「传递」,损耗才有下限。

这笔账可以用一个指标直接量化:协调调用占比。把总调用次数里「不产出业务内容、只做调度和转述」的部分数出来,除以总数。健康的 supervisor 结构这个比例通常在三四成,超过一半就说明大部分钱花在了组织本身。这个指标还随任务复杂度变化:任务越简单,协调占比越高,这也是「简单任务别拆多 agent」的量化注脚。

两种拓扑各自的失控模式

成本是可预算的,失控是更麻烦的。两种拓扑各有自己的典型失控形态,写代码前知道长什么样,出了征兆能对号入座。

Supervisor 的失控是派错活和循环调度。任务描述含糊时,supervisor 可能在两个子 agent 之间来回摇摆:派给 A,A 返回「这不该我做」,supervisor 再派给 B,B 退回,直到撞上轮次上限。征兆是调度轮次数异常高、单个任务的成功率低于任何一个子 agent 单独跑的成功率。缓解手段按优先级:把子 agent 的职责描述写清楚(上一节说的接口文档)、在 supervisor 的 prompt 里写明各 agent 的边界和转接规则、给整个图设 recursion_limit 让循环有底。监控上盯两个数:单任务的调度轮次数和「子 agent 声明职责外」的出现频率,两个数一起涨就是摇摆开始了。如果这些做完还是摇摆,通常说明任务本身的分解方式不对,两个子 agent 的职责有重叠区,该改的是分工,不是调度。

Swarm 的失控是移交循环。A 移给 B,B 判断「这不是我的事」移回 A,A 再移回 B,用户看着两个专家互相踢皮球。防它的机制是收敛结构:每个 agent 只允许移交给定义好的下游(售前可以到下单和退款,下单只能到退款,退款是终点),移交表写死在代码里而不是全靠模型自由发挥;再加上全图轮次上限兜底。移交链是 linear 的 swarm 很少失控,出现网状移交(任意 agent 可移任意 agent)时,失控概率随边数上升,设计时尽量让移交图是无环的。

可靠性不构成上多 agent 的理由

社区做过不少可靠性对比试验,一个被反复复现的结论是:单 agent 和多 agent 在任务成功率上并无稳定显著差异。

这个结论很反直觉,因为「多几个角色互相检查」听起来理应更可靠。为什么实际不是?因为多 agent 在增加「检查视角」的同时,也增加了错误的发生点和传递链:supervisor 可能派错活,子 agent 之间可能传丢信息,移交的边界可能截断上下文。新增的纠错能力和新增的出错机会大致抵消,成功率曲线是平的。

所以如果有人拿「多 agent 更可靠」当立项理由,这个理由不成立。可靠性要靠评测和回归体系保证(第 15 篇),不靠拓扑。补一个公平的说明:评测场景里确实有靠多角色提升分数的做法,比如让独立的评判者打分,但那是评测装置的设计,跑分结束就撤,不是生产系统的常驻结构,别把排行榜技巧当成架构。多 agent 真正买到的东西只有一个:隔离。这条很反直觉,但和上面那笔账放在一起看很合理:你多花的钱买的是隔离和权限边界,不是更高的成功率。接下来的三个信号,说的就是什么样的隔离才值这个价。

值得上多 agent 的三个信号

信号一:权限必须分开。 能读代码的 agent 不能碰生产配置,能发邮件的 agent 不能动数据库。权限隔离是多 agent 最硬的理由,工具集不同,拆开是唯一干净的做法。它硬在机制上:权限的最小单位是「这个 agent 能看见哪些工具」,单 agent 里所有工具都在同一个可见集里,靠 prompt 写「你不要用这个工具」是君子协定,模型偶尔会忘;拆成两个 agent,工具集物理分开,越权的可能性直接归零。第 16 篇讲安全边界时,这是第一道防线。判断标准是审计视角:合规或安全团队是否要求「改生产配置的动作」和「其他一切动作」有明确隔离。要求,就拆;只是口头说说,先别拆。

信号二:上下文真的塞不下。 子任务的中间产物会污染主流程的上下文,最典型的是检索类任务:原始检索结果几十万 token,全塞进主对话,主 agent 的有效注意力被稀释,回答质量反而下降,账单还贵。常见的三类脏源:联网检索的原始网页、大文件的解析文本、大型代码库的探索过程记录。共同点是「过程数据量大、结论数据量小」,最适合拆出去让子 agent 在自己的 state 里消化,只回传结论,主流程轻装上阵。注意措辞是「真的塞不下」:塞得下但「看起来乱」,不是理由;模型对上下文里的冗余有一定的容忍度,撑到容量和成本的真实约束出现再拆。第 04 篇的 token 账单能帮你判断「塞不下」什么时候发生。

信号三:角色间需要交叉验证。 研究员和批评者、作者和审稿人,相互独立的视角有真实价值时。这条的适用面比前两条窄得多,因为「交叉验证」的价值建立在独立性上:两个 agent 如果共享同一个模型、同一份提示词风格,它们的盲区高度重合,所谓互相检查有相当部分是走过场。独立视角真实存在的场景是有的,比如生成内容和评判标准需要不同的推理路径,但上之前值得先跑一个小实验:找二十个已知的坏样本,先让主 agent 自查一轮记录漏报率,再让第二个 agent 复查一轮记录新增捕获,如果第二轮只多抓了一两个,每多抓一个的成本是几十次调用的钱,这笔账一算就清楚。增量小,就不值一轮调用的钱。

三个信号都没有,就一个 agent 配几组工具。还有一个折中多数人不知道:工具本身可以藏复杂度,一个「search_and_summarize」工具内部干再多事,agent 眼里只是一次调用。很多「需要多 agent」的判断,实际是「需要一个更厚的工具」:你需要的隔离是「检索的脏活别污染主对话」,一个返回摘要的工具就解决了,不需要一个会自己跑 ReAct 循环的子 agent。厚工具的组合形态也常用:几个相关的小工具合并成一个「计划生成」或「订单操作」入口,agent 的选择空间变小,选错率跟着降。厚工具是封装,多 agent 是组织,能用封装解决的组织问题都是伪组织问题。

放弃多 agent 的时刻

拆完不是终点。多 agent 结构运行一段时间后,放弃的信号会陆续出现,出现这些情况,拆开的结构就是在亏损:

子 agent 之间传的是「半成品上下文」,谁都得把别人的结论重新解释一遍,转述本身成了主要工作,转述损耗成了主要错误来源。supervisor 频繁派错任务,人工看着调度来回折腾:派给 researcher 的活被退回来换 writer,两轮调度调用白烧。调试时一次失败要翻三个 agent 的轨迹:在 A 的日志里看到异常,根因却在 B 昨天写入的中间结果里,而 C 的输出格式变了导致 B 写入的内容变形,因果链跨了两个 agent 和一次状态写入,第 14 篇讲的调试成本在多 agent 结构里成倍放大。症状不等于病灶,是多 agent 调试和单 agent 调试最大的区别。

遇到这些,合回去。图结构改起来不贵:supervisor 拆掉,子 agent 的工具并回单 agent,prompt 合并重写,一两天的事。真正贵的是僵在错误结构里继续运维:每一天都在为错误的隔离付协调成本,团队还在这个结构上继续堆功能。还有一层人的成本藏在多 agent 里:每个 agent 一套 prompt、一套工具描述、一套行为习惯,三套东西的维护心智是三份,新同事要理解的结构是三份。判断「该不该合」有个朴素标准:如果让你重新选一次,你还会拆吗?答案犹豫,就在该合的路上了。

不想靠感觉判断的话,盯三个数字。协调调用占比(前面定义过),持续高于一半是红灯。移交失败率或派错率,swarm 看移交给非预期目标的次数,supervisor 看子 agent 返回「职责外」的次数,超过一成说明分工设计有问题。单任务成本的中位数趋势,同等任务量下逐月上升,而模型价格没涨、任务没变难,涨的部分就是结构税。三个数字有两盏红灯,合并不需要再讨论。

上多 agent 的三步决策法

把本篇的判断收拢成一个可执行的顺序,避免「一上来就画五个框」。

第一步,立单 agent 基线。一个 agent 配齐所有工具,跑评测集(第 15 篇的那套),记录成功率和单任务成本。这个基线是后面一切比较的锚,没有它,「多 agent 更好」永远是一句没法证伪的话。评测集太小、基线数字抖动大时,先补评测再谈结构,顺序不能反:拿不稳的尺子量不出结构差异。

第二步,先试厚工具。看第一步暴露的问题能不能用封装解决:上下文被检索污染,就把检索包成返回摘要的工具;工具太多选不过来,就把低频工具合并成组合工具。多数问题到这一步就解决了,成本只增加了一次工具调用的开销。

第三步,还不行才拆,而且只拆有信号支持的部分。对照三个信号,哪个成立拆哪个:只有权限要隔离,就拆两个 agent,不要顺势拆五个;只有检索上下文问题,拆出一个研究子 agent,其余留在主 agent。拆完跑同一套评测集,和基线比:成功率没升、成本翻倍,退回第二步的结构。退回不是失败,三步法的意义就在于每一步都可逆,每次比较都有数字。三步走完还站不住多 agent 的理由,答案就是不用。

这套流程里,第 08 篇的 Send 和本篇的多 agent 也顺带分清了:Send 并行的是同构的无状态任务(五百份简历各打各的分),多 agent 组织的是异构的有角色执行体(研究员和写手各司其职)。批量重复用 Send,职责分工才考虑多 agent,两者混用的场景(supervisor 之下再用 Send fan-out)也可以搭,但先分别站稳再叠加。

自己搭还是用封装库

多 agent 在 LangGraph 里没有一等公民抽象(1.x 的 multi-agent 文档并进了 LangChain 的 agent 章节),langgraph-supervisorlanggraph-swarm 是两个独立维护的封装库,选型时要看它们和你的 LangGraph 版本的匹配度,封装库的发布节奏和核心库不同步,升级前先对一遍 changelog。落地时给依赖版本立个规矩:两个库的版本号写死在依赖清单里,升级核心库后先在测试环境把 supervisor 和 swarm 的最小用例各跑一遍再发版,这条纪律的成本是一次十分钟的冒烟,收益是躲开「核心库小版本升级打挂拓扑」这类事故。这两个库的定位是「主流拓扑的快速起步」,标准形态用它们很快;一旦你的拓扑长出自己的形状(比如 supervisor 之外还要并行 fan-out,第 08 篇的 Send 和 supervisor 混搭),封装库就开始别扭。

也可以不依赖这两个库,自己用 Command 移交搭,代码量不大,控制力最强,适合拓扑特殊的团队。第 07 篇讲过 Command(graph=Command.PARENT) 的机制,swarm 的全部秘密就在那一个调用里,supervisor 的调度循环本质是一个带工具的 agent 循环加条件边。自己搭的隐藏成本不在代码量在维护:调度逻辑散在自己的代码里,框架升级时要自己盯着语义变化。所以路径建议是:标准拓扑从封装库起步,撞到形状不匹配再下沉自己搭,反过来「从零自建彰显掌控力」的路线,为多数团队付不起维护成本。

第 11 篇会回到抽象层级这个话题,那里讲的是单 agent 的高层封装(create_agent 到 deepagents),和这里的拓扑封装是同一个问题的两级,看完那篇再看本节的选型会更完整。

回到标题。这篇讲的所有内容里,最重要的不是 supervisor 和 swarm 怎么写,而是「放弃的时刻」那一节:多 agent 是工具箱里最贵的工具,最贵的工具最需要使用门槛。三个信号成立才拆,三个数字报警就合,中间地带永远先试厚工具。LangGraph 提供的其实只有 Command 移交和子图两个原语,剩下的都是你的组织设计,而组织设计的对错,评测集说了算。第 01 篇判断线的第三问到这里有了完整答案:多数项目过不了三步决策法的第一、二步,这不是遗憾,是省钱。

延伸阅读


原文出处:91ai / LangGraph 生产实战系列

评论

0
登录后可以参与评论和讨论。

还没有评论

欢迎留下第一条评论,帮助这篇内容更快形成讨论。