Bắt đầu "Rỉ Sét" Với Lập Trình

Nếu bạn dành đủ thời gian trên các diễn đàn lập trình như Hacker News, có lẽ bạn đã thấy cái tên "Rust", thường xuất hiện trong các ngữ cảnh châm chọc. Rust là một ngôn ngữ lập trình biên dịch tương đối ngách, nổi bật với hai đặc điểm quan trọng: tốc độ — điều thể hiện rõ qua các bài kiểm tra hiệu năng (benchmarks) khi nó có thể nhanh gấp 10 lần thư viện Python nhanh nhất — và tính an toàn bộ nhớ được thực thi ngay tại thời điểm biên dịch thông qua hệ thống "quyền sở hữu" (ownership) và "vay mượn" (borrowing), giúp giảm thiểu nhiều vấn đề tiềm ẩn. Trong hơn một thập kỷ, khẩu hiệu "Hãy viết lại bằng Rust" (Rewrite it in Rust) đã trở thành một meme, nơi những người ủng hộ lập luận rằng mọi thứ nên được viết lại bằng Rust vì những lợi ích của nó, kể cả những phần mềm cực kỳ lâu đời mà việc viết lại bằng một ngôn ngữ khác là điều bất khả thi. Ngay cả các công ty LLM lớn cũng đang tìm đến Rust để chắt lọc hiệu năng tối đa: Chủ tịch OpenAI Greg Brockman gần đây đã đăng tweet rằng "Rust là ngôn ngữ hoàn hảo cho các agent, vì nếu nó đã biên dịch được thì nghĩa là nó ~đúng", một tuyên bố dù hơi ngớ ngẩn ở góc độ kỹ thuật (vì mã nguồn vẫn có thể sai về mặt logic) — nhưng cho thấy OpenAI rất quan tâm đến Rust. Và nếu họ muốn viết code Rust, họ cần các LLM của mình phải có khả năng lập trình Rust thật tốt.
Bản thân tôi không mấy thành thạo Rust. Rust có một bộ hướng dẫn tương tác cực kỳ xuất sắc, nhưng vấn đề nan giải là có rất ít tài liệu dành cho những người ở trình độ trung cấp: hầu như không có gì nằm giữa khoảng "bài hướng dẫn cơ bản" và "tự viết một hệ điều hành từ con số 0". Đó là câu chuyện của khoảng năm 2020 và tôi đã quyết định chờ xem liệu hệ sinh thái có khắc phục được điểm này hay không (đến năm 2026 thì vẫn chưa), nhưng tôi vẫn theo dõi Hacker News để đọc các bài blog và các thư viện (crates) Rust mới, hy vọng một ngày nào đó mình cũng có thể viết ra những đoạn mã có hiệu năng cao nhất có thể.
Trước đây, các LLM thường rất tệ trong việc tạo mã nguồn Rust do tính chất "ngách" của nó so với Python hay JavaScript. Qua nhiều năm, một trong những bài kiểm tra của tôi để đánh giá các LLM mới là yêu cầu nó viết một ứng dụng tương đối đơn giản như: "Tạo một ứng dụng Rust có thể tạo hình ảnh trực quan hóa dạng 'đám mây từ ngữ' (word cloud) từ một đoạn văn bản dài." Nhưng ngay cả khi không có kiến thức chuyên sâu về Rust, tôi vẫn có thể nhận ra các kết quả trả về quá đơn giản và chỉ được triển khai một nửa, không bao giờ có thể hoạt động được dù có dùng thêm các câu lệnh bổ trợ.
Tuy nhiên, nhờ các phương pháp hậu huấn luyện (post-training) hiện đại, hoàn toàn có khả năng các LLM mới hơn đã được huấn luyện RLHF đặc biệt để viết code Rust tốt hơn bất chấp sự khan hiếm dữ liệu tương đối của nó. Tôi đã chạy thêm nhiều thử nghiệm với Opus 4.5 và sử dụng LLM trong Rust cho một vài dự án nhỏ thú vị, và kết quả thu được tốt hơn nhiều so với mong đợi. Dưới đây là bốn dự án như vậy:

icon-to-image

Là một người chủ yếu làm việc với Python, điều đầu tiên khiến tôi chú ý về Rust là thư viện PyO3: một thư viện cho phép truy cập mã nguồn Rust thông qua Python với tất cả lợi ích về tốc độ và bộ nhớ, trong khi người dùng Python cuối thậm chí chẳng hề hay biết. Lần đầu tôi tiếp xúc với pyo3 là thông qua các bộ mã hóa (tokenizers) tốc độ cao của Hugging Face, nhưng hiện nay nhiều thư viện Python phổ biến cũng sử dụng mô hình này để tăng tốc, bao gồm orjson, pydantic, và thư viện yêu thích của tôi là polars. Nếu các agent LLM giờ đây có thể vừa viết code Rust hiệu năng cao vừa tận dụng được cầu nối pyo3, đó sẽ là một điều cực kỳ hữu ích đối với tôi.
Tôi quyết định bắt đầu với một dự án rất đơn giản: một dự án có thể lấy các biểu tượng (icons) từ một tệp phông chữ biểu tượng (như phông chữ của Font Awesome) và kết xuất (render) chúng thành hình ảnh ở bất kỳ độ phân giải tùy ý nào.
icons_header.webp
Tôi từng thực hiện chính xác dự án này bằng Python vào năm 2021, nhưng nó cực kỳ chắp vá khi phải lôi kéo nhiều gói thư viện khác nhau và rất khó bảo trì. Một phiên bản tốt hơn viết bằng Rust với các ràng buộc (bindings) Python là cách tuyệt vời để thử nghiệm Opus 4.5.
Việc đầu tiên tôi làm là tạo một tệp AGENTS.md cho Rust bằng cách yêu cầu Opus 4.5 chuyển đổi các quy tắc từ Python sang các quy tắc tương đương về mặt ngữ nghĩa trong Rust. Điều này hoạt động khá ổn và bao gồm các đặc thù tiêu chuẩn của Rust: không dùng .clone() để xử lý vòng đời (lifetimes) một cách cẩu thả, không .unwrap() vô tội vạ, không dùng mã nguồn unsafe, v.v. Mặc dù tôi không phải là chuyên gia Rust và không thể khẳng định chắc chắn mã nguồn do agent tạo ra là chuẩn phong cách Rust (idiomatic Rust), nhưng không có đoạn mã Rust nào được trình bày trong bài blog này có dấu vết của "mùi" code tệ. Quan trọng nhất, agent được chỉ thị phải gọi clippy sau mỗi thay đổi lớn — đây là công cụ kiểm tra mã nguồn (linter) nổi tiếng của Rust giúp giữ cho code sạch sẽ, và Opus rất giỏi trong việc thực hiện các gợi ý từ những cảnh báo của công cụ này. Tệp AGENTS.md cho Rust cập nhật nhất của tôi có sẵn tại đây.
Với nền tảng đó, tôi đã xây dựng một "gigaprompt" (câu lệnh khổng lồ) để đảm bảo Opus 4.5 tính toán đến cả bản triển khai Python gốc lẫn một vài ý tưởng mới mà tôi nảy ra, chẳng hạn như supersampling (siêu lấy mẫu) để khử răng cưa cho hình ảnh đầu ra.
Hãy tạo một gói thư viện Rust/Python (thông qua `pyo3` và `maturin`) để kết xuất (render) hình ảnh từ phông chữ biểu tượng (Icon Font) một cách hiệu quả và cực nhanh. Các tệp phông chữ biểu tượng nằm trong thư mục `assets`, và tệp CSS ánh xạ tên biểu tượng với mã tham chiếu tương ứng nằm trong tệp `fontawesome.css`.

Bạn PHẢI tuân thủ TẤT CẢ các ghi chú triển khai SAU ĐÂY:

- Nếu tên biểu tượng có chứa từ `solid`, nó sẽ tham chiếu đến tệp `fa-solid.otf`.
- Có thể kết hợp `fa-brands.otf` và `fa-regular.otf`.
- Gói thư viện PHẢI hỗ trợ Python (thông qua `pyo3` và `maturin`).
- Gói thư viện PHẢI có khả năng xuất hình ảnh đã render dưới định dạng PNG và WEBP đã được tối ưu hóa, với độ phân giải mặc định là 1024 x 1024.
- Việc render hình ảnh PHẢI hỗ trợ siêu lấy mẫu (supersampling) để khử răng cưa cho văn bản và các điểm (mặc định là 2x).
- Gói thư viện PHẢI sử dụng `fontdue` làm phương thức render văn bản.
- Cho phép người dùng chỉ định màu sắc của biểu tượng và màu nền (cả mã Hex và RGB).
- Cho phép sử dụng nền trong suốt.
- Cho phép người dùng chỉ định kích thước biểu tượng và kích thước khung hình (canvas) riêng biệt.
- Cho phép người dùng chỉ định các vị trí neo (anchor positions - theo chiều ngang và chiều dọc) cho biểu tượng so với khung hình (mặc định: chính giữa và chính giữa).
- Cho phép người dùng chỉ định khoảng lệch pixel (offset) theo chiều ngang và chiều dọc cho biểu tượng so với khung hình.

Sau khi hoàn thành việc triển khai cơ bản, bạn PHẢI:

- Viết một bộ kiểm thử Python toàn diện sử dụng `pytest`.
- Viết một tệp Python Jupyter Notebook để hướng dẫn/demo.
- Tối ưu hóa kích thước tệp nhị phân Rust và kích thước gói thư viện Python.
Nó đã hoàn thành nhiệm vụ ngay trong một lần thử (one-shot), đáp ứng tất cả các ràng buộc tính năng phức tạp đã nêu. Yêu cầu "Python Jupyter Notebook" ở cuối chính là cách tôi kiểm tra thủ công xem cầu nối pyo3 có hoạt động hay không, và nó thực sự đã hoạt động mượt mà như một phép màu. Tuy nhiên, có một sai sót là lỗi của tôi: tôi đã ngây thơ chọn thư viện Rust fontdue làm trình render vì nhớ từng xem một bài kiểm tra hiệu năng cho thấy nó nhanh nhất trong việc render văn bản. Thế nhưng, khi thử nghiệm tạo các biểu tượng kích thước lớn, một điểm yếu đã lộ ra: fontdue đạt được tốc độ đó bằng cách chỉ render một phần các đường cong, đây là vấn đề cực lớn đối với các biểu tượng, vì vậy tôi đã yêu cầu bổ sung:
biểu tượng được tạo ra ở độ phân giải cao có dấu hiệu không có đường cong mà thay vào đó là các cạnh rời rạc (có đính kèm ảnh). Hãy kiểm tra trình render font fontdue xem có vấn đề gì ở đó không.

Trong trường hợp không thể khắc phục điều này trong fontdue, hãy thử nghiên cứu sử dụng ab_glyph thay thế."
Opus 4.5 đã sử dụng công cụ Tìm kiếm Web để xác nhận rằng vấn đề này là đặc tính vốn có của fontdue và đã triển khai ab_glyph thay thế, giúp khắc phục hoàn toàn các đường cong.
Dự án icon-to-image hiện đã được mở mã nguồn trên GitHub. Có khoảng 10 câu lệnh tổng cộng để thêm các tinh chỉnh và hoàn thiện, nhưng xuyên suốt quá trình đó, Opus 4.5 chưa bao giờ thất bại trong việc thực hiện nhiệm vụ như đã viết. Tất nhiên, việc tạo hình ảnh biểu tượng bằng Rust-với-bindings-Python nhanh hơn một bậc so với phương pháp chắp vá cũ của tôi, và nhờ trình render văn bản tốt hơn cùng kỹ thuật siêu lấy mẫu (supersampling), nó cũng trông đẹp hơn nhiều so với phiên bản Python tương đương.
Có một điểm cộng và điểm trừ phụ cho quy trình này: vì mã nguồn đã được biên dịch, nó giúp tránh việc phải chỉ định quá nhiều thư viện phụ thuộc (dependencies) trong chính Python; trong trường hợp của gói này, thư viện Pillow để xử lý ảnh trong Python là không bắt buộc và gói Python sẽ không bị lỗi nếu Pillow thay đổi API. Điểm trừ là việc biên dịch mã nguồn Rust thành các tệp Python wheels rất khó để tự động hóa, đặc biệt là cho nhiều hệ điều hành mục tiêu: may mắn thay, GitHub cung cấp các máy ảo (runner VMs) cho quy trình này, và sau một vài lần trao đổi qua lại với Opus 4.5, tôi đã tạo được một GitHub Workflow tự động chạy bản build cho tất cả các hệ điều hành mục tiêu khi phát hành (publish), vì vậy tôi không cần tốn thêm chút công sức nào nữa.

Tạo Đám mây từ ngữ (Word Clouds) ngay trên trình duyệt

Khi tôi dùng dự án "đám mây từ ngữ" (word cloud) bằng Rust làm bài kiểm tra năng lực hiểu biết về Rust của LLM, tôi thực sự có một động cơ kín đáo: Tôi rất thích biểu đồ đám mây từ ngữ. Quay lại năm 2019, tôi đã phát hành một gói thư viện Python mã nguồn mở tên là stylecloud: một thư viện được xây dựng dựa trên gói word cloud của Python, nhưng được bổ sung khả năng thêm các dải màu (gradient) đa dạng và các mặt nạ (masks) dựa trên biểu tượng để dễ dàng tạo hình cho đám mây từ ngữ (nghe quen thuộc chứ?).
stylecloud_banner_hu10339034291971611939.webp
Tuy nhiên, stylecloud vốn khá chắp vá và dễ lỗi, và một số tính năng tôi muốn thêm vào như xoay chữ theo các góc không phải 90 độ, nền trong suốt và xuất file SVG là hoàn toàn bất khả thi do nó phụ thuộc vào wordcloud/matplotlib của Python; hơn nữa gói này còn rất chậm. Cách duy nhất để thêm các tính năng tôi muốn là xây dựng lại mọi thứ từ đầu: và Rust chính là lựa chọn phù hợp nhất.
Quy trình thực hiện rất giống với dự án icon-to-image ở trên: yêu cầu Opus 4.5 đáp ứng một danh sách dài các ràng buộc kèm theo các bộ cài đặt (bindings) cho Python. Nhưng còn một thứ khác tôi muốn thử nghiệm mà nếu thành công sẽ cực kỳ hữu ích: xuất bản dưới dạng WebAssembly (WASM) thông qua wasm-bindgen. Mã nguồn Rust được biên dịch sang WASM cho phép nó chạy trên bất kỳ trình duyệt web hiện đại nào mà vẫn giữ nguyên lợi thế về tốc độ: không cần cài đặt thêm thư viện phụ thuộc, và do đó sẽ không lo bị lạc hậu trong tương lai.
Tuy nhiên, có một vấn đề: tôi sẽ phải thiết kế một giao diện, mà tôi thì không phải là dân chuyên front-end. Tôi nói không hề quá lời rằng đối với tôi, việc thiết kế dù chỉ là một giao diện HTML/CSS/JS đơn giản cho một dự án còn căng thẳng hơn cả việc huấn luyện một AI. Thế nhưng, Opus 4.5 có khả năng tiếp nhận các hướng dẫn chung và biến chúng thành một thứ gì đó dùng được: đầu tiên tôi bảo nó dùng Pico CSS và JavaScript thuần, thế là đã đủ ổn rồi, nhưng sau đó tôi nảy ra ý tưởng bảo nó dùng shadcn/ui — một framework thiết kế tối giản thường dành cho Web Components — kèm theo các ảnh chụp màn hình từ trang web đó làm ví dụ. Và kết quả là nó cũng hoạt động hoàn hảo.
wordcloud_rust_ui.webp
Sau nhiều lần trao đổi qua lại về các chi tiết thiết kế tỉ mỉ và thêm thắt tính năng, gói thư viện này đã hoàn thiện về mặt chức năng. Tuy nhiên, nó vẫn cần được trau chuốt thêm và một thiết kế độc đáo hơn trước khi tôi có thể phát hành chính thức, và tôi đã bị xao nhãng bởi một thứ khác có sức ảnh hưởng lớn hơn…

miditui

"Tạo một trình phát nhạc ngay trong terminal bằng Rust" là một bài kiểm tra áp lực khác về Rust mà tôi dành cho các LLM: terminal dòng lệnh thì làm sao phát được âm thanh, đúng không? Hóa ra là có thể, nhờ thư viện rodio. Với những thành công từ trước đến nay cùng Opus 4.5, tôi quyết định tăng độ khó cho các nhiệm vụ: terminal có thể phát âm thanh, nhưng liệu nó có thể sáng tác âm thanh không? Vì vậy, tôi đã yêu cầu Opus 4.5 tạo ra một bộ soạn thảo nhạc MIDI và một trạm làm việc âm thanh kỹ thuật số (DAW) để phát nhạc ngay trong terminal, và nó đã hoạt động. Việc thêm các tính năng mới đã buộc tôi phải tìm hiểu thêm về cách thức hoạt động thực sự của MIDI và SoundFonts, vì vậy đây cũng là một trải nghiệm mang tính giáo dục rất cao!
miditui.webp
miditui hiện đã được mở mã nguồn trên GitHub, và các câu lệnh (prompts) được sử dụng để xây dựng nó có thể tìm thấy tại đây.
Trong quá trình phát triển, tôi đã gặp phải một trở ngại: Opus 4.5 không thể chạy thử hay quan sát kết quả đầu ra của terminal, đặc biệt là với một ứng dụng có các yêu cầu chức năng khác thường. Tuy nhiên, dù "mù" về mặt hình ảnh, nó vẫn hiểu biết đủ sâu về framework terminal ratatui để triển khai bất kỳ thay đổi giao diện (UI) nào mà tôi yêu cầu. Có một số lượng lớn lỗi giao diện xuất hiện, nguyên nhân có lẽ là do Opus không có khả năng tự tạo ra các kịch bản kiểm thử (test cases), cụ thể là việc không tính toán đúng khoảng cuộn (scroll offsets) dẫn đến việc xác định sai vị trí nhấp chuột. Với tư cách là một người từng có 5 năm làm Kỹ sư Kiểm thử Phần mềm (QA) theo phương pháp "hộp đen" (black box) — người không thể xem mã nguồn bên dưới — tình huống này chính là sở trường của tôi. Tôi đã vận dụng kỹ năng QA của mình bằng cách "vọc" miditui, báo cho Opus bất kỳ lỗi nào kèm theo ảnh chụp màn hình thỉnh thoảng, và nó đã có thể sửa chúng một cách dễ dàng. Tôi không tin rằng những lỗi này là do các agent LLM giỏi hơn hay kém hơn con người, bởi con người chắc chắn cũng có thể mắc phải những sai lầm tương tự. Ngay cả khi bản thân tôi rất thành thạo trong việc tìm lỗi và đưa ra giải pháp, tôi không tin rằng mình có thể tránh khỏi việc gây ra các lỗi tương tự nếu tự tay lập trình một ứng dụng tương tác như vậy mà không có sự trợ giúp của AI: bộ não của dân QA khác với bộ não của kỹ sư phần mềm.

ballin

Vào một đêm — sau khi nhâm nhi một ly vang — tôi lại nảy ra một ý tưởng khác: một kỹ thuật hiện đại với ASCII art là sử dụng các ký tự unicode Braille (chữ nổi) để cho phép hiển thị chi tiết cực cao. Điều đó gợi nhắc tôi về các mô phỏng vật lý bóng nảy, vậy tại sao không xây dựng một trình mô phỏng vật lý đầy đủ ngay trong terminal? Vì vậy, tôi đã yêu cầu Opus 4.5 tạo ra một trình mô phỏng vật lý terminal sử dụng engine vật lý 2D rapier kèm theo lời giải thích chi tiết về kỹ thuật dùng ký tự Braille: lần này Opus đã làm tốt hơn và hoàn thành ngay trong một lần thử, vì vậy tôi đã dành thêm thời gian để khiến nó trở nên đầy màu sắc và thú vị hơn. Tôi từng bi quan nghĩ rằng engine này chỉ có thể xử lý được vài trăm quả bóng: nhưng thay vào đó, mã nguồn Rust này có thể xử lý hơn 10.000 quả bóng logic cùng lúc!
ballin.webp
ballin hiện đã được mở mã nguồn trên GitHub, và các câu lệnh dùng để xây dựng nó có tại [đây].
Thư viện rapier cũng vừa đăng một bài blog làm nổi bật một thay đổi lớn trong engine tính toán cốt lõi của nó ở phiên bản 0.32.0, vì vậy tôi đã yêu cầu Opus 4.5 nâng cấp lên phiên bản đó... và nó đã gây ra lỗi treo chương trình (crashes). Tuy nhiên, khi truy vết lỗi thì thấy nó bắt nguồn từ chính rapier. Việc hạ cấp về bản 0.31.0 lại hoạt động bình thường không chút trục trặc. Một hệ quả của việc chỉ sử dụng lập trình bằng agent cho quy trình này là tôi không thể tự xây dựng một kịch bản lỗi tối giản (minimal reproducible test case) để gửi báo cáo lỗi (bug report), hoặc không thể phân định được đó là lỗi hệ thống hay là tác dụng phụ của một API mới mà Opus 4.5 chưa biết rõ.
Bài học lớn nhất mà tôi rút ra được khi thực hiện các dự án này là: các agent hoạt động tốt nhất khi bạn có kiến thức khái quát về nhiều thứ, kèm theo đủ chuyên môn trong lĩnh vực đó để biết cái gì nên và không nên hoạt động. Opus 4.5 đủ giỏi để cuối cùng cho phép tôi thực hiện các dự án phụ — nơi tôi biết chính xác mình muốn gì nhưng không nhất thiết phải biết cách triển khai nó. Những dự án cụ thể này không phải là "Điều Kỳ Diệu Tiếp Theo" (Next Big Thing™) để biện minh cho sự tồn tại của một ngành công nghiệp đang ngốn hàng tỷ đô la vốn đầu tư mạo hiểm, nhưng chúng làm cho cuộc sống của tôi tốt đẹp hơn, và vì chúng là mã nguồn mở, hy vọng chúng cũng giúp ích cho ai đó. Tuy nhiên, tôi vẫn muốn thúc đẩy các agent thực hiện những điều có tác động lớn hơn nữa trong một lĩnh vực xứng đáng hơn.
Nguồn bài viết từ Tác giả Minimaxir