- Tác nhân LLM mạnh trong việc sinh mã từ đặc tả lỏng, nhưng vẫn còn yếu khi phải tuân thủ các ràng buộc mà backend cấp độ production yêu cầu như hợp đồng API, kiến trúc, DB và ORM
- Cố định yêu cầu chức năng bằng cùng một đặc tả OpenAPI, và áp dụng cùng một bộ kiểm thử hành vi cho 80 bài toán greenfield và 20 bài toán triển khai tính năng trên 8 framework web
- Các ràng buộc phi chức năng được chia thành 4 chiều: lựa chọn framework, mẫu kiến trúc, backend cơ sở dữ liệu và tích hợp ORM, để tách riêng ảnh hưởng của độ phức tạp cấu trúc
- Constraint decay là hiện tượng hiệu năng giảm mạnh khi các yêu cầu cấu trúc tích lũy; trong các bài toán được đặc tả đầy đủ với cấu hình cao, assertion pass rate giảm trung bình 30 điểm
- Cốt lõi của thất bại là lỗi ở tầng dữ liệu; việc xây dựng truy vấn sai và vi phạm ORM lúc runtime chiếm khoảng 45% số lần thất bại logic của tác nhân
Vấn đề cốt lõi và thiết lập đánh giá
- Tác nhân LLM mạnh trong sinh mã tự động với đặc tả lỏng, nhưng năng lực tuân thủ nghiêm ngặt các ràng buộc cấu trúc cần thiết cho phần mềm backend cấp độ production vẫn chưa được đánh giá đầy đủ
- Backend cấp production không chỉ cần các endpoint tuân theo hợp đồng API mà còn phải đáp ứng các yêu cầu ngoài chức năng như mẫu kiến trúc, tích hợp cơ sở dữ liệu và tầng ORM được chỉ định
- Nhiều benchmark trước đây vẫn thưởng cho các lời giải đúng về mặt chức năng nhưng tùy ý về mặt cấu trúc, nên chưa phản ánh đầy đủ độ khó của phát triển backend nhiều file có ràng buộc
- Các nghiên cứu trước chủ yếu tập trung vào việc xử lý các issue cụ thể trong codebase có sẵn, sinh mã không ràng buộc từ prompt ngôn ngữ tự nhiên, lời giải một file hoặc hoàn thiện skeleton code, và chưa xem xét tác động của việc thay đổi có hệ thống mức độ ràng buộc cấu trúc
- Tác động của độ phức tạp cấu trúc được tách riêng bằng cách cố định yêu cầu chức năng bằng cùng một đặc tả OpenAPI và áp dụng cùng một bộ kiểm thử hành vi end-to-end cho mọi điều kiện
- Thí nghiệm gồm 80 bài toán sinh mới greenfield và 20 bài toán triển khai tính năng trên 8 framework web
- Các ràng buộc phi chức năng được chia thành 4 chiều: lựa chọn framework, mẫu kiến trúc, backend cơ sở dữ liệu và tích hợp ORM
- Ở điều kiện cơ sở, chỉ cung cấp cùng một đặc tả API; còn ở điều kiện có ràng buộc, các yêu cầu như clean architecture, PostgreSQL và SQLAlchemy được thêm vào
- Đánh giá kết hợp kiểm thử hành vi end-to-end với trình kiểm tra tĩnh để tách biệt độ chính xác chức năng và mức độ tuân thủ cấu trúc
Kết quả chính và ý nghĩa
- Constraint decay được xác nhận là hiện tượng hiệu năng của tác nhân giảm đáng kể khi các yêu cầu cấu trúc được tích lũy
- Ngay cả những cấu hình có hiệu năng cao cũng giảm trung bình 30 điểm assertion pass rate khi đi từ điều kiện cơ sở sang bài toán được đặc tả đầy đủ; một số cấu hình yếu gần như về 0
- Ngay cả với cùng một hợp đồng API, tỷ lệ thành công khác biệt lớn theo framework; tác nhân hoạt động tốt hơn trên các framework nhẹ và tường minh như Flask
- Trong các môi trường nhiều quy ước như FastAPI và Django, hiệu năng trung bình thấp hơn đáng kể
- Phân tích lỗi cho thấy lỗi ở tầng dữ liệu là nguyên nhân chính, tiêu biểu là việc xây dựng truy vấn sai và vi phạm ORM lúc runtime
- Lỗi tầng dữ liệu được phân loại là nguyên nhân cốt lõi gây ra khoảng 45% số lần thất bại logic của tác nhân
- Việc đồng thời đáp ứng yêu cầu chức năng và yêu cầu cấu trúc vẫn là một bài toán quan trọng chưa được giải quyết đối với các tác nhân lập trình
- Pipeline đánh giá, bộ bài toán, quỹ đạo thực thi của tác nhân và các script phân tích được công bố tại constraint-decay
1 bình luận
Ý kiến trên Hacker News
Trước đây tôi hoàn toàn hoài nghi về việc tạo mã bằng LLM, nhưng giờ thì hơn 80% lượng mã tôi dùng trong công việc là mã được tạo ra
Tuy vậy, các giới hạn cũng đã trở nên khá rõ ràng, bắt đầu lộ ra ở một số dự án, và bài viết này dường như xác nhận nghi ngờ của tôi
Công việc càng phức tạp thì lại càng phải liên tục thêm ràng buộc vào đặc tả Markdown, quy tắc, kỹ năng, style guide, điều kiện biên, xử lý lỗi và hướng dẫn tối ưu hóa
Đến một lúc nào đó, nó trông như đang chuyển độ phức tạp từ thế giới hình thức và mang tính quyết định của ngôn ngữ lập trình sang thế giới phi hình thức và phi quyết định của ngôn ngữ tự nhiên
Tốc độ viết tăng lên cực lớn, và doanh nghiệp dĩ nhiên xem đó là tăng năng suất, nhưng cái giá phải trả thì rất rõ, chỉ là nhiều người có vẻ phớt lờ
Không ai rà soát 100%, mà ngay cả khi có rà soát thì cũng rất chủ quan
Khó mà phân biệt rõ giữa “hãy theo cách tiếp cận RESTful”, “chúng tôi dùng REST chứ không dùng GraphQL”, và “90% endpoint là định hướng tài nguyên nhưng một số cái trông giống RPC nên cứ bỏ qua”
Tất cả trông khá ngớ ngẩn
Về thực chất là compile các chương trình đầy hành vi không xác định, nhưng phần lớn lại “trông như hoạt động”
Việc doanh nghiệp xem đây là tăng năng suất khiến tôi có cảm giác chúng ta đang quay lại thời kỳ đo “năng suất” bằng số dòng mã mỗi giây
Khi codebase vượt ra ngoài mức có thể nằm trong 20% đầu của cửa sổ ngữ cảnh để được xử lý hoàn toàn bằng một lần suy luận có thể lặp lại, thì execution harness và kỹ thuật vá mã trở nên quan trọng hơn nhiều
Cách làm apply_patch mà OAI đã tinh chỉnh cho model có vẻ là phương án tốt nhất cho codebase siêu lớn
Những cách dựa trên phạm vi dòng hoặc tìm-thay đơn giản sẽ sụp đổ ở rìa, và để xử lý các ca khó như file cshtml thì cần nhiều neo không gian
Cơ chế prepare/commit là lý tưởng để lặp lại ngữ cảnh mơ hồ trên nhiều tệp lớn và tinh chỉnh các neo
LLM không thể tạo ra điều gì thực sự mới
“Nghiên cứu có hệ thống cho thấy hiện tượng suy giảm ràng buộc trong các tác nhân lập trình dựa trên LLM. Các model hiện tại rất giỏi ở việc sinh ra nội dung không có ràng buộc, nhưng hiệu năng giảm khi phải tuân theo các quy tắc kiến trúc tường minh. Với người dùng cuối, sự phân đôi này có nghĩa là các tác nhân đáng tin cho tạo mẫu nhanh, nhưng vẫn khó tin cậy cho phát triển backend cấp độ production.”
Điểm yếu lớn của nghiên cứu này là do vấn đề chi phí nên họ chưa thử nghiệm đủ với các model tuyến đầu, vì vậy cần thận trọng khi nhìn vào các con số hiệu năng cụ thể
Dù vậy, kết luận rằng hiệu năng model giảm khi vừa phải đúng về hành vi vừa phải đúng về kiến trúc vẫn rất đáng chú ý và đáng tiếp tục theo dõi
Nếu chỉ có yêu cầu chức năng thì về bản chất là đang làm tổng hợp chương trình, và học tăng cường có thể tối ưu việc này rất mạnh
Khi trộn yêu cầu chức năng với yêu cầu phi chức năng, về thực chất là đang đưa cho model một đặc tả không đầy đủ, và model sẽ phải phần nào đoán ý người dùng để lấp chỗ trống
Đây cũng là lý do việc đưa ví dụ về style mã mong muốn vào prompt lại mạnh đến vậy
Càng có nhiều tài liệu để tham chiếu, nó càng phụ thuộc vào việc lặp lại những gì đã xuất hiện trước đó
Cũng có thể là các tác giả càng về các chương sau càng ít chú ý hơn và bỏ ít công sức biên tập hơn
Trên Amazon có số lượng khổng lồ, nhưng LLM vẫn chưa ở mức viết tốt
Khi nó đưa ra các giải pháp không tương thích và tôi bổ sung thêm ngữ cảnh cùng yêu cầu, nó có xu hướng bị cố định vào kiến trúc ban đầu và rất khó thích nghi
Đôi khi nó còn cố lén nhét vào các thay đổi để phục vụ kế hoạch ban đầu
Có vẻ như những mảng lớn trong không gian lời giải khả dĩ trở nên không thể tiếp cận
Ví dụ, khoảng một năm trước khi áp guardrail lên trình tạo ảnh thì mọi người bắt đầu trông giống nhau, còn trình tạo truyện thì bắt đầu chỉ dùng vài cái tên tiêu chuẩn
Tôi tò mò liệu chuyện này có còn xảy ra ngay cả với các model tuyến đầu hiện nay hay không
Tôi không quá quan tâm đến việc phân tích điểm yếu của các model kiểu này. Theo kinh nghiệm của tôi, khi model mạnh hơn và tăng mức nỗ lực suy luận thì nhiều điểm yếu sẽ biến mất hoàn toàn
Đặc biệt là khi bạn nói rõ hành vi mong muốn, và việc tỷ lệ thất bại tăng lên khi tiêu chí chấp nhận nhiều hơn thì không có gì đáng ngạc nhiên
Tình hình còn tệ hơn. Tác nhân không chỉ gặp khó hơn dưới các “ràng buộc cấu trúc”, mà còn tệ hơn nữa khi chính các ràng buộc cấu trúc đó cần phải thay đổi
Khi thiết kế hệ thống hay thành phần, chúng ta đặt ra những ý tưởng làm bất biến
Có bất biến lớn như kiến trúc tổng thể, cũng có bất biến nhỏ như lựa chọn cấu trúc dữ liệu
Nhưng rồi cuối cùng cũng đến lúc ta muốn thêm một tính năng xung đột với những bất biến đó
Khi ấy thường có ba lựa chọn: không thêm tính năng, chồng tính năng lên trên các bất biến một cách kém thanh lịch hoặc kém hiệu quả, hoặc quay lại thay đổi các bất biến
Thường thì chỉ một trong số đó là đúng, và ít nhất một lựa chọn sẽ sai rất nghiêm trọng, dẫn đến kết quả tệ
Tác nhân, ngay cả khi có thể tuân thủ ràng buộc, vẫn cực kỳ kém trong việc nhận ra thời điểm cần thay đổi ràng buộc
Đây là một trong những ranh giới giữa nhận diện mẫu và suy luận, và trái với các tuyên bố marketing về chuỗi suy nghĩ, LLM thực ra không hề suy luận chút nào
Mọi nỗ lực khiến nó trông như đang suy luận, theo tôi, gần giống với việc harness cố gắng nhốt tia chớp vào trong chai bằng những nỗ lực cô lập đệ quy
Điều này làm tôi nhớ đến một bài báo gần đây giao nhiều tác vụ chỉnh sửa tài liệu ở nhiều lĩnh vực cho LLM https://arxiv.org/abs/2604.15597
Bài đó cho rằng lập trình là lĩnh vực duy nhất mà phần lớn LLM có thể thực hiện tác vụ đường chân trời dài mà không tích lũy lỗi và phá hỏng tài liệu
Tôi mới chỉ đọc phần tóm tắt của bài này, nhưng có vẻ nó xem xét kỹ hơn việc lập trình và cho thấy hiện tượng tương tự
Tuy vậy, có vẻ nó gần với một “đường chân trời phong cách dài” đối với một bó ràng buộc cấu trúc lớn hơn hơn là tác vụ đường chân trời dài
Thảo luận liên quan: https://news.ycombinator.com/item?id=48073246
Đây là một bài báo rất thú vị và tôi hoàn toàn đồng ý, nhưng tôi không nghĩ đó là điều mới mẻ
Ngay từ kỳ vọng ban đầu rằng chỉ cần thả một giải pháp coding kiểu agent vào dự án và ném cho nó danh sách công việc thì nó sẽ thần kỳ tuân theo các ràng buộc được định nghĩa sẵn của dự án đã hơi lệch rồi
Tôi không tin có stack coding kiểu agent nào có thể làm được điều này ở trạng thái mặc định
Để agent hiểu ngữ cảnh, ràng buộc và mục tiêu một cách ổn định thì vẫn cần những cơ chế phù hợp, và việc các phòng lab AI lớn liên tục cập nhật công cụ·kỹ năng·quy trình cho thấy đây vẫn là một lĩnh vực đang tiến triển
Lớp bổ sung này có thể còn sinh lợi hơn nhiều so với bản thân mô hình thuần túy và mức tiêu thụ token
Tôi nghĩ ngay cả những mô hình mở có vẻ như đã được thử nghiệm hiện nay, nếu vận hành đúng cách, cũng đã có thể tạo ra mã production tuân theo các ràng buộc mong muốn
Tôi tò mò không biết mã production của mọi người trong vài tháng gần đây ra sao
Tôi đã thử nghiệm khá nhiều với coding kiểu agent đường chân trời dài https://medium.com/@vishvananda/i-spent-2-billion-tokens-wri..., và cũng thấy rằng việc ép buộc các mẫu kiến trúc cụ thể có thể làm hiệu năng của agent kém đi
Nếu đưa các ràng buộc vào trong quá trình thực hiện thay vì thêm vào sau thì có khá hơn một chút
Có một tác dụng phụ mà tôi gọi là vôi hóa: khi một mẫu nào đó bắt đầu xuất hiện trong codebase, agent sẽ bám theo mẫu đó, rồi nó chi phối ngữ cảnh và tự củng cố
Trong codebase hiện có, điều này có thể là điểm mạnh hoặc điểm yếu tùy vào chất lượng mã
Có lẽ sẽ có thêm nhiều insight hơn khi các lần chạy trên codebase mới với hướng dẫn kiến trúc ngay từ đầu hoàn tất
Ngoài ra, mô hình mô-đun hóa khá ổn khi nó còn khoảng trống để “lập kế hoạch” cho việc triển khai, nhưng hiếm khi tự kết luận rằng về sau nên trừu tượng hóa để có lợi
Điều này đặc biệt đúng sau nhiều vòng lặp trên codebase mới hoặc khi được đưa vào codebase legacy, và thường dẫn tới các file khổng lồ
Khi người dùng chỉ ra điều đó thì mô hình phê bình rất đúng, nhưng khá buồn cười vì đó lại là chính đoạn mã nó đã viết
Nghe như một phiên bản khác của chuyện “chat càng dài thì guardrail càng mờ đi”
Lý do không thể dùng hết cửa sổ ngữ cảnh là vì ở phần cuối, đầu ra không còn tuân thủ ràng buộc hay guardrail nữa
Nhưng để tạo mã cấp production một cách ổn định, mô hình phải có nhận thức rộng, và điều đó nhanh chóng lấp đầy cửa sổ ngữ cảnh
Nó giống như nói “hãy ghi nhớ mọi thứ trong 6 thư mục này và thực hiện thay đổi này”, nhưng chỉ riêng việc ghi nhớ mọi thứ thôi cũng đã làm đầy cửa sổ ngữ cảnh và khiến nó mất khả năng tuân thủ ràng buộc
Tuy vậy, khi đó kiểu thất bại có lẽ sẽ chuyển sang việc nó tập trung vào làm hài lòng linter rồi dần quên mất yêu cầu
Việc lặp lại thử/thất bại cũng sẽ hoàn toàn không tốt cho ngữ cảnh
Nghiên cứu này dùng các ngôn ngữ kiểu động như Python và JS
Theo kinh nghiệm của tôi, codebase kiểu tĩnh dễ bảo trì hơn cho con người, nên có thể cũng như vậy với agent
Khi dùng Codex hoặc Claude Code trên mã Go, tôi đã vô số lần thấy agent sửa đổi, chạy build để tìm lỗi, rồi sửa tiếp
Dạo này các mô hình xử lý type của Python khá tốt
Trong Python, kiểu tĩnh mạnh đã là một lựa chọn từ vài năm nay, và đơn giản là nó nên trở thành mặc định
Bài viết nói “các tác vụ trải trên 8 web framework”, nên tôi tò mò không biết có ai cũng có trải nghiệm rằng LLM làm HTML+CSS+JS thuần tốt hơn là làm trên framework sẵn có không
Tổ hợp ấn tượng nhất tôi thấy gần đây là Razor Pages với progressive enhancement bằng JavaScript
Trong cấu hình này, các mô hình mới nhất phân biệt khá tốt việc gì nên diễn ra ở phía server (
cshtml) và việc gì nên diễn ra ở phía client (js)Tôi khuyên nên bỏ thời gian chỉnh một vài phần của codebase về dạng thành ngữ trước, rồi chỉ định các file đó bằng @ làm file ví dụ
Cách này hiệu quả hơn rất nhiều so với cố điều khiển bằng Markdown
Với các thứ như FastAPI thì khá ổn, nhưng JavaScript có vẻ là tệ nhất
Ngay cả khi có chỉ dẫn và ví dụ, nó vẫn có xu hướng nhét hàng đống mã vô ích inline thay vì dùng API đã được chỉ định