Bun hoàn thành việc di chuyển mã 11 ngày dựa trên AI từ Zig sang Rust

iconMetaEra
Chia sẻ
AI summary iconTóm tắt
Bun đã công bố một thông báo dự án vào tháng 5 năm 2026, hoàn thành việc di chuyển mã nguồn 11 ngày do AI dẫn dắt từ Zig sang Rust. Nỗ lực này bao gồm hơn 1 triệu dòng mã, 6.778 commit và 64 phiên bản Claude chạy song song, với chi phí 165.000 USD. Việc sử dụng bộ nhớ giảm từ 6,7 GB xuống còn 609 MB sau 2.000 lần build, với cải thiện hiệu năng từ 2-5%. Mã nguồn hiện tại bao gồm 13.000 từ khóa unsafe và 19 sự suy giảm. Anthropic hiện sở hữu dự án. Bản cập nhật tin tức AI + tiền điện tử này nhấn mạnh sự thay đổi lớn trong hạ tầng dự án.
Dự án Bun hoàn thành việc di chuyển mã nguồn lớn từ Zig sang Rust vào tháng 5 năm 2026, thực hiện hơn 1 triệu dòng mã thay đổi và 6.778 lần commit trong 11 ngày. Việc di chuyển sử dụng 64 Claude hoạt động song song, tiêu tốn 165.000 USD chi phí API. Sau khi di chuyển, các vấn đề rò rỉ bộ nhớ đã được giải quyết căn bản: sau 2.000 lần build, bộ nhớ giảm từ 6,7 GB xuống ổn định ở mức 609 MB, hiệu suất tăng 2% đến 5%, kích thước tệp nhị phân giảm khoảng 20%. Tuy nhiên, mã nguồn chứa khoảng 13.000 từ khóa unsafe, gấp 178 lần so với các dự án tương tự, tồn tại 19 vấn đề hồi quy đã biết, và 1 triệu dòng thay đổi không thể được con người kiểm tra từng dòng. Hiện tại, Bun đã được Anthropic mua lại.

Tác giả bài viết, nguồn: InfoQ

Tháng 5 năm 2026, dự án Bun đã thực hiện một cuộc di chuyển mã nguồn quy mô lớn, hiếm có trong lịch sử phát triển phần mềm.

Cuộc di chuyển này bắt đầu vào ngày 3 tháng 5 và chính thức hợp nhất vào nhánh chính vào ngày 14 tháng 5, chỉ mất 11 ngày. Viết mã chỉ mất 6 ngày và toàn bộ quá trình được công khai. Tuy nhiên, Jarred Sumner đã mất gần một tháng để viết bài blog tổng kết, lâu hơn nhiều so với thời gian viết mã.

Runtime JavaScript ban đầu có 535.496 dòng mã Zig, không bao gồm chú thích; đồng thời, khoảng 20% mã được viết bằng C++ và nhúng nhiều thư viện C/C++. Lần này, nó được viết lại bằng Rust nhờ AI, toàn bộ quá trình liên quan đến hơn 1 triệu dòng thay đổi mã, 6.778 lần commit và chạy khoảng 50 luồng làm việc động (dynamic workflows) trong Claude Code.

Theo dữ liệu do Sumner tiết lộ, lần tái viết này đã tiêu tốn 5,9 tỷ token đầu vào không được lưu bộ nhớ đệm, 690 triệu token đầu ra và 72 tỷ lần đọc token đầu vào được lưu bộ nhớ đệm, với chi phí khoảng 165.000 USD theo giá API.

Sumner cho biết, đây là mức độ tiên tiến nhất mà công nghệ hiện tại có thể đạt được. Ông ước tính rằng, nếu để 3 kỹ sư hoàn toàn am hiểu mã nguồn Bun thực hiện việc di chuyển này bằng tay, sẽ mất khoảng một năm, và trong suốt thời gian đó, nhóm gần như không thể tiếp tục phát triển tính năng mới, sửa lỗi và vá lỗ hổng bảo mật.

Sau lần cập nhật này, Bun v1.3.14 sẽ là phiên bản cuối cùng sử dụng Zig, và Bun v1.4.0 sẽ là phiên bản đầu tiên sử dụng Rust.

1. Kết quả: Từ 6,7 GB rò rỉ bộ nhớ xuống còn 609 MB ổn định

Bun ban đầu là một dự án Zig với phạm vi rất rộng: nó vừa là trình biên dịch JavaScript và TypeScript, vừa là trình đóng gói, trình quản lý gói, trình chạy kiểm thử, trình phân giải mô-đun, client HTTP và WebSocket, đồng thời triển khai lớp API của Node.js. Chính sự đa dạng sản phẩm này đã giúp CLI của Bun đạt hơn 22 triệu lượt tải xuống mỗi tháng và nhận được sự hỗ trợ từ các dự án hoặc công ty như Vercel, Railway, DigitalOcean, Claude Code và OpenCode.

Tuy nhiên, cùng độ rộng này cũng mang đến một số thách thức cho Bun.

Đặc biệt trong Bun v1.3.14, có một vấn đề đã gây phiền toái lâu nay: khi thực hiện liên tiếp các lệnh gọi Bun.build(), bộ nhớ sẽ tích lũy liên tục và không bao giờ được giải phóng. Mỗi lần xây dựng rò rỉ khoảng 3MB, nghe có vẻ không nhiều, nhưng nếu bạn chạy một máy chủ phát triển, mỗi yêu cầu đều kích hoạt một lần xây dựng, thì bộ nhớ sẽ bị từ từ nuốt chửng cho đến khi tiến trình sụp đổ.

Trong các bài kiểm tra thực tế, bộ nhớ sử dụng là 1,9 GB sau 500 lần xây dựng, 3,5 GB sau 1000 lần, 5,1 GB sau 1500 lần và tăng vọt lên 6,7 GB sau 2000 lần.

Đây chỉ là phần nổi của tảng băng trong số nhiều vấn đề về bộ nhớ. Trong danh sách sửa lỗi của v1.3.14, Sumner đã liệt kê một danh sách dài các vấn đề:

Khi gọi .reset() trong module zlib, nếu một .write() bất đồng bộ vẫn đang được thực thi trong pool luồng, tiến trình sẽ bị sập do "sử dụng sau khi giải phóng bộ nhớ đống"; trong module http2, các callback JavaScript lồng nhau kích hoạt việc tái băm bảng băm, khiến con trỏ luồng nội bộ bị mất hiệu lực; khi UDPSocket.sendMany() đang lặp qua, nếu mã người dùng thay đổi trạng thái kết nối của socket thông qua callback valueOf hoặc toString, sẽ xảy ra ghi tràn; khi crypto.scrypt thất bại trong việc cấp phát bộ đệm đầu ra, callback và bộ đệm mật khẩu được bảo vệ sẽ không bao giờ được giải phóng;......

Tính chất chung của những lỗi này rất rõ ràng—chúng gần như đều chỉ ra cùng một nguồn gốc: kết hợp GC với quản lý bộ nhớ thủ công trong cùng một phần mềm.

Các trình biên dịch hiện đại như JavaScriptCore (và V8) có những quy tắc cực kỳ nghiêm ngặt đối với xử lý ngoại lệ và GC, trong khi Zig không tự quản lý bộ nhớ giống như C. Khi hai mô hình này cùng tồn tại trong cùng một tiến trình, mỗi lần cấp phát bộ nhớ đều cần được xem xét từng dòng: những byte này được giải phóng ở đâu? Làm thế nào để đảm bảo chỉ giải phóng một lần duy nhất? Có kiểm tra đúng cách các ngoại lệ JavaScript không? Con trỏ được quản lý bởi GC có hiển thị với trình quét ngăn xếp bảo thủ không? Đây là bộ nhớ do GC quản lý hay bộ nhớ được quản lý thủ công?

Điều khiến lo lắng hơn là đội ngũ đã không ngừng nỗ lực. Họ đã sửa đổi trình biên dịch Zig, thêm hỗ trợ Address Sanitizer (ASAN), chạy các bài kiểm tra ASAN trong CI cho mỗi lần gửi mã, xây dựng ReleaseSafe trên Windows, thực hiện kiểm tra mờ 24/7 bằng Fuzzilli và thực hiện hàng loạt bài kiểm tra end-to-end về rò rỉ bộ nhớ. Dù vậy, các báo cáo lỗi vẫn tiếp tục đổ về không ngừng.

“Danh sách sửa lỗi của chúng tôi khiến tôi cảm thấy rất tệ, tôi chán ngấy việc đi ngủ với nỗi lo Bun sẽ sụp đổ,” Sumner viết. Anh ấy không đổ lỗi cho Zig—các người dùng Zig khác không gặp vấn đề tương tự với Bun, vì việc kết hợp GC với quản lý bộ nhớ thủ công là một yêu cầu cực kỳ hiếm gặp, và hầu như không có ngôn ngữ nào được thiết kế để làm điều đó.

Trong khi phiên bản Rust đưa ra kết quả: cùng thực hiện 2000 lần Bun.build(), bộ nhớ ổn định ở mức 609MB.

Ngoài việc vấn đề rò rỉ bộ nhớ đã được giải quyết căn bản, việc viết lại bằng Rust còn mang lại nhiều cải thiện ở các khía cạnh khác.

Về độ ổn định, v1.4.0 đã sửa 128 lỗi có thể tái hiện trong v1.3.14, từ rò rỉ bộ nhớ đến lỗi sập ứng dụng và lỗi hiển thị màu sắc trong văn bản trợ giúp.

Về kích thước, kết hợp việc viết lại bằng Rust, thay đổi ICU và cùng một phép gộp mã, kích thước tệp nhị phân của Bun đã giảm khoảng 20% trên Linux và Windows.

Về hiệu suất, đã được cải thiện tổng thể từ 2% đến 5%. Bun.serve tăng từ 169.600 req/s lên 177.700 req/s, node:http tăng từ 103.800 lên 108.500. Trong các tình huống thực tế, next build giảm từ 13,62 giây xuống 13,03 giây, tsc batch build giảm từ 0,94 giây xuống 0,89 giây.

Sau khi Claude Code được phát hành dựa trên Rust Bun, thời gian khởi động trên Linux đã giảm từ 517ms xuống 464ms, nhanh hơn khoảng 10%.

2 phương pháp: 64 Claude, 11 ngày, 50 quy trình làm việc

Sumner đã làm thế nào để đạt được điều này, có lẽ đây là phần đáng chú ý nhất—vì phương pháp anh ấy sử dụng khác với cách truyền thống “để AI viết mã”.

Sumner đã chia toàn bộ quy trình thành khoảng 50 luồng làm việc động, mỗi luồng là một vòng lặp. Anh ấy đã mô tả mô hình này bằng mã giả trên blog:

Mỗi nhiệm vụ đều có một ngữ cảnh (ví dụ: một vé Jira hoặc vấn đề GitHub), Claude dựa vào ngữ cảnh này để viết mã, sau đó hai người kiểm duyệt (cũng là Claude) xem xét mã, cuối cùng áp dụng phản hồi. Sau khi hoàn thành, tiếp tục xử lý nhiệm vụ tiếp theo.

Mô hình này xuyên suốt toàn bộ quá trình viết lại. Mỗi quy trình làm việc đảm nhiệm một mục tiêu cụ thể:

  • Tạo một hướng dẫn chuyển đổi, ánh xạ các mẫu và kiểu của Zig sang các mẫu và kiểu của Rust;
  • Chuyển đổi từng tệp .zig thành một tệp .rs một cách cơ học, đồng thời khớp với PORTING.md và LIFETIMES.tsv;
  • Sửa lỗi biên dịch cho từng crate;
  • Cho các subcommand như bun test hoặc bun build chạy;
  • Đảm bảo tất cả các bài kiểm tra trong bộ kiểm thử của Bun đều vượt qua; thực hiện vài vòng tái cấu trúc và dọn dẹp lớn.

Trong giai đoạn cao điểm, Sumner đồng thời chạy 4 luồng công việc, mỗi luồng chứa 16 Claude, tổng cộng 64 Claude đang hoạt động song song trên 4 cây công việc, mỗi cái đều gửi và đẩy file. Tại đỉnh điểm, Claude viết khoảng 1.300 dòng mã mỗi phút.

Thiết kế tách biệt giữa “người thực hiện” và “người kiểm duyệt” là then chốt. Claude, người viết mã, muốn mã được chấp nhận — cũng giống như các kỹ sư con người, họ có thiên kiến. Do đó, người kiểm duyệt và người thực hiện được tách biệt hoàn toàn — người kiểm duyệt chỉ xem sự khác biệt của mã, không xem quá trình suy luận của người thực hiện, và được thông báo rõ ràng “giả sử mã là sai”. Mỗi người thực hiện được đối chiếu với hơn hai người kiểm duyệt mang tính đối kháng, và công việc duy nhất của những người kiểm duyệt là tìm lỗi.

Viết xong mã chỉ là bước đầu tiên. Mã Zig là một đơn vị biên dịch duy nhất, trong khi Rust cần chia thành khoảng 100 crate để tăng tốc độ biên dịch, và các phụ thuộc vòng lặp khiến cargo check hiển thị khoảng 16.000 lỗi biên dịch cùng một lúc. Với một người, đây là thảm họa, nhưng với 64 Claude đang làm việc song song, đây là một hàng đợi công việc có thể xử lý được. Quy trình làm việc nhóm các lỗi theo từng crate, chạy cargo check cho từng crate, một Claude sửa lỗi, hai người kiểm duyệt, và một người áp dụng thay đổi.

Tiếp theo là chạy bun --version, sau đó là bun test. Quy trình kiểm thử chạy ngẫu nhiên 100 tệp tin kiểm thử mỗi lần, chia thành 4 nhánh công việc. Bộ kiểm thử cũng bao gồm nhiều loại khác nhau: một số kiểm thử chạy hơn một phút, một số làm cạn kiệt số lượng kết nối TCP của hệ thống, một số fork khoảng 10.000 tiến trình. Sumner sử dụng systemd-run để tạo cgroup nhằm giới hạn tài nguyên, nhưng máy vẫn bị sập nhiều lần do thiếu không gian đĩa.

Sau hai ngày, số bài kiểm tra thất bại trên nền tảng Linux giảm từ 972 xuống còn 23. Sau một ngày rưỡi, Linux đã hoàn toàn xanh. Năm ngày sau, cả sáu nền tảng — Linux x64, Linux arm64, macOS x64, macOS arm64, Windows x64, Windows arm64 — đều vượt qua.

Ngày 14 tháng 5, PR #30412 đã được hợp nhất chính thức, toàn bộ bộ kiểm thử đều vượt qua, không bỏ qua hoặc xóa bất kỳ kiểm thử nào.

3 Nỗi lo ngại: 13.000 dòng mã không an toàn và không thể kiểm tra từng dòng

Tuy nhiên, Sumner cũng thừa nhận rằng công việc này chưa thực sự kết thúc.

Tính đến nay, khoảng 4% mã Rust của Bun nằm trong các khối unsafe, với khoảng 13.000 từ khóa unsafe được phân bố trong khoảng 27.000 dòng mã, trong khi tổng lượng mã Rust là khoảng 780.000 dòng. Trong đó, 78% các khối unsafe chỉ gồm một dòng, thường là một con trỏ từ C++ hoặc một lần gọi đến thư viện C.

Anh ấy dự đoán các lần tái cấu trúc tiếp theo sẽ làm giảm tỷ lệ này. Nhưng có người đã tính toán: uv có khoảng 350.000 dòng mã, chỉ có 73 lần gọi unsafe. Trong khi đó, số lượng unsafe của Bun gấp 178 lần uv. Sự chênh lệch này rất khó giải thích bằng lý do “cần gọi thư viện C”.

Và sau đó còn phơi bày hành vi không xác định trong mã Rust an toàn. Điều này khó gỡ lỗi hơn C++, vì bạn sẽ nghĩ rằng mã an toàn không thể xảy ra sự cố.

Sau đó, nhóm Bun đã thay đổi PathString::init trong vấn đề này thành unsafe fn.

Sumner cũng tự thừa nhận rằng bản viết lại này đã giới thiệu 19 vấn đề hồi quy đã biết và cho biết hầu hết các vấn đề hồi quy đều xuất phát từ mã có cú pháp giống nhau nhưng ngữ nghĩa khác nhau.

Ví dụ, hai đoạn mã này trông rất giống nhau nhưng hành vi lại hoàn toàn khác biệt. Trong Zig, assert là một hàm, do đó các tham số của nó sẽ được thực thi trong mỗi lần biên dịch. Trong Rust, debug_assert! là một macro, vì vậy trong phiên bản phát hành, toàn bộ biểu thức (bao gồm cả lời gọi hàm) sẽ bị xóa bỏ insert_stale.

Mặc dù tất cả các vấn đề đã được sửa, điều này không có nghĩa là hàng triệu dòng mã AI không còn các vấn đề khác.

Ai bình thường lại chuyển ứng dụng sản xuất sang ngay sau khi nó được viết lại hoàn toàn trong lúc chạy? Nếu nghĩ rằng phiên bản 1.4 không引入 thêm bug nào hay không thay đổi hành vi, thì thật ngây thơ.

Một việc không thể bỏ qua là kiểm tra mã nguồn. Việc xem xét 1 triệu dòng thay đổi thực tế không thể thực hiện bởi con người từng dòng—ngay cả khi chỉ mất một phút để xem một dòng, cũng cần liên tục xem trong 11,7 ngày; với tốc độ kiểm tra mã thực tế (200 dòng mỗi giờ), sẽ mất hơn hai năm để xem hết.

Người xem xét PR lần này chủ yếu là claude[bot] và coderabbitai[bot]. Sumner cũng tự thừa nhận rằng cách ông xem xét là “kiểm tra xem agent xem xét đối kháng có phát hiện đúng các khác biệt không, đảm bảo tuân thủ hướng dẫn chuyển đổi, đồng thời tự mình đọc khá nhiều mã nguồn”. Nhưng “khá nhiều” là bao nhiêu, ông không nói rõ.

Một vấn đề khác không thể bỏ qua: Bun đã bị Anthropic mua lại vào tháng 12 năm 2025, và công cụ thực sự có thể duy trì hiệu quả kho mã này cơ bản chỉ có chính Claude. Một số người trong cộng đồng cho rằng điều này đã không còn là một dự án mã nguồn mở theo nghĩa truyền thống nữa—nếu bạn muốn gửi PR cho Bun, bạn phải đăng ký Anthropic, hoặc hy vọng vào vài thành viên cốt lõi đã hiểu rõ mã do AI tạo ra.

165.000 USD đổi lấy một năm công việc, có đáng không?

Sumner cũng tiết lộ trên blog rằng chi phí cho việc viết lại API này khoảng 165.000 đô la, tương đương với khối lượng công việc của 3 kỹ sư trong một năm. Con số này đã gây ra cuộc tranh luận sôi nổi trên Hacker News.

Một số người cho rằng khoản chi này thực sự rất đáng giá. 165.000 đô la Mỹ ở Thung lũng Silicon không thể thuê được nhiều kỹ sư toàn thời gian, huống chi là kỹ sư của các công ty cấp độ Anthropic. Dựa theo dữ liệu lương trên levels.fyi, tổng gói lương của kỹ sư Anthropic rất có thể đạt 500.000 đô la Mỹ hoặc cao hơn. Ngay cả khi tính trung bình 50 kỹ sư với mức lương hàng năm 336.000 đô la Mỹ, thì chi phí mỗi ngày khoảng 1.292 đô la Mỹ. Với 50 người làm việc liên tục trong 11 ngày, chi phí nhân sự đã gần đạt 710.000 đô la Mỹ, chưa kể các khoản phúc lợi, chi phí văn phòng, thiết bị và các chi phí quản lý khác.

Tuy nhiên, Sumner đang sử dụng “bản pre-release của Claude Fable 5”, một mô hình nâng cao chưa được mở rộng cho công chúng và có thể chịu sự kiểm soát xuất khẩu. Do đó, giá API chỉ là con số mà người dùng cuối nhìn thấy, đằng sau đó là chi phí nghiên cứu và phát triển khổng lồ mà Anthropic đã đầu tư. Một số người cũng chỉ ra rằng việc đơn giản hóa chi phí thành giá API là cố tình làm mờ đi mức đầu tư thực tế. Nếu tính cả chi phí phát triển mô hình, chi phí huấn luyện, đầu tư vào năng lực tính toán, nhân lực kỹ thuật, v.v., có thể tin rằng tổng chi phí cuối cùng sẽ rất cao, rất có thể vượt quá 1,5 triệu đô la Mỹ.

Và hiện tại, dù đổi 165.000 USD lấy một năm công việc, về mặt sổ sách thì khá hời.

Nhưng chi phí thực sự không nằm trên hóa đơn này. Kho mã này có 6.778 lần commit, và không một ai đã đọc toàn bộ từ đầu đến cuối. Dù hiện tại mọi thứ đều ổn, nhưng sáu tháng sau thì sao? Khi một vấn đề đồng thời kỳ lạ đột ngột xuất hiện vào lúc 3 giờ sáng, kỹ sư trực ca sẽ phải đối mặt với một hệ thống mà chính anh ta cũng không thể giải thích rõ logic bên trong. Kéo dài về sau, mọi thứ đều phải do AI duy trì — chi phí duy trì được tính thế nào, thực ra rất khó.

Tuyên bố miễn trừ trách nhiệm: Thông tin trên trang này có thể được lấy từ bên thứ ba và không nhất thiết phản ánh quan điểm hoặc ý kiến của KuCoin. Nội dung này chỉ được cung cấp cho mục đích thông tin chung, không có bất kỳ đại diện hay bảo đảm nào dưới bất kỳ hình thức nào và cũng không được hiểu là lời khuyên tài chính hay đầu tư. KuCoin sẽ không chịu trách nhiệm về bất kỳ sai sót hoặc thiếu sót nào hoặc về bất kỳ kết quả nào phát sinh từ việc sử dụng thông tin này. Việc đầu tư vào tài sản kỹ thuật số có thể tiềm ẩn nhiều rủi ro. Vui lòng đánh giá cẩn thận rủi ro của sản phẩm và khả năng chấp nhận rủi ro của bạn dựa trên hoàn cảnh tài chính của chính bạn. Để biết thêm thông tin, vui lòng tham khảo Điều khoản sử dụngTiết lộ rủi ro của chúng tôi.