对比单体会话与分叉子会话的20个编程任务表现,发现分叉开销在特定条件下反而更快,但关键变量是工程实现质量而非架构本身。
Mohammad Fauzel Sadeghizad 跑了 45 组对照实验,涵盖 20 个编程任务,来测量这个"分叉税"——也就是把一个智能体工作流拆成子会话而非内联运行时所付出的性能代价。方法论包括预注册的评分标准、确定性 fixture,以及独立对抗性验证审计。
结论毫无争议。有时候编排获胜,有时候输得很惨。区别取决于工程实现,而非理论。
子会话背后的架构主张很简单:一个协调者智能体生成子会话,每个子会话返回一个结构化报告,协调者的上下文按 O(report) 增长,而非 O(child transcript)。
人类操作员看到的是整棵树。协调者只看到摘要。
这个不变量在机制层面是成立的。每一个 gate、每一份报告契约、每一封 succession letter 都在强化它。真正没有被测量的是:在真实工作负载上,这个不变量是否值得为之付出编排成本。
两组对照,条件完全相同:
内联组(角色:worker) 一个单一自治会话。子会话工具集被结构性剥离(canSpawn: false)。智能体接收任务提示词,直接在自己的会话内完成所有代码导航、编辑、脚本执行和验证。
编排组(角色:coordinator) 一个被授权生成子会话的监督会话(canSpawn: true, depthCap: 2)。根据预注册协议修正案,协调者必须将工作委托给至少两个 worker 子会话,并在交付最终答案之前综合它们返回的报告。
相同的模型、相同的 temperature、相同的系统提示词结构
确定性 fixture:20 个有已知正确答案的编程任务
运行前的预注册评估评分标准(RUBRIC.md)
独立对抗性验证审计(results/VERIFICATION.md)
目标是隔离编排开销与模型方差。
当协调者生成一个子会话时,运行时执行以下步骤:
角色化生成:协调者调用 spawnSubsession(role, brief),传入一份带版本的 brief 文档
上下文隔离:子会话以 brief 启动,无法访问父会话记录
仅追加日志:每一次工具调用、每一次响应、每一次状态转换都被记录到 checkpoint journal
报告契约:子会话必须返回一个结构化报告(强制 JSON schema)
Succession letter:终止时,子会话写一封 succession letter 总结状态,供潜在的后继者使用
上下文合并:协调者只收到报告,而非完整记录
分叉税是以下各项之和:
编排组平均多消耗了 52% 的 token,时长多出 38%。成功率略有下降。
但协调者的上下文即便在最长的任务中也保持在 5,000 token 以下,而内联智能体在复杂多文件编辑时突破了 15,000 token。
任务有清晰的分界边界:
在这类任务上,编排组快了 10-20%,因为子会话并行工作,且协调者避免了重复读取整个代码库。
任务需要紧密的迭代循环:
在这些任务上,分叉税是灾难性的。为一个 3 行修复生成子会话要花费 2,000+ token 的 brief + report 开销。内联智能体直接改了就继续。
独立审计验证了:
确定性:重跑相同 fixture,95% 的情况产生相同输出(剩余 5% 是模型采样方差)
评分标准遵守:所有运行都按预注册评分标准打分,没有事后标准
无 cherry-picking:全部 45 次运行均已发布,包括失败案例
工具调用日志:每个子会话的完整 checkpoint journal,验证协调者确实做了委托
审计还发现了两次协议违规——协调者试图内联解决任务而非生成子会话。这些运行被排除并重新执行。
interface SubsessionBrief {
role: "worker" | "researcher" | "reviewer";
task: string;
context: Record<string, unknown>;
constraints: string[];
}
interface SubsessionReport {
status: "success" | "failure" | "blocked";
result: unknown;
tokensUsed: number;
toolCalls: number;
}
async function spawnSubsession(
brief: SubsessionBrief
): Promise<SubsessionReport> {
const session = await runtime.createSession({
role: brief.role,
canSpawn: false, // Workers cannot spawn children
depthCap: 0,
});
await session.initialize(brief);
const result = await session.run();
return {
status: result.status,
result: result.output,
tokensUsed: session.metrics.tokens,
toolCalls: session.metrics.toolCalls,
};
}
// Coordinator pattern
async function coordinatorLoop(task: string) {
const plan = await planDecomposition(task);
const reports = await Promise.all(
plan.subtasks.map(subtask =>
spawnSubsession({
role: "worker",
task: subtask.description,
context: subtask.context,
constraints: subtask.constraints,
})
)
);
return synthesizeReports(reports);
}
生成开销是前置的:会话创建、角色验证、brief 序列化。如果子会话运行 30 秒,这个开销可以忽略。如果只跑 5 秒,开销就占主导了。
在生产环境中测量分叉税:
生成延迟直方图:从 spawnSubsession() 调用到子会话第一次工具调用的时间
报告大小分布:每份报告的字节数,与任务复杂度关联
决策点上下文长度:协调者在决定是否生成时的上下文大小
重复率:跨子会话重新读取共享上下文所花费的 token 数
空闲时间:协调者等待子会话报告的墙上时间
重复率是沉默的杀手。如果三个子会话各自读取了相同的 2,000 token 代码库摘要,你就为本来可以只读一次的信息支付了 6,000 token。
过早分解:协调者在理解任务结构之前就生成子会话。子会话空转,返回"blocked"报告,协调者重新规划。成本:3 倍 token 预算。
报告契约不匹配:子会话返回非结构化文本而非 JSON。协调者无法解析,再生成一个子会话来"清理报告"。成本:2 倍 token 预算。
深度限制抖动:协调者达到 depthCap,无法继续生成子会话,回退到内联执行。但它已经花在了 brief 和报告上。成本:编排开销 + 内联成本。
并行重复:子会话独立导航相同的文件树或重复获取相同的 API 数据。没有共享缓存,没有去重。成本:N × 获取开销。
使用子会话编排当:
避免子会话编排当:
分叉税是真实的、可测量的。在这个基准测试上,编排多花了 52% 的 token,时长多 38%。但它让协调者上下文即便在复杂任务中也保持在 5,000 token 以下。
权衡不是"编排更好"或"内联更好"。权衡是:你愿意多花 50% 的 token 来换取协调者上下文缩小 50% 吗?
如果你的瓶颈是上下文窗口耗尽,付税。如果你的瓶颈是 token 预算或延迟,保持内联。
测量方法论和结果同样重要。预注册评分标准、确定性 fixture 和对抗性验证是避免自我欺骗的唯一方式。
跑你自己的基准测试。发布日志。在建立组织架构之前,先测量你工作负载上的分叉税。
Measuring the Multi-Agent Fork Tax(原始来源)