Anthropic 的 Claude Code 迁移在两周内将 Bun 从 Zig 转向 Rust,但速度并非最难的部分
- Aisha Washington

- 7月17日
- 讀畢需時 14 分鐘
已更新:7月20日
Anthropic 使用 Claude Code 将 Bun 从 Zig 迁移到 Rust,在不到两周内生成了约一百万行代码。Anthropic 的 Claude Code 迁移在合并前通过了 Bun 现有的持续集成测试。然而,合并后的代码库中仍然出现了 19 个回归问题。
这种反差比单纯的产出量更值得关注。Claude Code 生成代码的速度是任何传统工程团队都无法匹敌的。然而,只有在人类制定严格规则、设置独立审查者、建立机械化工作队列并采用与语言无关的测试后,项目才得以成功。
因此,真正的较量并非 AI 智能体对阵人类程序员,而是自动化代码生成对阵自动化验证。Anthropic 的结果表明,代码生成正变得廉价且充裕,而可信的验收机制仍是限制工程效率的核心问题。
Bun 联合创始人 Jarred Sumner 在 Bun 于 2025 年 12 月加入 Anthropic 后主持了此次迁移。他使用了一个预发布版 Claude 模型,并在 11 天内运行了约 50 个动态工作流。Anthropic 后来将这项工作中总结的经验转化为一套通用迁移流程。
这一结果挑战了软件工程领域最古老的警告之一:应尽可能避免彻底重写。这个警告依然有其道理,但支撑它的成本模型已经发生了变化。
Anthropic 的 Claude Code 迁移以机器规模重写了 Bun
Anthropic 将一个过去需要以工程师年计量的项目压缩为 11 天的智能体工作流,同时不必让 Bun 的正常开发停滞一年。
Bun 是一个 JavaScript 和 TypeScript 运行时,同时还包含包管理器、测试运行器、打包器以及 Node.js API 兼容层。其广泛的功能范围使语言迁移变得异常困难。
根据 Sumner 的 Rust 重写记录,迁移前 Bun 包含 535,496 行不含注释的 Zig 代码。该项目还依赖 C 和 C++ 组件,包括 JavaScriptCore、SQLite、BoringSSL 以及多个网络库。
传统重写会产生两个不断变化的目标。工程师既要复现现有行为,又要应对生产环境中的 Zig 版本持续接收修复和新功能。
Sumner 估计,一个小型团队大约需要一年时间。这样的时间表要么会延误产品开发,要么会迫使开发者同时维护两套实现。
Sumner 转而选择了保留结构的移植方式。Claude 会将现有设计迁移到 Rust,同时尽可能减少行为变化。待兼容性确立后,再进行架构清理。
这一区别非常重要。Claude Code 并不是根据产品规格从头发明一个新运行时,而是将 Zig 实现用作可执行参考,并将 Bun 的 TypeScript 测试套件用作外部裁判。
Sumner 首先花了约三个小时与 Claude 共同编写移植指南。最终形成的文档将 Zig 类型、所有权模式和常见惯用法映射到对应的 Rust 写法。
另一个独立工作流分析结构体字段,并为 Rust 生命周期提出建议。生命周期描述引用保持有效的时长,使 Rust 编译器能够拒绝许多不安全的内存关系。
这些决策成为共享资料,而非智能体内部私有的推理结果。每个迁移工作智能体都可以参考相同规则,审查者则可以标记偏离规则的情况。
随后,Sumner 在三个文件上测试了这种方法。每个文件由一个智能体迁移,两个相互隔离的智能体负责审查,另一个智能体则应用被接受的修复。
试点在迁移模式扩散到 1,448 个 Zig 文件之前暴露了其中的问题。Sumner 丢弃了试验产出,因为目标是改进流程,而非保留早期代码。
规则稳定后,四个工作流分片各自运行 16 个 Claude 实例。在产出峰值时,该系统据称每分钟生成约 1,300 行代码。
原始迁移结果仍然无法运行。承认这一点对于理解该项目至关重要。
Claude 的首要任务是创建一个完整的候选实现。随后,编译器、测试和对抗性审查者将该候选实现转化为可运行的软件。
整个过程产生了 6,502 次提交。在某个阶段,Rust 编译器报告了约 16,000 个错误。Anthropic 将这些失败视为待处理队列,而不是实验失败的证据。
修复编译问题暴露了两种语言之间更深层次的不兼容。Zig 的惰性编译容忍了一些循环导入,而 Rust 的模块系统则拒绝这些导入。
智能体对这些错误进行分类并修改迁移规则,随后系统性地重新生成或修复受影响的单元。
根据 Anthropic 的迁移记录,在代码合并前,Bun 完整的现有测试套件已在持续集成中通过。Rust 移植版本于 2026 年 6 月随 Claude Code 一同发布。
合并后出现了 19 个回归问题。Anthropic 表示,这 19 个问题现已全部修复。
这些回归问题使我们无法简单地将其描述为一场胜利。通过大型测试套件并不能证明行为完全一致,而是提供了足够的信心,使团队能够发布、监控生产环境并修复遗漏的问题。
Bun 为什么愿意离开 Zig
Claude Code 降低了迁移门槛,而反复出现的内存缺陷则提供了跨过这道门槛的商业理由。
Sumner 一直谨慎地避免将 Bun 的稳定性问题归咎于 Zig。在编程模型尚未广泛普及之前,Zig 帮助他在一年内构建了 Bun 的第一个版本。
困难源于 Bun 特殊的工作负载。Bun 将 JavaScript 中由垃圾回收管理的对象与手动管理的原生内存以及多个 C 或 C++ 库连接在一起。
这一边界带来了棘手的所有权问题。工程师必须知道由谁释放每次内存分配、回调的生命周期是否超过原生句柄,以及垃圾回收管理的引用是否仍然可见。
Bun 已经使用了 AddressSanitizer、启用安全检查的构建、持续模糊测试和内存泄漏测试。然而,其发布说明中仍不断出现释放后使用、重复释放、内存泄漏和竞态条件等问题。
释放后使用是指软件在释放内存后仍继续访问它。重复释放则是对同一块已分配内存释放两次,可能导致进程损坏。
这些故障通常存在于罕见的时序路径中。只有当测试复现正确的回调顺序、异常路径或状态变化时,错误才会显现。
Rust 将部分负担转移到其类型系统中。它的所有权规则决定由哪个值控制内存,而借用检查器则在编译期间拒绝冲突或无效的引用。
Rust 的 Drop 机制还会在值离开作用域时执行清理。这减少了在每个相关调用位置都要记得添加清理语句的依赖。
这门语言并不能消除所有内存风险。Bun 仍然需要与原生库和 JavaScriptCore 交互,因此有些操作无法完全纳入安全 Rust 的范围。
Anthropic 报告称,移植后的 Rust 代码中约有 4% 使用了 unsafe 块。Unsafe Rust 允许执行编译器无法完全验证的操作,将其正确性重新交由开发者和审查者负责。
尽管如此,Sumner 的观点并不是 Rust 能让 Bun 永远不会崩溃,而是 Rust 可以将更多缺陷提前暴露在反馈循环中。
编译器错误会在代码运行前出现。AddressSanitizer 和模糊测试需要实际执行代码,而生产遥测数据则要等用户遇到问题后才能获得。
这种先后顺序改变了预防问题的经济性。编译时被拒绝的成本通常低于跨平台诊断罕见运行时故障的成本。
Bun 表示,1.4 版本修复了 128 个可在 1.3.14 版本中复现的缺陷,其中包括内存泄漏、崩溃和较小的兼容性问题。
团队还报告称,在重复构建基准测试中,内存消耗有所降低。将同一构建运行 2,000 次时,移植前使用了 6,745 MB,移植后则使用了 609 MB。
Anthropic 表示,新二进制文件在 Linux 和 Windows 上缩小了 19%。它还报告称,在 HTTP 服务和部分真实工作负载中,性能提升了 2% 至 5%。
这些数据来自 Anthropic 和 Bun,而非独立基准测试。应将其视为现已可供外部用户检验的项目结果。
性能提升也并非最初的承诺。首要目标是在不暂停 Bun 产品路线图的情况下,降低反复出现的稳定性风险。
因此,这次移植的意义远不止展示 AI 的速度。它将一项可量化的工程负担,与一种能够通过机械方式捕获更多所有权错误的目标语言联系起来。
Claude Code 提供了工作能力,Rust 则提供了更严格的裁判。
真正的突破是验证循环,而非代码生成
项目之所以能够成功,是因为每次失败都会转化为结构化输入,并进入系统中的下一轮受控处理。
大型语言模型可以生成看似可信、能够编译但依然错误的代码。Bun 的迁移直接展示了这一问题。
一个迁移后的函数将原生指针传给异步关闭操作。随后 Rust 过早地丢弃了拥有该指针的 box,使原生库最终持有已释放的内存。
另一个迁移结果错误地表示了 1970 年之前的时间戳。第三个结果则会立即求值一个备用表达式,并可能在处理有效的 CSS 颜色函数时发生 panic。
据称,这三个例子都能通过编译。其表面上的合理性使普通的目视审查变得不可靠,尤其是在包含一百万行代码的变更中。
Sumner 将代码编写与审查分离。每个实现智能体都会收到原始 Zig 文件、移植规则以及各自独立的工作上下文。
审查智能体则在独立上下文中收到最终差异。它们被要求假定代码存在错误,并寻找某个具体故障。
这种分离旨在防止智能体为自己先前的推理辩护。每个单元由两名审查者检查,另一个智能体则负责处理分歧或执行修复。
Anthropic 将其称为对抗性审查。它并不能证明代码正确,因为审查者可能存在共同盲点,也可能对同一行为产生相同误解。
它的价值来自角色分离和重复执行。审查者拥有一个可衡量的目标,而实现智能体则拥有另一个目标。
这些工作流也避免了不加选择地使用编译器。在每个并行任务中运行完整的 Rust 构建会造成资源争用并浪费算力。
迁移智能体只需根据规则手册写入文件。在分散任务全部完成后,由集中式编译阶段生成错误列表。
修复智能体按 crate 和模块拆分该列表。它们提交有针对性的修正,而编排脚本则控制何时再次运行完整构建。
编译完成后,测试也发挥了相同作用。每个失败的断言都会成为一个具体的队列项目,并与旧实现和新实现的行为关联。
当某个失败只出现一次时,智能体可以修复受影响的实现。当相同模式反复出现时,团队则会修改上游迁移规则。
这种方法遵循 Anthropic 的核心原则:修复生成代码的流程,而不仅仅是修复生成的代码本身。
一次性的补丁只能改进一个文件,而规则变更则可以纠正在同一错误假设下生成的所有文件。
Anthropic 发布了一套通用的迁移工具包,其中包含提示词、模板、队列脚本和安全设置。该工具包首先进行可行性评估,而放弃迁移也被视为可接受的结果。
它的六个阶段涵盖映射、规则创建、压力测试、翻译、编译、执行和行为对比。每个关卡都要求满足一个机械式退出条件。
这种方法更像一条生产线,而非对话式编程。代理各司其职,共享制品承载策略,自动化检查则会拒绝有缺陷的输出。
这种模式也解释了 Anthropic 为何认为迁移尤其适合 AI 代理。
首先,源代码本身已经描述了大部分预期行为。代理无需从不完整的需求中推断出一个全新的产品。
其次,一旦依赖关系完成映射,许多文件便可以独立翻译。这使并行工作成为可能,而不必强迫每个代理理解整个代码仓库。
第三,编译器和测试可以提供客观反馈。代理能够反复执行循环,而无需让人工判断每一个局部决策。
第四,失败会形成自己的待办事项。编译器错误、崩溃或输出差异都会明确指出下一项任务。
Anthropic 的动态工作流将这一模型扩展到了静态子代理列表之外。Claude 可以编写编排脚本、启动并行工作代理、检查其结果,并修订工作流。
这种自主性提高了吞吐量上限,也让权限、隔离和可恢复状态变得更加重要。
Sumner 很早就遇到了其中的风险。并行代理开始执行相互冲突的 Git 操作,包括可能覆盖彼此工作的命令。
他随后修改了工作流,禁止使用宽泛的 Git 命令。代理可以提交特定文件,而编排器负责维护更大范围的迁移状态。
这一事件比精心打磨的演示更具启发性。代理的失败并不总是表现为错误代码,也可能破坏协作、代码仓库状态,或审计一次运行所需的证据。
因此,工程优势来自受约束的自主性。系统之所以能够完成更多工作,是因为其运行边界得到了明确界定。
通过所有测试后仍然出现了 19 个回归问题
Bun 合并后的缺陷表明,测试全部通过只是发布门槛,而不是实现等价性的数学保证。
Anthropic 的核心成果听起来十分明确:合并前,Bun 现有测试套件的通过率达到了 100%。但后来出现的 19 个回归问题揭示了这一百分比无法衡量的部分。
测试套件覆盖的是作者预见并编码的行为。它不会自动涵盖每一种环境、时序、集成方式或用户工作负载。
语言迁移还会改变一些隐藏属性。即使可见输出一致,内存分配时机、析构顺序、线程调度和外部函数边界也可能不同。
Bun 得益于一个格外有利的设计选择。其主要测试套件使用 TypeScript 而非 Zig 编写,因此可以通过相同的外部接口测试任一运行时。
许多遗留系统并不具备这种独立性。它们的测试会调用私有函数、检查内部数据结构,或依赖特定语言的模拟行为。
将这类测试迁移到新语言中,可能会复刻实现,而不是保留原始契约。错误的迁移随后可能与错误的测试相互吻合。
Anthropic 建议将测试分为可移植测试和依赖具体实现的测试。团队应针对两个版本运行可移植测试,并确认有意破坏的构建确实会测试失败。
最后这一步至关重要。一个永远通过的测试比没有测试更糟糕,因为它会制造虚假的信心。
据报道,在一次内部 Python 到 TypeScript 的迁移中,Anthropic Labs 联合负责人 Mike Krieger 没有完整的可移植测试套件。他的团队围绕七个真实场景构建了一套一致性验证框架。
该框架分别在原始 Python 版本和替代的 TypeScript 版本上运行命令,然后对比输出。任何行为差异都会被视为缺陷。
Krieger 的迁移在一个周末内生成了 165,000 行 TypeScript。Anthropic 表示,该项目使用了数百个代理、八个阶段关卡以及三轮对抗性审查。
团队还放弃了两次完整尝试。每次运行都会暴露工作流中的弱点,使下一次尝试能够改进规则和验证流程。
第三次运行时,迁移版本通过了一致性检查。随后,Claude 又生成了额外的端到端测试,并据报道连续四个夜晚修复测试失败。
这个案例进一步印证了 Bun 所揭示的同一条经验:当放弃一次糟糕的运行成本足够低时,快速生成才会真正有用。
传统重写会在数月间不断积累沉没成本。即使发现早期架构选择有误,团队也不愿重新开始。
代理式迁移可以在更改规则后重新生成大部分内容。分支可以被舍弃,而经过验证的流程则成为持久资产。
不过,重新生成并非没有成本。Anthropic 警告称,动态工作流消耗的 token 可能远高于普通 Claude Code 会话。
团队还需要经验丰富的工程师来设计验收标准、监控工作流、解释系统性故障,并判断行为变化是否可以接受。
Bun 中 4% 的不安全代码值得持续审视。在原生边界处,有时确实需要使用不安全代码块,但这些位置也正是 Rust 最强编译器保障失效的地方。
机械式迁移也可能保留历史遗留的复杂性。Sumner 有意选择了逐行迁移,因为重新设计架构会增加风险。
这一选择加速了行为一致性的实现,但并没有自动产出符合 Rust 惯用写法的代码。Bun 计划在发布 1.4 版本后减少不安全代码的使用,并重构实现。
在漫长的验证周期中,源版本和目标版本也可能产生分歧。两周的迁移可以限制这一问题,但活跃的代码仓库即使在这个时间窗口内也可能发生大量变化。
安全审查带来了另一项挑战。测试只能验证观察到的行为,而安全分析还必须考虑恶意输入和意外的状态组合。
因此,已公布的证据支持的结论比“Claude 可以重写任何代码库”更为有限。它证明了迁移适用于那些规格明确、工作可并行化且具有客观行为检查的项目。
对于需求缺乏文档、测试薄弱或依赖硬件时序的项目来说,迁移之路更加艰难。无论代理速度多快,补齐缺失的规格说明都会成为首要任务。
考虑开展类似工作的团队应首先改进评判系统。一个可搜索的技术决策集合可以帮助保留这些规则背后的上下文。
例如,一个工程知识库可以关联设计说明、迁移策略和测试证据。当数百个代理产生成千上万个提交时,这类记录尤其有用。
核心风险已不再只是 AI 编写糟糕代码,而是组织将高产出和测试全绿误认为已经实现了完整理解。
工程团队接下来应该关注什么
下一阶段将通过持续的生产质量、更低的不安全代码占比,以及在 Anthropic 异常有利的环境之外成功完成迁移来接受检验。
第一个信号是 Bun 在接下来几个版本中的生产表现。真正重要的数字不是生成的代码行数,也不是每小时的最高提交次数。
随着更多用户采用 Rust 构建版本,开发者应该关注回归问题数量、崩溃报告、内存缺陷和兼容性故障。
如果这些指标始终低于 Zig 基线,Anthropic 的论点就会更有说服力。如果新故障集中出现在迁移后的代码中,则说明合并前的验证流程还需要再次修订。
第二个信号是不安全 Rust 的占比和分布位置。如果报告中的 4% 能够进一步降低,就说明机械式迁移可以逐渐成熟为更符合惯用写法的实现。
位置与百分比同样重要。围绕经过审计的 C 接口设置少量不安全边界,与在核心运行时组件中分散使用不安全逻辑,二者带来的风险截然不同。
Bun 的公开代码仓库让外部 Rust 开发者有机会审查这些决策。独立基准测试和缺陷报告将提供超越 Anthropic 自身测量结果的证据。
第三个信号是其他组织能否复现这一方法。Bun 拥有独立的 TypeScript 测试套件、一位技术能力极强的创始人,并且可以直接使用 Anthropic 的最新模型。
更具说服力的广泛成果应来自这样的遗留系统:文档较弱、测试位于内部、存在多个负责人,并且需要满足监管或安全要求。
Anthropic 的第二个案例,即 Python 到 TypeScript 的迁移,在一定程度上朝这个方向迈进。不过,它仍然是由工具开发公司自己描述的内部项目。
该公司表示,在 7 月 16 日发布公告之前的一个月内,开发者迁移了十个软件包。这些项目的规模从数万行到数十万行不等。
更详细的案例研究应该披露团队放弃尝试的频率、投入的人工时长,以及哪些缺陷未能被自动化审查发现。
与之竞争的编码代理也将面临支持长期运行、可恢复工作流的压力。当有价值的任务横跨数千个相互依赖的单元时,单文件补全的重要性就会下降。
产品竞争将越来越聚焦于编排、权限、评估和恢复。模型智能依然必不可少,但它本身无法提供运行纪律。
工程负责人应避免将迁移视为一种自动化的现代化策略。Anthropic 自己的启动流程首先要问的,就是这次重写是否应该发生。
成功的迁移能够保留行为,但不能保证带来更好的架构、更清晰的产品需求或更低的运维复杂度。
最合适的候选项目具有明确的技术负担,以及能够解决该负担的目标平台。它们还拥有能够以相同标准评判两种实现的外部测试。
Bun 满足这些条件。手动内存管理导致了反复出现的稳定性维护工作,而 Rust 将更多所有权检查移入了编译阶段。
随后,Claude Code 让这项曾经不切实际的迁移变得足够迅速,可以在不暂停产品路线图的情况下进行尝试。正是这种组合,而非单纯的 AI 输出,造就了最终结果。
Anthropic Claude Code 的迁移改变了工程团队能够合理提出的问题。一次完整的语言迁移不再需要从一项持续数年的承诺开始。
它可以从一个具有明确关卡和可舍弃分支的有限实验开始。失败可以产出更好的规则,而不是留下一次被放弃的重写。
但举证责任并未消失。问题已经从“代理能否生成代码?”转变为“组织能否构建一个可靠拒绝错误代码的评判系统?”
这才是团队在启动数百个代理之前应该验证的问题。选择一个范围受限的组件,定义可观察的行为一致性,并有意破坏评判系统。
如果系统能够捕获这些故障,更大规模的迁移才具有可信度。如果不能,更快的代码生成只会以更大的规模制造不确定性。


