Anthropic 收购后 Bun 的 Rust 重写:每月 2200 万次下载让风险陡增
- Olivia Johnson

- 3小时前
- 讀畢需時 16 分鐘
在被 Anthropic 收购后,Bun 已完成 Rust 重写,将一个由 AI 生成的代码库置于每月超过 2200 万次 CLI 下载的基础之下。
这次变化远不只是一场常规的编程语言迁移。Bun 表示,Claude 协助将超过 50 万行 Zig 代码转换为约 100 万行 Rust 代码。高强度的移植过程仅耗时 11 天。
速度固然最吸引眼球,但可靠性才是真正的焦点。如今,Claude Code、OpenCode、Prisma Compute 以及众多期望基础设施稳定运行的开发者都依赖 Bun。这次重写提出了一个关键问题:编译器检查、自动化审查与庞大的测试套件,能否让 AI 生成的系统代码值得信赖?
这也带来了一种令人不安的反转。Zig 曾帮助一名开发者在一年内构建出 Bun 功能广泛的工具集,但同样是这种广度,后来引发了内存泄漏、释放后使用缺陷和维护压力,而 Bun 希望借助 Rust 缓解这些问题。
Anthropic 收购后,Bun 的 Rust 重写改变了风险格局
Bun 更换语言并不是为了贴上一个时髦标签,而是因为反复出现的内存故障已经成为运营负担。
Bun 集 JavaScript 运行时、包管理器、打包器、转译器、测试运行器以及众多 Node.js API 实现于一体。凭借这样的功能范围,开发者只需一个工具,就能完成通常需要多个软件包配合的工作。
但这也在 JavaScript 与原生代码之间制造了大量边界。JavaScript 使用垃圾回收机制,自动回收不再可访问的对象。Bun 的原生组件必须协调这些对象与由底层代码管理的内存。
这种协调长期以来都是错误频发的根源。Bun 创建者 Jarred Sumner 列举了近期涉及释放后使用崩溃、重复释放、越界访问、竞态条件和内存未释放的缺陷。
释放后使用是指软件在释放一块内存后仍对其进行访问,后果可能是程序崩溃、行为不可预测,甚至产生安全漏洞。
Bun v1.3.14 修复的问题遍及压缩流、HTTP/2 连接、UDP 套接字、缓冲区、密码学、TLS 会话、文件监视器和 CSS 解析器。这些并不是同一个孤立错误的不同表现。
有些故障发生在 JavaScript 回调意外改变原生状态时,另一些则源于清理代码没有执行、执行了两次,或在内存分配失败后仍继续执行。
Bun 已经采用了多种防御措施。其团队修改了 Zig 编译器,使其支持 AddressSanitizer——一种用于检测无效内存访问的运行时工具。该项目会针对每一次提交运行这些检查。
团队还持续使用 Fuzzilli。Fuzzilli 会生成非常规的 JavaScript 程序,以暴露常规测试可能遗漏的引擎和运行时故障。
这些系统只能在代码写完后发现缺陷,而 Sumner 希望采用一种能在编译阶段拒绝更多所有权错误的编程模型。
Rust 的所有权系统会追踪程序中的哪一部分控制着某个值,其借用检查器负责执行引用相关规则,而 Drop 会在值离开作用域时自动运行清理逻辑。
在安全 Rust 中,许多释放后使用和重复释放模式都会直接变成编译错误。这比模糊测试、持续集成或生产环境崩溃报告更早提供反馈。
因此,Bun 的 Rust 重写 改变了团队预期发现故障的环节。如今,一些错误应当能在二进制文件运行之前就阻止开发流程继续推进。
此次迁移发生在 Anthropic 于 2025 年 12 月 3 日收购 Bun 之后。Anthropic 表示,Bun 已成为 Claude Code 的重要基础设施,而 Claude Code 在当年 11 月达成了一个可观的营收里程碑。
官方的 Bun 收购公告将该运行时与 Anthropic 的编程战略直接联系起来,也因此提高了系统不稳定所要付出的代价。
Bun 表示,其命令行界面每月下载量超过 2200 万次。Vercel、Railway 和 DigitalOcean 也为该运行时提供官方支持。
下载次数并不等同于活跃开发者数量、生产部署次数或独立设备数量。自动化构建可能反复下载同一个软件包。尽管如此,这一数字依然体现了 Bun 必须支持的分发范围之广。
首个 Rust 版本并不只是某项小众实验背后的全新实现。它位于各种工具的底层,而这些工具运行在代码仓库、构建系统和部署流水线之中。
因此,Anthropic 收购后的 Bun Rust 重写,实际上是在检验两项承诺:Rust 应当能够防止常见的内存错误,而 Claude 则应当让原本不具现实可行性的迁移在经济上成为可能。
最终的评判标准,是这两项承诺能否经受住生产环境的考验。
每月 2200 万次下载,让稳定性本身成为产品
以 Bun 当前的规模,可靠性已不再是次要的工程目标,而是开发者安装的产品本身的一部分。
Bun 最初源于 Sumner 将 esbuild 的 JavaScript 和 TypeScript 转译器逐行从 Go 移植到 Zig。他在 2021 年 4 月写下了自己的第一段 Zig 代码。
最初版本花费约一年时间完成。Sumner 曾表示,在现代编程模型出现之前,正是 Zig 的简洁性和底层控制能力让这样的开发速度成为可能。
这一背景非常重要,因为此次重写并不能简单证明 Rust 与 Zig 之间谁是赢家。正是 Zig 帮助 Bun 以一套异常广泛的功能组合进入市场。
但随着 Bun 承担的职责不断增加,手动管理生命周期的成本也越来越高。其运行时嵌入了 Safari 使用的 JavaScriptCore 引擎,以及多个 C 和 C++ 库。
这些依赖项包括网络、加密、数据库和压缩组件。此前的 Bun 代码库中,约五分之一已经由 C++ 编写。
Rust 无法自动保证这些外部库的安全性。外部函数接口,也就是 FFI 边界,将 Rust 与编译器无法完整验证其内存规则的代码连接起来。
不过,Rust 可以将这些交互集中到明确标记的 unsafe 区域中。这样一来,开发者就能识别出编译器的常规保障在哪些位置不再适用。
这门语言还能让日常清理工作更加一致。在 Zig 中,开发者通常会在每个需要释放资源的调用位置附加 defer。
这种显式模型赋予工程师充分的控制权,但也要求他们始终严格重复执行相应操作。罕见的错误路径可能跳过清理,也可能意外执行两次清理。
Rust 的 Drop 机制则将清理工作与对象的生命周期绑定。Bun 表示,这一变化已经帮助修复了涉及文件路径和构建数据的内存泄漏。
在一项内部测试中,团队在同一进程中反复打包一个包含 60 个模块的项目。Bun 报告称,v1.3.14 每次构建都会泄漏约 3MB 内存。
Bun 称,在进行 2,000 次构建后,Zig 版本在测试中占用了 6,745MB 内存,而 Rust 实现最终稳定在 609MB。
这一对比尚未在多种工作负载下得到独立复现,但它仍直观展示了 Bun 试图消除的故障模式。
开发服务器可能会在每次请求或文件更新后重新构建代码。当进程连续运行数天时,即使规模不大的内存泄漏也会演变成严重问题。
同样的担忧也适用于编程智能体。Claude Code 在检查文件、运行命令和修改代码仓库时,可能会反复启动辅助进程。
运行时故障可能中断智能体、破坏中间结果,或迫使开发者转而调试基础设施,而不是专注于自己的应用程序。
在 Bun 1.4 正式发布之前,Claude Code 就已经迁移到了 Rust 移植版本。Bun 表示,6 月 17 日发布的 Claude Code 2.1.181 使用了这一新实现。
根据 Bun 的生产遥测数据,Linux 上的启动时间中位数从 517 毫秒降至 464 毫秒,提升幅度约为 10%。
速度并非此次重写的核心目标。更有意义的一点是,大多数用户并未察觉底层语言发生了变化。
对用户而言不可见的基础设施迁移,往往才是成功的迁移。应用程序应当保持相同行为,而底层的可维护性和可靠性得到改善。
Prisma 提供了另一项早期生产环境测试。其无服务器数据库平台在 Prisma Compute 公测版中采用了 Rust 重写版本。
Prisma 表示,早期实现曾遇到内存泄漏,而且虚拟机暂停后再恢复时,连接池无法复原。其工程师针对移植版本重新测试了这些场景。
据 Prisma 的生产环境评估显示,新实现能够应对这些特定故障模式。Prisma 同时提醒,unsafe 代码仍然需要审计和人工审查。
这种情况比单纯的下载量更能体现此次迁移的利害关系。移植版本已经带来了可衡量的改进,但要建立生产环境信心,仅靠通过演示还远远不够。
Node.js 和 Deno 同样面临 Bun 进展带来的压力,尽管二者都不是这个故事的主要对手。Node.js 仍然是服务器端 JavaScript 的兼容性基准。
Deno 已经围绕 V8 JavaScript 引擎使用 Rust。它的架构为如何借助 Rust 和原生依赖管理 JavaScript 运行时提供了具有参考价值的对照。
Bun 必须在维持性能主张和更广泛工具集的同时,保留对 Node.js 的兼容性。如果重写减少了崩溃,却引入了行为差异,那只不过是用一种可靠性问题换取另一种可靠性问题。
因此,团队选择了机械式移植,而不是立即重新设计。新的 Rust 代码有意保留了与先前 Zig 架构相似的结构。
这一决定减少了迁移期间的行为变化,但也将旧有假设和底层模式带入了一门具有不同安全规则的语言。
由此产生的结果构成了该项目的核心矛盾:Bun 选择 Rust 是为了获得更强的保障,但为了确保兼容性而采取的最稳妥路径,在初期却保留了大量 unsafe 代码。
Claude 将耗时一年的重写变成了 11 天的验证循环
值得关注的机制并不是单纯生成代码,而是一套将实现、批评、修正与测试相互分离的受控循环。
Bun 估计,采用传统方式重写需要三名经验丰富的工程师投入约一年时间。在此期间,功能开发和兼容性改进将会放缓,甚至完全停滞。
现有 Zig 代码库包含 535,496 行代码,且未计入注释。手动移植还会产生一个长期存在的分支,并不断偏离生产版本。
Sumner 转而测试了 Anthropic 一款名为 Claude Fable 5 的预发布模型。他花了大约三个小时,为 Zig 模式、类型和生命周期如何转换为 Rust 制定规则。
Claude 将这些决策记录在一份移植指南中。另一份生成的文档则梳理了整个代码库中各字段的预期生命周期。
团队先从三个文件入手,而不是立即翻译全部代码。每项移植工作由一个 Claude 实例负责实现,两个独立实例负责审查,另一个实例负责应用修正。
这种职责分离是有意为之。生成变更的模型可能会倾向于认可自己的推理。
负责审查的实例只会收到差异内容,而不会获得实现者的完整上下文。它们的任务是寻找错误行为和回归问题。
Sumner 将其称为对抗式审查。它类似于独立代码审查,但所有参与者都是同一模型家族的实例。
整个项目使用了约 50 个动态 Claude Code 工作流。高峰时,有四个工作流组同时运行,每组协调 16 个 Claude 实例。
这意味着大约有 64 个智能体同时工作。据报道,移植速度最高达到每分钟生成约 1,300 行代码。
这个过程一开始并不顺利。在同一代码仓库中工作的智能体使用了相互冲突的 Git 命令,包括 stash 操作和 hard reset。
Sumner 随后修改指令,禁止执行影响范围过大的 Git 操作。系统最终采用四个独立的 worktree,让智能体提交特定文件,并通过分支共享成果。
这次失败很重要,因为它表明,仅凭模型能力并不能完成重写。工作流还需要针对共享状态和破坏性操作设置明确约束。
考虑开展类似迁移的团队,也需要制定同样清晰的操作规则。即使智能体能够编写正确代码,也可能因不当处理代码仓库、凭据、构建系统或部署工具而破坏工作成果。
此次迁移生成了 6,502 个不含合并提交的 commit,而 Bun 表示,在这 11 天内共有 6,778 个 commit。最终合入的 diff 新增了略多于 100 万行代码。
这些数字体现的是活动量,而非质量。小型 commit 有助于提高可追溯性,但数千个自动化 commit 也会让传统的人工审查难以承受。
Bun 主要依靠编译器、自动化审查工具和现有测试套件。该套件在受支持的平台上包含约 100 万条断言。
团队报告称,合并前持续集成中的测试完成率达到 100%。团队还表示,没有删除或跳过任何测试。
在 Debian 上,Bun 的 60,624 项测试共执行了 1,386,826 次 expect() 调用。macOS 和 Windows 各自也运行了超过 100 万条断言。
使用 TypeScript 编写的测试套件为 Bun 带来了重要优势。这些测试评估的是可观察行为,不依赖底层运行时究竟使用 Zig 还是 Rust。
这种架构让机械式移植变得可衡量。每个经过转换的组件都必须继续满足同一套外部测试已经定义的预期结果。
Claude 还将编译器错误作为待办任务队列来处理。Bun 将 Rust 代码拆分为约 100 个 crate,也就是 Rust 项目中可以分别编译的软件包。
在某一阶段,cargo check 产生了约 16,000 个错误。工作流按 crate 对这些失败进行分组,将任务分配给智能体,审查修复结果,然后重复这一过程。
这种编译循环将一项令人望而生畏的迁移,转化为一系列边界清晰的任务。每个错误都会提供局部反馈,供智能体采取行动。
这种方法尤其奏效,是因为 Rust 编译器能够准确解释许多所有权和类型错误。编译器既成为质量关卡,也成为结构化指令的来源。
合并前,整个过程消耗了 59 亿个未缓存输入 token 和 6.9 亿个输出 token,另外还读取了 720 亿个缓存输入 token。
Bun 按 API 定价估算,总成本约为 165,000 美元。这个数字并未涵盖所有组织成本,包括原始代码库、测试、人员专业知识和后续维护。
因此,将其与三名工程师工作一年进行比较,只能反映大致方向,并不完整。Claude 并非凭空创造出 Bun 的架构、兼容性工作或测试语料库。
它利用的是多年积累的工程上下文。此次迁移之所以如此迅速,取决于这些上下文能否以智能体可以读取和验证的形式提供。
这一点对其他团队十分重要。成熟的测试套件和定义明确的行为,可以让自动化迁移具备可行性。
而测试不足的系统没有与之相当的判断依据。智能体可能生成能够编译的代码,却悄然改变用户赖以使用的行为。
工程团队还需要持久保存能够解释智能体决策的记录。可搜索的知识库可以跨越单个上下文窗口,长期保存迁移规则、审查发现和责任归属假设。
Bun 项目通过移植文档、生命周期映射、commit 历史和测试实现了这一点。这些产物并非额外的行政负担。
正是它们构成了一套系统,让高速生成的代码真正具备可审查性。
Rust 无法保证 Bun 中 unsafe 代码的安全性
此次重写降低了多类风险,但这并不意味着 Bun 可以因此被视为天然具备内存安全性。
Bun 的机械式转换保留了底层指针操作,以及与 C 和 C++ 库的大量交互。这些领域往往需要使用 Rust 的 unsafe 关键字。
unsafe 块允许执行借用检查器无法验证的操作。程序员必须手动确保必要规则得到遵守。
这并不意味着每个 unsafe 块都存在缺陷。许多大型 Rust 系统都会使用 unsafe 代码来实现高效抽象,并与操作系统或原生库交互。
但这确实意味着,Rust 最有价值的安全保证取决于这些边界如何设计、记录和审计。
Sumner 表示,Bun 最初约有 4% 的 Rust 代码位于 unsafe 块中。他称,在约 780,000 行 Rust 代码中,大约有 27,000 行 unsafe 代码。
他还表示,其中 78% 的 unsafe 块只有一行。许多代码用于处理一个 C++ 指针,或对原生库进行一次调用。
这种解释具有参考价值,但代码块的长度并不能证明其正确性。一次 unsafe 指针转换就可能造成生命周期错误,并影响其他位置的安全代码。
5 月 14 日公开的一项内存安全问题证明了这一风险。报告显示,一个安全函数抹去了切片的生命周期,从而允许产生悬空引用。
用于检测 Rust 程序未定义行为的解释器 Miri 标记了这个示例。所谓未定义行为,是指语言无法对运行结果提供任何可靠约束。
Bun 的自动化贡献者复现了该问题,并发现了另一个类似的生命周期漏洞。拟议修复方案将受影响的函数标记为 unsafe,并记录其生命周期要求。
这一响应表明,项目能够迅速处理具体报告。它同时也说明,编译和现有测试套件并未阻止所有无效抽象。
这一缺口支撑了针对重写最有力的质疑:如果自动化测试遗漏了 Zig 中的内存错误,同样的测试也无法证明大规模 Rust 移植在内存层面是健全的。
Rust 增加了编译器层面的强制检查,但 unsafe 区域会将责任重新交还给工程师。机械式转换可能会在这些区域中原样保留原有的指针处理方式。
Zig 创始人 Andrew Kelley 提出了最尖锐的公开批评。他在对重写的回应中认为,Bun 的问题源于工程实践和累积的技术债务,而非 Zig 本身的失败。
Kelley 还质疑,大量由模型生成的代码是否经过了充分的人工审查。他的批评有些地方转向了人身攻击,反而分散了人们对技术问题的注意力。
但这个问题依然成立:团队需要进行何种程度的独立审查,才应信任由 AI 生成的基础设施重写?
Bun 表示,每一行代码都经过两个不同 Claude 实例的审查。然而,模型审查并不等同于独立的人类判断。
同一模型的不同实例可能共享盲点、训练模式和错误假设。独立的上下文窗口可以减少锚定效应,却无法创造真正独立的专业判断。
自动化审查工具在合并前发现了多个可能导致实际问题的错误。其中一个涉及异步关闭操作,会导致同一资源被释放两次。
另一个错误未能正确处理负时间戳。第三个错误使用了 Rust 中一种立即求值的方法,导致解析某些 CSS 颜色表达式时发生 panic。
这些案例表明,对抗式审查确实带来了实际价值。但它们无法说明所有审查智能体共同遗漏了多少缺陷。
这场争论不应简化为接受或拒绝 AI 生成代码的二选一。更有意义的问题是如何提供可信保障。
团队早已在使用编译器、静态分析器、模糊测试工具、形式化模型和自动化测试系统。编码智能体可以成为这套工具体系的一部分,但不应成为最终裁决者。
Prisma 的立场提供了一条务实的中间路线。它已在公开测试版中部署此次移植成果,并报告称,在已知故障场景下表现有所改善。
与此同时,Prisma 表示,unsafe 代码需要审计,转换后的代码也需要审查。它建议将不符合 Rust 惯用写法的部分重构为人类能够理解的模块。
Bun 也作出了类似承诺。其初始目标是保持行为一致,随后逐步减少 unsafe 的使用,并采用更符合 Rust 惯例的写法。
这一顺序有其合理性,但也推迟了部分安全收益。在 unsafe 代码面缩小之前,此次迁移仍是一项持续推进的工程计划。
这一讨论也不仅限于内存安全。运行时还可能因模块解析错误、API 不兼容、网络行为异常、性能回退,或不同操作系统之间的细微差异而失败。
Rust 无法防止逻辑错误。拥有 100 万条断言的测试套件,也无法证明它对生态中每一个 JavaScript 软件包都能表现正确。
因此,Bun 还需要接受外部工作负载验证、独立审计、模糊测试和长期生产部署。每一种方式都能提供内部验证无法单独给出的证据。
Anthropic 收购后的 Bun Rust 重写,应被视为一项仍在积极验证中的、前景可期的迁移。现有证据既不足以将其称为彻底的安全成功,也不足以断言这是一次自动化失败。
三个信号将决定 Bun 的重写是否成功
下一阶段不如 11 天移植那样引人注目,但它将决定此次重写究竟会成为范例还是警示。
第一个信号,是 Bun 1.4 在常规生产部署中的表现。Bun v1.3.14 是最后一个 Zig 版本,而 v1.4 引入了 Rust 实现。
团队应关注更广泛采用后的崩溃报告、内存消耗、兼容性回退和版本回滚情况。一次成功的发布应当减少内存故障,同时避免引入新的行为缺陷类别。
Claude Code 和 Prisma 的早期部署增强了 Bun 的论据。但它们无法覆盖软件包组合、操作系统、原生模块和工作负载模式的全部多样性。
广泛使用将触达 Bun 内部测试套件从未覆盖的代码路径。连续多个发布周期的稳定表现,将比发布时的基准测试提供更有力的证据。
第二个信号,是 Bun 的 unsafe Rust 代码面的规模与设计。单纯的数量需要结合上下文理解,因为高度依赖 FFI 的运行时无法彻底消除 unsafe 代码。
更有意义的问题是,unsafe 操作能否被收拢到小型且文档完善的接口之后。每个接口都应明确调用者必须遵守的生命周期、别名、所有权和线程安全假设。
独立审计将增强这项工作的可信度。公开发现的 Miri 问题、sanitizer 结果和模糊测试结果,也应得到可见的修复,并配套加入回归测试。
如果 unsafe 的使用持续减少,同时 Bun 仍能保持性能和兼容性,那么此次重写的安全性论据将更加有力。如果安全接口内部反复出现生命周期错误,这一论据就会被削弱。
第三个信号,是能否有另一个成熟项目复现 Bun 的迁移方法。Bun 拥有异常有利的起点:广泛的测试、一位核心架构师,以及一位能够使用预发布模型的所有者。
第二次成功的迁移需要证明的不只是快速生成代码,还应记录人工审查、缺陷发现、运维控制和发布后的维护工作。
如果这些成果能够重现,AI 辅助语言迁移可能会成为那些因多年重写成本而受困项目的常规选择。
如果 Bun 仍只是一个孤立案例,其启示范围就会相对有限。这项成就依然意义重大,但它更多反映的将是 Bun 的测试基础设施,而非软件开发领域的普遍情况。
这场更广泛的较量并非 Rust 与 Zig 之争,而是机器生成代码的速度,与获得基础软件信任所需证据之间的较量。
Bun 将这场较量从玩具项目带入了一个月下载量超过 2200 万次的运行时。Anthropic 还在公众争论尚未尘埃落定之前,就将成果集成到了 Claude Code 中。
这一选择为 Bun 带来了宝贵的生产环境反馈,也让 Anthropic 有责任证明,其编码智能体能够维护自己生成的代码。
在进行高风险迁移之前,开发者应持续关注发布说明、尚未解决的安全报告以及独立部署结果,同时还应在真实负载下测试自己的依赖项。
Anthropic 收购 Bun 后进行的 Rust 重写已经表明,AI 辅助移植可以突破过去难以逾越的规模界限。
尚待解答的问题是,其验证流程能否跟上生成流程的速度。接下来应关注 Bun 1.4 的实际运行表现、不安全代码审计,以及下一个尝试采用相同方法的大型项目。


