作者构建Sol-Luna Orchestrator,让GPT作为Supervisor决定何时需要其他AI agent协助,结果发现协调成本往往大于并行收益,最终最有价值的发现是「何时不委托」。
我原本以为更多的 AI Agent 会让编码更快。
但结果并非我所预期的那样——不过这反而成为了这个项目最有意思的发现。
过去几周,我一直在构建 Sol-Luna Orchestrator,这是一个面向 OpenAI Codex 的开源编排层。
这个想法源于一个简单的问题:
如果一个强大的 AI 能够自己决定何时真正需要其他 AI Agent 的帮助,会怎样?
我不想让每一个编码任务都自动分配给多个 worker,而是希望 supervisor 先审视工作本身,再判断委托的成本是否值得。
这个区别最终比我预想的要重要得多。
GPT-5.6 Sol 扮演 supervisor。它拥有整体任务、任务分解、验证和最终审查。
GPT-5.6 Luna 实例则在 Sol 判断委托有意义时,作为有边界的 worker 运行。
Task
|
v
Sol Supervisor
|
Should I delegate?
/ \
No Yes
| |
Sol Split into
handles bounded tasks
the work |
Choose worker
effort
|
Luna Luna Luna
|
Results
|
Sol verifies
and reviews
实际上有两个独立的自适应决策。
Sol 决定是否进行委托。
最优的 worker 数量可以为零。
小型任务、紧耦合的工作,或者协调成本明显高于自己完成的任务,可以完全交给 Sol 处理。
如果 Sol 决定委托,它会分别为每个 Luna worker 决定所需的推理投入。
一个 worker 可以获得不同层次的投入:
一个机械性的改动不一定需要和困难调试问题相同的推理预算。
所以目标从来不是简单地生成更多 Agent。
目标是让最强大的模型决定工作应该怎样执行。
一旦多个编码 Agent 同时开始工作,实际问题很快就会出现。
Worker 可能会编辑重叠的文件。Worker 可能超出其声明的任务范围。验证结果可能与 worker 报告的不一致。并行的 Git 操作可能相互干扰。
Sol-Luna 为这些问题添加了控制机制。
并行 worker 在隔离的 Git worktree 中运行。任务声明其预期的文件范围,执行后会检查范围违规。验证独立重新运行,而不是信任 worker 自己的 PASS 结果。Sol 负责审查最终输出。
Worker 也不能递归调用编排器来创建自己的 worker 树。
这给了我一个正常运行的编排系统。
但我仍然有一个更基本的问题。
我之前的基准测试已经表明,并行的 Luna worker 可以击败顺序 Luna 委托。
但一个 Sol 单独工作仍然更快。
对于小任务,这是合理的。委托本身就有开销。
所以我假设一定有一个盈亏平衡点。
把任务做得足够大。给 worker 真正独立的模块。最终多个 Agent 同时工作应该能赶上并胜出。
这就是下一个实验。
我创建了逐步增大的确定性工程 fixture。
重要的一点是,并行工作负载是精心设计为具有独立工作流的。
我不想给并行 Agent 一个人为耦合的任务,然后得出并行性不好的结论。
更大的基准测试包括:
六模块 fixture 包含大约 530 行规格说明和 85 个确定性断言。
每个模块可以独立工作,所以六个 worker 理论上可以同时推进。
这故意比之前的 fixture 大得多,但仍然可以舒适地放在一个 Sol 会话中。
这个限制很重要。
我在测试纯并行是否足以产生交叉点。我不是在模拟一个大型生产仓库或运行数小时的任务。
对于每个 fixture,我比较了三种模式。
禁用委托。委托被禁用。
自由选择委托。委托可用,但 Sol 可以自由决定是否使用它。这最接近我实际想要的编排器行为。
强制并行委托。Sol 必须委托独立工作,所以我可以测量当 worker 路径被确定使用时会怎样。
规模基准测试完成了全部 19 次运行。
然后是有趣的部分。
在所有六次自由选择运行中,Sol 都拒绝委托。
起初,这听起来像是编排系统拒绝做它的工作。
但当我将这些决策与强制委托的结果进行比较时,情况就不一样了。
四独立模块:自由选择运行使用了零个 Luna worker。
六独立模块:同样是零个 worker。
有趣的结果不仅仅是并行 worker 输了。
supervisor 被给予使用它们的选项后拒绝了,而所有测量过的工作负载都没有给我证据表明这个决定是错误的。
从四个独立流增加到六个也没有让强制并行执行更接近 solo 基线。
反而更远了。
在四流时,强制并行比 solo 慢约 46%;在六流时,慢约 108%。
所以基准测试没有找到我所期望的交叉点。
Token 用量讲述了类似的故事。
在独立工作负载上,强制并行执行使用了大约:
也没有 token 交叉点。
这并不意味着 worker 没用。
并行 worker 仍然可以提供有用的特性,例如隔离的工作空间、有边界的任务、独立的上下文、独立的验证,以及不同工作片段的明确所有权。
而且当委托已经必要时,早期的基准测试表明并行 worker 可以击败顺序委托。
但就我测量的工作负载的原始速度而言,强制委托显然没有胜出。
一种可能性是编排机制本身开销很大。
也许是 Git worktree 或集成占用了所有时间。
测量的中位阶段大致如下:
机械性的 Git 编排开销很小。
Worktree 设置加上集成大约需要 1.2 秒。
大部分固定开销来自有用的 supervisor 工作:分解任务、编写有边界的 worker 契约,以及事后审查结果。
但在六 worker 运行中,另一种效应变得更加明显。
并行完成时间严重依赖于最后完成的 worker。
在一次六 worker 运行中,五个 worker 在大约 95 秒内完成。
一个 worker 花了 333 秒。
在两次六 worker 运行中,观察到的 max-to-median worker 持续时间比约为 3.5 倍和 2.7 倍。
所以在这些运行中,快速完成五个任务并没有足够帮助,因为整个批次仍然需要等待最后一个 worker。
我还用测量的时间计算了一个简单的反事实。
如果六流运行中的每个 worker 都以该运行的中位 worker 持续时间完成,并行执行应该在 176 秒左右,而 solo 中位时间是 189.5 秒。
那个反事实将会穿过 solo 中位数。
但没有实际运行真正做到。
176 秒是测量时间的算术结果,不是基准测试结果。
而且由于六 worker 单元只有两次重复,我没有足够的数据来描述 worker 持续时间的完整分布。
所以谨慎的结论是,慢 worker 尾部看起来是并行延迟的一个重要约束的有力候选。
但它没有被证明是唯一的约束。
当我开始这个项目时,我认为一个成功的编排器主要擅长分配工作。
我现在认为这个定义是不完整的。
一个好的编排器也应该擅长不分配工作。
在我测量的所有工作负载中,Sol 在每次自由选择运行中都选择了零个 worker。强制委托在相应 fixture 上更慢。
这并不能证明自由选择策略本身导致了更快的计时。这些是随机模型运行,不同的运行可能表现不同。
但所有测量过的工作负载都没有提供证据表明拒绝委托是错误的决定。
这引出了到目前为止这个项目我最喜欢的想法:
最优的 worker 数量可以为零。
更多 Agent 是一种工具,不是目标。
好的编排不是关于最大化 Agent 数量。
有时候最强的 Agent 应该自己做工作。
我想对这些结果实际展示的内容保持谨慎。
它们不能证明一个强 Agent 普遍优于多个 Agent。
我测试的每个工作负载仍然可以舒适地放在一个 Sol 会话中。
一个更大的生产仓库可能有不同的表现。
运行数小时的任务可能有不同的表现。
需要多个高度专业化上下文的工作可能有不同的表现。
而且一个大到超出单个 supervisor 可以舒适保持在上下文中的工作负载,可能正是委托开始变得更有价值的地方。
这仍然是一个开放的问题。
在什么时候,把所有东西放在一个强 Agent 内部开始比协调多个 worker 更贵?
我还没有这个答案。
而且我认为这比简单地在另一个合成 fixture 上添加八个或十个 Agent 直到找到并行性获胜的基准测试要有趣得多。
开发者工具基准测试的一个诱惑是不断改变实验直到你的工具获胜。
我不想那样做。
我最初的预测是更大的独立工作负载最终会产生延迟交叉点。
在我测试的范围内,基准测试证伪了这个预测。
所以方法论、基准测试工具、原始记录和结果都保持公开。
如果有人想在真正的大型实际工作负载上尝试相同的设置,我真的想知道会发生什么。
这是开源的其中一个好处。
Sol-Luna Orchestrator 是开源的:
https://github.com/mahadansar/sol-luna-orchestrator
npm install -g sol-luna-orchestrator
sol-luna-orchestrator init
仓库包含架构、安全模型、基准测试 fixture、原始结果和围绕委托策略的文档。
目前,我故意搁置主要新功能。
我宁愿看看人们实际上如何使用它,什么样的更大实际工作负载会暴露问题,以及在决定下一步值得构建什么之前,项目的假设是否继续成立。
我开始这个实验时问:
多少个 Agent 应该处理一个编码任务?
我有了一个喜欢得多的问题:
一个强 Agent 何时应该委托?
对于迄今为止我测量过的工作负载,答案往往是:
零个。
而且我认为知道这一点也是编排的一部分。