身兼 JavaScript 執行環境、打包工具與套件管理員的 Bun,如今跑在 Rust 而非 Zig 上,而促成這件事的移植只花了 11 天、由持續受監督的代理程式工作流完成,而不是其作者原先為人類工程師抓的一年。Jarred Sumner 詳細記錄了整個過程;隨著 Bun v1.4 出貨,Claude Code 與 Prisma 的 Compute 測試版都跑在上面,我們已有足夠的正式環境證據,可以追問要信任上百萬行機器寫成的系統程式碼,實際代價是多少。
重點整理
- 橫跨 1,448 個檔案、共 535,496 行的 Zig 程式碼,由大約 50 條 Claude Code 工作流完成移植;它們分散在四個 git worktree,每個各跑 16 個代理程式實例,尖峰約為每分鐘 1,300 行,單一小時內產生 695 次提交。
- 每個負責實作的代理程式都配上兩個敵對審查者,審查者只看得到差異內容,並被要求先假定這段程式碼是錯的。
- Bun v1.4.0 修掉了 128 個在最後一版 Zig 釋出 v1.3.14 上仍可重現的錯誤,但 HTTP 吞吐量只提升 2 到 5 個百分點。
是什麼讓百萬行差異還勉強可審
前提是 Sumner 幾年前就存下的運氣:Bun 的測試套件以 TypeScript 撰寫,因此只驗證行為,不在意底下的執行環境由哪種語言實作。這讓整段移植擁有一個超過百萬條斷言、且全程不變的固定基準。如果測試是用原本的語言寫的,就不會有這根定錨。
第二項決定屬於結構層面。Sumner 沒有讓單一代理程式既寫程式又自行檢查,而是把角色拆開:一個實作者,兩個以上在獨立脈絡視窗中、只收到差異內容的敵對審查者,最後由另一個修補者套用審查結果。他給的理由關乎行為而非技術——寫出這段程式碼的模型會希望它被合併,就跟人類作者一模一樣,所以審查者必須是拿到不同指令的另一個實例。公開的例子包括:libuv 仍持有指標時就被丟棄的 Box<uv::Pipe>;一個提前求值的 unwrap_or,在合法的 CSS color-mix() 上直接 panic;以及一段 timespec 轉換,對 1970 年之前的檔案時間戳產生了負的奈秒值。三者都順利通過編譯。
第三,當輸出出錯時,修的是流程而不是產物。第一次完整執行後兩分鐘內,代理程式就用 git stash 互相覆蓋彼此的成果;當時的處置是改寫工作流的指令,而不是去修補受損的提交。約三小時的規劃產出了一份把 Zig 慣用寫法對應到 Rust 的 PORTING.md,以及記錄每個結構欄位預期生命週期的 LIFETIMES.tsv,兩份文件本身都在動手移植任何一行之前先經過敵對審查。
那些順利通過編譯的回歸
漏掉的比抓到的更具啟發性。Sumner 表示,多數回歸來自在兩種語言中看起來相同、行為卻不同的寫法。Zig 的 assert 是函式,因此其引數在每個建置版本中都會被求值;Rust 的 debug_assert! 則是巨集,在 release 建置中會把整個運算式抹掉。原本寄生在那句斷言裡的副作用——把檔案加進熱重載相依圖——在 release 版本中悄悄不再執行,導致 React 的 fast refresh 失效,而 debug 版本依舊全綠。
其餘案例形狀相同。一個原本會默默忽略結尾多出的奇數位元組的輔助函式,被移植成 bytemuck::cast_slice,遇到同樣情況改為 panic,結果在 UTF-16 位元組順序標記上讓行程當掉。一個被留在 64 的佔位常數,把 interned 檔名上限從 840 萬壓到 270,272,而這是真實專案會撞到的限制。Bun 的顏色標記格式化器失去了 Zig 的編譯期求值,開始連被替換進來的引數內部的標記也一併改寫。InfoQ 統計出 19 個這類語意回歸,另有 11 輪安全審查與來自持續剖析器模糊測試的 15 個 pull request。這些全都不是記憶體安全問題——借用檢查器做到了它該做的事。它們是語意上的失誤,而那正是編譯器抓不到的類別。
這次改寫真正換到了什麼
效能數字不大,也被誠實地公布:HTTP 吞吐量提升 2 到 5 個百分點,vite build 從 1.69 秒降到 1.65 秒。真正的報酬在記憶體紀律。Rust 的 Drop 會自動執行清理,而 Zig 的 defer 得在每個呼叫點手寫;一項在單一行程內把同一專案打包 2,000 次的基準測試,在 v1.3.14 上每次建置約漏 3 MB 且無上限,如今會趨於平穩。把連結器最佳化與精簡 ICU 併入這次移植後,Linux 與 Windows 的二進位檔大小減少約 20%。Claude Code 自 6 月的 v2.1.181 起就跑在 Rust 版本上,Linux 的啟動速度快了 10%,而用 Sumner 的話說,幾乎沒人注意到。
來自 Zig 作者的異議
Zig 作者 Andrew Kelley 發表了措辭尖銳的反駁,認為這種論述方式誤導了焦點:錯誤是靠投入工程資源消除的,不是靠在風格指南與語言特性之間二選一。他更犀利的問題關乎一致性——若 Bun 的測試套件不足以抓出 Zig 程式碼中的錯誤,那就很難看出它為何足以驗證上百萬行未經人工審查的生成式 Rust。
這是個公允的挑戰,而誠實的回答是:測試套件並非唯一的把關機制,敵對審查、CI 中的 Miri、LeakSanitizer 與全天候模糊測試都層層疊在其上。至於這一整套是否能取代人類對程式碼的理解,恰恰是仍未被驗證的部分。
值得盯著看的理由
Sumner 公布的成本數字——合併前用掉 59 億個未快取輸入 token 與 6.9 億個輸出 token,按 API 價格約 16.5 萬美元——為一項過去幾乎不可逆的決定重新標價。成熟程式庫的語言選擇本是一扇單向門,如今卻成了一個預算項目。2025 年 12 月收購 Bun 並雇用 Sumner 的Anthropic,對這個結論顯然有其利害關係,而這也是今年出貨的多起代理程式主導改寫之一。真正待解的問題是維護:一套沒有任何人從頭到尾讀過的程式庫,未來幾年仍得由人來擴充、除錯與推敲。每月有 2,200 萬次 CLI 下載的 Bun,正是整個產業找到答案的地方。
常見問題
Bun 的 Rust 程式碼全是 AI 在無人監督下寫的嗎?
不是。Sumner 在這 11 天全程監看工作流,手動閱讀輸出,並在代理程式產出不佳結果時反覆修改流程。他也透過確認敵對審查者是否真的抓到偏差來檢視這次移植,並把 Zig 與 Rust 並排讀過相當大的篇幅。
為何報導說四個月,移植卻只有 11 天?
11 天指的是移植本身,從啟動到完整測試套件在所有平台上通過為止。較長的數字則反映了額外驗證與釋出所經過的時間:該篇紀錄發表於 2026 年 7 月,穩定版 Bun v1.4.0 於 8 月跟上。
Bun 現在還有用到 Zig 嗎?
沒有了。Bun v1.3.14 是最後一個 Zig 版本,v1.4.0 則是第一個 Rust 版本。Bun 仍有約 20% 是 C++,包含 JavaScriptCore 與 uWebSockets 等內嵌相依套件,這次改寫並未動到那部分。






