史上最高调的AI重写:Claude花11天搞定Bun,创始人花一个月才敢交底
2026 年 5 月,Bun 项目完成了一次在软件开发史上近乎罕见的大规模代码迁移。
这次迁移从 5 月 3 日启动,到 5 月 14 日正式合并入主分支,只用了 11 天。写代码只用了 6 天,并且整个过程公开。但 Jarred Sumner 写博客总结却花了快一个月,比写代码的时间长多了。
这个 JavaScript 运行时原本拥有 535,496 行 Zig 代码,不包括注释;同时,约 20% 的代码由 C++ 编写,并嵌入了多个 C/C++ 库。此次借助 AI 重写为 Rust,整个过程涉及超过 100 万行代码变更、6778 次提交,并在 Claude Code 中运行了大约 50 个动态工作流(dynamic workflows)。
根据 Sumner 披露的数据,这次重写在 API 层面消耗了 59 亿个未缓存输入 token、6.9 亿个输出 token,以及 720 亿个缓存输入 token 读取,按 API 定价计算约花费 16.5 万美元。
Sumner 说,这是目前技术所能达到的前沿水平。他估计,如果让 3 名完全熟悉 Bun 代码库的工程师手工完成这次迁移,大约需要一年时间,而且在这一年里,团队几乎无法继续推进新功能开发、bug 修复和安全修复。
这次重写之后,Bun v1.3.14 成为最后一个 Zig 版本,Bun v1.4.0 将成为第一个 Rust 版本。
1 成果:从 6.7GB 内存泄漏到 609MB 稳定
Bun 最初是一个 Zig 项目,覆盖面非常广:它既是 JavaScript 和 TypeScript 转译器,也是打包器、包管理器、测试运行器、模块解析器、HTTP 和 WebSocket 客户端,还实现了 Node.js API 层。正是这样的产品宽度,让 Bun 的 CLI 月下载量超过 2200 万次,并获得了 Vercel、Railway、DigitalOcean、Claude Code 和 OpenCode 等项目或公司的支持。
但同样是这种宽度,也给 Bun 带来了一些挑战。
特别是在 Bun v1.3.14 中,有一个让大家头疼已久的问题:连续执行 Bun.build() 调用时,内存会不断累积,永不释放。每次构建大约泄漏 3MB,看起来不多,但如果你运行的是一个开发服务器,每次请求都触发一次构建,那么内存就会被一点点吞噬,直到进程崩溃。
在实际测试里,执行 500 次构建后内存占用 1.9GB,1000 次后 3.5GB,1500 次后 5.1GB,2000 次后飙升到 6.7GB。
这只是诸多内存问题的冰山一角。在 v1.3.14 的 bug 修复清单中,Sumner 列出了一长串问题:
zlib 模块里调用.reset() 时,如果还有一个异步.write() 正在线程池中执行,进程就会因为"堆释放后使用"而崩溃;http2 模块里嵌套的 JavaScript 回调触发了哈希表重哈希,导致内部流指针失效;UDPSocket.sendMany() 在遍历过程中,如果用户代码通过 valueOf 或 toString 回调改变了套接字的连接状态,就会发生越界写入;crypto.scrypt 在输出缓冲区分配失败时,回调和受保护的密码缓冲区永远得不到释放;......
这些 bug 的共性非常明显——它们几乎都指向同一个根源:将 GC 与手动内存管理在同一个软件里混合使用。
JavaScriptCore(以及 V8)这样的现代引擎对异常处理和 GC 有极其严格的规则,而 Zig 像 C 语言一样不会自动管理内存。当这两种范式在同一个进程中,每个内存分配都需要被逐行审查:这些字节在哪里被释放?怎么确保只释放一次?是否正确检查了 JavaScript 异常?这个被 GC 管理的指针对保守栈扫描器可见吗?这是 GC 内存还是手动管理的内存?
更令人焦虑的是,团队并非没有努力。他们已经给 Zig 编译器进行了修改,加了 Address Sanitizer 支持(ASAN),每次提交都在 CI 中运行 ASAN 测试,在 Windows 上使用 ReleaseSafe 构建,用 Fuzzilli 做 24/7 的模糊测试,还有大量端到端的内存泄漏测试。即便如此,崩溃报告仍然源源不断。
“我们的 bug 修复列表让人感觉很糟糕,我厌倦了带着对 Bun 崩溃的担忧去睡觉。”Sumner 写道。他并不责怪 Zig——其他 Zig 用户并没有遇到 Bun 这样的问题,因为将 GC 与手动管理内存混合使用,本身就是一种极罕见的需求,几乎没有语言为此设计。
而 Rust 版本交出的答卷是:同样执行 2000 次 Bun.build(),内存稳定在 609MB。
除了内存泄漏问题得到根本性解决,Rust 重写还带来了其他几个维度的改善。
在稳定性方面,v1.4.0 修复了 v1.3.14 中可复现的 128 个 bug,从内存泄漏到崩溃到颜色显示错误的帮助文本都得到了解决。
从体积上,结合 Rust 重写、ICU 更改和相同的代码折叠,Bun 在 Linux 和 Windows 上的二进制文件大小减少了约 20% 。
在性能方面,普遍提升了 2% 到 5%。Bun.serve 从 16.96 万 req/s 提升到 17.77 万 req/s,node:http 从 10.38 万提升到 10.85 万。实际应用场景中,next build 从 13.62 秒降至 13.03 秒,tsc 批量编译从 0.94 秒降至 0.89 秒。
而 Claude Code 在基于 Rust Bun 发布后,Linux 上的启动时间从 517ms 降至 464ms,快了约 10%。
2 方法:64 个 Claude,11 天,50 个工作流
Sumner 是怎么做到的,这可能是最值得关注的部分——因为他用的方法,和传统的“让 AI 写代码”不同。
Sumner 把整个过程拆成了大约 50 个动态工作流,每个工作流都是一个循环。他在博客里用伪代码描述了这个模式:
每个任务都有一个上下文(比如一个 Jira ticket 或 GitHub issue),Claude 基于这个上下文写出代码,然后两个审查者(也是 Claude)审查代码,最后应用反馈。完成之后,再取下一条任务。
这种模式贯穿了整个重写过程。每个工作流负责一个特定目标:
- 生成一份 porting guide,把 Zig 的模式和类型映射到 Rust 的模式和类型;
- 把每个 .zig 文件机械式移植成一个 .rs 文件,并匹配 PORTING.md 和 LIFETIMES.tsv;
- 修复每个 crate 的编译错误;
- 让 bun test 或 bun build 这样的 subcommand 跑起来;
- 让 Bun 整个测试套件里的每个测试都通过;做几轮大型重构和清理。
峰值时期,Sumner 同时运行了 4 个工作流,每个工作流里 16 个 Claude,总共 64 个 Claude 同时在 4 个工作树中并行工作,各自提交和推送文件。在最高峰时,Claude 每分钟写了约 1300 行代码。
这种“实现者 / 审查者”的分离设计是关键。写代码的 Claude 想让代码被接受,这和人类工程师一样有偏见。所以审查者和实现者完全分开——审查者只看代码差异,不看实现者的推理过程,而且被明确告知“假设代码是错的”。每个实现者对应两个以上的对抗性审查者,审查者的唯一工作就是找 bug。
代码写完只是第一步。Zig 代码是单一编译单元,而 Rust 要拆分成约 100 个 crate 来加快编译速度,循环依赖导致了 cargo check 一次性输出约 16000 个编译错误。对于一个人来说这是灾难,但对于 64 个并行工作的 Claude 来说,这是可以处理的工作队列。工作流把错误按 crate 分组,每个 crate 跑一遍 cargo check,一个 Claude 修复,两个审查,一个应用修改。
接下来是让 bun --version 跑起来,然后是 bun test。测试工作流每次随机跑 100 个测试文件,分片到 4 个工作树。测试套件也包含好几种:有些测试会运行超过一分钟,有些会耗尽系统 TCP 连接数,有些会 fork 约 10000 个进程。Sumner 用 systemd-run 创建 cgroup 来限制资源,但机器还是因为磁盘空间不足崩溃了好几次。
两天后,Linux 平台的失败测试从 972 个降到了 23 个。一天半之后,Linux 全绿了。五天后,全部六个平台——Linux x64、Linux arm64、macOS x64、macOS arm64、Windows x64、Windows arm64——全部通过。
5 月 14 日,PR #30412 正式合并,测试套件全部通过,没有跳过或删除任何测试。
3 隐忧:13,000 个 unsafe 和无法逐行审查的代码
不过,Sumner 也承认,这项工作还没有真正结束。
截至目前,Bun 的 Rust 代码中大约有 4% 位于 unsafe block 内,约 13,000 个 unsafe 关键字,分布在约 27,000 行代码中,而 Rust 总代码量约为 780,000 行。其中 78% 的 unsafe block 只有一行,通常是一个来自 C++ 的指针,或者一次对 C 库的调用。
他预计后续重构会让这个比例降下来。但有人算了一笔账:uv 约 35 万行代码,只有 73 次 unsafe 调用。而 Bun 的 unsafe 数量是 uv 的 178 倍。这个差距很难用“需要调用 C 库”来解释。
并且随后还在安全 Rust 代码中也暴露了未定义行为。这比 C++ 还难调试,因为你会以为安全代码不可能出问题。
Bun 团队随后把这个问题中的 PathString::init 改成了 unsafe fn。
Sumner 自己也承认,这次重写引入了 19 个已知的回归问题,并表示大多数回归问题都源于语法相同但语义不同的代码。
比如这两个代码片段看起来很相似,但行为却截然不同。Zig 的代码 assert 是一个函数,因此它的参数在每次构建中都会运行。Rust 的代码 debug_assert! 是一个宏,因此在发布版本中,整个表达式(包括函数调用)都会被删除 insert_stale。
虽然已经问题都修了,但这并不表示百万行 AI 代码就没有其他问题。
正常人谁会在一个运行时被彻底重写之后,立刻把自己的生产应用迁过去?如果以为 1.4 版本没有引入新的 bug,或者没有带来行为变化,那就太天真了。
还有一个不能忽略的事情是代码审查。100 万行的变更实际上没法由人类逐行看——就算一分钟看一行,也要连续看 11.7 天;按实际的代码审查速度(一小时 200 行),要两年多才能看完。
这次 PR 的审查者主要是 claude[bot] 和 coderabbitai[bot]。Sumner 自己也承认,他的审查方式是“检查对抗性审查 agent 是否正确捕获了差异,确保转换指南被遵守,同时自己也手动读了不少代码”。但“不少”是多少,他没说。
还有一个绕不开的问题:Bun 在 2025 年 12 月被 Anthropic 收购了,真正能有效维护这套代码库的工具,基本只有 Claude 自己。社区里有人说,这已经算不上传统意义上的开源项目了——你想给 Bun 提 PR,得先订阅 Anthropic,或者指望那几个已经看懂了 AI 生成代码的核心成员。
16.5 万美元换一年工作量,值吗?
Sumner 在博客中还披露,这次重写的 API 成本约为 16.5 万美元,等于 3 名工程师一年的工作量。这个数字在 Hacker News 上引发了激烈的讨论。
有人认为,这笔账其实很划算。16.5 万美元在硅谷请不了几个全职工程师,更不用说 Anthropic 这种级别公司的工程师了。按照 levels.fyi 上的薪资数据,Anthropic 工程师的总包很可能达到 50 万美元甚至更高。即便按 50 名工程师平均年薪 33.6 万美元粗略计算,折合到每天大约是 1292 美元。50 个人连续工作 11 天,光人力成本就已经接近 71 万美元,还不包括福利、办公场地、设备和其他管理开销。
但是,Sumner 用的是“Claude Fable 5 的预发布版本”,一个尚未对公众开放、可能受出口管制的高阶模型。所以 API 定价只是最终用户看到的数字,背后是 Anthropic 投入的巨额研发费用。还有人指出,把成本简化成 API 定价,是在刻意淡化真实投入。如果算上模型研发成本、训练成本、算力投入、工程人力等,相信最终的总成本肯定很高,很可能超过 150 万美元。
而且目前看来,虽然 16.5 万美元换一年工作量,账面上看挺划算。
但真正的成本不在这张账单上。这个代码库有 6778 次提交,没有一个人从头到尾完整读过,虽然眼下一切正常,可六个月后呢?当某个诡异的并发问题在凌晨三点突然冒出来,负责值班的工程师面对的是一个连他自己都说不清内部逻辑的系统。延伸到以后都得 AI 来维护,维护成本怎么算,其实挺难。
参考链接:
https://bun.com/blog/bun-in-rust
https://hn.edgecompute.app/item/48837877
本文来自微信公众号 “InfoQ”(ID:infoqchina),作者:Tina,36氪经授权发布。















