跳到正文
原文
Anthropic:Engineering·· 2026-02-05精选AI 评分68

Building a C compiler with a team of parallel Claudes

Building a C compiler with a team of parallel ClaudesFeb 05, 2026

文章要点
  • 1Anthropic 研究员用 16 个并行 Claude 智能体从零写出 10 万行 Rust 版 C 编译器,可编译启动 x86、ARM、RISC-V 的 Linux 6.9。
  • 2项目历时两周、近 2000 个 Claude Code 会话,Opus 4.6 消耗 20 亿输入和 1.4 亿输出 tokens,API 成本近 2 万美元。
  • 3编译器在含 GCC torture test suite 的大多数套件通过率 99%,可编译 Doom、QEMU、FFmpeg 等,但代码效率低于关闭优化的 GCC。
  • 4作者认为无人监督的多智能体团队能自主完成大型项目,同时担忧开发者部署未经本人验证的软件。
决策要点

并行智能体加无限循环的编排方式,把大模型可自主完成的工程任务推到数周和十万行代码量级,瓶颈在测试与环境设计而非模型调用本身。

  • 影响:作者称近 2 万美元成本远低于自己或团队开发的开销;企业引入的前提是任务能被测试自动验证;无人复核即部署的代码存在质量与安全风险。
  • 参考:可考虑在测试完善、结果可自动验证的场景试点长任务智能体;值得为长任务预置隔离容器和日志规范,并先算清单个项目的 token 与 API 预算。
  • 依据:全部为 Anthropic 研究员自述实验数据,含近 2000 会话、20 亿输入 tokens、近 2 万美元成本等,官方口径,暂无独立验证。
正文 · AI 翻译

本文由我们 Safeguards 团队的研究员 Nicholas Carlini 撰写。

我一直在试验一种监督语言模型的新方法,我们称之为“智能体团队”(agent teams)。

在智能体团队模式下,多个 Claude 实例在无需人工主动干预的情况下,并行地在同一个共享代码库上工作。这种方法极大地扩展了 LLM 智能体所能实现的范围。

为了对其进行压力测试,我让 16 个智能体从零开始编写一个基于 Rust 的 C 编译器,要求能够编译 Linux 内核。在近 2,000 次 Claude Code 会话和 20,000 美元的 API 费用之后,这个智能体团队产出了一个 100,000 行的编译器,可以在 x86、ARM 和 RISC-V 上构建 Linux 6.9。

这个编译器本身就是一个有趣的成果,但我在这里重点关注的是我在为长期运行的自主智能体团队设计 harness 时学到的东西:如何编写测试,让智能体在无人监督的情况下不偏离轨道;如何组织工作,让多个智能体能够并行推进;以及这种方法的天花板在哪里。

让 Claude 长时间运行

现有的智能体框架(如 Claude Code)要求操作者在线并随时可以协同工作。如果你要求它解决一个漫长而复杂的问题,模型可能会解决其中一部分,但最终它会停下来等待后续输入——一个提问、一次状态更新,或一个澄清请求。

为了获得持续、自主的进展,我构建了一个 harness,让 Claude 处于一个简单的循环中(如果你见过 Ralph-loop,这应该看起来很眼熟)。它每完成一个任务,就立即开始下一个任务。(请在容器中运行,而不是在你的真实机器上)。

#!/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


在智能体提示词中,我告诉 Claude 要解决什么问题,并让它把问题拆分成小块、跟踪自己正在做的事情、确定接下来要做什么,从而有效地持续进行,直到做到完美为止。(在最后这一点上,Claude 没有选择余地。这个循环会永远运行下去——尽管有一次,我确实看到 Claude 意外地 pkill -9 bash,从而杀死了自己并结束了循环。哎呀!)。


并行运行 Claude

并行运行多个实例可以解决单智能体 harness 的两个弱点:

  • 一个 Claude Code 会话一次只能做一件事。尤其是当项目规模扩大时,并行调试多个问题的效率要高得多。
  • 运行多个 Claude 智能体可以实现专业化分工。当几个智能体负责解决手头的实际问题时,还可以调用其他专门的智能体来(例如)维护文档、关注代码质量,或解决专门的子任务。

我的并行 Claude 实现非常简单。首先创建一个新的 bare git 仓库,然后为每个智能体启动一个 Docker 容器,并将该仓库挂载到 /upstream。每个智能体将本地副本克隆到 /workspace,完成后,再从自己的本地容器推送到上游。

为了防止两个智能体同时尝试解决同一个问题,该 harness 使用了一个简单的同步算法:

  1. Claude 通过向 current_tasks/ 写入一个文本文件来对任务进行“加锁”(例如,一个智能体可能锁定 current_tasks/parse_if_statement.txt,而另一个智能体锁定 current_tasks/codegen_function_definition.txt)。如果两个智能体试图认领同一个任务,git 的同步机制会迫使第二个智能体选择另一个任务。
  2. Claude 处理该任务,然后从上游拉取(pull)、合并其他智能体的更改、推送自己的更改,并移除锁。合并冲突很常见,但 Claude 足够聪明,能够自己解决。
  3. 这个无限的智能体生成循环(agent-generation-loop)会在一个全新的容器中启动新的 Claude Code 会话,然后循环往复。

这是一个非常早期的研究原型。我还没有实现任何其他智能体间通信的方法,也没有强制执行任何管理高层目标的流程。我没有使用编排智能体。

相反,我把如何行动的决定权交给每个 Claude 智能体。在大多数情况下,Claude 会接手“下一个最明显”的问题。当被某个 bug 卡住时,Claude 通常会维护一份持续更新的文档,记录失败的尝试和剩余的任务。在项目的git 仓库中,你可以浏览历史记录,观察它对各项任务加锁的过程。

与 Claude 智能体团队协作编程的经验教训

脚手架让 Claude 在循环中运行,但只有当 Claude 能够判断如何推进时,这个循环才有用。我大部分精力都花在了设计 Claude 周围的环境——测试、运行环境、反馈——以便它能在没有我的情况下自我定位。以下是我在编排多个 Claude 实例时发现最有帮助的一些方法。

编写极其高质量的测试

Claude 会自主工作,解决我交给它的任何问题。因此任务验证器必须近乎完美,否则 Claude 就会解决错误的问题。改进测试框架需要寻找高质量的编译器测试套件,为开源软件包编写验证器和构建脚本,留意 Claude 犯的错误,然后在我识别出这些失败模式时设计新的测试。

例如,在项目接近尾声时,Claude 开始在每次实现新功能时频繁破坏现有功能。为了解决这个问题,我构建了一个持续集成流水线,并实施了更严格的强制检查,让 Claude 能够更好地测试自己的工作,从而确保新的提交不会破坏现有代码。

设身处地为 Claude 着想

我必须不断提醒自己,这个测试框架是为 Claude 编写的,而不是为我自己,这意味着我要重新思考许多关于测试应如何传达结果的假设。

例如,每个智能体都被放入一个没有任何上下文的新容器中,会花费大量时间来熟悉环境,尤其是在大型项目上。在接触测试之前,为了帮助 Claude 自助,我在其中加入了维护详尽 README 和进度文件的说明,这些文件应经常更新当前状态。

我还牢记语言模型存在固有局限性这一事实,在本例中,需要围绕这些局限性进行设计。其中包括:

  • 上下文窗口污染:测试框架不应输出数千字节的无用信息。最多应打印几行输出,并将所有重要信息记录到文件中,以便 Claude 在需要时查找。日志文件应易于自动处理:如果出现错误,Claude 应写入 ERROR 并把原因放在同一行,这样 grep 才能找到它。预先计算汇总统计数据也很有帮助,这样 Claude 就不必重新计算。
  • 时间盲症:Claude 无法感知时间,如果放任不管,它会乐此不疲地花上数小时运行测试而不是推进进度。测试框架很少打印增量进度(以避免污染上下文),并包含一个默认的 --fast 选项,可运行 1% 或 10% 的随机样本。这个子样本对每个 agent 而言是确定性的,但在不同 VM 之间是随机的,因此 Claude 仍能覆盖所有文件,而每个 agent 都能准确识别回归。

让并行变得容易

当存在许多不同的失败测试时,并行化就很简单:每个 agent 选择一个不同的失败测试来处理。当测试套件的通过率达到 99% 后,每个 agent 致力于让一个不同的小型开源项目(例如 SQlite、Redis、libjpeg、MQuickJS、Lua)成功编译。

但当 agent 们开始编译 Linux 内核时,它们陷入了困境。与拥有数百个独立测试的测试套件不同,编译 Linux 内核是一个巨大的整体任务。每个 agent 都会遇到同一个 bug,修复它,然后互相覆盖对方的修改。运行 16 个 agent 也无济于事,因为每个 agent 都卡在解决同一个任务上。

解决办法是使用 GCC 作为在线的已知良好编译器基准进行对比。我编写了一个新的测试框架,用 GCC 随机编译内核的大部分文件,而只对其余文件使用 Claude 的 C 编译器。如果内核能正常工作,说明问题不在 Claude 负责的那部分文件中。如果编译失败,则可以通过用 GCC 重新编译其中一些文件来进一步缩小范围。这样每个 agent 就能并行工作,修复不同文件中的不同 bug,直到 Claude 的编译器最终能够编译所有文件。(在这之后,仍需应用 delta debugging 技术来找出那些单独编译正常、合在一起却失败的文件对。)

多种 agent 角色

并行还能实现角色分工。LLM 编写的代码经常重复实现已有的功能,因此我指派一个 agent 合并它发现的任何重复代码。我让另一个 agent 负责提升编译器本身的性能,再让第三个负责输出高效的编译后代码。我还让一个 agent 从 Rust 开发者的视角对项目设计提出批评,并对项目进行结构性修改以提升整体代码质量,另外再让一个 agent 负责编写文档。

压力测试 agent 团队的极限

这个项目被设计成一个能力基准测试。我有兴趣对 LLM 如今勉强能够达到的极限进行压力测试,以帮助我们为模型未来能够稳定实现的能力做好准备。

我一直在整个 Claude 4 模型系列中使用这个 C 编译器项目作为基准测试。与之前的项目一样,我先起草了我想要的东西:一个从零开始、无依赖、与 GCC 兼容的优化编译器,能够编译 Linux 内核,并在设计上支持多种后端。虽然我指定了设计的某些方面(例如,它应该有一个 SSA IR 以支持多个优化 pass),但我没有详细说明如何实现。

之前的 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、postgres、redis,并且在大多数编译器测试套件上拥有 99% 的通过率,其中包括 GCC torture test suite。它还通过了开发者的终极试金石测试:能编译并运行 Doom。

不过,这个编译器并非没有局限。这些局限包括:

  • 它缺少从实模式启动 Linux 所必需的 16 位 x86 编译器。为此,它会调用 GCC(x86_32 和 x86_64 编译器则是它自己的)。
  • 它没有自己的汇编器和链接器;这是 Claude 最后才开始自动化的部分,目前仍存在一些 bug。演示视频是用 GCC 的汇编器和链接器制作的。
  • 该编译器能成功构建许多项目,但并非全部。它还不是一个可直接替换真实编译器的即插即用替代品。
  • 生成的代码效率不高。即使开启所有优化,它输出的代码也不如 关闭 所有优化的 GCC 所输出的代码高效。
  • Rust 代码质量尚可,但与专家级 Rust 程序员所能写出的代码质量相去甚远。

最终得到的编译器已接近 Opus 能力的极限。我尝试(非常努力地!)修复上述几项局限,但并未完全成功。新功能和 bug 修复经常破坏现有功能。

举一个特别有挑战性的例子:Opus 无法实现启动进入 16 位实模式所需的 16 位 x86 代码生成器。虽然编译器可以通过 66/67 操作码前缀输出正确的 16 位 x86 代码,但生成的编译输出超过 60kb,远超 Linux 强制执行的 32k 代码上限。因此,Claude 在这一阶段干脆作弊,调用 GCC 来完成(只有 x86 是这种情况。对于 ARM 或 RISC-V,Claude 的编译器可以完全自行编译。)

编译器的源代码已经可用。下载它,通读代码,并在你最喜欢的 C 项目上试用。我一直发现,理解语言模型能做什么的最佳方式,就是把它们逼到极限,然后研究它们从哪里开始失效。在接下来的几天里,我会继续让 Claude 推送新的改动,如果你想跟进 Claude 为解决这些局限所做的持续尝试,不妨关注。

展望未来

每一代语言模型都会开辟与它们协作的新方式。早期模型适用于 IDE 中的 Tab 补全。不久之后,模型就能根据 docstring 补全函数体。Claude Code 的发布让智能体走向主流,使开发者能够与 Claude 结对编程。但以上每一款产品都建立在这样一种假设之上:用户定义一个任务,LLM 运行几秒或几分钟并返回一个答案,然后用户再提出后续请求。

Agent 团队展示了自主实现整个复杂项目的可能性。这让我们作为这些工具的用户,能够为自己设定更有雄心的目标。

我们仍处于早期阶段,完全自主的开发也伴随着真实的风险。当人类在开发过程中与 Claude 并肩工作时,可以确保质量始终如一,并实时发现错误。而对于自主系统来说,很容易看到测试通过就认为工作已经完成,但事实很少如此。我曾在渗透测试领域工作,利用大公司产品中的漏洞进行攻击,想到程序员部署自己从未亲自验证过的软件,这是一个真正令人担忧的问题。

因此,虽然这个实验让我兴奋,但也让我感到不安。构建这个编译器是我近来最有趣的经历之一,但我没想到在 2026 年这么早的时候这就几乎成为可能。语言模型以及我们用来与之交互的脚手架的快速进展,为编写大量新代码打开了大门。我预计积极的应用将超过负面影响,但我们正在进入一个新世界,需要新的策略才能安全前行。

致谢

特别感谢 Josef Bacik、Edwin Chen、Bernardo Meurer Costa、Jake Eaton、Dan Kelley、Felix Klock、Jannet Park、Steve Weis 以及 Anthropic 内许多其他人员的协助与贡献。

来源:Anthropic:Engineering · anthropic.com