Github仓库里面除下面的介绍由人类撰写外,本仓库中的所有代码和文档均由Claude Opus 4.6编写。人类通过编写测试用例来指导部分开发过程(要求Claude通过这些测试),但从未与Claude进行交互式结对编程来调试或提供代码质量反馈
https://github.com/anthropics/claudes-c-compiler
【构建出的C编译器介绍】
一个完全用Rust从零编写的C编译器,支持x86-64、i686、AArch64和RISC-V 64架构。零编译器专用依赖——前端、基于SSA的中间表示、优化器、代码生成器、窥孔优化器、汇编器、链接器和DWARF调试信息生成均为完全自主实现。Claude的C编译器无需任何外部工具链即可生成ELF可执行文件。
该编译器能够针对所有四种架构构建现实世界中的C语言代码库,包括Linux内核。成功编译并通过测试套件的项目包括PostgreSQL(全部237个回归测试)、SQLite、QuickJS、zlib、Lua、libsodium、libpng、jq、libjpeg-turbo、mbedTLS、libuv、Redis、libffi、musl、TCC和DOOM——所有这些项目均使用完全独立的汇编器和链接器完成,无需依赖外部工具链。此外,还有150多个项目已成功构建,包括FFmpeg(在x86-64和AArch64架构上通过全部7331项FATE checkasm测试)、GNU coreutils、Busybox、CPython、QEMU和LuaJIT
视频:
针对这款C编译器,专门撰写的一篇博文,这里也为大家做了翻译整理
【前言】
我们利用Agent团队让Opus 4.6构建了一个C编译器,然后(大部分时候)放手不管。以下是这个实验教给我们关于自主软件开发未来的启示。本文由我们安全团队的研究员 Nicholas Carlini 撰写。
我一直在试验一种监督语言模型的新方法,我们称之为"Agent团队"。
采用Agent团队的模式,多个Claude实例可以在无需人工主动干预的情况下,在同一个代码库上并行工作。这种方法极大地扩展了利用LLM智能体所能完成的任务范围。
为了对其进行压力测试,我让16个智能体通力合作,从头开始编写一个基于Rust的C编译器,目标是能够编译Linux内核。经过近2000次Claude Code会话,花费了2万美元的API成本,这个智能体团队最终产出了一个拥有10万行代码的编译器,能够成功构建x86、ARM和RISC-V架构上的Linux 6.9内核。
这个编译器本身就是一个有趣的成果,但我在这里想重点分享的是,我在为长期运行的自主Agent团队设计框架时所获得的经验:如何编写测试,使得智能体能够在无需人工监督的情况下持续推进;如何组织工作,让多个智能体能够并行取得进展;以及这种方法的能力天花板在哪里。
【实现长期运行的Claude】
现有的智能体框架(如Claude Code)需要操作员在线并随时准备协同工作。如果你要求解决一个长期而复杂的问题,模型可能会解决其中一部分,但最终它会停下来,等待进一步的输入——可能是一个问题、一个状态更新,或者一个澄清请求。
为了激发持续、自主的进展,我构建了一个框架,让Claude进入一个简单的循环(如果你见过Ralph-loop,这应该很眼熟)。当它完成一个任务时,会立即开始下一个任务。(请在容器中运行,不要在你的实际机器上运行)。
[C] 纯文本查看 复制代码 #!/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】
并行运行多个实例可以解决单智能体框架的两个弱点:
1、一个Claude Code会话一次只能做一件事。特别是随着项目范围的扩大,并行调试多个问题要高效得多。
2、运行多个Claude智能体可以实现专业化分工。当一些智能体被分配去解决当前的实际问题时,可以调用其他专门的智能体来(例如)维护文档、关注代码质量或解决专门的子任务。
我的并行Claude实现非常简陋。创建一个新的裸git仓库,然后为每个智能体启动一个Docker容器,并将该仓库挂载到/upstream。每个智能体克隆一个本地副本到/workspace,工作完成后,将其从自己的本地容器推送到上游。
为了防止两个智能体试图同时解决同一个问题,框架使用了一个简单的同步算法:
1、Claude通过将一个文本文件写入current_tasks/目录来"锁定"一个任务(例如,一个智能体可能锁定current_tasks/parse_if_statement.txt,而另一个锁定current_tasks/codegen_function_definition.txt)。如果两个智能体试图认领同一个任务,git的同步机制会强制第二个智能体选择不同的任务。
2、Claude处理该任务,然后从上游拉取,合并其他智能体的更改,推送其更改,并移除锁。合并冲突很频繁,但Claude足够聪明,能够解决这个问题。
3、这个无限生成智能体的循环会在一个全新的容器中产生一个新的Claude Code会话,然后循环重复。
这是一个非常早期的研究原型。我还没有实现任何其他智能体间通信的方法,也没有强制执行任何管理高层级目标的流程。我没有使用协调智能体。
相反,我把决定权留给每个Claude智能体,让它们自己决定如何行动。在大多数情况下,Claude会选择"下一个最明显"的问题。当卡在一个bug上时,Claude通常会维护一个持续更新的文档,记录失败的方法和剩余任务。在项目的git仓库中,你可以阅读整个历史记录,观察它如何锁定各种任务。
【与Claude Agent团队一起编程的经验教训】
框架让Claude进入一个循环,但这个循环只有在Claude知道如何取得进展时才有效。我的大部分精力都投入到设计Claude周围的环境上——测试、环境、反馈——以便它能够在我缺席的情况下自行定位。以下是我在编排多个Claude实例时发现最有用的方法。
编写极其高质量的测试
Claude会自主地解决我交给它的任何问题。因此,任务验证器必须近乎完美,否则Claude会解决错误的问题。改进测试框架需要寻找高质量的编译器测试套件,为开源软件包编写验证器和构建脚本,观察Claude常犯的错误,然后根据我发现的这些失败模式设计新的测试。
例如,在项目接近尾声时,Claude每次实现新功能都开始频繁地破坏已有功能。为了解决这个问题,我建立了一个持续集成流水线,并实施了更严格的执行机制,允许Claude更好地测试其工作,以确保新的提交不会破坏现有代码。
设身处地为Claude着想
我不得不经常提醒自己,这个测试框架是为Claude编写的,而不是为我自己,这意味着要重新思考许多关于测试应如何传达结果的假设。
例如,每个智能体被丢进一个全新的容器中,没有任何上下文,它会花费大量时间来定位自己,尤其是在大型项目中。在我们甚至还没开始测试之前,为了帮助Claude自助,我指示它维护详尽的README和进度文件,并频繁地用当前状态更新这些文件。
我还牢记语言模型有其固有的局限性,在这种情况下,需要针对这些局限性进行设计。这些局限性包括:
1、上下文窗口污染:测试框架不应打印数千字节的无用信息。最多,它应该打印几行输出,并将所有重要信息记录到文件中,以便Claude在需要时可以找到。日志文件应易于自动处理:如果有错误,Claude应该写ERROR并将原因放在同一行,以便grep能找到。预先计算汇总统计摘要也很有帮助,这样Claude就不必重新计算了。
2、时间盲点:Claude无法判断时间,如果放任不管,它会乐此不疲地花费数小时运行测试,而不是取得进展。框架会不频繁地打印增量进度(以避免污染上下文),并包含一个默认的--fast选项,用于运行1%或10%的随机样本。这个子样本对每个智能体是确定性的,但在不同虚拟机之间是随机的,因此Claude仍然覆盖所有文件,但每个智能体可以完美地识别出回归问题。
让并行变得容易
当存在许多不同的失败测试时,并行化是简单的:每个智能体挑选一个不同的失败测试来处理。在测试套件达到99%的通过率后,每个智能体着手让不同的开源小项目(例如SQLite、Redis、libjpeg、QuickJS、Lua)能够编译成功。
但是,当智能体开始编译Linux内核时,它们卡住了。与包含数百个独立测试的测试套件不同,编译Linux内核是一个巨大的单一任务。每个智能体都会遇到相同的bug,修复它,然后互相覆盖对方的更改。让16个智能体同时运行并没有帮助,因为每个都被困在解决同一个任务上。
解决方法是将GCC作为一个在线已知良好的编译器预言机来进行对比。我编写了一个新的测试框架,它使用GCC随机编译大部分内核文件,只留下剩余的文件用Claude的C编译器编译。如果内核能工作,那么问题就不在Claude负责的那部分文件里。如果内核崩溃了,那么可以通过用GCC重新编译其中一些文件来进一步缩小范围。这使得每个智能体可以并行工作,修复不同文件中的不同bug,直到Claude的编译器最终能够编译所有文件。(这步成功之后,仍然需要使用delta调试技术来找到那些单独编译能通过但一起编译就会失败的文件对。)
多智能体角色
并行化也使得专业化成为可能。LLM编写的代码经常重复实现已有功能,所以我指派一个智能体负责合并它发现的任何重复代码。我让另一个智能体负责提高编译器本身的性能,第三个负责输出高效的编译后代码。我又请了一个智能体从Rust开发者的角度来评审项目的设计,并对项目进行结构性更改以提高整体代码质量,还有一个负责文档工作。
【压力测试Agent团队的极限】
这个项目被设计为一个能力基准测试。我感兴趣的是,压力测试当今LLM刚刚能够达到的能力极限,以帮助我们为未来模型将可靠实现的目标做准备。
我一直将C编译器项目作为整个Claude 4模型系列的基准测试。正如我之前做过的项目一样,我首先起草了我的目标:一个从头开始编写的、无依赖的优化编译器,与GCC兼容,能够编译Linux内核,并设计为支持多个后端。虽然我指定了设计的一些方面(例如,它应该有一个SSA IR以支持多种优化),但我没有详细说明如何实现。
之前的Opus 4模型几乎无法生成一个功能正常的编译器。Opus 4.5是第一个跨越门槛,能够生成通过大型测试套件的功能编译器的模型,但它仍然无法编译任何真正的大型项目。我对Opus 4.6的目标是再次测试其极限。
评估
在两周的时间里,Opus 4.6进行了近2000次Claude Code会话,消耗了20亿输入tokens,生成了1.4亿输出tokens,总成本略低于2万美元。即使与最昂贵的Claude Max计划相比,这也是一个极其昂贵的项目。但这笔总额只是我自己(更不用说一个完整的团队了)完成这项工作所需成本的一小部分。
这是一个闭门实现(Claude在开发过程中的任何时刻都无法访问互联网);它仅依赖于Rust标准库。这个10万行代码的编译器可以在x86、ARM和RISC-V架构上构建一个可启动的Linux 6.9内核。它还可以编译QEMU、FFmpeg、SQLite、Postgres、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代码,但生成的编译后输出超过60kb,远远超过Linux强制执行的32kb代码大小限制。因此,Claude在这个阶段简单地作弊,调用了GCC来完成这项工作(这只针对x86架构。对于ARM或RISC-V,Claude的编译器可以完全独立编译)。
该编译器的源代码现已开放。您可以下载它,阅读代码,并在您喜欢的C项目上尝试。我一直认为,理解语言模型能力的最佳方式是将其推向极限,然后研究它们从哪里开始崩溃。在接下来的日子里,如果您想跟进Claude为解决这些限制所做的持续尝试,我会继续让Claude推送新的更改。
【未来展望】
每一代语言模型都开启了与之协作的新方式。早期的模型对IDE中的制表符补全很有用。不久之后,模型可以根据文档字符串完成函数体。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的许多其他人员的协助和贡献。
|