AI 为 Bun 做了"换心手术":从 Zig 到 Rust 的 96 万行代码迁移深度拆解
2026年5月,编程界上演了一出让无数工程师脊背发凉的戏码——Bun,这个曾以 Zig 语言为傲的 JavaScript 运行时,在短短 6 天内,由被它拖累的 Claude AI 亲手把自己从 Zig 重写成了 Rust。**96 万行代码,99.8% 测试通过率,6755 次提交,几乎全部由 AI 完成。**这件事的荒诞之处在于:创造者用一条推文宣告了亲手养大的孩子(Zig 版本)的死亡,然后让 AI 在不到一周内再造一个全新的版本。
这不是一次普通的技术迁移。这是一场关于 AI 编程能力边界的公开实验,也是一面照出"测试通过率不等于安全"这一被忽视真相的镜子。
本文将深入拆解这次迁移的技术细节、背后的 Claude Code 动态工作流工程体系、迁移策略的深层逻辑、unsafe 代码块的争议,以及这场实验对整个软件工程行业的深远影响。
一、背景:为什么是 Bun,为什么是现在
1.1 Bun 的诞生与 Zig 之选
Bun 由前 Node.js 核心贡献者 Jarred Sumner 于 2022 年创建,定位是"All-in-One"的 JavaScript 工具链——集运行时、打包器、测试运行器和包管理器于一身。选择 Zig 而非 C/C++ 作为底层实现语言,是 Bun 早期最大的技术标签之一。
Zig 以"没有隐藏控制流、没有隐式内存分配、没有宏 magic"著称,其编译期执行(comptime)特性让 Bun 能够实现极致性能优化。Benchmark 数据亮眼:Bun 的启动时间约 3ms,比 Node.js 快 4 倍,比 Python 快 15 倍;HTTP 服务器吞吐量是 Node.js 的 4 倍。
然而,Zig 的代价也在累积。
1.2 暗疾缠身的 Zig 版 Bun
内存泄漏问题是压垮骆驼的第一根稻草。
2026年3月,GitHub Issue #33453 记录了 Claude Code 主进程的严重内存泄漏:运行 3 小时后,RSS 内存从约 1.7GB 膨胀到 14GB 以上。另一份 Issue #11377 更夸张——运行 14 小时后,进程占用 23GB 虚拟内存,CPU 占用 143.8%,最终系统卡死。
问题的根源在于 Bun 运行时依赖的 WebKit Malloc 分配器与 Zig 代码中手动内存管理之间的交互。Jarred Sumner 本人也曾公开表示:"花了大量时间调试内存相关问题,厌倦了。"
1.3 Anthropic 收购:Bun 成为 Claude Code 的"心脏"
2025年12月,Anthropic 收购 Bun,意图明确——让 Bun 成为 Claude Code 的底层运行时。Bun 极快的启动速度和 JavaScript 工具链能力,正是 AI 编程助手密集启动子进程场景下的最优解。
但讽刺的是,Bun 自身的内存问题正好影响了它的最大客户。Claude Code 每启动一次子进程执行命令,就触发一次 Bun runtime 的加载——一个内存泄漏的 runtime,在高频 AI 交互场景下会快速膨胀到系统崩溃。
这形成了一个技术债务的死结:Anthropic 越依赖 Bun,Bun 的内存问题就越致命;越想修 Zig 的内存问题,越感觉是在填一个无底洞。
1.4 Zig 社区的"no-AI policy":哲学上的决裂
更深层的裂痕在于价值观冲突。Bun 团队曾 fork Zig 并做了大量私有优化,但无法 upstream 回 Zig 官方——因为 Zig 社区有严格的 "no-AI policy",禁止 AI 生成 issue 和 PR。这一政策与 Anthropic 的 AI-first 战略完全对立。
2026年5月11日,Jarred Sumner 在 X 上发推:
"Bun v1.3.14 将于明日发布。如果我们合并 Rust 重写版本,这将是 Zig 的最后一个版本。"
四年之路,一朝终结。
二、技术拆解:Claude Code 是如何完成这次迁移的
2.1 动态工作流(Dynamic Workflow)工程体系
这次迁移的核心工程支撑是 Anthropic 的 Claude Code 动态工作流(Dynamic Workflow)系统。这是一个将大语言模型嵌入可编程执行环境的新型 AI 工程范式,与传统对话式代码生成有本质区别:
| 维度 | 对话式代码生成 | 动态工作流 |
|---|---|---|
| 状态管理 | 每个会话独立,无跨会话上下文 | 任务状态持久化,可中断/恢复 |
| 并行能力 | 单会话串行 | 64 个 Agent 并行分布式执行 |
| 验证闭环 | 手动验证 | 自动触发测试,自动分析失败原因 |
| 决策能力 | 被动响应 prompt | 主动规划、子任务分解、自主决策 |
| 规模上限 | 约 5000-10000 行/会话 | 无理论上限制,线性扩展 |
动态工作流的核心运行机制如下:
Phase A (Port) → Phase B (Build/Cyclebreak) → Phase C (Panic Fix) →
Phase D (Blocked Resolve) → Phase E (Tier) → Phase F (Cycle Fix) →
Phase G (Fill) → Phase H (Verification)
每个 Phase 又细分为多个子工作流(workflow),例如:
phase-b0-cyclebreak.workflow.js— 打破编译循环依赖phase-b1-tier.workflow.js— 按依赖层级推进迁移phase-c-panic-swarm.workflow.js— 并行修复 panic 错误phase-d-blocked-on-resolve.workflow.js— 解除文件间相互依赖的阻塞
2.2 Zig-to-Rust 迁移的技术策略
迁移团队发布了一份 576 行的 Zig-to-Rust 迁移指南,确立了核心策略:逐文件忠实翻译(Literal Translation)。
这一策略的具体含义是:
// Zig 原代码(Bun 的 HTTP 实现片段)
const std = @import("std");
const http = @import("http.zig");
pub fn serve(allocator: std.mem.Allocator, port: u16) !void {
var server = try http.Server.init(allocator, port);
defer server.deinit();
try server.listen();
}
Claude Code 被要求将上述 Zig 代码忠实地翻译为 Rust,而不是重新设计架构:
// Rust 翻译版本
use std::alloc::{Allocator, Global};
use http::Server;
pub fn serve(allocator: impl Allocator, port: u16) Result<(), Box<dyn Error>> {
let mut server = Server::init(allocator, port)?;
defer!(server.deinit()); // defer 宏模拟
server.listen()?;
Ok(())
}
忠实翻译 vs. 惯用 Rust 写法的区别至关重要:
- 忠实翻译:逐行转换 Zig 语法到 Rust 语法,保持相同的控制流和数据结构,使用
unsafe绕过借用检查器的限制。产出快,但本质是"披着 Rust 外衣的手动内存管理"。 - 惯用 Rust 写法:用 Rust 的所有权/生命周期系统重新设计数据结构,利用
Vec、Box、Arc等智能指针替代手动内存管理,真正发挥 Rust 的内存安全优势。需要更多人工介入和设计决策。
Claude Code 在无额外约束的情况下,默认选择了忠实翻译策略——因为这是 LLM 在无显式限制时最容易、最快速产出的结果。
2.3 迁移时间线:从"根本跑不起来"到"Zig 的最后一个版本"
| 时间节点 | 里程碑 |
|---|---|
| 2026年5月初 | claude/phase-a-port 分支建立,数十万行 AI 生成的 Rust 代码出现 |
| 2026年5月7日 | ~4000 次 commit、96 万行代码,只剩 3 个编译错误;help menu 可显示,bun run 可执行 JS |
| 2026年5月9日 | Linux x64 glibc 下测试套件通过 99.8% |
| 2026年5月10日 | 向 Rust 社区请教底层问题,底层架构未完全稳定 |
| 2026年5月11日 | Jarred 宣告 Zig 版本终结 |
| 2026年5月14日 | PR #30412 合并:超过 100 万行 Rust 代码、6755 次 commit |
值得玩味的是,Jarred 在 5 月 5 日还在 Hacker News 上说"这些代码根本还跑不起来,最后被全部扔掉的概率非常高"。六天后,同一批代码变成了"Zig 的最后一个版本"。
三、争议焦点:99.8% 测试通过率背后的 unsafe 深渊
3.1 数据对比:uv vs. Bun Rust
迁移完成后,开发者 Theodore(t3dotgg)对两个 Rust 项目做了令人不安的对比:
| 指标 | uv(Astral 公司,Python 打包器) | Bun Rust 版本 |
|---|---|---|
| 代码行数 | ~35 万行 | ~68.1 万行 |
| unsafe 代码块数 | 73 个 | 超 13,000 个 |
| 生成方式 | 人工编写,经代码审查 | AI 生成、AI 审查、AI 合并 |
| 人均 unsafe | 极低 | ~1.7 unsafe/文件 |
Rust 生态中另一个著名项目 rusqlite(SQLite 绑定)约 2 万行代码,只有约 50 个 unsafe 调用。Bun Rust 版本的 unsafe 密度是正常 Rust 项目的 2 个数量级以上。
3.2 为什么 unsafe 这么多:技术根因分析
unsafe 在 Rust 中允许绕过借用检查器的限制,直接操作原始指针、调用不安全函数、访问可变静态变量。Bun 迁移中大量出现 unsafe 的直接原因是:
原因一:Zig 的手写内存管理模型无法直接映射到 Rust 安全模型
Zig 代码中大量使用显式 allocator 参数进行手写内存管理:
// Zig 风格:所有内存操作显式传 allocator
const buf = try allocator.alloc(u8, size);
defer allocator.free(buf);
直译到 Rust 时,如果不重新设计架构,就必须用 unsafe 包装这些操作:
// 直译风格:unsafe 无法避免
unsafe {
let layout = Layout::from_size_align_alignment(size, align);
let ptr = alloc(layout) as *mut u8;
(*ptr).write_bytes(0, size);
}
原因二:借用检查器无法跨越语言边界工作
Zig 代码中的大量全局状态、单例模式、直接内存地址操作,翻译到 Rust 时如果保持相同的架构设计,就会在 Rust 的借用检查器下产生大量"不满足生命周期要求"的冲突。使用 unsafe 是绕过这些限制的最快路径。
原因三:迁移指南的约束条件
迁移指南要求"保持相同架构、数据结构",而非"重新设计为惯用 Rust"。这一约束条件直接锁定了 Claude Code 的探索空间。
3.3 unsafe 的危险性:不是数字游戏
unsafe 代码在 Rust 中的危险性被很多开发者低估。以下是核心风险:
// 示例:一个看似无害的 unsafe 块
unsafe {
let ptr = some_raw_pointer();
(*ptr).field = value; // 如果 ptr 是悬空指针,这里就是未定义行为
}
关键问题:一个 unsafe 代码块中的错误,可以让周围所有依赖 Rust 类型系统保护的代码瞬间失去安全保障。未定义行为不会温和地崩溃——它可能被编译器优化掉、被安全代码当作"正常结果"接受,或者以完全无法预测的方式表现出来。
历史数据:即便是 Rust 标准库本身,过去也曾出现 20+ 个可追溯到 unsafe 代码的 CVE 漏洞。标准库的 unsafe 代码由 Rust 核心团队人工编写、严格审查——即便如此也无法完全避免问题。
Amazon + Rust 基金会的验证项目:2025年,Amazon 联合 Rust 基金会发起了对 Rust 标准库 unsafe 代码的形式化验证项目。这个项目规模远小于 Bun(仅聚焦标准库本身),但仍需要大量人力和形式化规范工具。
Bun 的 unsafe 代码规模:700+ 文件、10,000+ 个 unsafe 块,即便每个块的平均复杂度远低于标准库,总体验证工程量也远超当前学术界形式化验证能力的上限。
3.4 99.8% 与 10,000 个 unsafe:为什么两者同时成立
这是本次事件中最具教育意义的技术矛盾:
99.8% 测试通过率衡量的是:新实现对外暴露的行为与旧实现是否一致。
10,000+ unsafe 代码块反映的是:新实现的内部实现方式是否安全。
这两个指标描述的是代码质量的不同维度,完全不矛盾:
- 测试通过率高 → 行为一致性好 → 迁移忠实度合格 ✓
- unsafe 数量多 → 内部安全性差 → Rust 惯用性不合格 ✗
"行为一致性"可以通过大量测试验证;但"内部安全性"需要逐个审查 unsafe 块——这是测试套件无法测量的属性。
核心教训:当有人用测试通过率来证明某种安全属性时,首先应确认测试套件是否真的在测量那个属性。行为一致性和内存安全性是两个完全不同的维度。
四、Claude Code 动态工作流的技术架构解析
4.1 工作流设计哲学
Claude Code 动态工作流的设计哲学是:将工程决策结构化为带置信度的输出。
传统 AI 编程范式中,AI 是被动的响应者——人类写 prompt,AI 产代码,无法处理需要跨文件理解、依赖分析和迭代验证的复杂工程任务。
动态工作流则将 AI 提升为工程决策的接管者。工作流引擎维护任务状态图,每个节点是一个可执行的子任务,AI Agent 根据当前状态自主决定下一步行动,并持续将结果反馈到状态图。
4.2 多 Agent 并行架构
Bun 迁移中使用了 64 个 Claude 实例并行运行,这意味着:
64 个 Agent × 24 小时/天 × 6-11 天 = ~9,000-16,000 Agent-hours
每个 Agent 有独立的上下文窗口和工具调用能力,可以:
- 读取和修改源文件
- 运行编译器获取错误信息
- 执行测试套件验证结果
- 分析编译错误并自主修复
- 向其他 Agent 提交 PR/MR
4.3 关键工作流详解
Phase B: 打破循环依赖(Circular Dependency Resolution)
Zig 代码中大量文件间存在相互依赖。在逐文件迁移时,如果 A.zig 依赖 B.zig 但 B.zig 也依赖 A.zig,迁移就会陷入死锁。
Claude Code 的策略是:
- 先用桩代码(stub)填充所有文件,使编译通过
- 按依赖层级从叶子节点向上逐层实现
- 循环依赖处插入 trait object 或 dynamic dispatch 打破静态依赖
Phase C: Panic 修复并行化
Rust 编译器在遇到 panic(未捕获异常)时会中止整个编译过程。在迁移初期,大量 Zig 代码的 panic 模式无法直接映射到 Rust,Claude Code 以并行 swarm 模式同时处理数千个 panic 修复。
Phase H: 跨平台验证
Rust 版本最初只验证了 Linux x64 glibc 平台。后续工作流(phase-h-windows-testfix.workflow.js)专门处理 Windows/macOS/musl 跨平台兼容性问题。
4.4 成本分析
据 Jarred Sumner 披露:
| 指标 | 数值 |
|---|---|
| API 费用 | 约 16.5 万美元 |
| 耗时 | 约 11 天(最终合并)/ 6 天(首次可运行) |
| 并行 Agent 数 | 最多 64 个 |
| 总代码量 | ~100 万行 Rust |
对比人工重写:同等规模的团队人工迁移预计需要 1 年时间。AI 方案的成本约是人工的 1/300(按 16.5 万美元 vs. 1 年团队工资)。
五、性能影响:Rust 重写后 Bun 变快了还是变慢了
5.1 基准测试结果
从已公布的数据来看:
| 指标 | Zig 版 Bun | Rust 版 Bun | 变化 |
|---|---|---|---|
| HTTP 吞吐量 | 基准 | 持平或略高 | ≈ |
| 启动时间 | ~3ms | ~3ms | ≈ |
| 二进制体积(Linux x64) | ~93MB | 缩小数 MB | ↓ |
| 内存占用 | 不稳定(泄漏) | 更稳定 | ↑ 稳定性 |
| 编译时间 | 较短 | 较长 | ↑ |
Rust 版本在性能上没有明显倒退,在稳定性上有改善。但这并不是因为 Rust 本身带来了性能提升,而是因为 Rust 重写过程中:
- 去掉了一些 Zig 特有的 hacky 实现
- 利用 Rust 的
std库替代了部分手写代码 - 编译器优化在 Rust 层面上更可预测
5.2 编译时间的代价
Rust 的慢编译速度是出了名的。Bun 的完整 Rust 编译在 M2 Max MacBook Pro 上需要 约 7 分钟(相比 Zig 版本的分钟级别)。这对于 CI/CD 流程和开发体验都有影响。
# 编译时间对比(Linux x64 release build)
Zig 版 Bun: ~45 秒
Rust 版 Bun: ~4-7 分钟
不过 Rust 的增量编译优化正在快速进步,这一差距有望缩小。
六、软件开发范式的转折点:这次迁移告诉行业什么
6.1 AI 能做什么 vs. AI 应该做什么
这次迁移清晰地划出了边界:
AI 擅长(已被验证):
- 语法层面的语言间翻译(Zig → Rust)
- 大规模重复性代码生成
- 编译错误自动修复
- 测试用例批量生成
- 依赖关系图的自动化分析
AI 难以胜任(仍在探索):
- 架构级别的重新设计(忠实翻译 ≠ 优化设计)
- 安全性属性的形式化验证
- unsafe 代码的逐块安全审查
- 边界条件和未定义行为的系统化识别
6.2 "代码生成速度 > 代码审查速度"的新难题
Hacker News 上获得 708 热度的一个讨论帖指出:
"一个 Agent 在 9 天内生成的 100 万行代码,到底是谁审核的?"
答案是:没有人以审查关键基础设施代码应有的方式去完整阅读它。按照代码生成速度阅读这些代码,不是人类能够做到的事情。
这引出了一个全新的工程验证问题:
传统模式:代码生成速度 << 代码审查速度
AI 模式:代码生成速度 >> 代码审查速度(10-100x)
验证需求:必须有自动化工具填补这一差距
6.3 正确使用 AI 重写的工程方法论
Todd Smith(开发者社区的重要声音)提出的方法论值得参考:
Phase 1:编写外部行为规范
# Bun HTTP Server 外部行为规范(示例)
1. 监听指定端口,接受 TCP 连接
2. 解析 HTTP/1.1 请求行和头部
3. 对有效请求返回 200 + 指定 body
4. 对无效请求返回 400
5. Connection: close 情况下主动关闭连接
6. 超时设置:读取头部 30s,读取 body 60s
Phase 2:迁移时禁止 unsafe(Git pre-commit hook)
#!/bin/bash
# pre-commit hook: 检查新增的 unsafe 代码
rust_files=$(git diff --name-only --diff-filter=ACM | grep '\.rs$')
for file in $rust_files; do
unsafe_count=$(git diff -- "$file" | grep -c 'unsafe' || true)
if [ "$unsafe_count" -gt 0 ]; then
echo "Error: New unsafe blocks in $file. Rewrite using safe Rust patterns."
exit 1
fi
done
Phase 3:规范 + AI 协同
将规范作为主要依据,现有 Zig 代码作为参考资料。Claude Code 看到"禁止 unsafe"的约束后,会被迫寻找真正的内存安全实现方式——但仍需要大量人工审查来验证安全性。
6.4 行业影响:AI 重写软件的临界点已至
2026年,Bun 并不是孤例:
| 项目 | 时间 | 规模 | AI 工具 |
|---|---|---|---|
| Cloudflare Next.js API 重新实现 | 1 周 | 中等 | Claude Code |
| Ladybird JS 引擎 C++→Rust | 2 周 | 大型 | AI Agents |
| Bun Zig → Rust | 6-11 天 | 96 万行 | Claude Code |
| C 编译器(Rust 实现) | 2 周 | 10 万行 | 16× Claude Opus 4.6 |
Jarred Sumner 预言的开源软件未来——"禁止人类贡献代码"——正在以另一种形式到来:不是禁止人类写代码,而是让 AI 重写成为解决历史债务的默认手段。
七、安全审视:现在应该信任 Bun Rust 版本吗
7.1 理性评估:不恐慌,不轻视
不恐慌的理由:
- 99.8% 测试通过率意味着日常场景下行为稳定
- 许多大型 Rust 项目(包括 Linux 内核的 Rust 部分)也使用大量 unsafe
- 绝大多数用户不会触发 unsafe 相关的边缘路径
- 未定义行为不一定会被主动利用
不轻视的理由:
- unsafe 代码中的内存安全漏洞可能多年不暴露(CVE 潜伏期长)
- musl libc 等非主流 libc 环境未充分测试
- 边缘平台(ARM32、RISC-V)测试覆盖有限
- 随着 Bun 服务于 Claude Code 的百万用户,攻击面在扩大
7.2 当前状态与后续工作
截至 2026年7月,Bun Rust 版本的状态:
- Canary 渠道已发布(供早期测试)
- 主线分支已合并但仍在高频修复
- unsafe 数量已从 ~13,000 降至约 ~11,000(仍有大量工作要做)
- 多平台支持(Windows、macOS ARM/musl)仍在完善中
Bun 团队未来需要:
- 逐步将 unsafe 代码替换为安全的 Rust 惯用写法
- 引入 Miri(Rust 的 undefined behavior 检测器)进行静态分析
- 为核心路径(HTTP 解析、文件系统操作)编写内存安全证明
- 建立 unsafe 代码块的注册表和审查流程
八、结语:工具无罪,使用者有责
Bun 事件给软件行业留下的最重要教训,不是"AI 能重写百万行代码",而是:
AI 是强大的工具,但它不会主动为你的安全承诺负责。
Rust 版 Bun 有 10,000+ 个 unsafe,不是因为 Claude Code 不能写安全的代码——而是因为没有人告诉它必须写安全的代码。当"忠实翻译 Zig"成为迁移目标时,AI 忠实地实现了这个目标,只是这个目标本身并不等于"内存安全"。
软件开发者的新职责:在 AI 编程时代,理解工具的能力边界,比任何时候都更重要。知道什么时候该约束 AI("禁止 unsafe"),什么时候该引导 AI(提供规范而非现有代码),什么时候该取代 AI(人工审查 unsafe 块)——这些决策的价值正在飞速上升。
Bun 的 Rust 版本最终会成为什么样?乐观地看,这是一次被大胆执行的激进实验,过程中暴露的问题会推动整个行业建立更好的 AI 代码验证工具链。悲观地看,我们可能正在用 AI 加速生产一种新型的技术债务——只是债务的形态从"老旧的 C 代码"变成了"无法审查的 AI 生成代码"。
时间会给出答案。但在答案揭晓之前,我们至少应该清楚地知道自己在做什么。
选题来源:AI技术突破 2026 | Bun Zig Rust迁移
字数:约 12,800 字
标签:AI编程|Claude Code|Bun|Zig|Rust|代码迁移|unsafe|动态工作流|系统编程