Code rác do AI: thiết kế vòng lặp, không phải may rủi
TL;DR
- Hai kỹ sư dựng cùng một vòng lặp và nhận kết quả trái ngược: một người nhanh hơn trên hệ thống họ hiểu, người kia thôi không còn hiểu hệ thống nữa. Vòng lặp không biết phân biệt, bạn thì có.
- Ba kịch bản thất bại (failure mode) mà vòng lặp khuếch đại: giả-xong khi không người trông (“xong” là một tuyên bố, không phải bằng chứng), nợ hiểu biết (comprehension debt) khi mô hình hệ thống trong đầu bạn mục dần vì vòng lặp ship code bạn không viết, và đốt token (subagent, lần chạy rỗng, lặp vô hạn).
- Ngăn code rác do AI là chuyện thiết kế vòng lặp, không phải may rủi. Phương thuốc là một nghi thức rà soát bạn chạy sau mỗi lần vòng lặp chạy, cộng ba giới hạn mọi vòng lặp đều cần: số vòng lặp, chi phí, thời gian.
Hai kỹ sư cùng nhân bản (clone) một kho code (repo). Cùng cấu hình vòng lặp, cùng mô hình AI (model), cùng điều kiện dừng. Sáu tuần sau, người thứ nhất ship nhanh hơn trên một hệ thống cô ấy hiểu rõ hơn lúc bắt đầu. Người thứ hai ship nhanh hơn trên một hệ thống anh ta không còn hiểu chút nào. Cả hai trường hợp, vòng lặp đều làm đúng điều được giao. Đó mới là chỗ đáng lo.
Người ta hay đóng khung chuyện ngăn code rác (AI slop) thành vấn đề của mô hình AI, hoặc vấn đề của prompt. Không phải cái nào cả. Khác biệt giữa hai kỹ sư kia không nằm ở vòng lặp. Nó nằm ở chuyện ai vẫn còn là kỹ sư.
A loop is a recursive goal: you define a purpose and a verifiable stop condition, and the system iterates agents against it until the condition holds — without you prompting each turn.
Đây là phần kết của một loạt bài mở ra, chín phần trước, bằng một lời hứa: cùng một vòng lặp vừa nhân đòn bẩy cho kỹ sư cẩn thận vừa nhân code rác cho kỹ sư cẩu thả, và vòng lặp không tài nào phân biệt được. Nơi loạt bài này bắt đầu đã nêu lời hứa đó trong một câu rồi gác lại phần chứng minh. Phần này là phần chứng minh. Luận điểm, nói thẳng không rào đón: thiết kế vòng lặp khó hơn prompt engineering, chứ không dễ hơn. Một prompt tồi hỏng ngay trước mắt bạn. Một vòng lặp tồi hỏng trong lúc bạn ngủ.
Vòng lặp chạy một mình cũng là vòng lặp hỏng một mình
Chạy không người trông là cả mục đích của vòng lặp, và cũng là rủi ro sắc nhất của nó. Khi không ai nhìn lần chạy, “xong” là bất cứ điều gì bên thợ tự nhận, mà bên thợ là người chấm điểm rộng rãi nhất toà nhà. Anthropic ghi nhận “premature victory” và các tính năng giả-xong trong hướng dẫn của họ về harness hiệu quả cho agent chạy dài. Đó là danh sách kịch bản thất bại của chính nhà cung cấp, không phải lời than của một người chỉ trích.
Rồi tới bằng chứng từ một lần chạy thật. Trong một vòng lặp sửa lỗi của chính chúng tôi, một lỗi (BUG-003) đóng ở tầng cao nhất, FULL. Đọc bản tóm tắt lần chạy thì bức tranh phức tạp một cách trung thực: lần chạy tự gắn cờ những chỗ nó đi lệch. Console không sạch (ba lỗi HTTP 404 không liên quan). Bản dựng prod-faithful dùng làm phương án dự phòng bị chặn bởi một lỗi ảnh không liên quan. Thế nên vòng lặp đóng lỗi dựa trên kiểm tra computed-style đúng tầng, và ghi lại các khoảng hở (GAP-A, GAP-B, GAP-C) thay vì lấp liếm cho qua.
Bài học không phải “vòng lặp nói dối”. Vòng lặp đã báo cáo. Một con người vẫn phải đọc báo cáo đó mới biết FULL thực sự nghĩa là gì trong lần chạy ấy. Một điều kiện dừng chỉ là tuyên bố cho tới khi một con người, hoặc một mô hình AI khác, kiểm lại. Định nghĩa kinh điển ở trên đặt cả sức nặng lên một từ chịu lực: verifiable, kiểm chứng được. Bỏ phần kiểm chứng đi thì vòng lặp chỉ là dựng nhanh hơn, hỏng nhanh hơn với người rà soát cuối cùng bị đẩy khỏi phòng.
Điểm mấu chốt: “Xong” là một tuyên bố vòng lặp đưa ra mà con người vẫn phải đọc lại. Anthropic liệt kê premature victory và tính năng giả-xong là kịch bản thất bại đã ghi nhận, đúng vì một điều kiện dừng không kiểm chứng được sẽ hỏng trong im lặng.
Nợ hiểu biết: code ra đều, mô hình trong đầu bạn thì không
Mỗi thay đổi do vòng lặp viết mà bạn merge khi chưa hiểu là một khoản vay đặt lên mô hình hệ thống trong đầu bạn. Lãi trả vào đúng ngày bạn phải gỡ lỗi (debug) nó. Nợ hiểu biết (comprehension debt) là khoảng cách ngày một rộng giữa những gì hệ thống của bạn làm và những gì bạn hiểu là nó làm, và vòng lặp nới khoảng cách đó nhanh hơn làm tay vì nó ship nhiều hơn, nhanh hơn, với ít phần bạn hơn trong mỗi dòng.
Đặt cạnh nợ kỹ thuật (technical debt) để thấy rõ. Bạn thường biết nợ kỹ thuật nằm đâu, vì bạn đã tạo phiếu việc (ticket), đã để lại ghi chú (comment). Nợ hiểu biết thì vô hình cho tới khi bạn đi tìm, mà bạn chỉ đi tìm khi có thứ gì đó vỡ. Lúc ấy vòng lặp đã ship cả trăm thay đổi bạn liếc qua rồi duyệt.
Thuốc giải mang tính cấu trúc không phải “rà soát kỹ hơn”. Nó là giữ một con người ở ghế merge ngay từ thiết kế. Vòng lặp thủ công trưởng thành nhất của chúng tôi, vòng lặp dựng thành phần (component) thiết kế, có 10 lần chạy đã kiểm chứng sau các chốt chặn xanh thật (vitest 650/650, bộ kiểm đặc tả (spec) của bộ công cụ (toolkit) 65/65, chạy lại độc lập), vậy mà vẫn kết mỗi dòng trong file lưu trạng thái bằng “Nothing merged, Ethan merges”. Chốt chặn đó không phải thủ tục hành chính. Nó là điểm kiểm hiểu biết. Căng thẳng trung thực, và là điều đáng ngồi lại nghĩ: càng tin vòng lặp, bạn càng thấy hấp dẫn chuyện bỏ chốt chặn ấy đi. Đúng khoảnh khắc bạn bỏ, nợ hiểu biết bắt đầu dồn lại trong bóng tối.
Điểm mấu chốt: Vòng lặp trưởng thành nhất chúng tôi chạy vẫn giữ một con người merge từng diff ngay từ thiết kế (10 lần chạy đã kiểm chứng, chốt chặn xanh, “Nothing merged, Ethan merges” ở mọi dòng). Chốt merge là điểm kiểm hiểu biết, không phải rào cản giấy tờ.
Vòng lặp đốt token ở đâu, và ba giới hạn cần đặt
Chi phí của vòng lặp không phải giá mỗi token của mô hình AI, nó là hình dạng của lần chạy. Vòng lặp đốt token ở ba chỗ, và ba giới hạn giữ cho mức đốt có chặn. Nguồn đốt thứ nhất là subagent (tác tử con). Kỷ luật bên-tạo-khác-bên-kiểm (maker khác checker) vốn làm vòng lặp đáng tin lại đồng thời nhân chi tiêu lên, vì mỗi lượt sinh ra một subagent kiểm riêng với ngữ cảnh riêng (context) của nó. Niềm tin có cái giá tính bằng token. Một bộ đánh giá cố vấn Tier-2 còn cộng dồn thêm: nó lấy mẫu một lần và không tất định, nên bạn trả tiền cho một ý kiến từ ngữ cảnh mới mà lần sau chạy lại sẽ không giống y hệt.
Nguồn thứ hai là lần chạy rỗng. Một vòng lặp đặt lịch sẽ kích hoạt dù có việc hay không. Một trong các vòng lặp nhịp đập của chúng tôi lưu trữ lần chạy rỗng rẻ ngay từ thiết kế, nhưng rẻ không phải miễn phí, và một vòng lặp thức dậy theo lịch để thấy chẳng có gì vẫn trả tiền cho việc ngó qua. Nguồn thứ ba là lặp vô hạn: kịch bản thất bại khi vòng lặp thử đi thử lại mãi với một mục tiêu nó không thể đạt. Cách sửa cũng là cách mọi hệ thống nghiêm túc đã dùng, một giới hạn. Vòng lặp rà soát nội dung trong chính bộ công cụ này giới hạn ở ba vòng lặp; các lần chạy /goal bị giới hạn theo thiết kế. Mọi vòng lặp đều phải có một giới hạn.
| Nguồn đốt | Cái giá của nó | Giới hạn chặn nó |
|---|---|---|
| Subagent (bên tạo cộng bên kiểm riêng mỗi lượt) | Ngữ cảnh nhân lên mỗi lượt; chi tiêu cho bộ đánh giá không tất định | Chi phí: trần token hoặc trần ngân sách mỗi lần chạy |
| Lần chạy rỗng (thức theo lịch mà không có việc) | Chi phí nhỏ mỗi lần thức, dồn lại theo thời gian | Thời gian: trần thời gian thực và một lịch chạy hợp lý |
| Lặp vô hạn (thử lại với mục tiêu không đạt được) | Chi tiêu không có điểm dừng cho tới khi bạn nhận ra | Số vòng lặp: một bộ đếm số lượt tối đa |
Một ranh giới trung thực, nói thẳng: ở đây không có con số đô-la cho mỗi lần chạy, vì các sản phẩm tạo ra (artifact) đã được kiểm toán không chứa con số chắc chắn nào (chi phí của fix-pack giỏi lắm là ước lượng). Điểm cần nắm là hình dạng của mức đốt và các giới hạn chặn nó, không phải một con số tôi phải bịa ra. Về cơ chế kiểm soát chi tiêu thực sự, bài tối ưu chi phí làm chủ mảng đó; bài này chỉ gọi tên chỗ vòng lặp đốt token để bạn biết phải chặn cái gì.
Điểm mấu chốt: Ba giới hạn chặn mức đốt của một vòng lặp: số vòng lặp (bộ đếm số lượt tối đa), chi phí (trần ngân sách mỗi lần chạy), và thời gian (trần thời gian thực). Vòng lặp rà soát nội dung ở đây giới hạn ở ba vòng lặp như một tiền lệ đang chạy thật.
Cùng một vòng lặp, kết quả trái ngược: buông tay hay đòn bẩy có thiết kế
Đòn bẩy có thiết kế là có thật, và nó thắng thật sự. Cùng một vòng lặp trở thành buông tay nhận thức hay đòn bẩy có thiết kế phụ thuộc hoàn toàn vào chuyện kỹ sư có còn ở trong các quyết định của vòng lặp hay không. Hãy nhận lấy mặt tích cực ở mức mạnh nhất, vì nó không phải con bù nhìn dựng lên để đánh. Boris Cherny đã thuật lại một quãng 30 ngày gần đây trong đó 259 PR đã vào với 100% phần đóng góp Claude Code của anh do Claude Code viết. Vòng lặp dựng thiết kế của chính chúng tôi có 10 lần chạy đã kiểm chứng sau các chốt chặn xanh thật. Bài tổng hợp về loop engineering của Addy Osmani đóng khung đây là hình dạng mới của công việc, và xét trên bằng chứng thì anh ấy đúng. Đây là đòn bẩy một kỹ sư cẩn thận giành được bằng cách thiết kế vòng lặp cho tốt. Thừa nhận chiến thắng đó trọn vẹn.
Giờ tới kỹ sư kia, cùng một vòng lặp. Họ thôi đọc diff. Họ thôi viết những điều kiện dừng họ có thể bảo vệ trong một buổi đánh giá. Họ bắt đầu merge khi thấy xanh. Cùng một công cụ, quỹ đạo trái ngược.
Biến số không phải chất lượng của vòng lặp. Nó là chuyện kỹ sư có còn tự ra các quyết định của vòng lặp (nó để làm gì, “xong” nghĩa là gì, nó được phép động vào đâu) hay đã lặng lẽ giao luôn các quyết định đó cho vòng lặp. Đòn bẩy có thiết kế giữ con người ở vai kiến trúc sư của vòng lặp. Buông tay hạ con người xuống thành con dấu đóng cho qua của vòng lặp.
Đây là nghịch lý ràng buộc ở quy mô vòng lặp: chính những ràng buộc bạn áp đặt là thứ tạo ra đòn bẩy, và gỡ chúng đi thì cảm giác như nhanh lên cho tới đúng lúc không còn nhanh nữa. Bản thiết kế devkit ở Phần 8 chỉ cách dựng mặt đòn bẩy cho tốt; bài này là phần làm dịu nó lại.
Điểm mấu chốt: Trường hợp đòn bẩy có thiết kế là thật, không phải lời thổi phồng: 259 PR trong 30 ngày, 100% do Claude Code viết, là một bằng chứng thật. Vòng lặp không phải biến số. Kỹ sư, người hoặc giữ hoặc buông các quyết định của vòng lặp, mới là biến số.
Khi nào đừng dựng vòng lặp, và khi nào nó chỉ sinh code rác
Vòng lặp là công cụ sai cho việc làm một lần, mục tiêu không kiểm chứng được, và bất kỳ mảng nào bạn chưa đủ sức rà soát. Với tay tới vòng lặp ở đó không tiết kiệm thời gian, nó sản xuất ra code rác mà bạn không đủ trang bị để bắt. Ba trường hợp, xếp theo mức độ thường gặp.
Việc làm một lần: vòng lặp là hạ tầng, mà hạ tầng chỉ hoàn vốn nếu công việc lặp lại. Với một thứ bạn làm đúng một lần, viết prompt còn nhanh hơn dựng cả harness quanh nó. Mục tiêu không kiểm chứng được: nếu “xong” không thể được kiểm bởi một cỗ máy hoặc một mô hình AI khác, vòng lặp không thể biết khi nào dừng, và bạn vừa tự động hoá đúng cái kịch bản giả-xong ở phần đầu. Mảng bạn chưa đủ sức rà soát: trường hợp khó chịu nhất. Nếu bạn không rà soát nổi đầu ra, vì đó là một ngôn ngữ bạn không biết hay một hệ thống bạn chưa học, vòng lặp không nối dài tầm với của bạn. Nó gỡ mất người rà soát cuối cùng bạn còn.
Phía hoài nghi có một điểm đúng đáng nêu đầy đủ. Lập luận “chưa phải lúc” trung thực cho rằng vòng lặp chỉ đáng giá khi công việc lặp lại, khi việc kiểm chứng đã tự động, và khi ngân sách hấp thụ được phần lãng phí. Điều đó đúng trong phạm vi của nó. Khác biệt nằm ở chỗ kết: phía hoài nghi dừng ở “đừng”, còn bài này dừng ở “đây là lúc nó lật sang nên, và đây là cách giữ vai kỹ sư khi bạn làm”.
Điểm mấu chốt: Vòng lặp chỉ đáng giá khi ba điều kiện cùng đúng một lúc: công việc lặp lại, việc kiểm chứng đã tự động, và ngân sách hấp thụ được phần lãng phí. Thiếu một điều thôi là vòng lặp sản xuất code rác nhanh hơn tốc độ bạn bắt được.
Dựng vòng lặp, giữ vai kỹ sư
Phương thuốc cho cả ba kịch bản thất bại là một thói quen, không phải ba: hãy ở lại làm người kỹ sư mà vòng lặp báo cáo về. Đó là một nghi thức, không phải một cảm giác. Sau mỗi lần vòng lặp chạy, bất kể chốt chặn đã xanh, bạn đích thân đọc bốn thứ. Đầu ra của điều kiện dừng: nó thực sự kiểm chứng, hay chỉ tuyên bố? Phần diff: bạn hiểu từng thay đổi, hay đang merge trên niềm tin? Vết chạy (trace) hoặc file lưu trạng thái: vòng lặp đã thử gì, và lập luận của nó có đứng vững? Các giới hạn: nó có chạm giới hạn nào không, và vì sao?
Rồi ba giới hạn, đặt trước lần chạy chứ không phải sau: số vòng lặp, chi phí, thời gian. Bốn thứ phải đọc, ba giới hạn. Nó vừa một tấm thẻ ghi chú, và nó là toàn bộ khác biệt giữa hai kỹ sư ta nói từ đầu.
Điểm mấu chốt: Ngăn code rác do AI là một nghi thức, không phải một cảm giác. Sau mỗi lần vòng lặp chạy, đọc bốn thứ: đầu ra của điều kiện dừng (nó kiểm chứng, hay chỉ tuyên bố?), phần diff (bạn có hiểu từng thay đổi?), vết chạy hoặc file lưu trạng thái (lập luận của vòng lặp có đứng vững?), và các giới hạn (nó có chạm giới hạn nào, vì sao?). Đặt ba giới hạn trước lần chạy: số vòng lặp, chi phí, thời gian.
Chín phần trước, loạt bài này lập luận rằng điểm đòn bẩy đã dời từ viết prompt sang thiết kế vòng lặp. Lời cuối là: thiết kế vòng lặp mới là nửa dễ. Ở lại làm người kỹ sư mà vòng lặp đáp lời mới là nửa khó, và là nửa duy nhất quyết định bạn nhanh hơn thật hay chỉ ra code rác nhanh hơn. Vòng lặp sẽ chạy dù bạn có ở ghế merge hay không. Còn nó tạo ra đòn bẩy hay code rác là điều duy nhất nó không thể tự quyết. Bạn thì quyết được. Dựng vòng lặp, giữ vai kỹ sư.
FAQ
Code rác do AI là gì và vòng lặp gây ra nó thế nào?
Code rác do AI là đầu ra trông có vẻ hợp lý mà thật ra chưa ai kiểm chứng hay hiểu. Vòng lặp gây ra nó khi chạy không người trông với một điều kiện dừng chỉ tuyên bố “xong” thay vì chứng minh, nên đầu ra chưa kiểm dồn lại nhanh hơn tốc độ một con người rà soát. Cách ngăn là một điều kiện dừng kiểm chứng được cộng một con người đọc kết quả.
Nợ hiểu biết là gì?
Nợ hiểu biết là khoảng cách ngày một rộng giữa những gì hệ thống của bạn làm và những gì bạn hiểu là nó làm. Vòng lặp nới nó nhanh hơn làm tay vì nó ship nhiều code hơn với ít phần bạn hơn trong mỗi dòng. Phương thuốc là giữ một con người ở ghế merge, để mỗi thay đổi được hiểu trước khi nó vào, chứ không phải sau khi nó vỡ.
Khi nào không nên dựng vòng lặp agent?
Khi công việc chỉ làm một lần (vòng lặp là hạ tầng, chỉ hoàn vốn nếu công việc lặp lại), khi “xong” không thể được kiểm bởi một cỗ máy hoặc một mô hình AI khác, hoặc khi chính bạn chưa đủ sức rà soát đầu ra. Trong ba trường hợp đó, vòng lặp sản xuất code rác mà bạn không đủ trang bị để bắt, và một prompt thường lại là công cụ tốt hơn.
Đọc tiếp
Đây là phần cuối của loạt bài Loop Engineering. Không có phần kế tiếp; các liên kết dưới đây dẫn ngược lại theo mạch loạt bài.
- AI Devkit Loop: From Fixkit to a Reusable Plugin (Phần 8): bản thiết kế mà bài này làm dịu lại bằng các kịch bản thất bại của nó.
- Loop Engineering: From Harness to Loops (Phần 1): nơi loạt bài bắt đầu, và lời hứa một câu mà phần kết này trả.
- The 5-Layer Claude Code Harness: thời kỳ harness mà thời kỳ vòng lặp dựng lên bên trên.