让一组并行 Claude 构建 C 编译器
Anthropic 研究员 Nicholas Carlini 分享让 16 个 Claude Agent 从零构建 C 编译器的实验,以及长期自主开发中的测试、并行协作与能力边界。
Hex4C59 12 分钟阅读 更新于 2026-10-17
AI 与 Agent·译文
译文信息
- 原文:Building a C compiler with a team of parallel Claudes
- 作者:Nicholas Carlini(Anthropic Safeguards 团队研究员)
- 原文发布:2026-02-05
- 中文翻译:Hex4C59
- 翻译整理:2026-10-10
本文为非官方中文译文。正文中的「我」「我们」指原文作者及其团队;模型版本、实验结果和费用均保留原文记录,译者未独立复现实验。
我们让一组 Opus 4.6 Agent 构建一个 C 编译器,然后基本上就放手了。这次实验让我们对自主软件开发的未来有了一些认识。
我一直在尝试一种监督语言模型的新方式,我们把它称为「Agent 团队」(agent teams)。
在 Agent 团队中,多个 Claude 实例在共享代码库上并行工作,不需要人类主动介入。这种方式大幅拓展了大语言模型 Agent 能够完成的任务范围。
为了对它进行压力测试,我让 16 个 Agent 从零开始,用 Rust 编写一个能够编译 Linux 内核的 C 编译器。经过近 2,000 次 Claude Code 会话、花费约 20,000 美元的 API 费用,这个 Agent 团队产出了一个约 10 万行代码的编译器,能够为 x86、ARM 和 RISC-V 构建 Linux 6.9。
这个编译器本身就是一个有意思的成果,但本文主要讨论我在为长期自主运行的 Agent 团队设计 Harness 时学到的经验:如何编写测试,让 Agent 在没有人类监督的情况下沿正确方向推进;如何组织工作,让多个 Agent 能够并行取得进展;以及这种方式会在哪里碰到能力上限。
译者注:Harness 指围绕模型构建的运行与编排系统,本文包括持续运行循环、任务同步、测试验证与反馈,详见文末译注。
让 Claude 持续运行 #
Claude Code 这类现有的 Agent 支撑工具,需要操作者在线并随时参与协作。如果你要求模型解决一个漫长而复杂的问题,它可能会完成其中一部分,但最终还是会停下来,等待你继续提供输入,例如回答一个问题、回应一条状态更新,或者澄清某个要求。
为了让 Claude 持续、自主地推进工作,我构建了一个 Harness,让 Claude 在一个简单的循环中运行。如果你见过 Ralph-loop,这种方式应该会很熟悉。完成一项任务后,它就立即开始下一项。请在容器中运行这段代码,不要直接在你的实际机器上运行。
下面是原文中的 Bash 示例,保留原样,用于展示实验中的运行循环;它并不是本博客项目的运行脚本。
#!/bin/bash
while true; do
COMMIT=$(git rev-parse --short=6 HEAD)
LOGFILE="agent_logs/agent_${COMMIT}.log"
claude --dangerously-skip-permissions \
-p "$(cat AGENT_PROMPT.md)" \
--model claude-opus-X-Y &> "$LOGFILE"
done在给 Agent 的提示中,我会说明要解决什么问题,并要求它把问题拆成小块、跟踪正在进行的工作、确定接下来该做什么,实际上就是一直干下去,直到做到完善。关于最后一点,Claude 其实别无选择:这个循环会永远运行下去。不过有一次,我确实看到 Claude 意外执行了 pkill -9 bash,结果把自己终止了,循环也随之结束。哎呀!
让 Claude 并行运行 #
并行运行多个实例,可以弥补单 Agent Harness 的两个弱点:
- 一个 Claude Code 会话同一时间只能做一件事。尤其当项目范围扩大时,并行调试多个问题会高效得多。
- 运行多个 Claude Agent 可以实现专业分工。当几个 Agent 负责解决眼前的核心问题时,还可以调用其他专门的 Agent,例如维护文档、关注代码质量,或者处理专门的子任务。
我的并行 Claude 实现十分简陋。先创建一个新的 Git 裸仓库,再为每个 Agent 启动一个 Docker 容器,将这个仓库挂载到 /upstream。每个 Agent 都把仓库克隆到自己的 /workspace,完成工作后,再从各自的本地容器推送到上游仓库。
为了避免两个 Agent 同时尝试解决同一个问题,Harness 使用了一个简单的同步算法:
- Claude 在
current_tasks/中写入一个文本文件,给任务「上锁」。例如,一个 Agent 可以锁定current_tasks/parse_if_statement.txt,另一个锁定current_tasks/codegen_function_definition.txt。如果两个 Agent 尝试认领同一项任务,Git 的同步机制会迫使后一个 Agent 选择其他任务。 - Claude 处理任务,然后从上游拉取更新、合并其他 Agent 的改动、推送自己的改动,并移除锁。合并冲突经常发生,但 Claude 足够聪明,能够处理这些冲突。
- 这个不断生成 Agent 的无限循环,会在一个全新的容器中启动新的 Claude Code 会话,然后重复整个过程。
这是一个非常早期的研究原型。我尚未实现任何其他 Agent 间通信方式,也没有强制规定管理高层目标的流程。我没有使用编排 Agent。
相反,我让每个 Claude Agent 自行决定如何行动。大多数时候,Claude 会接手「下一个最显而易见」的问题。遇到难以解决的缺陷时,它往往会维护一份持续更新的文档,记录已经失败的方法和剩余任务。在这个项目的 Git 仓库中,你可以翻阅历史记录,看到它如何为各种任务上锁。
使用 Claude Agent 团队编程的经验 #
这套支撑系统让 Claude 在循环中运行,但只有当 Claude 能够判断如何取得进展时,这个循环才有用。我把大部分精力花在设计 Claude 周围的环境上,包括测试、环境配置和反馈,让它在没有我的情况下,也能自己找到方向。以下是我在编排多个 Claude 实例时发现最有帮助的方法。
编写质量极高的测试 #
无论我给出什么问题,Claude 都会自主尝试解决它。因此,用来判断任务是否完成的验证程序必须近乎完美,否则 Claude 就会去解决错误的问题。为了改进测试 Harness,我需要寻找高质量的编译器测试套件,为开源软件包编写验证器和构建脚本,观察 Claude 会犯哪些错误,再针对发现的失败模式设计新测试。
例如,项目接近尾声时,Claude 开始频繁地在实现新功能时破坏已有功能。为了解决这个问题,我搭建了持续集成流水线,并加入更严格的约束,让 Claude 更充分地测试自己的工作,确保新提交不会破坏现有代码。
站在 Claude 的角度思考 #
我必须不断提醒自己:这套测试 Harness 是为 Claude 编写的,而不是为我自己。这意味着,我需要重新审视自己关于「测试应该怎样传达结果」的许多假设。
例如,每个 Agent 一开始都会被放进一个全新的容器,没有任何上下文,因此会花费大量时间了解当前情况,尤其是在大型项目中。为了让 Claude 自己了解项目进展,我在开始测试之前,就已在指令中要求它维护详尽的 README 和进度文件,并经常更新,以反映当前状态。
我也始终记得,语言模型本身存在一些局限,在这个项目中,需要通过设计来应对。包括:
- 上下文窗口污染:测试 Harness 不应该输出数千字节的无用信息。它最多只应打印几行输出,把所有重要信息写入文件,让 Claude 在需要时能够找到。日志文件也应该便于自动处理:如果存在错误,Claude 应写出
ERROR,并把原因放在同一行,这样grep就能找到。预先计算汇总统计信息也有帮助,可以避免让 Claude 重新计算。 - 时间盲区:Claude 无法感知时间;如果放任它运行,它会欣然花上几个小时执行测试,而不是推进工作。Harness 只会偶尔输出阶段性进度,避免污染上下文,并提供一个默认的
--fast选项,只运行随机抽取的 1% 或 10% 的测试样本。同一个 Agent 每次运行时使用固定的测试样本,不同虚拟机则随机选取各自的样本。这样,Claude 整体仍能覆盖所有文件,而每个 Agent 也能准确识别回归问题。
让并行工作更容易 #
当存在许多彼此不同的失败测试时,并行化非常简单:每个 Agent 选择一个不同的失败测试来处理。在测试套件通过率达到 99% 之后,每个 Agent 又分别负责让一个不同的小型开源项目能够编译,例如 SQLite、Redis、libjpeg、MQuickJS 和 Lua。
但当 Agent 开始编译 Linux 内核时,它们就卡住了。与包含数百个独立测试的测试套件不同,编译 Linux 内核是一个巨大的整体任务。每个 Agent 都会遇到同一个缺陷,修复它,然后相互覆盖对方的改动。即使同时运行 16 个 Agent,也无济于事,因为它们全都困在同一项任务上。
解决办法是把 GCC 作为运行过程中可用的、已知正确的编译器参照,用来对比结果。我编写了一个新的测试 Harness,随机选择内核中的大部分文件交给 GCC 编译,只把剩下的文件交给 Claude 的 C 编译器。如果内核能够正常工作,就说明问题不在 Claude 编译的这部分文件中。如果内核出错,就可以把其中一些文件改为用 GCC 重新编译,进一步缩小范围。这样,每个 Agent 就能并行工作,修复不同文件中的不同缺陷,直到 Claude 的编译器最终能够编译所有文件。做到这一点后,仍然需要应用差分调试(delta debugging)技术,找出那些单独使用时正常、组合在一起却会出错的文件对。
为 Agent 设置不同角色 #
并行也使专业分工成为可能。大语言模型编写的代码经常会重复实现已有功能,因此我让一个 Agent 负责合并它发现的重复代码。另一个负责提高编译器自身的性能,第三个负责让编译器生成更高效的代码。我还让一个 Agent 从 Rust 开发者的角度审视项目设计,通过结构调整改善整体代码质量;另一个则负责文档。
对 Agent 团队的能力极限进行压力测试 #
这个项目被设计为一项能力基准测试。我感兴趣的是,对大语言模型目前勉强能够做到的事情进行极限测试,以便帮助我们为模型未来能够可靠完成的事情做好准备。
我一直把 C 编译器项目用作整个 Claude 4 模型系列的基准测试。与之前的项目一样,我先写下自己想要什么:一个从零实现、没有依赖、兼容 GCC、能够编译 Linux 内核,并且设计上支持多个后端的优化编译器。虽然我规定了一些设计要点,例如采用静态单赋值形式的中间表示(SSA IR),以支持多轮优化,但没有详细说明应该怎样实现。
此前的 Opus 4 模型,勉强才能生成一个能用的编译器。Opus 4.5 是第一个跨过某个门槛的模型,能够生成可通过大型测试套件的实用编译器,但仍然无法编译任何真正的大型项目。对于 Opus 4.6,我的目标是再次测试它的极限。
评估结果 #
在两周内的近 2,000 次 Claude Code 会话中,Opus 4.6 消耗了 20 亿个输入 token,生成了 1.4 亿个输出 token,总费用略低于 20,000 美元。即便与最昂贵的 Claude Max 套餐相比,这也是一个极其昂贵的项目。但如果由我亲自完成,总成本会高得多,更不用说投入一整个团队;这笔费用只相当于其中的一小部分。
这是一个净室实现:Claude 在整个开发过程中都无法访问互联网。它只依赖 Rust 标准库。这个约 10 万行代码的编译器,能够为 x86、ARM 和 RISC-V 构建可启动的 Linux 6.9。它也能编译 QEMU、FFmpeg、SQLite、PostgreSQL 和 Redis,并在包括 GCC torture 测试套件在内的大多数编译器测试套件上达到 99% 的通过率。它还通过了开发者的终极检验:能够编译并运行 Doom。
不过,这个编译器仍然存在一些限制,包括:
- 它缺少启动 Linux 并退出实模式所需的 16 位 x86 编译器。这部分会调用 GCC;
x86_32和x86_64编译器则是它自己实现的。 - 它没有自己可用的汇编器和链接器。这是 Claude 最后才开始自动实现的部分,目前仍有一些缺陷。演示视频使用的是 GCC 的汇编器和链接器。
- 它能成功构建许多项目,但并非所有项目。它还不能直接替代成熟编译器。
- 它生成的代码效率不高。即使开启全部优化,生成代码的效率仍然低于关闭全部优化的 GCC。
- Rust 代码质量尚可,但远远达不到专业 Rust 程序员能够写出的水平。
最终得到的编译器,已经接近 Opus 的能力极限。我曾经非常努力地尝试解决上述一些限制,但没有完全成功。新增功能和缺陷修复,经常会破坏已有功能。
一个特别棘手的例子是,Opus 无法实现启动进入 16 位实模式所需的 16 位 x86 代码生成器。虽然编译器可以借助 66/67 操作码前缀输出正确的 16 位 x86 代码,但编译结果超过 60 KB,远远超出 Linux 规定的 32 KB 代码大小限制。因此,Claude 在这里直接「作弊」,在这个阶段调用 GCC。这种情况只发生在 x86 上;对于 ARM 和 RISC-V,Claude 的编译器可以自行完成整个编译过程。
编译器的源码已经公开。你可以下载它,阅读代码,并用自己喜欢的 C 项目试一试。我一直认为,理解语言模型能做什么的最佳方式,就是把它们推到极限,然后研究它们从哪里开始失效。在接下来的几天里,我会继续让 Claude 推送新的改动。如果你感兴趣,可以关注它为解决这些限制所做的后续尝试。
展望未来 #
每一代语言模型,都会带来新的使用方式。早期模型适合在集成开发环境(IDE)中提供 Tab 补全。没过多久,模型就能根据文档字符串补全整个函数体。Claude Code 的推出让 Agent 进入主流,使开发者能够与 Claude 结对编程。但这些产品都有一个共同假设:用户定义一项任务,大语言模型运行几秒或几分钟后返回答案,然后用户继续提供后续输入。
Agent 团队展示了自主实现整个复杂项目的可能性。这让我们这些工具的使用者,可以设定更有雄心的目标。
我们仍处于早期阶段,完全自主的开发也确实伴随着风险。在开发过程中,如果人类坐在 Claude 身边,就可以确保质量保持一致,并实时发现错误。对于自主系统,人们很容易看到测试通过,就以为工作已经完成,而实际情况很少如此。我以前从事渗透测试,利用大型公司产品中的漏洞;一想到程序员可能会部署自己从未亲自验证过的软件,我就十分担忧。
因此,这次实验让我兴奋,也让我感到不安。构建这个编译器,是我最近做过的最有趣的事情之一,但我没有想到,在 2026 年这么早的时候,这件事就已经接近可行。语言模型,以及我们用来与它们交互的支撑工具,都在快速进步,这为编写海量新代码打开了大门。我预计,正面应用将超过负面应用,但我们正在进入一个新世界,需要新的策略才能安全地前行。
致谢 #
特别感谢 Josef Bacik、Edwin Chen、Bernardo Meurer Costa、Jake Eaton、Dan Kelley、Felix Klock、Jannet Park、Steve Weis,以及 Anthropic 的许多其他同事,感谢他们的帮助与贡献。
译注 #
- Agent teams:译为「Agent 团队」,指多个 Claude 实例在共享代码库中并行协作。Agent 保留英文。
- Harness:围绕模型构建的运行与编排系统。本文中包括持续运行循环、任务同步、测试验证与反馈机制。
- SSA IR:Static Single Assignment Intermediate Representation,静态单赋值形式的中间表示。
- Oracle:在测试语境中指用来判定结果是否正确的参照。本文采用已知正确的 GCC 编译结果进行对照;原文中的 online 指运行过程中使用该参照,不代表 Claude 能访问互联网。
- Delta debugging:译为「差分调试」,通过逐步缩减触发失败的输入或配置,定位导致问题的最小组合。
- Bash 示例中的
claude-opus-X-Y沿用原文占位写法;本文仅转录示例,未执行该脚本。 - 本文依据所提供的正文文本翻译。演示视频及原文中的其他链接,请参阅原文页面。正文中的「接下来的几天」等时间表述,均以原文发布日期 2026 年 2 月 5 日为参照。
原文著作权归原作者及 Anthropic 所有。本文为非官方中文译文;如需核对技术细节或措辞,请以原文为准。
一起讨论
选中正文中的文字,可以针对这段内容发起讨论。
正在读取讨论…
在 GitHub 查看与管理讨论 ↗