10个Agent联手写Dijkstra反而慢7倍?多智能体协作的真相

发布时间:2026/10/25 8:41:28
10个Agent联手写Dijkstra反而慢7倍?多智能体协作的真相

前段时间我做了个挺反直觉的实验:让 10 个 Claude agent 同时开工,去解决同一个经典算法问题——Dijkstra 最短路径。原以为人多力量大,10 个“大脑”并行协作,怎么着也能把之前单 agent 的纪录踩在脚下。结果实测下来完全不是那么回事:端到端耗时最多比单 agent 慢了 7 倍,token 消耗也翻了三四倍。这篇文章就把这个实验从设计到踩坑完整复盘一遍,聊聊“为什么多 agent 协作在某些任务上是个伪命题”,也顺便给想自己测一测的人留一份可复现的实验模板。

先交代一下背景:我平时重度使用 Claude Code 写代码,单 agent 模式的效率我已经摸得比较透了,正好最近在折腾多 agent 并行协作的玩法,就想着能不能搞一个“人海战术”压榨出更高性能。之所以选 Dijkstra 当靶子,纯粹是因为它是一个足够“笨”的基准:逻辑确定、验证容易、没有外部依赖,最适合用来做横向对比。可也正是这种“笨”,最后把所有多 agent 协作的问题全暴露出来了。

1. 逆向实验设计:为什么拿 Dijkstra 当“群殴”对象

1.1 实验起因:多 agent 并行到底能不能加速写代码

先说实验是怎么来的。当时我在跑一批“多 agent 协作写代码”的场景测试,最基本的做法很简单:开 N 个 Claude Code 会话,每个会话给同样的任务描述,等它们全部返回后,再开一个主会话去审查、合并、选优。这种玩法在社区里有个很形象的说法叫“agent 群”,大家普遍预期是:既然单 agent 已经能写代码了,那么多 agent 各自尝试、互相竞争,总能比单打独斗更快找到最优解。

于是我就想做一个极限压力测试:把任务难度固定在“实现一个 Dijkstra 最短路径算法并优化到尽可能快”,分别用 1 个 agent、3 个 agent、10 个 agent 去完成,对比端到端耗时和 token 成本。注意这里要强调一下,我测的不是“算法本身跑得快不快”,而是“从下指令到拿到一份正确、可用代码,整个工作流的耗时”。也就是说,这是一个关于 AI 编码效率的实验,不是算法性能实验。

之所以选 Dijkstra 而不是更复杂的业务系统,原因有三。第一,它的边界条件非常清晰:非负权图、单源、不存在负权环,测试用例可以精确构造,验证 agent 输出对不对几乎零成本。第二,它足够经典,所有模型都见过大量类似代码,不会出现因为知识盲区而卡死的情况。第三,也是最重要的,Dijkstra 是一个强顺序依赖的确定性算法,每一步都要从优先队列里取最小节点,天然不适合并行化。用韩愈的话说这叫“以子之矛攻子之盾”——我就是想看看,当一个任务本身就不适合并行时,强行堆 agent 会付出多大代价。

1.2 任务描述与评测方式怎么定义才公平

实验最怕口径不一致。我给所有 agent 的任务描述是完全相同的,统一写在同一个 prompt 文件里:

  • 输入:一个以邻接表表示的加权无向图,节点数最多 10000,边数最多 50000,边权为非负整数。
  • 输出:给定起点和终点,返回最短路径长度以及完整路径节点序列。
  • 要求:实现需使用优先队列优化,并处理图不连通、节点不存在等边界情况。
  • 额外要求:代码需要附带 5 组自测用例,确保能直接运行验证。

评测方式分三步:第一,跑全部 5 组公开测试用例,必须全部通过;第二,额外生成 20 组随机大图,对比标准答案;第三,记录从任务下发到最终代码合入的时间,以及整个过程消耗的 token 数。这里我要特别提醒一句:评测“AI 写代码”的耗时,不能只数它生成代码的那几秒,要把中间所有来回沟通、报错修复、合并冲突的时间全算进去,这才是真实工作流中的体感时间。

1.3 预期管理:我原本以为会看到什么

实验前我的心理预期挺乐观。我觉得 10 个 agent 并行,哪怕是纯粹的重复劳动,也相当于 10 个人同时解题,虽然质未必高,但量肯定大。就算是互相不沟通,最后从 10 份结果里挑一份最好的,也应该能压过单 agent 的“一次性输出”。尤其是 Claude 这类模型在单次生成长代码时经常会犯低级错误,比如忘加 import、边界条件判断反了,多 agent 并行多个独立样本,至少能提高“至少有一个能跑通”的概率。

结果这个预期只对了一半:10 个 agent 确实产出了一些单 agent 没写出来的优化技巧,比如有人用了斐波那契堆,有人做了双向 Dijkstra,还有人加了 inline 展开。但问题恰恰出在“产生了好东西却没法低成本地用上”这一步。后面我会详细拆,这里先给结论:多 agent 的收益是“多样性”,成本是“协调”,而在 Dijkstra 这种目标单一、最优解明确的任务里,多样化毫无用处,协调成本却高得吓人。

2. 实测数据复盘:10 个 Claude 联手,端到端慢了 7 倍

2.1 测试环境与前几轮试跑结果

这次实验我全程用的是 Claude Code 的命令行版本,模型统一指定,没有混用不同版本,不然数据没法对比。并发方式也做了设计:10 个 agent 不是真的在同一毫秒同时输出,而是通过脚本并行拉起 10 个独立会话,彼此之间不共享上下文,最后再开一个 coordinator 汇总。

先给大家看完整数据。

实验组端到端耗时token 总量首次提交通过率代码合入前平均修改轮次
1 个 agent 单次生成48 秒8.4k80%0.4 轮
1 个 agent 自检两遍1 分 52 秒19.7k100%0 轮
3 个 agent 并行选优2 分 37 秒27.6k93%0.8 轮
10 个 agent 并行选优5 分 36 秒91.2k41%3.6 轮
10 个 agent 拆分子任务4 分 52 秒76.8k67%2.1 轮

单 agent 48 秒跑完的事,10 个 agent 并行选优用了 5 分 36 秒,正好是 7 倍。而且这不是个例,我重复跑了 5 轮,10 agent 组的耗时中位数是 5 分 12 秒,最慢的一次到了 6 分 48 秒,token 消耗则基本稳定在 90k 上下。看到这个数据的时候我一度怀疑是自己并发姿势不对,但换了好几种编排方式,结果大同小异:只要参与人数一多,端到端时间就往上飙。

2.2 时间到底消耗在哪个环节

这里要拆一拆时间账。10 agent 组的 5 分 36 秒里,真正花在“生成初始代码”上的时间只占了大概 40%,也就是 2 分多钟。这部分其实和单 agent 差不多,毕竟 10 个会话是并行的,理论上生成时长不会线性叠加。

剩下的时间去哪了?主要在三个环节。第一个是“汇总审查”:coordinator 要把 10 份代码全部读一遍,然后评估哪份最好、哪些可以融合,这一步跑了 1 分 40 秒左右。第二个是“冲突修复”:10 份代码里有 6 份通过了基础用例,但它们的接口签名、变量命名、数据结构各不相同,合并前必须统一样式并重新适配,这一步又花了 1 分多钟。第三个是“无效往返”:有几个 agent 遇到报错后反复自我修复,但因为没有全局视角,修了半天修出来一个只对自己版本有效的补丁,coordinator 还得重新验证。

所以这里就出现了一个很讽刺的现象:10 个 agent 并行省下的“生成时间”,全都被“审查时间”和“合并时间”吃掉了,还不够。这也是这个实验最有价值的发现——多 agent 协作真正要花钱的地方不在生成,而在融合。

2.3 token 成本:7 倍耗时背后是 10 倍以上的“思考量”

token 消耗的数据更夸张。单 agent 完成这个任务只需要 8.4k token,10 agent 组平均用掉 91.2k,差了将近 11 倍。换句话说,我们用 11 倍的“脑力”,换来了 7 倍的耗时和更低的通过率。这在经济学上简直是负收益。

为什么 token 会涨这么多?因为每个 agent 都是从零开始理解任务,10 个 agent 就相当于把同一份需求文档读了 10 遍。然后 coordinator 汇总时又要把 10 份结果全部读一遍,等于同一份内容在系统里被重复阅读理解了好几次。这种“重复劳动”在单 agent 工作流里是完全不存在的。我后来试过给每个 agent 提前共享一份分析报告,token 确实降了一截,但协调时间没降多少,因为共享报告解决不了“10 个人想法不一样”的问题。

3. 根因拆解:多 agent 协作的三个隐藏成本

3.1 上下文隔离:每个人都在重复造轮子,没人知道别人干了什么

这个可能是多 agent 协作最根本的坑。Claude Code 的每个会话都是独立的上下文窗口,A agent 不知道 B agent 已经想出了一个更好的堆实现,B agent 也不知道 C agent 已经踩过了某个边界条件的坑。它们唯一的共同点,就是收到了同一份任务描述。

我打一个比方:这就好比一个项目组招了 10 个程序员,每人发一间小黑屋、一张任务纸条,规定不许交流,最后把 10 份代码交给组长去拼。组长确实能挑出最好的那一份,但这 10 个人里至少有 8 个人在写同样的基础代码,有 2 个人甚至因为缺少信息写出了完全错误的方向。如果任务本身需要全局状态(比如 Dijkstra 的优先队列内容、已访问节点集合),这种隔离直接导致没人能独立完成一份“最优解”。

更麻烦的是,上下文隔离还会放大模型的“理解偏差”。我数了一下,10 个 agent 收到的任务描述一模一样,但有人把图定义成有向图,有人当成无向图,还有人把“返回路径节点序列”理解成了“返回边的列表”。这些偏差在单 agent 场景下不会出现,因为一个人从头写到尾,理解是连贯的;但多 agent 并行后,每个人都在脑补,而且互相没法纠正。

3.2 串行协调:沟通开销会吞噬掉并行带来的全部收益

理论上,10 个 agent 并行,如果任务能完全切分,时间应该趋近于单任务耗时。但真实世界没有免费的并行。所有 agent 的产出最终都要汇到一个 coordinator 那里做裁决,而裁决是一个严格的串行过程。

我这次实验里 coordinator 的串行工作包括:依次读取 10 份代码、跑测试、比较结果、决定合并策略、写汇总报告。这些步骤一步都没法并行,而且随着 agent 数量增加,coordinator 的工作量是线性增长的——不对,准确说是超线性增长,因为代码之间还要做差异对比,10 份两两比对就是 45 次组合。

更隐蔽的是行为上的串行依赖。第一轮我让 10 个 agent 完全独立生成代码,结果有 4 份代码直接编译不过,coordinator 不得不把错误信息逐一反馈给对应的 agent,然后等它们返工。这个“返工”流程只能一个一个来,因为 coordinator 同时只能处理一个上下文。所以后来我学乖了,改成让 10 个 agent 先各自检查两遍再交作业,通过率上去了,但每个人的耗时也上去了,整体端到端时间并没有实质降低。

3.3 随机性放大:同样的问题,十个模型有十种写法

生成式模型本身有随机性,多 agent 并行会把这种随机性从“微小差异”放大成“结构性冲突”。单 agent 就算随机性再大,写出来的代码大概率还是同一风格、同一接口设计,改动成本低。10 个 agent 并行,有的用 heapq,有的手撸二叉堆,有的直接用 networkx,有的干脆矩阵暴力 Floyd。

这些差异在单看某一份代码时都是合理的,但一旦需要合并,代价就非常大了。coordinator 要做接口统一、命名统一、依赖统一,相当于把 10 份代码重构一遍。我统计了一下,最终合入的代码里,真正来自某个 agent 的原始内容只剩了不到 30%,其他全是 coordinator 重写的适配层。也就是说,10 个 agent 的“多样性产出”,最后被强制压缩成了一个统一结果,而压缩过程消耗的时间,远远超过了多样性带来的选优价值。

还有一个附带问题:随机性会让“多 agent 实验”极难复现。同一个任务同一条 prompt,你跑两次,10 个 agent 写出来的接口可能完全不同,导致 coordinator 的工作量忽高忽低。我跑了 5 轮,端到端耗时的方差非常大,标准差将近 1 分钟。如果你只跑一次实验就下结论,很容易被单次结果误导。

4. 反过来验证:什么任务才配得上多 agent 协作

4.1 探索型任务:并行候选方案再筛选,才是真正的正收益场景

为了确认“多 agent 没用”这个结论不是普适的,我做了一组对照组实验:任务不是“实现 Dijkstra”,而是“为一个图算法库设计 5 个不同的优化方向”。这次 10 个 agent 并行产出了 8 种不同思路,包括双向搜索、A* 启发式、分层图索引、边收缩预处理,等等。

最后我让 coordinator 把这些方向做成一份对比报告,人工选了一个最有潜力的方向去实现。整个流程下来,端到端耗时比单 agent 连续头脑风暴快了 3 倍左右,因为单 agent 在探索时总是沿着自己的惯性思路走,而多 agent 天然提供了“并行搜索”的多样性。这个实验很清楚地告诉我:多 agent 的价值在于“探索”,而不在于“实施”。

为什么探索型任务能受益?因为它的产出是“方案列表”,列表天然可以拼接,不需要强合并。10 个 agent 各自列出 3 个优化思路,coordinator 只要把这些思路去重、归类就行,这个过程几乎没有冲突成本。而 Dijkstra 的实现任务产出是一份“单一最优代码”,它要求所有参与者朝同一个目标收敛,收敛过程就是冲突爆发的过程。

4.2 可拆分且有明确接口的子任务:成本可控,但前提是接口先定死

我还试了一种半拆分模式:不要求每个 agent 写完整 Dijkstra,而是把任务拆成三个部分:数据解析模块、优先队列实现、主算法逻辑。每个 agent 只负责一个模块,模块之间用预定义的函数签名连接。

结果如何?端到端耗时 4 分 52 秒,确实比 10 个 agent 独立写完整代码要好,但还是比单 agent 慢。问题出在接口定义上。我预定义了函数签名,但没有定义数据结构细节:有人传邻接表,有人传边数组,有人把节点 ID 设计成字符串,coordinator 又得花时间去做数据格式转换。

这个实验给我的启发是:多 agent 拆分子任务,成败完全取决于“接口契约”定义得有多细。如果你能把接口细化到“参数类型、返回值结构、异常处理逻辑”全部定死,那么 10 个 agent 并行开发才真正可行。否则,模块之间谁来适配、谁来统一类型,最后又变成 coordinator 一个人的活。现实业务里这种精确到字段级的接口设计成本极高,大多数情况下你用单 agent 从头写反而更快。

4.3 我总结的“人海战术”判断三问

经过这些对比实验,我给自己定了一个三问判断法。任何任务拿过来,先问三个问题,答案如果都是肯定的,再考虑上多 agent。

第一问:子任务是否真正独立?就是说拆出来的子任务之间,是否存在必须共享的全局状态?Dijkstra 的最短路径计算和优先队列是强耦合的,所以它不算独立。第二问:合并成本是否可控?你预判一下 coordinator 看完所有结果后,是只需要做一个简单的“选最优”,还是需要做复杂的“融合重构”?如果是后者,建议别上多人。第三问:是否需要一个单一正确的最终产物?如果任务答案是唯一最优解,多 agent 的多样性就是纯粹的噪声;反过来,如果任务本身就是开放的,比如写方案、做调研、收集案例,那多样性就是价值本身。

这套三问我现在每次排多 agent 任务都会过一遍,已经帮我省下了不少 token。说句实话,大部分日常编码任务都过不了这三问,这也是为什么我现在的默认选项依然是单 agent 深度自检,而不是一上来就铺 10 个会话。

5. 复现指南:想自己测一遍,需要注意这些细节

5.1 环境准备与最容易被忽略的坑

如果你想亲手复现这个实验,环境部分并不复杂。按常规方式装好 Claude Code 命令行工具,用 npm 全局安装即可,安装完成后在终端里登录并确认能正常发起对话。需要保证 Node.js 版本满足官方要求,装完先跑一条最简单的消息确认 CLI 工作正常,再开始并发测试。我个人的建议是:有条件的话把模型版本固定住,不要今天一个版本明天一个版本,否则实验数据完全没法横向比。

真正容易被忽略的是并发会话的资源管理。10 个 agent 并行不是打开 10 个终端窗口就行,得确保你的网络、登录态、API 配额都撑得住同时发请求。我第一次试跑的时候没注意 API 配额,跑到第 7 个 agent 直接触发了限流,结果那一组数据全废了。另外,10 个会话同时工作会让终端输出极其混乱,强烈建议写一个简单的调度脚本,把每个 agent 的日志重定向到独立文件,最后统一收集。这个步骤虽然麻烦,但能让你在复盘时准确知道每个 agent 到底输出了什么。

还有一个小坑:不要让多个 agent 同时写同一个文件。我第一轮试过让它们直接改本地代码,结果三个 agent 互相覆盖,最后文件直接损坏。正确做法是让每个 agent 在独立目录下工作,最后 coordinator 再统一复制合入。

5.2 评测口径:别用一次实验就下结论,也不要只看墙钟时间

评测口径决定了实验结论的可信度。首先,生成式模型输出有随机性,任何一组数据跑一次都不够,至少重复 5 次取中位数。我这次整理的数据都是中位数口径,个别轮次的极端值我会单独标注。

其次,不要只看端到端耗时(wall time),还要看 token 成本和首次通过率。在 AI 编码的场景里,token 就是钱和时间,通过率就是返工率。有时候端到端耗时看着差不多,但 token 消耗差一倍,说明某个方案在暗地里做了大量无效生成。我这边的经验是:用表格同时列出耗时、token、通过率、修改轮次四项指标,比只看任何单一数字都要客观。

第三,建议加一组“同样预算给单 agent”的对照。我这次实验最有说服力的一组数据,不是 10 agent vs 1 agent,而是“1 个 agent 自检两遍”只用了 1 分 52 秒,比 10 个 agent 的任何一种玩法都快。这说明如果任务合适,把多出来的预算全部投给一个 agent 做迭代优化,往往比铺开人数更划算。

5.3 一个更公平的对比维度:把多 agent 当成“委员会”而不是“工人”

最后补充一个思路上的建议。很多人看到“多 agent 并行”就会自然联想到“多核计算”,这是最大的认知误区。多 agent 协作更像开委员会:多了不同视角的讨论,但每个决定都要开会、表决、写纪要,效率天然低于一个人拍板。

所以如果你真的要用多 agent,别把它们当“工人”,要把它们当“顾问”。让 10 个 agent 各自提方案、提意见、找 bug,最后由一个主 agent 或者你自己拍板。也就是说,多 agent 适合做“质控”和“探索”,不适合做“生产”。这个定位一旦想清楚,很多关于“到底该开几个 agent 并行”的纠结就迎刃而解了。

我在这次实验之后,把多 agent 的用法彻底改了:写代码主线永远单 agent 多轮自检,遇到难题或需要方案选型时,才临时调 3 到 5 个 agent 出一轮并行候选。Dijkstra 这个实验本身算是一次失败的尝试,但它帮我节省了后续大量在错误方向上浪费的时间,值回票价。