← 返回文章列表
2026-02-05

用并行Claude智能体(Agent)团队构建C编译器

Building a C compiler with a team of parallel Claudes

Building a C compiler with a team of parallel Claudes

Written by Nicholas Carlini, a researcher on our Safeguards team. I've been experimenting with a new approach to supervising language models that we’re calling "agent teams." With agent teams, multiple Claude instances work in parallel on a shared codebase without active human intervention. This approach dramatically expands the scope of what's achievable with LLM agents. To stress test it, I tasked 16 agents with writing a Rust-based C compiler, from scratch, capable of compiling the Linux kernel. Over nearly 2,000 Claude Code sessions and $20,000 in API costs, the agent team produced a 100,000-line compiler that can build Linux 6.9 on x86, ARM, and RISC-V. The compiler is an interesting artifacton its own, but I focus here on what I learned about designing harnesses for long-running autonomous agent teams: how to write tests that keep agents on track without human oversight, how to structure work so multiple agents can make progress in parallel, and where this approach hits its ceiling.

作者:Nicholas Carlini,Anthropic安全防护团队研究员。

Enabling long-running Claudes

我一直在尝试一种监督语言模型的新方法,我们称之为"智能体团队"(Agent Teams)。

Existing agent scaffolds like Claude Code require an operator to be online and available to work jointly. If you ask for a solution to a long and complex problem, the model may solve part of it, but eventually it will stop and wait for continued input—a question, a status update, or a request for clarification. To elicit sustained, autonomous progress, I built a harness that sticks Claude in a simple loop (if you’ve seen Ralph-loop, this should look familiar). When it finishes one task, it immediately picks up the next.(Run this in a container, not your actual machine).

通过智能体团队,多个Claude实例可以在共享代码库上并行工作,无需人工主动干预。这种方法极大地扩展了LLM智能体所能完成任务的范围。

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

#!/bin/bash

这个编译器本身就是一个有趣的产物,但我在这里重点介绍的是我在设计长时间运行的自主智能体团队运行框架方面的经验:如何编写测试来确保智能体在没有人类监督的情况下保持正轨,如何组织工作使多个智能体能够并行推进,以及这种方法的局限性在哪里。

while true; do COMMIT=$(git rev-parse --short=6 HEAD) LOGFILE="agent_logs/agent_${COMMIT}.log"

让Claude长时间运行

claude --dangerously-skip-permissions \ -p "$(cat AGENT_PROMPT.md)" \ --model claude-opus-X-Y &> "$LOGFILE" done In the agent prompt, I tell Claude what problem to solve and ask it to approach the problem by breaking it into small pieces, tracking what it’s working on, figuring out what to work on next, and to effectively keep going until it’s perfect. (On this last point, Claude has no choice. The loop runs forever—although in one instance, I did see Claudepkill -9 bashon accident, thus killing itself and ending the loop. Whoops!). pkill -9 bash

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

Running Claude in parallel

为了实现持续的自主进展,我构建了一个运行框架,将Claude置于一个简单的循环中(如果你见过Ralph-loop,这个应该看起来很熟悉)。当它完成一个任务后,会立即开始下一个。(请在容器中运行,不要在你的实际机器上运行。)

Running multiple instances in parallel can address two weaknesses of a single-agent harness:

#!/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
  • One Claude Code session can only do one thing at a time. Especially as the scope of a project expands, debugging multiple issues in parallel is far more efficient.
  • Running multiple Claude agents allows for specialization. While a few agents are tasked to solve the actual problem at hand, other specialized agents can be invoked to (for example) maintain documentation, keep an eye on code quality, or solve specialized sub-tasks.

在智能体提示中,我告诉Claude要解决什么问题,并要求它将问题分解为小块,跟踪当前工作内容,确定下一步做什么,并持续工作直到完美。(关于最后一点,Claude别无选择。循环会永远运行——尽管在某个实例中,我确实看到Claude意外执行了 pkill -9 bash,从而杀死了自己并结束了循环。糟糕!)

My implementation of parallel Claude is bare-bones. A new bare git repo is created, and for each agent, a Docker container is spun up with the repo mounted to/upstream. Each agent clones a local copy to/workspace, and when it's done, pushes from its own local container to upstream. /upstream /workspace To prevent two agents from trying to solve the same problem at the same time, the harness uses a simple synchronization algorithm:

并行运行Claude

  • Claude takes a "lock" on a task by writing a text file to current_tasks/ (e.g., one agent might lock current_tasks/parse_if_statement.txt, while another locks current_tasks/codegen_function_definition.txt). If two agents try to claim the same task, git's synchronization forces the second agent to pick a different one.
  • Claude works on the task, then pulls from upstream, merges changes from other agents, pushes its changes, and removes the lock. Merge conflicts are frequent, but Claude is smart enough to figure that out.
  • The infinite agent-generation-loop spawns a new Claude Code session in a fresh container, and the cycle repeats.

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

This is a very early research prototype. I haven’t yet implemented any other method for communication between agents, nor do I enforce any process for managing high-level goals. I don’t use an orchestration agent. Instead, I leave it up to each Claude agent to decide how to act. In most cases, Claude picks up the “next most obvious” problem. When stuck on a bug, Claude will often maintain a running doc of failed approaches and remaining tasks. In thegit repositoryof the project, you can read through the history and watch it take out locks on various tasks.

  • 一个Claude Code会话一次只能做一件事。随着项目范围的扩大,并行调试多个问题会高效得多。
  • 运行多个Claude智能体可以实现专业化分工。当一些智能体被分配解决实际问题时,其他专业化的智能体可以被调用来(例如)维护文档、监控代码质量或解决专门的子任务。

Lessons from programming with Claude agent teams

我实现的并行Claude方案非常简陋。创建一个新的空git仓库,为每个智能体启动一个Docker容器,将仓库挂载到 /upstream。每个智能体将本地副本克隆到 /workspace,完成后从自己的本地容器推送到 /upstream。

The scaffolding runs Claude in a loop, but that loop is only useful if Claude can tell how to make progress. Most of my effort went into designing the environment around Claude—the tests, the environment, the feedback—so that it could orient itself without me. These are the approaches I’ve found most helpful when orchestrating multiple Claude instances.

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

Write extremely high-quality tests

  • Claude通过在 current_tasks/ 目录下写入一个文本文件来对任务加"锁"(例如,一个智能体可能锁定 current_tasks/parse_if_statement.txt,而另一个锁定 current_tasks/codegen_function_definition.txt)。如果两个智能体尝试认领同一个任务,git的同步机制会强制第二个智能体选择其他任务。
  • Claude完成任务后,从上游拉取代码,合并其他智能体的更改,推送自己的更改,然后移除锁。合并冲突很常见,但Claude足够聪明,能够自行解决。
  • 无限的智能体生成循环在新容器中生成新的Claude Code会话,循环往复。

Claude will work autonomously to solve whatever problem I give it. So it’s important that the task verifier is nearly perfect, otherwise Claude will solve the wrong problem. Improving the testing harness required finding high-quality compiler test suites, writing verifiers and build scripts for open-source software packages, and watching for mistakes Claude was making, then designing new tests as I identified those failure modes. For example, near the end of the project, Claude started to frequently break existing functionality each time it implemented a new feature. To address this, I built a continuous integration pipeline and implemented stricter enforcement that allowed Claude to better test its work so that new commits can’t break existing code.

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

Put yourself in Claude’s shoes

相反,我让每个Claude智能体自行决定如何行动。在大多数情况下,Claude会处理"下一个最明显的"问题。当卡在某个bug上时,Claude通常会维护一个记录失败方法和剩余任务的文档。在项目的 git 仓库中,你可以浏览历史记录,观察它如何对各种任务加锁。

I had to constantly remind myself that I was writing this test harness for Claude and not for myself, which meant rethinking many of my assumptions about how tests should communicate results. For example, each agent is dropped into a fresh container with no context and will spend significant time orienting itself, especially on large projects. Before we even reach the tests, to help Claude help itself, I included instructions to maintain extensive READMEs and progress files that should be updated frequently with the current status. I also kept in mind the fact that language models have inherent limitations, which, in this case, needed to be designed around. These include:

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

  • Context window pollution:The test harness should not print thousands of useless bytes. At most, it should print a few lines of output and log all important information to a file so Claude can find it when needed. Logfiles should be easy to process automatically: if there are errors, Claude should write ERROR and put the reason on the same line so grep will find it. It helps to pre-compute aggregate summary statistics so Claude doesn't have to recompute them.
  • Time blindness:Claude can't tell time and, left alone, will happily spend hours running tests instead of making progress. The harness prints incremental progress infrequently (to avoid polluting context) and includes a default--fastoption that runs a 1% or 10% random sample. This subsample is deterministic per-agent but random across VMs, so Claude still covers all files but each agent can perfectly identify regressions.

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

--fast

编写极其高质量的测试

Make parallelism easy

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

When there are many distinct failing tests, parallelization is trivial: each agent picks a different failing test to work on. After the test suite reached a 99% pass rate, each agent worked on getting a different small open-source project (e.g., SQlite, Redis, libjpeg, MQuickJS, Lua) to compile. But when agents started to compile the Linux kernel, they got stuck. Unlike a test suite with hundreds of independent tests, compiling the Linux kernel is one giant task. Every agent would hit the same bug, fix that bug, and then overwrite each other's changes. Having 16 agents running didn't help because each was stuck solving the same task. The fix was to useGCCas an online known-good compiler oracle to compare against. I wrote a new test harness that randomly compiled most of the kernel using GCC, and only the remaining files with Claude's C Compiler. If the kernel worked, then the problem wasn’t in Claude’s subset of the files. If it broke, then it could further refine by re-compiling some of these files with GCC. This let each agent work in parallel, fixing different bugs in different files, until Claude's compiler could eventually compile all files. (After this worked, it was still necessary to apply delta debugging techniques to find pairs of files that failed together but worked independently.)

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

Multiple agent roles

站在Claude的角度思考

Parallelism also enables specialization. LLM-written code frequently re-implements existing functionality, so I tasked one agent with coalescing any duplicate code it found. I put another in charge of improving the performance of the compiler itself, and a third I made responsible for outputting efficient compiled code. I asked another agent to critique the design of the project from the perspective of a Rust developer, and make structural changes to the project to improve the overall code quality, and another to work on documentation.

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

Stress testing the limits of agent teams

例如,每个智能体被投入到一个全新的容器中,没有任何上下文,会在定位自身上花费大量时间,尤其是在大型项目上。在我们接触测试之前,为了帮助Claude自助,我包含了维护详尽README和进度文件的说明,这些文件应频繁更新当前状态。

This project was designed as a capability benchmark. I am interested in stress-testing the limits of what LLMs can justbarelyachieve today in order to help us prepare for what models will reliably achieve in the future. I’ve been using the C Compiler project as a benchmark across the entire Claude 4 model series. As I did with prior projects, I started by drafting what I wanted: a from-scratch optimizing compiler with no dependencies, GCC-compatible, able to compile the Linux kernel, and designed to support multiple backends. While I specified some aspects of the design (e.g., that it should have an SSA IR to enable multiple optimization passes) I did not go into any detail on how to do so. Previous Opus 4 models were barely capable of producing a functional compiler. Opus 4.5 was the first to cross a threshold that allowed it to produce a functional compiler which could pass large test suites, but it was still incapable of compiling any real large projects. My goal with Opus 4.6 was to again test the limits.

我还考虑到语言模型固有的局限性,这些局限性在本场景中需要通过设计来规避。包括:

Evaluation

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

Over nearly 2,000 Claude Code sessions across two weeks, Opus 4.6 consumed 2 billion input tokens and generated 140 million output tokens, a total cost just under $20,000. Compared to even the most expensive Claude Max plans, this was an extremely expensive project. But that total is a fraction of what it would cost me to produce this myself—let alone an entire team. This was a clean-room implementation (Claude did not have internet access at any point during its development); it depends only on the Rust standard library. The 100,000-line compiler can build a bootable Linux 6.9 on x86, ARM, and RISC-V. It can also compile QEMU, FFmpeg, SQlite, postgres, redis, and has a 99% pass rate on most compiler test suites including theGCC torture test suite. It also passes the developer's ultimate litmus test: it can compile and run Doom. The compiler, however, is not without limitations. These include:

使并行化变得简单

  • It lacks the 16-bit x86 compiler that is necessary to boot Linux out of real mode. For this, it calls out to GCC (the x86_32 and x86_64 compilers are its own).
  • It does not have its own assembler and linker; these are the very last bits that Claude started automating and are still somewhat buggy. The demo video was produced with a GCC assembler and linker.
  • The compiler successfully builds many projects, but not all. It's not yet a drop-in replacement for a real compiler.
  • The generated code is not very efficient. Even with all optimizations enabled, it outputs less efficient code than GCC with all optimizationsdisabled.
  • The Rust code quality is reasonable, but is nowhere near the quality of what an expert Rust programmer might produce.

当有许多不同的失败测试时,并行化很简单:每个智能体选择一个不同的失败测试来处理。当测试套件达到99%通过率后,每个智能体负责让一个不同的小型开源项目(如SQLite、Redis、libjpeg、QuickJS、Lua)成功编译。

The resulting compiler has nearly reached the limits of Opus’s abilities. I tried (hard!) to fix several of the above limitations but wasn’t fully successful. New features and bugfixes frequently broke existing functionality. As one particularly challenging example, Opus was unable to implement a 16-bit x86 code generator needed to boot into 16-bit real mode. While the compiler can output correct 16-bit x86 via the 66/67 opcode prefixes, the resulting compiled output is over 60kb, far exceeding the 32k code limit enforced by Linux. Instead, Claude simply cheats here and calls out to GCC for this phase (This is only the case for x86. For ARM or RISC-V, Claude’s compiler can compile completely by itself.) Thesource code for the compiler is available. Download it, read through the code, and try it on your favorite C projects. I’ve consistently found the best way to understand what language models can do is to push them to their limits, and then study where they start to break down. Over the coming days, I’ll continue having Claude push new changes if you want to follow along with Claude’s continued attempts at addressing these limitations.

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

Looking forward

解决方案是使用 GCC 作为在线的已知可用编译器来进行对比。我编写了一个新的测试框架,随机使用GCC编译内核的大部分文件,只用Claude的C编译器编译剩余的文件。如果内核正常工作,则说明问题不在Claude负责的文件子集中。如果出错了,可以进一步细化,将其中一些文件重新用GCC编译。这让每个智能体能够并行工作,修复不同文件中的不同bug,直到Claude的编译器最终能够编译所有文件。(在此方案奏效后,仍然需要应用增量调试技术来找到成对失败但单独工作的文件。)

Each generation of language models opens up new ways of working with them. Early models were useful for tab-completion in IDEs. Before long, models could complete a function body from its docstring. The launch of Claude Code brought agents into the mainstream and enabled developers to pair-program with Claude. But each of these products operates under the assumption that a user defines a task, an LLM runs for a few seconds or minutes and returns an answer, and then the user provides a follow-up. Agent teams show the possibility of implementing entire, complex projects autonomously. This allows us, as users of these tools, to become more ambitious with our goals. We are still early, and fully autonomous development comes with real risks. When a human sits with Claude during development, they can ensure consistent quality and catch errors in real time. For autonomous systems, it is easy to see tests pass and assume the job is done, when this is rarely the case. I used to work in penetration testing, exploiting vulnerabilities in products produced by large companies, and the thought of programmers deploying software they’ve never personally verified is a real concern. So, while this experiment excites me, it also leaves me feeling uneasy. Building this compiler has been some of the most fun I’ve had recently, but I did not expect this to be anywhere near possible so early in 2026. The rapid progress in both language models and the scaffolds we use to interact with them opens the door to writing an enormous amount of new code. I expect the positive applications to outweigh the negative, but we’re entering a new world which will require new strategies to navigate safely.

多智能体角色

Acknowledgements

并行化还支持专业化分工。LLM编写的代码经常重复实现已有功能,因此我分配了一个智能体负责合并它发现的任何重复代码。我让另一个智能体负责提高编译器本身的性能,第三个负责输出高效的编译代码。我还让一个智能体从Rust开发者的角度评审项目设计,并进行结构性修改以提高整体代码质量,另一个负责文档工作。

Special thanks to Josef Bacik, Edwin Chen, Bernardo Meurer Costa, Jake Eaton, Dan Kelley, Felix Klock, Jannet Park, Steve Weis, and many other people across Anthropic for their assistance and contributions.

压力测试智能体团队的极限

这个项目被设计为一个能力基准测试。我对压力测试LLM今天"勉强能够"达到的极限感兴趣,以帮助我们为模型未来能够可靠实现的目标做准备。

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

之前的Opus 4模型勉强能够产生一个功能性的编译器。Opus 4.5是第一个跨越门槛的版本,能够产生一个能通过大型测试套件的功能性编译器,但它仍然无法编译任何真实的大型项目。我使用Opus 4.6的目标是再次测试极限。

评估

在近2000次Claode Code会话、跨越两周的时间里,Opus 4.6消耗了20亿个输入token和1.4亿个输出token,总成本略低于20000美元。即使与最昂贵的Claude Max计划相比,这也是一个极其昂贵的项目。但这个总数只是我自己完成这项工作所需成本的一小部分——更不用说一个完整的团队了。

这是一个洁净室实现(Claude在开发过程中任何时间点都没有互联网访问权限);它仅依赖Rust标准库。这个10万行的编译器能够在x86、ARM和RISC-V上构建可引导的Linux 6.9。它还能编译QEMU、FFmpeg、SQLite、PostgreSQL、Redis,并且在大多数编译器测试套件上(包括 GCC 压力测试套件)达到99%的通过率。它还通过了开发者的终极检验:它能编译并运行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强制执行的32KB代码限制。因此,Claude在这里干脆作弊,调用GCC来完成这个阶段(这只针对x86。对于ARM或RISC-V,Claude的编译器可以完全独立编译。)

编译器的源代码已经公开。下载它,阅读代码,并在你喜欢的C项目上试试。我一贯发现,理解语言模型能力的最好方法是将它们推向极限,然后研究它们在哪里开始崩溃。在接下来的日子里,如果你想关注Claude持续解决这些限制的尝试,我会继续让Claude推送新的更改。

展望

每一代语言模型都开启了与之协作的新方式。早期模型在IDE中用于补全。不久之后,模型可以从函数文档字符串完成函数体。Claude Code的发布将智能体带入主流,使开发者能够与Claude结对编程。但这些产品的运作前提都是:用户定义任务,LLM运行几秒或几分钟后返回答案,然后用户提供后续指令。

智能体团队展示了自主实施完整复杂项目的可能性。这使我们作为这些工具的使用者,能够设定更具雄心的目标。

我们仍处于早期阶段,完全自主开发伴随着真正的风险。当人类在开发过程中与Claude协同工作时,他们可以确保一致的质量并实时捕获错误。对于自主系统,很容易看到测试通过就认为任务完成了,但事实很少如此。我曾经从事渗透测试工作,利用大型公司生产的产品中的漏洞,想到程序员部署他们从未亲自验证过的软件,这确实令人担忧。

因此,虽然这个实验让我兴奋,但也让我感到不安。构建这个编译器是我最近最有乐趣的经历之一,但我没想到在2026年这么早就能实现这一切。语言模型及其交互框架的快速进步,为编写大量新代码打开了大门。我预计正面应用将超过负面影响,但我们正在进入一个新世界,需要新的策略来安全地航行。

致谢

特别感谢Josef Bacik、Edwin Chen、Bernardo Meurer Costa、Jake Eaton、Dan Kelley、Felix Klock、Jannet Park、Steve Weis以及Anthropic许多其他同事的帮助和贡献。

作者:Nicholas Carlini,Anthropic安全防护团队研究员。

我一直在尝试一种监督语言模型的新方法,我们称之为"智能体团队"(Agent Teams)。

通过智能体团队,多个Claude实例可以在共享代码库上并行工作,无需人工主动干预。这种方法极大地扩展了LLM智能体所能完成任务的范围。

为了对其进行压力测试,我分配了16个智能体从零开始编写一个基于Rust的C编译器,要求能够编译Linux内核。在近2000次Claude Code会话和20000美元的API成本下,智能体团队构建了一个10万行的编译器,能够在x86、ARM和RISC-V架构上构建Linux 6.9。

这个编译器本身就是一个有趣的产物,但我在这里重点介绍的是我在设计长时间运行的自主智能体团队运行框架方面的经验:如何编写测试来确保智能体在没有人类监督的情况下保持正轨,如何组织工作使多个智能体能够并行推进,以及这种方法的局限性在哪里。

让Claude长时间运行

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

为了实现持续的自主进展,我构建了一个运行框架,将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

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

  • 一个Claude Code会话一次只能做一件事。随着项目范围的扩大,并行调试多个问题会高效得多。
  • 运行多个Claude智能体可以实现专业化分工。当一些智能体被分配解决实际问题时,其他专业化的智能体可以被调用来(例如)维护文档、监控代码质量或解决专门的子任务。

我实现的并行Claude方案非常简陋。创建一个新的空git仓库,为每个智能体启动一个Docker容器,将仓库挂载到 /upstream。每个智能体将本地副本克隆到 /workspace,完成后从自己的本地容器推送到 /upstream。

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

  • Claude通过在 current_tasks/ 目录下写入一个文本文件来对任务加"锁"(例如,一个智能体可能锁定 current_tasks/parse_if_statement.txt,而另一个锁定 current_tasks/codegen_function_definition.txt)。如果两个智能体尝试认领同一个任务,git的同步机制会强制第二个智能体选择其他任务。
  • Claude完成任务后,从上游拉取代码,合并其他智能体的更改,推送自己的更改,然后移除锁。合并冲突很常见,但Claude足够聪明,能够自行解决。
  • 无限的智能体生成循环在新容器中生成新的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%的随机样本。这个子样本对每个智能体是确定性的,但在不同虚拟机之间是随机的,因此Claude仍然覆盖所有文件,但每个智能体都能完美识别回归问题。

使并行化变得简单

当有许多不同的失败测试时,并行化很简单:每个智能体选择一个不同的失败测试来处理。当测试套件达到99%通过率后,每个智能体负责让一个不同的小型开源项目(如SQLite、Redis、libjpeg、QuickJS、Lua)成功编译。

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

解决方案是使用 GCC 作为在线的已知可用编译器来进行对比。我编写了一个新的测试框架,随机使用GCC编译内核的大部分文件,只用Claude的C编译器编译剩余的文件。如果内核正常工作,则说明问题不在Claude负责的文件子集中。如果出错了,可以进一步细化,将其中一些文件重新用GCC编译。这让每个智能体能够并行工作,修复不同文件中的不同bug,直到Claude的编译器最终能够编译所有文件。(在此方案奏效后,仍然需要应用增量调试技术来找到成对失败但单独工作的文件。)

多智能体角色

并行化还支持专业化分工。LLM编写的代码经常重复实现已有功能,因此我分配了一个智能体负责合并它发现的任何重复代码。我让另一个智能体负责提高编译器本身的性能,第三个负责输出高效的编译代码。我还让一个智能体从Rust开发者的角度评审项目设计,并进行结构性修改以提高整体代码质量,另一个负责文档工作。

压力测试智能体团队的极限

这个项目被设计为一个能力基准测试。我对压力测试LLM今天"勉强能够"达到的极限感兴趣,以帮助我们为模型未来能够可靠实现的目标做准备。

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

之前的Opus 4模型勉强能够产生一个功能性的编译器。Opus 4.5是第一个跨越门槛的版本,能够产生一个能通过大型测试套件的功能性编译器,但它仍然无法编译任何真实的大型项目。我使用Opus 4.6的目标是再次测试极限。

评估

在近2000次Claode Code会话、跨越两周的时间里,Opus 4.6消耗了20亿个输入token和1.4亿个输出token,总成本略低于20000美元。即使与最昂贵的Claude Max计划相比,这也是一个极其昂贵的项目。但这个总数只是我自己完成这项工作所需成本的一小部分——更不用说一个完整的团队了。

这是一个洁净室实现(Claude在开发过程中任何时间点都没有互联网访问权限);它仅依赖Rust标准库。这个10万行的编译器能够在x86、ARM和RISC-V上构建可引导的Linux 6.9。它还能编译QEMU、FFmpeg、SQLite、PostgreSQL、Redis,并且在大多数编译器测试套件上(包括 GCC 压力测试套件)达到99%的通过率。它还通过了开发者的终极检验:它能编译并运行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强制执行的32KB代码限制。因此,Claude在这里干脆作弊,调用GCC来完成这个阶段(这只针对x86。对于ARM或RISC-V,Claude的编译器可以完全独立编译。)

编译器的源代码已经公开。下载它,阅读代码,并在你喜欢的C项目上试试。我一贯发现,理解语言模型能力的最好方法是将它们推向极限,然后研究它们在哪里开始崩溃。在接下来的日子里,如果你想关注Claude持续解决这些限制的尝试,我会继续让Claude推送新的更改。

展望

每一代语言模型都开启了与之协作的新方式。早期模型在IDE中用于补全。不久之后,模型可以从函数文档字符串完成函数体。Claude Code的发布将智能体带入主流,使开发者能够与Claude结对编程。但这些产品的运作前提都是:用户定义任务,LLM运行几秒或几分钟后返回答案,然后用户提供后续指令。

智能体团队展示了自主实施完整复杂项目的可能性。这使我们作为这些工具的使用者,能够设定更具雄心的目标。

我们仍处于早期阶段,完全自主开发伴随着真正的风险。当人类在开发过程中与Claude协同工作时,他们可以确保一致的质量并实时捕获错误。对于自主系统,很容易看到测试通过就认为任务完成了,但事实很少如此。我曾经从事渗透测试工作,利用大型公司生产的产品中的漏洞,想到程序员部署他们从未亲自验证过的软件,这确实令人担忧。

因此,虽然这个实验让我兴奋,但也让我感到不安。构建这个编译器是我最近最有乐趣的经历之一,但我没想到在2026年这么早就能实现这一切。语言模型及其交互框架的快速进步,为编写大量新代码打开了大门。我预计正面应用将超过负面影响,但我们正在进入一个新世界,需要新的策略来安全地航行。

致谢

特别感谢Josef Bacik、Edwin Chen、Bernardo Meurer Costa、Jake Eaton、Dan Kelley、Felix Klock、Jannet Park、Steve Weis以及Anthropic许多其他同事的帮助和贡献。

Written by Nicholas Carlini, a researcher on our Safeguards team. I've been experimenting with a new approach to supervising language models that we’re calling "agent teams." With agent teams, multiple Claude instances work in parallel on a shared codebase without active human intervention. This approach dramatically expands the scope of what's achievable with LLM agents. To stress test it, I tasked 16 agents with writing a Rust-based C compiler, from scratch, capable of compiling the Linux kernel. Over nearly 2,000 Claude Code sessions and $20,000 in API costs, the agent team produced a 100,000-line compiler that can build Linux 6.9 on x86, ARM, and RISC-V. The compiler is an interesting artifacton its own, but I focus here on what I learned about designing harnesses for long-running autonomous agent teams: how to write tests that keep agents on track without human oversight, how to structure work so multiple agents can make progress in parallel, and where this approach hits its ceiling.

Enabling long-running Claudes

Existing agent scaffolds like Claude Code require an operator to be online and available to work jointly. If you ask for a solution to a long and complex problem, the model may solve part of it, but eventually it will stop and wait for continued input—a question, a status update, or a request for clarification. To elicit sustained, autonomous progress, I built a harness that sticks Claude in a simple loop (if you’ve seen Ralph-loop, this should look familiar). When it finishes one task, it immediately picks up the next.(Run this in a container, not your actual machine).

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

#!/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 In the agent prompt, I tell Claude what problem to solve and ask it to approach the problem by breaking it into small pieces, tracking what it’s working on, figuring out what to work on next, and to effectively keep going until it’s perfect. (On this last point, Claude has no choice. The loop runs forever—although in one instance, I did see Claudepkill -9 bashon accident, thus killing itself and ending the loop. Whoops!). pkill -9 bash

Running Claude in parallel

Running multiple instances in parallel can address two weaknesses of a single-agent harness:

  • One Claude Code session can only do one thing at a time. Especially as the scope of a project expands, debugging multiple issues in parallel is far more efficient.
  • Running multiple Claude agents allows for specialization. While a few agents are tasked to solve the actual problem at hand, other specialized agents can be invoked to (for example) maintain documentation, keep an eye on code quality, or solve specialized sub-tasks.

My implementation of parallel Claude is bare-bones. A new bare git repo is created, and for each agent, a Docker container is spun up with the repo mounted to/upstream. Each agent clones a local copy to/workspace, and when it's done, pushes from its own local container to upstream. /upstream /workspace To prevent two agents from trying to solve the same problem at the same time, the harness uses a simple synchronization algorithm:

  • Claude takes a "lock" on a task by writing a text file to current_tasks/ (e.g., one agent might lock current_tasks/parse_if_statement.txt, while another locks current_tasks/codegen_function_definition.txt). If two agents try to claim the same task, git's synchronization forces the second agent to pick a different one.
  • Claude works on the task, then pulls from upstream, merges changes from other agents, pushes its changes, and removes the lock. Merge conflicts are frequent, but Claude is smart enough to figure that out.
  • The infinite agent-generation-loop spawns a new Claude Code session in a fresh container, and the cycle repeats.

This is a very early research prototype. I haven’t yet implemented any other method for communication between agents, nor do I enforce any process for managing high-level goals. I don’t use an orchestration agent. Instead, I leave it up to each Claude agent to decide how to act. In most cases, Claude picks up the “next most obvious” problem. When stuck on a bug, Claude will often maintain a running doc of failed approaches and remaining tasks. In thegit repositoryof the project, you can read through the history and watch it take out locks on various tasks.

Lessons from programming with Claude agent teams

The scaffolding runs Claude in a loop, but that loop is only useful if Claude can tell how to make progress. Most of my effort went into designing the environment around Claude—the tests, the environment, the feedback—so that it could orient itself without me. These are the approaches I’ve found most helpful when orchestrating multiple Claude instances.

Write extremely high-quality tests

Claude will work autonomously to solve whatever problem I give it. So it’s important that the task verifier is nearly perfect, otherwise Claude will solve the wrong problem. Improving the testing harness required finding high-quality compiler test suites, writing verifiers and build scripts for open-source software packages, and watching for mistakes Claude was making, then designing new tests as I identified those failure modes. For example, near the end of the project, Claude started to frequently break existing functionality each time it implemented a new feature. To address this, I built a continuous integration pipeline and implemented stricter enforcement that allowed Claude to better test its work so that new commits can’t break existing code.

Put yourself in Claude’s shoes

I had to constantly remind myself that I was writing this test harness for Claude and not for myself, which meant rethinking many of my assumptions about how tests should communicate results. For example, each agent is dropped into a fresh container with no context and will spend significant time orienting itself, especially on large projects. Before we even reach the tests, to help Claude help itself, I included instructions to maintain extensive READMEs and progress files that should be updated frequently with the current status. I also kept in mind the fact that language models have inherent limitations, which, in this case, needed to be designed around. These include:

  • Context window pollution:The test harness should not print thousands of useless bytes. At most, it should print a few lines of output and log all important information to a file so Claude can find it when needed. Logfiles should be easy to process automatically: if there are errors, Claude should write ERROR and put the reason on the same line so grep will find it. It helps to pre-compute aggregate summary statistics so Claude doesn't have to recompute them.
  • Time blindness:Claude can't tell time and, left alone, will happily spend hours running tests instead of making progress. The harness prints incremental progress infrequently (to avoid polluting context) and includes a default--fastoption that runs a 1% or 10% random sample. This subsample is deterministic per-agent but random across VMs, so Claude still covers all files but each agent can perfectly identify regressions.

--fast

Make parallelism easy

When there are many distinct failing tests, parallelization is trivial: each agent picks a different failing test to work on. After the test suite reached a 99% pass rate, each agent worked on getting a different small open-source project (e.g., SQlite, Redis, libjpeg, MQuickJS, Lua) to compile. But when agents started to compile the Linux kernel, they got stuck. Unlike a test suite with hundreds of independent tests, compiling the Linux kernel is one giant task. Every agent would hit the same bug, fix that bug, and then overwrite each other's changes. Having 16 agents running didn't help because each was stuck solving the same task. The fix was to useGCCas an online known-good compiler oracle to compare against. I wrote a new test harness that randomly compiled most of the kernel using GCC, and only the remaining files with Claude's C Compiler. If the kernel worked, then the problem wasn’t in Claude’s subset of the files. If it broke, then it could further refine by re-compiling some of these files with GCC. This let each agent work in parallel, fixing different bugs in different files, until Claude's compiler could eventually compile all files. (After this worked, it was still necessary to apply delta debugging techniques to find pairs of files that failed together but worked independently.)

Multiple agent roles

Parallelism also enables specialization. LLM-written code frequently re-implements existing functionality, so I tasked one agent with coalescing any duplicate code it found. I put another in charge of improving the performance of the compiler itself, and a third I made responsible for outputting efficient compiled code. I asked another agent to critique the design of the project from the perspective of a Rust developer, and make structural changes to the project to improve the overall code quality, and another to work on documentation.

Stress testing the limits of agent teams

This project was designed as a capability benchmark. I am interested in stress-testing the limits of what LLMs can justbarelyachieve today in order to help us prepare for what models will reliably achieve in the future. I’ve been using the C Compiler project as a benchmark across the entire Claude 4 model series. As I did with prior projects, I started by drafting what I wanted: a from-scratch optimizing compiler with no dependencies, GCC-compatible, able to compile the Linux kernel, and designed to support multiple backends. While I specified some aspects of the design (e.g., that it should have an SSA IR to enable multiple optimization passes) I did not go into any detail on how to do so. Previous Opus 4 models were barely capable of producing a functional compiler. Opus 4.5 was the first to cross a threshold that allowed it to produce a functional compiler which could pass large test suites, but it was still incapable of compiling any real large projects. My goal with Opus 4.6 was to again test the limits.

Evaluation

Over nearly 2,000 Claude Code sessions across two weeks, Opus 4.6 consumed 2 billion input tokens and generated 140 million output tokens, a total cost just under $20,000. Compared to even the most expensive Claude Max plans, this was an extremely expensive project. But that total is a fraction of what it would cost me to produce this myself—let alone an entire team. This was a clean-room implementation (Claude did not have internet access at any point during its development); it depends only on the Rust standard library. The 100,000-line compiler can build a bootable Linux 6.9 on x86, ARM, and RISC-V. It can also compile QEMU, FFmpeg, SQlite, postgres, redis, and has a 99% pass rate on most compiler test suites including theGCC torture test suite. It also passes the developer's ultimate litmus test: it can compile and run Doom. The compiler, however, is not without limitations. These include:

  • It lacks the 16-bit x86 compiler that is necessary to boot Linux out of real mode. For this, it calls out to GCC (the x86_32 and x86_64 compilers are its own).
  • It does not have its own assembler and linker; these are the very last bits that Claude started automating and are still somewhat buggy. The demo video was produced with a GCC assembler and linker.
  • The compiler successfully builds many projects, but not all. It's not yet a drop-in replacement for a real compiler.
  • The generated code is not very efficient. Even with all optimizations enabled, it outputs less efficient code than GCC with all optimizationsdisabled.
  • The Rust code quality is reasonable, but is nowhere near the quality of what an expert Rust programmer might produce.

The resulting compiler has nearly reached the limits of Opus’s abilities. I tried (hard!) to fix several of the above limitations but wasn’t fully successful. New features and bugfixes frequently broke existing functionality. As one particularly challenging example, Opus was unable to implement a 16-bit x86 code generator needed to boot into 16-bit real mode. While the compiler can output correct 16-bit x86 via the 66/67 opcode prefixes, the resulting compiled output is over 60kb, far exceeding the 32k code limit enforced by Linux. Instead, Claude simply cheats here and calls out to GCC for this phase (This is only the case for x86. For ARM or RISC-V, Claude’s compiler can compile completely by itself.) Thesource code for the compiler is available. Download it, read through the code, and try it on your favorite C projects. I’ve consistently found the best way to understand what language models can do is to push them to their limits, and then study where they start to break down. Over the coming days, I’ll continue having Claude push new changes if you want to follow along with Claude’s continued attempts at addressing these limitations.

Looking forward

Each generation of language models opens up new ways of working with them. Early models were useful for tab-completion in IDEs. Before long, models could complete a function body from its docstring. The launch of Claude Code brought agents into the mainstream and enabled developers to pair-program with Claude. But each of these products operates under the assumption that a user defines a task, an LLM runs for a few seconds or minutes and returns an answer, and then the user provides a follow-up. Agent teams show the possibility of implementing entire, complex projects autonomously. This allows us, as users of these tools, to become more ambitious with our goals. We are still early, and fully autonomous development comes with real risks. When a human sits with Claude during development, they can ensure consistent quality and catch errors in real time. For autonomous systems, it is easy to see tests pass and assume the job is done, when this is rarely the case. I used to work in penetration testing, exploiting vulnerabilities in products produced by large companies, and the thought of programmers deploying software they’ve never personally verified is a real concern. So, while this experiment excites me, it also leaves me feeling uneasy. Building this compiler has been some of the most fun I’ve had recently, but I did not expect this to be anywhere near possible so early in 2026. The rapid progress in both language models and the scaffolds we use to interact with them opens the door to writing an enormous amount of new code. I expect the positive applications to outweigh the negative, but we’re entering a new world which will require new strategies to navigate safely.

Acknowledgements

Special thanks to Josef Bacik, Edwin Chen, Bernardo Meurer Costa, Jake Eaton, Dan Kelley, Felix Klock, Jannet Park, Steve Weis, and many other people across Anthropic for their assistance and contributions.