16 个 Claude 如何从零写出一个 C 编译器 | Anthropic

发布于:2026-3-14|最后更新: 2026-3-18|
category
library
Created time
Mar 18, 2026 08:24 AM
date
Mar 14, 2026
icon
password
slug
for-c-compiler-by-16-claude-agents
status
Published
summary
通过使用16个Claude智能体团队,成功从零开始构建了一个C编译器,能够编译Linux内核,并展示了在没有人工干预的情况下,智能体如何并行合作完成复杂项目的可能性。
tags
Claude
工程实践
type
post
作者: Nicholas Carlini(Anthropic 安全保障团队研究员)

我一直在尝试一种新的语言模型监管方式,我们把它叫作 “智能体团队”(agent teams)
在这种模式下,多个 Claude 实例会在没有人工干预的情况下,并行协作,共同维护一个共享代码库。这种做法大大拓展了 LLM 智能体能够胜任的任务边界。
为了做一次高强度压力测试,我给 16 个智能体布置了同一个目标:从零开始用 Rust 写一个 C 编译器,并最终让它能够编译 Linux 内核。经过将近 2,000 次 Claude Code 会话、约 2 万美元的 API 成本投入后,这个智能体团队最终交付了一个 10 万行代码 的编译器。它已经能够成功构建运行在 x86、ARM 和 RISC-V 架构上的 Linux 6.9 内核。
这个编译器本身就是个很有意思的成果,但这篇文章里我更想分享的是:在设计这种可长时间自主运行的智能体团队时,我总结出了哪些经验?
比如,怎样设计测试,才能让智能体在没有人工监督的情况下不偏离目标;怎样组织工作,才能让多智能体真正并行起来;以及这种方法的瓶颈究竟在哪里。

让 Claude 长时间持续工作

现有的智能体框架(例如 Claude Code)通常都需要操作员在线、实时配合。如果你给它一个又长又复杂的问题,模型往往只能先解决其中一部分,随后就会停下来,等待新的输入——比如回答一个问题、提供一条状态更新,或者补充某些澄清信息。
为了让系统能够持续、自主地推进任务,我写了一个很简单的循环脚本(如果你见过 Ralph-loop,应该会觉得它很像)。每当它完成一个任务,就会立刻开始下一个。(请在容器中运行此脚本,而不是你的主机)。
在智能体提示词(Prompt)里,我告诉 Claude 要解决什么问题,并要求它按照这样的方式工作:拆解任务、跟踪进度、判断下一步、持续推进,直到做到足够完善。至于最后这一点,Claude 其实也没有太多选择,因为这个循环永远不会自己停下——当然,中间也出过一次意外:我曾看到 Claude 不小心执行了 pkill -9 bash,把自己直接杀掉了,整个循环也就当场结束。挺尴尬的。

并行运行 Claude

并行运行多个实例,可以弥补单智能体框架的两个主要短板:
  1. 效率受限:一次 Claude Code 会话只能处理一件事。项目一旦变大,同时并行排查多个问题显然会高效得多。
  1. 可以做角色分工:多个智能体并行运行之后,就能自然形成专业化分工。一部分智能体负责解决核心问题,其他智能体则可以专门负责维护文档、监控代码质量,或者处理特定子任务。
我实现并行的方法其实很粗糙:先建一个空的 Git 仓库,再为每个智能体启动一个 Docker 容器,并把仓库挂载到 /upstream。每个智能体都会先在本地把仓库克隆到 /workspace,完成工作后,再从各自容器里把改动推回上游。
为了避免两个智能体同时处理同一个问题,这套系统采用了一个非常简单的同步机制
  1. 锁定任务:Claude 会通过在 current_tasks/ 目录里写入一个文本文件来“占坑”(例如某个智能体锁定 parse_if_statement.txt)。如果两个智能体同时试图抢同一个任务,Git 的同步机制会迫使后来的那个智能体重新选择任务。
  1. 执行与合并:Claude 完成任务后,会先从上游拉取最新代码,合并其他智能体的改动,再推送自己的更新,最后删除锁定文件。合并冲突(Merge conflicts) 经常发生,但 Claude 足够聪明,通常能够自己解决。
  1. 循环往复:这个无限循环会不断在新的容器中生成新的 Claude Code 会话。
这是一个非常早期的研究原型。我没有实现智能体之间更多样的通信方式,也没有强制加入任何高层目标管理机制,更没有设置所谓的“编排智能体”(orchestration agent)。
相反,我让每个 Claude 智能体自己决定接下来该做什么。大多数时候,Claude 会去挑那个“眼下最明显应该先解决的问题”。如果它卡在某个 Bug 上,通常会顺手维护一份运行中的记录文档,把失败过的尝试和剩余任务都记下来。在项目的 Git 仓库 里,你也可以从历史记录中看到它们是怎样逐项锁定任务的。

与 Claude 智能体团队协作的几点经验

循环脚本只是让系统转起来;但如果 Claude 不知道怎样才能真正推进工作,这个循环本身并没有意义。我真正花最多精力的地方,其实是围绕 Claude 去设计环境——包括测试、运行环境和反馈机制——让它在没有我干预的情况下,也能自己判断方向。下面这些做法,是我在组织多实例 Claude 协作时觉得最有效的。

1. 编写足够高质量的测试

Claude 会自动去解决我交给它的任何问题。因此,任务校验器(task verifier) 几乎必须做到万无一失,否则 Claude 很可能会认真地解决一个错误的问题。要把测试套件打磨好,就意味着你得去找高质量的编译器测试集,为开源软件编写校验器和构建脚本,并持续观察 Claude 会犯哪些错,再据此反过来补测试。
例如在项目后期,Claude 每新增一个功能,往往都会顺手把已有功能弄坏。为了解决这个问题,我搭建了一条 CI(持续集成)流水线,用更严格的约束确保新提交不会破坏旧代码。

2. 站在 Claude 的角度设计系统

我必须不断提醒自己:我是在为 Claude 写测试套件,而不是为人写。这意味着,测试反馈方式也必须重新设计。
比如,每个智能体进入一个新容器时,都是“零上下文”状态,需要花不少时间重新熟悉环境。为了帮 Claude 更快进入状态,我要求它持续维护详细的 README 和进度文件,并频繁更新当前状态。
此外,我还专门针对语言模型本身的一些局限做了设计:
  • 避免污染上下文窗口:测试套件不应该一股脑打印几千行无意义的输出。它应当只打印少量关键信息,把重要内容写入文件。日志文件也要足够适合自动处理:如果发生错误,Claude 应该把 ERROR 和原因写在同一行,方便用 grep 检索。
  • 弥补“时间盲区”:Claude 并不能真正感知时间,如果不做额外设计,它可能会连续几个小时都耗在跑测试上,却没有任何实质性进展。为此,这套系统会低频输出进度,并提供一个 -fast 选项(只跑 1% 或 10% 的随机样本)。这个子样本对单个智能体来说是确定的,但在不同虚拟机之间又是随机的,这样既保证了一定覆盖率,也能让每个智能体更快发现回归错误(regressions)

3. 让并行化真正变简单

当有很多彼此独立的测试项失败时,并行化并不难:每个智能体各领一个任务去修就行了。等到测试通过率接近 99% 以后,每个智能体开始尝试编译不同的开源项目,比如 SQLite、Redis、libjpeg 等。
但到编译 Linux 内核这一步时,它们就卡住了。编译内核本质上是一个体量巨大的单一任务,所有智能体都会撞上同一个 Bug,修完之后又互相覆盖彼此的改动。此时,16 个智能体几乎发挥不出什么作用。
后来我的解决办法,是把 GCC 当作“在线真值编译器”(online known-good compiler oracle)。我写了一个新的测试套件:随机让 GCC 负责编译大部分内核文件,只让 Claude 的编译器去编译剩下的一小部分。如果内核仍然可以正常运行,就说明问题不在 Claude 编译的那部分。借助这种增量调试(delta debugging) 方法,每个智能体终于可以并行地去修不同文件里的 Bug。

4. 多智能体带来的角色分工

并行化带来的另一个结果,就是专业化分工。LLM 写代码时经常会重复造轮子,所以我专门安排了一个智能体负责合并重复代码。另一个负责提升编译器性能,第三个负责优化生成的机器码。除此之外,我还让一个智能体以 Rust 专家的视角审查整体设计并进行重构,另一个则专门负责文档。

压力测试:智能体团队的极限在哪里

这个项目本质上是一个能力基准测试。我想做的,是测一测 LLM 当前“勉强能够完成”的极限到底在哪里,从而据此判断,未来的模型大概会稳定做到什么程度。
我把这个 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,总成本略低于 2 万美元。这个价格当然比任何 Claude Max 套餐都高得多,但如果拿它和雇一个团队来做同样的事情相比,其实只是很小的一笔钱。
这是一次纯净实现(clean-room implementation):在整个开发过程中,Claude 都无法访问互联网,只能依赖 Rust 标准库。
  • 成果:10 万行代码,能够构建 x86、ARM 和 RISC-V 架构的引导级 Linux 6.9。
  • 兼容性:可以编译 QEMU、FFmpeg、SQLite、PostgreSQL、Redis。
  • 测试:在 GCC torture 测试集中达到了 99% 的通过率。
  • 终极测试:它已经能编译并运行 Doom(毁灭战士)
当然,它也有明显局限:
  • 16 位模式缺失:它还不具备引导 Linux 退出实模式所需的 16 位 x86 编译能力,这一部分仍然要依赖 GCC。
  • 汇编器与链接器:这是 Claude 到最后才开始尝试自动化的部分,目前依然存在 Bug。演示视频中仍然使用的是 GCC 的汇编器和链接器。
  • 代码效率:它生成出来的代码效率并不高。即便打开所有优化,其表现依然比 GCC 在关闭优化(-O0)时更慢。
  • 代码质量:Rust 代码整体还算过得去,但距离专家级水准仍有明显差距。
这个编译器已经非常接近 Opus 能力的边界。我曾经努力尝试修复上面这些限制,但始终没能彻底解决。新功能一加进去,往往又会把原有的稳定性打坏。

展望未来

每一代语言模型都在打开新的协作方式。最早的模型主要用于代码补全;后来它们可以根据注释写函数;再到 Claude Code 把智能体带进主流,开始真正支持结对编程。但这些产品背后的默认范式始终是:用户定义任务 -> LLM 运行几秒 -> 用户给出反馈。
而智能体团队展示的是:自主完成整个复杂项目,已经开始变得可能。 这意味着,作为工具使用者,我们终于可以把目标设得更大。
这个实验一方面让我非常兴奋,另一方面也让我隐隐感到不安。2026 年初就已经能做到这种程度,确实超出了我的预期。自主系统很容易因为“通过了测试”就让人误以为问题已经解决,但现实往往没有这么简单。我以前做过渗透测试,所以一想到程序员可能会部署那些从未经过人工验证的软件,还是会觉得很不踏实。
我们正在进入一个全新的世界,而要想安全地航行其中,也必须建立一套新的方法。

相关文章

AI如何在测试中“作弊”?Anthropic 首次记录 AI 反向破解 BenchmarkAI 不仅改变了产品,更重塑了销售方式