Agent Coding 101Chapter 10 of 10

Bài tổng kết: từ một ý tưởng tới pull request

Ghép toàn bộ Agent Coding 101 vào một tính năng thật, từ lúc yêu cầu còn mơ hồ tới một pull request có thể review đàng hoàng.

howznguyen

howznguyen

26 min read

Bài tổng kết: từ một ý tưởng tới pull request

Đây là bài cuối của Agent Coding 101.

Mình không muốn kết series bằng một checklist tóm tắt chín bài trước. Checklist thì dễ đọc, dễ gật gù, nhưng tới lúc mở coding agent lên mình vẫn có thể ngồi nhìn con trỏ nhấp nháy và không biết bắt đầu từ đâu.

Vì vậy bài này là một bài tổng kết thực hành. Gọi là bài cuối khoá cũng được, miễn là đừng bắt mình đứng lên thuyết trình.

Mình sẽ lấy tính năng mời thành viên vào workspace đã xuất hiện nhiều lần trong series rồi đi hết một vòng: làm rõ ý tưởng, tạo nguồn chuẩn, nhìn codebase, chốt quyết định, chia task, giao agent làm, xử lý một lỗi, review trạng thái cuối và chuẩn bị .

Mục tiêu cuối không phải "agent đã viết code".

Mục tiêu là một gói thay đổi đủ nhỏ, có bằng chứng, nói rõ rủi ro và sẵn sàng để người review quyết định.

Đề bài ban đầu cố tình mơ hồ

Giả sử mình bắt đầu với một câu như vầy:

Plain Text

Nếu đưa thẳng câu này cho agent, nó vẫn có thể tạo được code.

Nó có thể tự chọn ai được mời, lời mời hết hạn bao lâu, lời mời trùng xử lý ra sao, email gửi lúc nào và token lưu thế nào. Diff nhìn đầy đủ, nhưng phần lớn cách hoạt động đến từ những điều chưa ai chốt.

Trước khi cho phép sửa file, mình cần biến ý tưởng thành một bản mô tả có thể kiểm tra.

Mình bắt đầu bằng cách viết rõ vấn đề:

Plain Text

Phần “chưa quyết định” quan trọng không kém “kết quả mong muốn”.

Nó nói rõ vùng nào agent được tìm hiểu, nhưng chưa được tự chọn cách hoạt động.

Chốt một lát cắt đủ nhỏ để review

Tính năng lời mời hoàn chỉnh có thể gồm form, API, database, mẫu email, luồng chấp nhận, hết hạn, gửi lại, thu hồi, audit log và trang quản trị.

Làm tất cả trong một pull request sẽ rất khó review.

Google Engineering Practices khuyên mỗi thay đổi nên tự đứng được, tập trung vào một việc và đi cùng test liên quan. Thay đổi nhỏ dễ review kỹ hơn, ít bug hơn và cũng dễ quay lại hơn nếu có chuyện.

Lát cắt của bài tổng kết này chỉ là:

Plain Text

Trong phạm vi:

  • Phân quyền cho admin của workspace
  • Chuẩn hoá email
  • Không tạo lời mời nếu email đã là thành viên
  • Tối đa một lời mời đang chờ cho cùng workspace và email
  • Token thô không lưu trong database và không xuất hiện trong log
  • Email chỉ được đưa vào hàng đợi sau khi lời mời hợp lệ được tạo
  • Service, route, migration và test liên quan

Không làm trong vòng này:

  • Form giao diện
  • Chấp nhận lời mời
  • Gửi lại, thu hồi và dọn lời mời hết hạn
  • Gửi email thật
  • Deploy và chạy migration trên môi trường thật

Phần chưa làm không phải phần bị quên.

Nó là ranh giới để pull request này kể đúng một câu chuyện, thay vì đang kể invitation rồi tiện đường rẽ sang sửa luôn hệ thống email.

Năm mảnh tài liệu thay cho một prompt khổng lồ

Mình không nhồi toàn bộ dự án vào một prompt.

Bài tổng kết này có năm mảnh tài liệu chính:

Tài liệuChứa gìAi dùng
Sổ tay projectCâu lệnh, quy ước, giới hạn và nguồn chuẩnMọi agent
Đặc tả tính năngMục tiêu, cách hoạt động, tiêu chí và phần chưa làmAgent tìm hiểu, agent thực thi, người review
Ghi chú quyết địnhNhững lựa chọn không được phép tự đoánAgent thực thi và người review
TaskMột phần việc có người chịu trách nhiệm, đầu vào, đầu ra và cách kiểm traAgent thực thi
Gói bằng chứngDiff, câu lệnh, kết quả, rủi ro và phần chưa kiểm traNgười review và PR

Chat là nơi mình trao đổi.

Các tài liệu này mới là nơi giữ trạng thái qua nhiều session.

Nếu session bị rút gọn, agent thực thi mới vẫn có thể đọc đặc tả và task. Nếu người review không thấy đoạn chat cũ, họ vẫn hiểu kết quả và quyết định cần kiểm tra.

Quy trình từ ý tưởng qua ngữ cảnh, đặc tả, thực thi và review tới pull request
Bài tổng kết không đi thẳng từ ý tưởng tới code. Mỗi giai đoạn để lại một mảnh thông tin cho giai đoạn tiếp theo.

Giai đoạn 1: Chỉ đọc và tìm hiểu

Task tìm hiểu chưa được phép sửa file.

Nó cần trả lời những câu hỏi có thể tìm thấy từ repository hiện tại:

  • Project lưu membership ở đâu?
  • Project đang kiểm tra quyền theo cách nào?
  • Database transaction được mở ở lớp nào?
  • Email adapter có interface hoặc bản giả sẵn không?
  • Lỗi API và validation theo quy ước nào?
  • Test tích hợp khởi tạo database ra sao?
  • Có ràng buộc duy nhất hoặc helper chuẩn hoá nào tương tự không?

Prompt tìm hiểu có thể là:

Plain Text

Đầu ra tốt không phải một bài luận.

Nó là một gói ngữ cảnh ngắn:

Plain Text

Agent tìm hiểu không được tự biến câu hỏi còn mở thành quyết định triển khai.

Giai đoạn 2: Chốt quyết định trước khi chia task

Từ phần tìm hiểu, mình chốt những quyết định ảnh hưởng tới cách lát cắt này hoạt động.

Ví dụ:

Plain Text

Mỗi quyết định cần lý do ngắn nếu có đánh đổi.

Ví dụ chọn conflict cho lời mời trùng làm API kém idempotent hơn một chút, nhưng giữ lát cắt nhỏ và không phải tự định nghĩa chuyện gửi lại trong pull request này.

Điểm quan trọng là người review có một thoả thuận để đối chiếu.

Nếu agent thực thi tự chọn conflict rồi cũng tự viết test theo lựa chọn đó, test xanh chỉ chứng minh code khớp với giả định của chính nó.

Giai đoạn 3: Viết tiêu chí cùng bằng chứng dự kiến

Mình viết tiêu chí hoàn thành cùng loại bằng chứng sẽ dùng.

Tiêu chí hoàn thànhBằng chứng dự kiến
Admin tạo được lời mời đang chờTest tích hợp và kiểm tra database
Thành viên thường bị từ chốiTest phân quyền, số bản ghi không đổi
Người đã là thành viên không tạo lời mờiTest tích hợp, không đưa email vào hàng đợi
Lời mời đang chờ bị trùng trả conflictTest đồng thời, database chỉ có một bản ghi
Email được chuẩn hoá nhất quánTest chữ hoa, chữ thường và khoảng trắng
Database chỉ lưu mã băm của tokenKiểm tra database và review diff
Token thô không vào logKiểm tra log đã thu lại
Email chỉ vào hàng đợi sau khi tạo thành côngKiểm tra adapter giả

Tiêu chí mô tả kết quả. Bằng chứng dự kiến giúp agent thực thi biết cần chứng minh bằng gì.

Mình chưa viết cách triển khai vào tiêu chí. “Dùng unique partial index tên X” là quyết định thiết kế, không phải kết quả người dùng nhận được, trừ khi project đã chốt ràng buộc đó thành yêu cầu.

Giai đoạn 4: Viết bản giao việc cho agent thực thi

Một task đủ giao cho agent có thể viết như sau:

Plain Text

Task này dài hơn một câu prompt, nhưng vẫn ngắn hơn nhiều so với một session gỡ lỗi sau khi agent tự mở rộng tính năng. Viết sớm vài dòng thường rẻ hơn đọc muộn vài trăm dòng diff.

Giai đoạn 5: Kiểm tra đường đi trước khi sửa

Agent thực thi chưa code ngay.

Nó trả một bản tóm tắt ngắn trước khi bắt đầu:

Plain Text

Mình review kế hoạch ở mức ranh giới, không cầm tay chỉ từng hàm.

Nếu agent thực thi định refactor toàn bộ module thành viên chỉ để dùng lại một helper, đây là lúc cắt phạm vi trước khi diff xuất hiện.

Nếu nó nói cần package mới để băm token trong khi project đã có helper, mình quay lại bằng chứng từ bước tìm hiểu.

Nếu mọi thứ hợp lý, task chuyển từ lập kế hoạch sang thực thi.

Giai đoạn 6: Làm theo từng điểm kiểm tra

Agent thực thi vẫn là một agent, nhưng công việc không cần chạy thành một khối đen tới done.

Mình đặt điểm kiểm tra ở nơi mức rủi ro thay đổi:

Điểm A: thoả thuận dữ liệu.

Agent thực thi xác nhận schema, quy tắc không trùng và kế hoạch migration. Chưa cần chạy migration ngoài database dùng xong có thể bỏ.

Điểm B: cách service hoạt động.

Phân quyền, chuẩn hoá email, kiểm tra thành viên, xử lý lời mời trùng, mã băm token và ranh giới transaction đã nằm trong diff.

Điểm C: route và tác động phụ.

Cách ánh xạ validation và lỗi đã rõ. Email adapter giả chỉ nhận dữ liệu hợp lệ ở thời điểm đã chốt.

Điểm D: bằng chứng.

Test liên quan, typecheck, kiểm tra migration và diff cuối đều chạy trên cùng một trạng thái.

Không phải điểm nào cũng cần mình tự tay duyệt.

Agent có thể tự đi qua các bước local, quay lại được và đã nằm trong thoả thuận. Nó chỉ dừng nếu phạm vi, quyền hoặc rủi ro thay đổi.

Khi test đồng thời làm task trật đường

Giả sử test luồng thuận đã qua, nhưng test hai yêu cầu đồng thời lại tạo ra hai lời mời đang chờ.

Agent thực thi thử thêm câu truy vấn kiểm tra trước khi ghi. Test vẫn lúc xanh lúc đỏ. Đây là điều kiện dừng từ bài 08.

Mình chốt trạng thái và chuyển sang chẩn đoán chỉ đọc:

Plain Text

Phép thử tiếp theo là xem ranh giới transaction và schema thật, không thêm delay để cầu may.

Nếu bằng chứng xác nhận kiểm tra ở tầng ứng dụng không đủ chống tranh chấp dữ liệu, agent thực thi đề xuất ràng buộc phù hợp với quyết định đã chốt. Kế hoạch migration quay lại điểm A để review.

Sau khi sửa:

  • Chạy lại test đồng thời
  • Chạy test phân quyền và regression test cho người đã là thành viên
  • Xem trạng thái database
  • Review cách ánh xạ lỗi khi ràng buộc bị xung đột

Vòng phục hồi này không tạo thêm một task khổng lồ.

Nó làm rõ một quy tắc vốn đã nằm trong tiêu chí hoàn thành.

Giai đoạn 7: Chốt trạng thái rồi review từ rộng tới hẹp

Khi agent thực thi báo xong, mình yêu cầu dừng sửa.

Chụp trạng thái:

Bash

Review bắt đầu từ task chứ không bắt đầu từ chuyện đặt tên.

Review phạm vi:

  • Chỉ có service, route, migration, test và cách dùng adapter liên quan?
  • Có lockfile, cấu hình, file sinh tự động hoặc module ngoài phần được giao không?
  • Phần không làm có bị kéo vào vì “tiện làm luôn” không?

Review cách hoạt động:

  • Việc kiểm tra quyền xảy ra trước tác động phụ?
  • Email đã chuẩn hoá được dùng nhất quán khi tra cứu và kiểm tra trùng?
  • Ranh giới transaction có giữ đúng quy tắc?
  • Xung đột ràng buộc được ánh xạ về kết quả API đã chốt?
  • Email được đưa vào hàng đợi ở trạng thái nào?
  • Token thô có đường nào đi vào log, exception hoặc database?

Test review:

  • Test có đỏ nếu bỏ phần code tương ứng?
  • Test đồng thời có thật sự dùng chung trạng thái?
  • Mock có che mất ranh giới transaction hoặc adapter?
  • Assertion có kiểm tra database và tác động phụ, không chỉ mã trạng thái?

Review độ phức tạp:

  • Có abstraction mới cho tương lai chưa tồn tại không?
  • Cách làm sẵn có của project có được dùng lại không?
  • Comment giải thích quyết định hay chỉ kể lại code?

Vấn đề được phân loại trước khi sửa. Sau mỗi lần sửa, trạng thái cuối đổi nên các bước kiểm tra bị ảnh hưởng phải chạy lại.

Giai đoạn 8: Gom gói bằng chứng

Phần mô tả PR tốt không nên bắt người review đọc lại cả đoạn chat để biết agent đã làm gì.

Mình yêu cầu gói bằng chứng trước:

Plain Text

Gói bằng chứng không cần dán toàn bộ log test.

Nó chỉ cần đủ để người review lần từ lời báo tới câu lệnh, diff hoặc trạng thái quan sát được.

Task, diff, test và rủi ro được đóng gói thành một pull request có thể review
Pull request là một đề xuất kèm ngữ cảnh và bằng chứng, không chỉ là nơi chứa diff.

Giai đoạn 9: Chuẩn bị pull request, chưa merge

GitHub mô tả pull request là một đề xuất để ghép thay đổi code. Người review có thể xem phần mô tả, commit và các file đã đổi trước khi đồng ý hoặc yêu cầu sửa.

Từ “đề xuất” khá đúng với ranh giới mình muốn.

Agent có thể chuẩn bị tiêu đề và nội dung. Việc push hoặc mở PR tạo tác động ra bên ngoài, nên vẫn phải đi qua điểm xin phép từ bài 09.

Bản nháp PR có thể là:

Plain Text

Nếu repository có issue tương ứng, PR có thể gắn liên kết để người review thấy vấn đề và tiến độ ở cùng một chỗ. Từ khoá đóng issue phải đúng nhánh đích và ý định của team; đừng để agent tự thêm Closes khi PR chưa thật sự giải quyết toàn bộ issue.

Trước khi cho phép push hoặc mở PR, mình xem trước:

  • Repository và nhánh đích
  • Commit hoặc diff sẽ được gửi
  • Tiêu đề và nội dung PR
  • Người review dự kiến
  • Không bao gồm merge/deploy

Lần đồng ý này chỉ có hiệu lực với đúng nội dung đó.

Giai đoạn 10: Đưa phản hồi từ review về lại task

PR không phải nơi quy trình làm rơi mất nguồn chuẩn.

Người review có thể Comment, Approve hoặc Request changes. Với nhận xét cần xử lý, mình đưa nó về task hoặc ghi chú cùng mức độ nghiêm trọng, file, vị trí, bằng chứng và người phụ trách.

Agent thực thi nhận một phạm vi sửa cụ thể:

Plain Text

Đừng bảo “sửa mọi comment trong PR” khi các comment còn lẫn câu hỏi, góp ý theo sở thích và lỗi thật sự chặn việc merge.

Sau khi sửa, agent thực thi cập nhật gói bằng chứng. Người review được mời lại nếu thay đổi đáng kể khiến lần đồng ý cũ không còn phản ánh trạng thái cuối.

PR sẵn sàng merge khi:

  • Vấn đề chặn merge đã xử lý
  • Các bước kiểm tra bắt buộc chạy trên commit hiện tại
  • Trao đổi quan trọng đã được giải quyết
  • Tiêu chí hoàn thành có bằng chứng hoặc phần chưa chắc chắn được chấp nhận rõ
  • Quy tắc bảo vệ nhánh và người có thẩm quyền đã đồng ý

Bài tổng kết dừng ở trạng thái sẵn sàng để merge.

Merge và deploy vẫn là hai quyết định khác.

Một vòng làm việc thực tế

Nếu gom lại theo từng chặng, vòng làm việc sẽ giống vầy:

Plain Text

Không phải tính năng nào cũng cần biến từng dòng thành nghi lễ.

Với task nhỏ, phần tìm hiểu, đặc tả và task có thể nằm trong một ghi chú ngắn. Với task nhiều rủi ro, mỗi quyết định cần người phụ trách và dấu vết rõ hơn.

Điểm không đổi là trạng thái phải đi qua tài liệu và bằng chứng, không chỉ qua ký ức của đoạn chat.

Prompt điều phối cho cả vòng

Nếu công cụ hỗ trợ vòng làm việc dài, mình vẫn chia prompt theo giai đoạn thay vì một prompt “làm từ A tới Z”.

Prompt chính có thể là:

Plain Text

Agent chính có thể tự đi qua các giai đoạn local đã được duyệt.

Nhưng nó phải dừng ở ranh giới quyết định và quyền hạn, không chỉ dừng khi token gần hết.

Với Knowns, công việc để lại dấu vết rõ ràng

Trong Knowns, mình có thể giữ:

  • Đặc tả cho kết quả và tiêu chí hoàn thành
  • Ghi chú quyết định cho lời mời trùng, token và tác động phụ
  • Task cho người phụ trách, hàng rào, kế hoạch và tiến độ
  • Ghi chú task cho phát hiện từ bước tìm hiểu, phép thử, câu lệnh và bằng chứng
  • Memory cho cách làm đã được kiểm chứng và có thể dùng lại

Session của agent thực thi không cần ôm toàn bộ lịch sử.

Người review cũng không cần tin một bản tóm tắt đã mất nguồn.

Nếu test đồng thời loại một giả thuyết, kết quả âm tính nằm trong ghi chú task. Nếu cách xử lý lời mời trùng thay đổi, ghi chú quyết định trở thành nguồn chuẩn mới. Nếu project rút ra quy tắc “tác động ra bên ngoài luôn xảy ra sau transaction”, quy tắc đó chỉ xứng đáng thành memory sau khi được kiểm chứng.

Knowns ở đây không thay Git, test hoặc PR review.

Nó nối những tài liệu đó bằng một thoả thuận mà cả người lẫn agent đều có thể đọc lại.

Khi nào bài tổng kết này được xem là xong

Mình xem vòng này hoàn thành khi:

  • Vấn đề và kết quả người dùng được viết rõ
  • Lát cắt đủ nhỏ để review độc lập
  • Quyết định còn mở đã có người phụ trách và được chốt
  • Sổ tay project, đặc tả và task không mâu thuẫn
  • Agent thực thi biết được đọc gì, sửa gì, chạy câu lệnh nào và dừng khi nào
  • Phần thực thi không vượt phạm vi
  • Lỗi được chẩn đoán bằng bằng chứng, không che bằng retry hoặc test nới lỏng
  • Diff cuối đã được chốt và review trên trạng thái đã ghép
  • Mỗi tiêu chí hoàn thành có bằng chứng hoặc NOT VERIFIED
  • Rủi ro, cách quay lại và phần chưa kiểm tra được ghi rõ
  • Bản nháp PR giải thích vì sao đổi, đổi gì, kiểm tra thế nào và cần tập trung review ở đâu
  • Push hoặc mở PR có lần xin phép riêng
  • Merge và deploy chưa bị coi là phần phụ của việc viết code

Done ở đây không có nghĩa code sẽ không bao giờ có bug.

Nó có nghĩa phần chưa chắc chắn còn lại đã được nhìn thấy, thay đổi đủ nhỏ để người khác hiểu và quyết định cuối không bị giấu trong sự tự tin của agent.

Kết series

Mở một coding agent lên rất dễ.

Phần khó hơn là tạo một môi trường nơi agent biết project, nhận task đủ rõ, có vòng phản hồi tốt, dừng đúng lúc và đưa cho mình bằng chứng thay vì chỉ đưa một câu trả lời trôi chảy.

Qua bài tổng kết này, mình muốn giữ một ý chính:

Plain Text

Coding agent không loại bỏ công việc kỹ thuật.

Nó đẩy công việc lên một tầng khác: mình dành ít thời gian gõ từng dòng hơn, nhưng phải rõ hơn về ý định, giới hạn, trạng thái và cách kiểm tra.

Và thật ra mình thấy đây là phần khá thú vị.

Code có thể đến nhanh hơn. Nhưng quyết định tốt, vòng phản hồi tốt và một pull request dễ review vẫn là thứ phải được thiết kế.

Cảm ơn các bạn đã đi hết Agent Coding 101 cùng mình.

See yah.

Tài liệu tham khảo