2026 年 5 月 3 日到 14 日,Bun 的作者 Jarred Sumner 用 Claude Code 的 Dynamic Workflows 把 Bun 的 53.5 万行 Zig 代码重写成了 Rust。11 天,峰值 64 个 Claude 并行,合并时新增了约 100 万行代码,测试套件 100% 通过、0 个跳过或删除,花费约 $165,000 的 API 调用。这不是一次好运气的自动化,而是三个 harness 层面的机制同时到位——本文要拆的就是这三个机制,以及它们共享的同一个动作。
本文是 《什么才是好的 Harness》 半年后的续篇。那篇的结论是一句话:判断归模型,物理归代码。 半年过去,“物理归代码”这半句在三个具体维度同时被坐实了——本文按这三条战线展开,每条都配一个可核实的一手案例。
名词速查
| 术语 | 一句话解释 |
|---|---|
| Dynamic Workflows | Claude Code 2026 年新增能力:模型现写一段编排脚本,由 harness 执行这段脚本来调度几十到上百个子 Agent,而不是每一步都由模型临场决定 |
| Worktree | Git 原生功能:同一个仓库的多个独立工作目录,共享 .git 对象库但互不干扰未提交的改动 |
| Adversarial Review(对抗式复核) | 复核者的任务不是「挑错顺便认可」,而是被明确要求「假设代码是错的,只负责找出它为什么不对」,且复核者看不到实现者的推理过程 |
| 控制面 / 数据面 | 控制面决定「谁、何时、按什么规则做」;数据面真正执行模型调用与代码修改。详见 Ruflo 源码深读 |
| 元 Harness | 不服务单个 Agent,而是给 Claude Code、Codex 等现成 harness 再加一层协调、记忆与治理的系统 |
三条战线共享的一个动作
先说主线,再展开证据:2026 年下半年前沿玩的所有花活,都在把某个原本”由模型运行时临场决定”的环节,改造成”运行前就能审查、运行时不能被绕过”的外部结构。三条战线分别对应三个环节:
- 控制流——原来是模型一步步决定要不要分派子任务,现在是一段脚本预先写死调度逻辑;
- 隔离——原来是”祈祷两个 Agent 别改同一个文件”的约定,现在是文件系统级的独立工作目录;
- 验证——原来是模型自己检查自己的输出,现在是专门扮演反方、看不到你推理过程的复核角色。
战线一:控制流从”模型决定”变成”脚本决定”
Claude Code 原生的子 Agent 调用(Task 工具)本质上是模型在对话里临场决定”这一步要不要委派、委派给谁”——决策权仍在模型的推理循环里,每一轮都可能被上下文污染或注意力漂移打断。
Anthropic 在 2026 年 7 月上线的 Dynamic Workflows 改了这个环节的所有权:模型不再一步步决定,而是先写一段确定性的编排脚本(可以用 pipeline/parallel 这类原语描述”哪些子任务顺序执行、哪些并行、哪里需要等所有结果到齐”),脚本写好之后交给 harness 执行,模型自己退出决策链。Anthropic 官方博客把这个定位说得很直接:它填的是”扔出一个子 Agent”和”搭一整套 Agent Team”之间的空白(“Introducing dynamic workflows”)。
Bun 的重写是目前公开的最大规模验证。据 Anthropic 官方博客与 Sumner 本人在 Bun 官方工程博客的描述:
| 指标 | 数值 | 来源 |
|---|---|---|
| 重写前 Zig 代码 | 53.5 万行,1,448 个源文件 | Bun 官方博客 |
| 合并时新增代码 | 约 100.9 万行 | 同上 |
| 耗时 | 11 天(2026-05-03 至 05-14) | 同上 |
| 峰值并行 Agent 数 | 64 个 Claude,分 4 个 workflow shard,每 shard 16 个、各自独立 worktree | 同上 |
| 提交数 | 移植分支 6,502 次提交(不含 merge),峰值单小时 695 次、单分钟 58 次 | 同上 |
| 测试通过率 | 三平台 CI 100% 通过,0 个测试被跳过或删除 | 同上 |
| Token 用量与成本 | 59 亿未缓存输入 token、6.9 亿输出 token、720 亿缓存输入读取,约 $165,000 | 同上 |
流程被 Anthropic 概括成三段:一个 workflow 先给 Zig 代码里每个 struct 字段推导对应的 Rust 生命周期,第二个 workflow 让”数百个 Agent 并行”把每个 .zig 文件端到端翻译成行为等价的 .rs 文件(每个文件配两个复核者),第三个 workflow 跑 fix loop,把编译报错和测试失败喂回去直到通过(Anthropic 博客)。
这里最值得记住的不是数字本身,而是脚本先于执行存在这件事本身改变了什么:脚本可以被人读、被复用、被 resume(同样的脚本 + 同样的输入,中断后能从缓存的中间结果续跑,而不是从头再来)。这正是”物理归代码”的字面含义——调度逻辑一旦写成脚本,就不再是模型每次重新即兴发挥的判断,而是可以审查、可以复现的确定性程序。
这条战线不是 Anthropic 一家在玩,只是切入角度不同——有的把控制流交给一段临时脚本,有的交给一张预先画好的图,有的交给角色化的对话协议:
| 产品/框架 | 控制流交给谁 | 定位差异 |
|---|---|---|
| Claude Code Dynamic Workflows | 模型现写的一次性编排脚本(JS,pipeline/parallel 原语) | 临场生成、可 resume,适合”这一个任务”没有预先设计过流程图的场景 |
| LangGraph | 预先定义的有状态图(节点+条件边),带 checkpoint 和 time travel | 企业级生产系统首选,月下载量 3,450 万,代价是要先画好图(LangChain 官方对比) |
| CrewAI | 角色化任务分解(Crew 自治委派 + Flow 事件驱动确定性控制) | 上手最快(约 20 行代码),但缺内建 checkpoint,粗粒度错误处理,常见”原型用 CrewAI、上生产切 LangGraph”的迁移路径 |
| AutoGen(微软,已转维护模式) | 多 Agent 群聊,由 selector 决定下一个发言者 | 对话式辩论范式的开创者,但微软已把新功能重心转向 Microsoft Agent Framework(2026 年 4 月 GA),社区正在转向 CrewAI 等替代品(框架对比综述) |
三者本质分歧在”谁来写控制流、写死到什么程度”:Dynamic Workflows 让模型自己现写、CrewAI 让人写角色分工再交给自治委派、LangGraph 让人预先画死状态图——图越死,越适合稳定重复的生产流程;越现写,越适合”这次任务的形状我们还没见过”的探索性场景。
战线二:隔离从”君子协定”变成文件系统原语
三个 Agent 同时改同一个工作目录,即便每个都”表现完美”,结果也是混乱——这是多 Agent 并行绕不开的物理约束,靠提示词说”请不要冲突”没有用。2026 年这半年,几乎所有主流 harness 都收敛到了同一个答案:用 git worktree 给每个 Agent 一份独立的工作目录,共享同一个 .git 对象库、各自持有独立的 HEAD 和暂存区。
这个收敛发生在不止三条产品线上,值得摊开逐一确认,因为”大家都这么做”和”我猜大家都这么做”是完全不同的证据强度——更值得注意的是,即便共识是”用 worktree”,各家在”隔离发生在本地还是云端""默认开启还是按需开启”上仍然分了岔路:
| 产品 | 隔离方式 | 取舍 |
|---|---|---|
| Claude Code | 内置 EnterWorktree/ExitWorktree 工具,本地文件系统级 | Bun 重写的 4 个 workflow shard 各自跑在独立 worktree 里;默认不开,需显式调用 |
| Cursor 3.0 | /worktree、/best-of-n 两个显式命令 | 前者把”这段对话剩下的部分”搬进独立 checkout,后者让同一任务在多个模型上各开一个 worktree 并行跑,替代了 2.0 时代的下拉菜单(Cursor 官方文档) |
| Zed | Parallel Agents,线程默认共享工作副本 | worktree 隔离是”per-thread 可选项”而非默认——刻意把”共享+人工审查 diff”作为默认路径,理由是多数任务不需要隔离的开销 |
| Devin / Windsurf(现 Devin Desktop) | 隔离推到云端(分支+PR),本地机制未公开 | 和 GitHub Copilot、JetBrains 一样选择”云端分支”而非”本地 worktree”,代价是失去本地即时 diff 的即时性,换来不占用本地资源 |
| Grok Build(xAI) | 单个终端 Agent 内置最多 8 个子 Agent,各自独立 worktree | 把并行度上限做成产品参数(8),而不是留给用户手动开多少个 |
| Codex CLI 生态 | 官方 CLI 无原生 --worktree,社区拼装 | 催生 worktrunk(Max Sixty,Rust 写的 worktree 管理器,2026 年 7 月 5,850 星)、oh-my-codex(33,000 星,给 Codex CLI 加多 worker 编排)等第三方层,均以 worktree 为底层原语 |
这张表更重要的信息在”隔离方式”这一列的分裂:本地 worktree(Claude Code、Cursor、Grok Build)与云端分支(Devin、Copilot、JetBrains)是两种不同的物理化路径,前者的代价是本地磁盘和进程开销,后者的代价是失去本地即时反馈——但两者的共同点是,都不再依赖”两个 Agent 会自觉不冲突”这句祈祷。
三条产品线独立得出同一个答案,这本身就是证据:这不是某家的品味,而是”多 Agent 并行”这个任务对隔离原语的物理要求。这和站内 《AI Coding 时代,Git Worktree 为什么突然变成刚需》 半年前的判断,以及 《什么才是好的 Harness》 引用的 Fork-Explore-Commit 论文(把”能便宜地撤销,才敢大胆地探索”做成操作系统原语)是同一条脉络的延续——只是从论文原型走到了三家产品的默认配置。
代价也要如实说:worktree 隔离解决的是”文件写冲突”,解决不了”语义合并冲突”。最难的失败模式仍然是——一个 Agent 在重构接口,另一个在给这个接口的调用方加字段,两人从没碰过同一行代码,合并时依然会冲突(多篇 2026 年社区实践文章的共识,未见权威量化数据,标注为观察)。
战线三:验证从”自评”变成角色对立
Bun 重写里真正让 100 万行新代码可信的,不是测试套件(虽然它必要),而是对抗式复核(adversarial review)——这是 Sumner 反复强调、也是 Anthropic 官方博客点名的机制。它的结构比”多找一个人看看”精确得多:
实现者(implementer)
拿到:原始 Zig 文件、移植计划(PORTING.md / LIFETIMES.tsv)、自己的推理过程
写出:一个 diff
复核者 A、复核者 B(各自独立的上下文窗口)
拿到:只有 diff 本身,看不到实现者的推理过程
被要求:假设这段代码是错的,唯一任务是找出它为什么不对
产出:一份"这里为什么会炸"的报告,不是"看起来还行"的背书
修复者(fixer)
拿到:复核者的报告
写出:应用修复后的新 diff
三个角色的边界是硬性的:实现者不做复核,复核者不做实现(Bun 官方博客)。这个设计直接回应了 Anthropic 自己研究里的一个已知问题——模型自评自己的输出会系统性偏乐观,而独立的评估者能避免这一点(《什么才是好的 Harness》 里已经引用过 planner/generator/evaluator 三角色分离的研究)。这里的新意在于把”独立”做到了机制级:复核者物理上看不到实现者怎么想的,只能看到最终 diff——这比”换一个模型再看一眼”更接近真正的独立视角。
据 Sumner 描述,这套流程真的抓到了不容易被发现的 bug:一处 async 管道关闭时的 use-after-free/double-free、一个把负时间戳截断成非法 timespec 的边界错误、一个 color-mix() 解析器里的 eager-evaluation panic(Bun 官方博客)。这类 bug 的共同特征是——它们不是”代码写错了”,而是”代码在某个具体输入下才会错”,正是自评容易放过、专职找茬的角色容易揪出来的类型。
Sumner 给复核者的原话立场很硬:“如果你需要一段话来解释为什么这个 workaround 没问题,那代码就是错的——把代码修对。“(Bun 官方博客)这句话本身就是”判断归模型、物理归代码”的一个变体:不接受用自然语言的辩解替代结构上的正确性。
Bun 这套三角色分工是自建的一次性 workflow,但”多 Agent 复核”已经在独立产品化,且各家选的角色设计不完全相同:
| 产品 | 复核机制 | 已知效果/取舍 |
|---|---|---|
| Qodo | 多 Agent 复核架构 | 2026 年 2 月一份跨 8 款工具的基准里 F1 分数最高(Greptile 对比报告),厂商自测数据,未见第三方复现 |
| Anthropic Claude Code Review | 托管式多 Agent PR 复核 | 2026 年 3 月上线,Team/Enterprise 研究预览,单次复核 token 成本约 $15-25 |
| Greptile | 对整仓库建语义图,派”agent swarm”带架构上下文复核 PR | 自测抓到 82% 的植入 bug(CodeRabbit 44%),但误报率也更高(约 11 次/run vs CodeRabbit 2 次);独立机构 Macroscope 的复现基准给出不同排名(Macroscope 48%、CodeRabbit 46%、Cursor BugBot 42%、Greptile 24%)——厂商自测和第三方复现的结论方向相反,应把两者都当参考而非定论 |
| OpenAI Codex 插件(接入 Claude Code) | /codex:adversarial-review 显式命令,用不同厂商模型互相挑战设计 | 把”对抗式复核”做成了跨模型的显式功能位,而不是隐藏在流程里的一个步骤 |
这张表里最扎眼的一行是 Greptile:厂商自测和独立复现给出的名次几乎相反。这不是说对抗式复核没用,而是提醒——复核机制本身也需要被复核,一款工具”支持多 Agent 复核”不等于它的复核质量已经被验证过。
第四条暗线:状态从”这次对话”搬到”外部系统”
前三条战线都在处理”单次任务内”的问题。还有一条更底层的暗线没有在 Bun 案例里出现,但同样是 2026 年的前沿玩法——把经验和状态从”这次对话的上下文”搬到”下次任务也能读到的外部系统”。这是 Ruflo 源码深读 拆过的”元 harness”模式:不接管宿主的推理循环,而是靠 MCP 工具、持久化 Registry 和 Post-Task Hook,把”这次路由选对了还是选错了”物化成下次决策能检索到的记录。这条暗线和 《MCP 状态不会消失,只会搬家》 是同一个命题:状态不能靠进程内存碰运气,必须有明确归属。本文不重复拆解,只标出它和前三条战线属于同一族——都是把原本会随对话结束而消失的东西,改造成外部可持久化的结构。
灰度:这些重家伙不是每个任务都配得上
$165,000、11 天、64 个 Agent——这组数字本身就是一个提醒:协调本身是有成本的,而且成本不会因为任务简单就自动降为零。《深度解读 Agent Swarm》 已经拆过这笔”协调税”记在账本哪一行;这里补一个更具体的判断标准:
- 一次性小改动、单文件修复:不需要 Dynamic Workflows,模型自己决定要不要委派就够了——脚本化调度的价值在”任务能被拆成可并行的独立单元”,拆不开就是纯开销;
- 大规模迁移、语言移植、跨文件重构:这正是 Bun 案例的形状——任务天然可以按文件/模块切成独立单元,且每个单元的正确性能被测试套件机械判定,值得上这套重家伙;
- 没有硬验证器的任务:对抗式复核能揪出”代码为什么会炸”,但前提是复核者有能力判断对错。如果任务本身缺少测试套件或明确的正确性标准,复核会退化成”两个模型互相猜测”,收益存疑。
诚实的提醒
本文里 Bun 案例的所有数字,均来自 Anthropic 官方博客与 Bun 官方工程博客的公开数字,属于”核实过的来源”档,我没有亲手复现过百万行规模的移植。Codex CLI 生态里”三条产品线独立收敛到 worktree”这个判断,其证据来自多篇 2026 年社区实践文章和官方文档的交叉印证,而不是我逐一读过三家的源码——如果你想亲手验证,成本最低的实验是:在 Claude Code 里对一个可以拆成 3-5 个独立文件的小型重构任务说”用一个 workflow 来做这件事,对每个文件的改动做对抗式复核”,观察 /workflows 里是否真的出现了独立的复核角色,以及复核报告是否引用了具体的失败场景而不是空泛的”看起来没问题”。
收尾:判断你的任务在哪条战线上值得下重注
| 问题 | 如果答案是”是” |
|---|---|
| 任务能拆成互不依赖、可并行验证的独立单元吗? | 值得写成 Dynamic Workflows 脚本,而不是让模型临场决定 |
| 多个 Agent 会同时改同一批文件吗? | 值得上 worktree 隔离,不要靠”应该不会冲突”的祈祷 |
| 任务有客观的正确性标准(测试、编译、可运行)吗? | 值得配对抗式复核,且复核者应该看不到实现者的推理过程 |
| 这次任务的经验下次还用得上吗? | 值得考虑外部持久化状态,而不是让上下文窗口结束就归零 |
四条战线共享同一个纪律:凡是”世界不允许出错”的环节,都该从模型的判断力里搬出来,做成代码层面无法绕过的物理约束。模型每一代都在变强,但这条纪律本身不会过期。
参考来源
工程实践
- Introducing dynamic workflows | Claude by Anthropic
- Rewriting Bun in Rust | Bun 官方博客
- Rewriting Bun in Rust — Simon Willison 的评论
- Cursor Worktrees 官方文档
- worktrunk(Max Sixty)
- oh-my-codex(Yeachan-Heo)
- LangChain 官方框架对比
- CrewAI vs LangGraph vs AutoGen 综述
- Best AI Code Review Tools 2026(Greptile)