TranFu
返回

用一组并行 Claude 构建 C 编译器

TFTranFu 精选2026/06/25 08:54

Anthropic 研究员 Nicholas Carlini 发表文章,介绍用 Opus 4.6、Claude Code 和并行 agent teams 构建 C 编译器的实验。原文主要说明实验设置、产出规模,以及作者从长时间自主软件开发中总结出的 harness 设计经验。

Anthropic logo
图片来源:anthropic.com
文章作者、来源:anthropic.com

正文

我们让 Opus 4.6 通过智能体团队来构建一个 C 编译器,然后(基本上)就撒手不管了。这件事让我们看到了自主软件开发的未来会是什么样子。

作者 Nicholas Carlini,是我们 Safeguards 团队的研究员。

我一直在尝试一种新的语言模型监督方法,我们把它称为“agent teams”。

在 agent teams 模式下,多个 Claude 实例会在没有人类持续干预的情况下,并行协作处理同一个代码库。这种方法极大地拓展了 LLM agent 能够完成的事情范围。

为了对它进行压力测试,我让 16 个 agent 从零开始编写一个基于 Rust 的 C 编译器,要求它能够编译 Linux 内核。经过近 2,000 次 Claude Code 会话以及 2 万美元的 API 成本,这个 agent 团队产出了一个 10 万行代码的编译器,能够在 x86、ARM 和 RISC-V 上构建 Linux 6.9。

这个编译器本身就是一个值得关注的成果,但我在这里更关注的是:在为长时间运行的自治 agent 团队设计 harness 时,我学到了什么——如何编写测试,让 agent 在没有人工监督的情况下保持正轨;如何组织工作,让多个 agent 能并行推进;以及这种方法的能力边界到底在哪里。

像 Claude Code 这样的现有 agent 脚手架,要求操作者在线并随时可以协同工作。如果你让它解决一个漫长而复杂的问题,模型可能会先完成其中一部分,但最终它会停下来,等待进一步输入——一个问题、一次状态更新,或者一条澄清请求。

为了让它持续、自主地推进,我构建了一个把 Claude 放进简单循环里的 harness(如果你见过 Ralph-loop,这应该会很熟悉)。当它完成一项任务后,就会立刻接手下一项。(请在容器里运行,不要在你自己的机器上运行)。

在这个 agent 提示词里,我告诉 Claude 要解决什么问题,并要求它把问题拆解成小块,跟踪自己正在做什么,判断下一步该做什么,并有效地一直推进,直到达到完美。(在最后这一点上,Claude 没有选择余地。这个循环会永远运行——不过有一次,我确实看到 Claude 误执行了 `pkill -9 bash`,结果把自己杀掉,循环也就结束了。哎呀!)

同时运行多个实例,可以弥补单一 agent harness 的两个弱点:

一个 Claude Code 会话一次只能做一件事。尤其当项目范围不断扩大时,并行调试多个问题要高效得多。

运行多个 Claude agent 还可以实现分工。除了让少数 agent 负责解决眼前的实际问题之外,还可以调用其他专门的 agent 来(例如)维护文档、关注代码质量,或者处理特定的子任务。

我的并行 Claude 实现非常简陋:先创建一个全新的空 git 仓库,然后为每个 agent 启动一个 Docker 容器,并将该仓库挂载到 `/upstream`。每个 agent 都会在 `/workspace` 克隆一份本地副本,完成工作后,再从自己的本地容器把更改推送回 `upstream`。

为了防止两个 agent 同时去解决同一个问题,harness 使用了一种简单的同步算法:

Claude 会通过在 `current_tasks/` 目录下写入一个文本文件来给任务加上“锁”(例如,一个 agent 可能锁定 `current_tasks/parse_if_statement.txt`,而另一个则锁定 `current_tasks/codegen_function_definition.txt`)。如果两个 agent 试图认领同一个任务,git 的同步机制会强制第二个 agent 改选其他任务。

Claude 会先处理任务,然后从 `upstream` 拉取更新,合并其他 agent 的改动,推送自己的更改,并移除锁。合并冲突很常见,但 Claude 足够聪明,能处理好这一点。

这个无限的智能体生成循环会在一个全新的容器中启动一个新的 Claude Code 会话,然后周而复始地重复下去。

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

相反,我把如何行动的决定权交给每个 Claude 智能体。在大多数情况下,Claude 会接手“下一个最明显”的问题。遇到 bug 卡住时,Claude 往往会维护一份运行中的文档,记录失败的尝试和剩余任务。在项目的 git 仓库里,你可以翻阅历史,看到它为各项任务依次加锁。

这个脚手架让 Claude 进入循环运行,但只有当 Claude 知道如何推进时,这个循环才有用。我的大部分精力都花在为 Claude 设计周边环境——测试、环境、反馈——以便它无需我介入也能自行判断方向。以下是我在编排多个 Claude 实例时发现最有帮助的方法。

Claude 会自主处理我交给它的任何问题。因此,任务验证器必须几乎完美,否则 Claude 就会解决错误的问题。要改进测试 harness,我需要找到高质量的编译器测试套件,为开源软件包编写验证器和构建脚本,并持续观察 Claude 犯下的错误,然后在识别出这些失败模式后设计新的测试。

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

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

例如,每个 agent 都会被放进一个没有上下文的新容器里,而且会花相当多的时间来熟悉环境,尤其是在大型项目中。甚至在进入测试之前,为了让 Claude 更好地帮助自己,我加入了相关说明,要求维护详尽的 README 和进度文件,并且这些文件应当频繁更新当前状态。

我也始终牢记,大语言模型本身有内在局限,而在这里,设计时就必须围绕这些局限展开。这些局限包括:

上下文窗口污染:测试 harness 不应该输出成千上万字节的无用内容。它最多只应打印几行输出,并把所有重要信息记录到文件里,方便 Claude 在需要时查找。日志文件应该便于自动处理:如果出现错误,Claude 应该写上 ERROR,并把原因放在同一行,这样 `grep` 就能找到。预先计算汇总统计信息也很有帮助,这样 Claude 就不必再重新计算一遍。

时间盲:Claude 无法感知时间,如果放任不管,它会开心地花上几个小时跑测试,而不是推动进展。harness 会偶尔打印一次增量进度(以免污染上下文),并提供默认的 `--fast` 选项,运行 1% 或 10% 的随机样本。这个子样本对每个 agent 来说是确定性的,但在不同 VM 之间是随机的,因此 Claude 仍然会覆盖所有文件,而每个 agent 都能准确识别回归问题。

当有许多彼此独立的失败测试时,并行化很简单:每个 agent 选一个不同的失败测试来处理。在测试套件的通过率达到 99% 之后,每个 agent 都转而去让一个不同的小型开源项目(例如 SQlite、Redis、libjpeg、MQuickJS、Lua)成功编译。

但当智能体开始编译 Linux 内核时,它们就卡住了。不同于拥有数百个彼此独立测试的测试套件,编译 Linux 内核是一个巨大的单一任务。每个智能体都会撞上同一个 bug,修复它,然后又覆盖彼此的修改。即便有 16 个智能体同时运行也无济于事,因为它们都卡在解决同一个任务上。

解决办法是把 GCC 作为一个在线的、已知可用的编译器 oracle 来对照。我写了一个新的测试 harness,随机用 GCC 编译内核的大部分文件,只用 Claude's C Compiler 编译剩余文件。如果内核能正常工作,那问题就不在 Claude 负责的那部分文件里;如果出错,就可以进一步把其中一些文件改用 GCC 重新编译来缩小范围。这样,每个智能体就能并行工作,在不同文件里修复不同 bug,直到 Claude 的编译器最终能够编译所有文件。(在这套方法生效之后,仍然有必要应用 delta debugging 技术,找出那些单独看都能通过、但放在一起就会失败的文件对。)

并行性还带来了专门化。LLM 写出的代码经常会重新实现已有功能,所以我让一个智能体负责合并它发现的任何重复代码。我又让另一个智能体负责提升编译器本身的性能,并让第三个智能体负责输出高效的编译结果。我还让另一个智能体从 Rust 开发者的角度审视这个项目的设计,并对项目做结构性调整,以提升整体代码质量;再让一个智能体负责文档。

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

我一直把 C Compiler 项目作为整个 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 方案相比,这也是一个极其昂贵的项目。但这个总额只相当于让我自己完成这一切所需成本的一小部分——更不用说还要组建整支团队了。

这是一个 clean-room 实现(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 刚刚开始自动化的最后几部分,目前仍然有些不稳定。演示视频使用的是 GCC 的汇编器和链接器制作的。

这个编译器已经能成功构建许多项目,但还不是全部。它还不能直接替代真正的编译器。

生成的代码效率不高。即使开启了所有优化,它输出的代码效率也比关闭所有优化的 GCC 还要低。

Rust 代码的质量还算不错,但远远达不到资深 Rust 程序员可能写出的水平。

最终生成的编译器已经几乎逼近了 Opus 能力的极限。我(真的很努力地)尝试修复上述若干局限,但并没有完全成功。新的功能和 bug 修复经常会破坏已有功能。

作为一个尤其棘手的例子,Opus 无法实现一个用于启动到 16-bit real mode 的 16-bit x86 代码生成器。虽然编译器可以通过 66/67 opcode 前缀输出正确的 16-bit x86,但生成的编译结果超过 60kb,远远超出 Linux 强制执行的 32k 代码限制。于是,Claude 在这里只是偷了个懒,在这个阶段直接调用 GCC 来完成。(这只适用于 x86。对于 ARM 或 RISC-V,Claude 的编译器可以完全独立完成编译。)

编译器的源代码已经公开。下载下来,通读代码,并把它用于你最喜欢的 C 项目。我一直认为,理解语言模型能力的最佳方式,就是把它们推到极限,然后观察它们从哪里开始崩溃。接下来的几天里,如果你愿意持续关注 Claude 为解决这些限制所做的尝试,我也会继续让 Claude 推出新的改动。

每一代语言模型都会打开与之协作的新方式。早期模型主要用于 IDE 里的自动补全。没过多久,模型就可以根据文档字符串补全函数体。Claude Code 的发布把 agent 带入主流,并让开发者能够与 Claude 进行结对编程。但这些产品都建立在同一个假设之上:由用户定义任务,LLM 运行几秒或几分钟后返回答案,然后用户再给出后续指令。

agent 团队展示了自主实现整个复杂项目的可能性。这也让我们这些工具的使用者,能够为自己的目标设定更高的 ambition。

我们仍然处于早期阶段,完全自主开发也伴随着真实风险。当人类在开发过程中与 Claude 共同工作时,他们可以确保质量保持一致,并实时捕捉错误。对于自主系统来说,测试通过很容易让人误以为工作已经完成,而事实往往并非如此。我曾在渗透测试领域工作,利用大型公司产品中的漏洞开展攻击,因此,想到程序员部署自己从未亲自验证过的软件,这确实令人担忧。

所以,虽然这个实验让我感到兴奋,但也让我隐隐不安。构建这个编译器,是我最近做过最有趣的事情之一,但我没想到在 2026 年这么早的时候,这件事竟然已经接近可行。语言模型以及我们用来与之交互的脚手架都在快速进步,这为编写海量新代码打开了大门。我预计积极应用会多于负面影响,但我们正在进入一个新的世界,而要安全地驾驭它,需要新的策略。

特别感谢 Josef Bacik、Edwin Chen、Bernardo Meurer Costa、Jake Eaton、Dan Kelley、Felix Klock、Jannet Park、Steve Weis,以及 Anthropic 内部还有许多其他为此提供帮助和贡献的人。

产品更新、实用教程、社区聚焦等内容,按月发送到您的收件箱。

阅读原文

AI解读

这值得关注,因为文章把重点放在长时间自主 agent teams 的 harness 设计上,而不只是展示单次编码能力;它讨论了测试、任务拆分、并行协作、锁机制和上限等更接近真实工程自动化的问题。

对 AI builder 和开发者而言,这类实践提示:要让 agent 长时间推进复杂项目,关键不只是模型能力,还包括可验证测试、任务同步、容器化隔离、持续集成和面向 agent 的项目文档。对创业者而言,它可能影响 agentic coding 工具的编排、监控和质量保障设计。

建议关注原文中 harness、任务锁、CI、测试反馈和 agent 文档维护的设计细节;如果要复现实验,应先在容器和小规模任务上验证,并明确成本、权限和代码合并风险。