Đừng để coding agent tự review code của chính nó

Tách maker và checker thành hai process riêng, chỉ truyền state qua file và lỗi có cấu trúc, rồi cắm graph đó vào Cursor CLI để verify code do agent viết.

Đã duyệt độc lập · cập nhật 27/10/2026 · 15 min

1. Vòng quen thuộc: agent viết code, tự test, tự review, mở PR

Yeyu Lab mở đầu bằng một chuỗi việc mà, theo anh, ai đang chạy AI coding agent trên project thật đều đã quen: model AI viết code, chạy test của chính nó, xem lại diff của chính nó, rồi mở pull request. Mọi thứ trông ổn, cho tới khi một reviewer là người thật mở PR đó ra và tìm thấy các boundary bug (video đăng ngày 19/10/2026).

Người trình bày của Yeyu Lab nói trước camera, phía sau là kệ sách và hai bức tranh
Người trình bày của Yeyu Lab nói trước camera ở phần mở đầu, trước khi chuyển sang các sơ đồ và phần code demo.

Anh gọi tên vấn đề là context contamination (context bị nhiễm). Model được yêu cầu tự audit code của mình, tự xác minh bằng integration test, nhưng lại làm việc đó ngay bên trong đúng cái lịch sử hội thoại nơi nó đã sinh ra code. Để hiểu vì sao chuyện này cứ lặp lại với nhiều model khác nhau, theo Yeyu Lab (video đăng ngày 19/10/2026), phải nhìn vào cách kiến trúc agent thật sự được chia lớp.

2. Bốn lớp của một hệ thống agent

Theo Yeyu Lab (video đăng ngày 19/10/2026), các hệ thống agent chạy production thường chia thành bốn lớp:

  • Lớp 1, prompt: nơi đặt ra chỉ dẫn (theo Yeyu Lab, video đăng ngày 19/10/2026).
  • Lớp 2, context: đưa vào các file trong workspace, các rule và những tài liệu khác (theo Yeyu Lab, video đăng ngày 19/10/2026).
  • Lớp 3, loop: vòng lặp cho phép một agent đơn lẻ lặp đi lặp lại cho tới khi một lệnh kết thúc (theo Yeyu Lab, video đăng ngày 19/10/2026).
  • Lớp 4, graph: graph điều phối các process tách biệt thông qua những routing rule tường minh (theo Yeyu Lab, video đăng ngày 19/10/2026).
Sơ đồ bốn lớp xếp dọc: Prompt, Context, Loop, Graph; lớp Graph được tô xanh
Layer 1 Prompt (Raw Instructions & Personas), Layer 2 Context (Workspace Files, Invariants, Docs), Layer 3 Loop (Autonomous Single-Agent Iteration) và Layer 4 Graph (Multi-Agent Routing & Process Isolation), lớp cuối được tô sáng.

3. Vì sao tự review không bắt được lỗi, và cách tách maker khỏi verifier

Yeyu Lab mô tả điều xảy ra bên trong cửa sổ chat khi bạn bảo một agent tự review chính nó. Một model đóng vai maker agent đã tiêu hàng trăm token để biện minh cho một cách implement. Yêu cầu nó review lại chính đoạn code đó trong cùng session nghĩa là nó đánh giá diff qua đúng những giả định cũ (theo Yeyu Lab, video đăng ngày 19/10/2026). README của thư mục demo trên GitHub (đọc ngày 27/10/2026) viết rằng model trở thành "defense attorney" cho chính output của nó.

Vì cái thiên lệch (bias) đó nằm ngay trong context window, theo anh (video đăng ngày 19/10/2026), muốn sửa thì phải thay đổi về mặt vật lý cách chạy các agent: tách phần sinh code (generator) khỏi phần đánh giá (evaluator). Khi maker làm xong, kill process đó và bỏ hẳn lịch sử hội thoại. Verifier khởi động lại bằng một process mới tinh. Nó chỉ đọc hai thứ từ đĩa: contract của task và các file đã được sinh ra. Nó nhận đúng không token nào từ phần lập luận của maker.

Sơ đồ so sánh Single Chat và Isolated Graph với Supervisor Router, Human Authorization Gate, Maker Node và Shared Disk State
Sơ đồ trong video (đăng ngày 19/10/2026). Bên trái, "Single Chat": Maker Agent, "Same Memory (Biased Tokens)", Self-Review, "False Confidence", rồi "Buggy PR Opened". Bên phải, "Isolated Graph": Process 1 Maker Node ghi file vào Shared Disk State (src/ và tests/), process bị kill, memory về 0, session bị huỷ; Process 2 Checker Subprocess đọc sạch từ đĩa; Supervisor Router đi tới Human Authorization Gate khi exit code bằng 0, hoặc rollback về maker chỉ kèm error diagnostic.

Trên sơ đồ, anh chỉ vào nhánh của maker: maker chỉ gửi các file vào shared disk state, memory được đưa về 0 và process bị kill. Theo Yeyu Lab (video đăng ngày 19/10/2026), điều đó bảo đảm checker subprocess đọc một thứ rất sạch.

4. Từ hai process tách rời tới một graph thật sự

Khi đã tách process như vậy, theo Yeyu Lab (video đăng ngày 19/10/2026), bạn có nền móng của một graph thật sự. Một graph chia việc thực thi thành các process cô lập, chỉ truyền state qua các file trên đĩa, route ngược về maker khi một lần audit bằng test fail, và chuyển sang một cổng phê duyệt của con người (human authorization gate) để báo cho người đó biết khi code không còn vấn đề gì nữa.

task.md Maker processghi file rồi exit Đĩa chungsrc/ và tests/ Checkerprocess mới Supervisor Human authorization gate fail: rollback, chỉ kèm error diagnostic pass
Hình 4.1Graph Yeyu Lab mô tả (video đăng ngày 19/10/2026): state chỉ đi qua file trên đĩa, checker đọc trong một process sạch, supervisor route về maker khi test fail hoặc chuyển cho người duyệt khi pass.

Tiếp theo anh mở một codebase demo. Anh nói codebase này cũng được AI agent sinh ra, nhưng nó được dùng để minh hoạ cách tổ chức kiểu graph engineering này trong project thật của bạn (video đăng ngày 19/10/2026).

5. task.md: bản contract của task

Mọi thứ bắt đầu từ file task.md. Theo Yeyu Lab (video đăng ngày 19/10/2026), đây là một file rất đơn giản, và nó chính là contract: trong demo này, đó là nơi định nghĩa task là gì. Task ở đây là một multi-tenant sliding window limiter, một hàm rất đơn giản, nhưng objective được viết rất cụ thể: implement một sliding-window rate limiter thread-safe, phân vùng theo tenant, bằng Python.

Cửa sổ editor mở task.md ở chế độ Preview: Production Task Specification Multi-Tenant Sliding Window Limiter
File task.md trong thư mục demo, mở ở chế độ Preview (video đăng ngày 19/10/2026): mục 1 Objective, mục 2 Invariant Contracts (Enforced by Independent Auditor) với ba invariant A, B, C, và mục 3 Delivery Requirements; cây thư mục bên trái có agent_cli.py, orchestrator.py, review_report.json, task.md.

Trên màn hình, nội dung chính của task.md là:

Production Task Specification: Multi-Tenant Sliding Window Limiter

1. Objective
Implement a thread-safe, tenant-partitioned sliding-window rate limiter in Python.

2. Invariant Contracts (Enforced by Independent Auditor)
- Invariant A (Strict Types): capacity must be a positive integer; window_seconds must be a positive number. Invalid inputs must raise ValueError or TypeError.
- Invariant B (Multi-Tenant Isolation): Requests from tenant-a must never consume quota from tenant-b.
- Invariant C (Time Boundary): Timestamps older than (now - window_seconds) must be evicted.

3. Delivery Requirements
- Core Module: src/rate_limiter.py

Anh giải thích từng contract mà coding agent phải tuân theo, để một auditor độc lập có thể kiểm. Invariant A là kiểu dữ liệu chặt: tham số capacity phải là số nguyên dương, window_seconds cũng phải là số dương, và input không hợp lệ phải raise ValueError hoặc TypeError. Invariant B là các tenant phải được cô lập với nhau: request của tenant A không bao giờ được tiêu quota của tenant B. Invariant C là ranh giới thời gian: các timestamp cũ hơn now - window_seconds phải bị loại bỏ. Với contract đó, verifier sẽ kiểm trực tiếp các rule này (demo trong video đăng ngày 19/10/2026).

6. orchestrator.py và hàm run_maker_cli với hai nhánh

Trong file orchestrator.py có hàm run_maker_cli, hàm khởi chạy maker như một process riêng (demo trong video đăng ngày 19/10/2026). Anh nhắc lại rằng bên cạnh maker còn có checker, tức verifier.

Bên trong maker có hai nhánh. Nếu bạn truyền vào một lệnh agent CLI hợp lệ (anh nói mình luôn dùng Cursor Agent hoặc Claude Code), lệnh đó được đưa vào tham số agent binary, và nó khởi chạy lệnh CLI thật để chạy một agent thật; phần này anh dùng ở cuối video. Nếu không có flag đó, nó chạy một file demo là agent_cli.py nằm ngay trong thư mục demo (demo trong video đăng ngày 19/10/2026).

Code Python của run_maker_cli: docstring, resolve_cursor_agent_bin, prompt cho Maker Node và chú thích các flag của cursor-agent
Thân hàm run_maker_cli (video đăng ngày 19/10/2026): docstring ghi hàm spawn Node 1 (Maker Agent) như một OS subprocess cô lập và có thể gọi cursor-agent, claude hoặc demo/agent_cli.py; prompt cho maker được ghép từ nội dung task.md, kèm dòng "PRIOR VERIFICATION FAILED" khi có feedback lỗi.

Trên màn hình, phần prompt mà orchestrator gửi cho maker được ghép như sau:

prompt = (
    f"You are the Maker Node in an isolated agent graph.\n"
    f"Fulfill the contract in {task_file.name}:\n\n"
    f"{task_text}\n\n"
    f"Create the code in src/ and tests in tests/."
)
if feedback and feedback.get("error"):
    prompt += f"\n\nPRIOR VERIFICATION FAILED: {feedback['error']}\nFix this contract vi

Trên màn hình, dòng cuối bị cắt ở mép phải.

7. agent_cli.py: một coding agent giả, cố tình sai ở cycle 1

agent_cli.py là code mockup, giả vờ chạy một coding agent để sinh code; thật ra code đã được viết sẵn. Theo Yeyu Lab (demo trong video đăng ngày 19/10/2026), nó là vật thế chỗ cho một coding agent thật và chạy theo cách Cursor Agent hay Claude Code CLI sẽ chạy: khởi động bằng process riêng, đọc task.md, ghi rate_limiter.py cùng file test của nó xuống đĩa, rồi exit. Khác biệt là nó không dùng model nào cả: code cho mỗi cycle là cố định.

Trong code có cycle 1 và cycle 2. Cycle 1 bỏ sót một bước kiểm tra validation, cycle 2 thêm nó trở lại sau khi nhận lỗi. Anh cố tình giả lập việc agent mắc lỗi ở cycle đầu, vì một model thật có thể làm đúng hết ngay lần đầu, và như vậy rất khó demo: bạn sẽ không bao giờ thấy bước rollback sang cycle 2. Với vật thế chỗ này, theo Yeyu Lab (video đăng ngày 19/10/2026), demo chạy giống hệt nhau mỗi lần, và bạn chạy được offline, không cần API key, để xem nó hoạt động thế nào.

Dù là agent giả hay thật, theo anh (video đăng ngày 19/10/2026), một khi process của maker exit, hệ điều hành giải phóng memory, và không prompt token hay phần lập luận nào sống sót sang bước tiếp theo. Như anh đã nói, để thấy graph làm việc này, bước verification phải fail ít nhất một lần.

Code cycle 1 trong agent_cli.py: dòng 41 gán self.capacity = capacity không kiểm tra
Nhánh cycle 1 trong agent_cli.py (demo trong video đăng ngày 19/10/2026): chú thích "Cycle 1 candidate: works for happy path, forgets negative…", và ở dòng 41 constructor gán self.capacity = capacity mà không kiểm tra gì.

Ở cycle 1, tại dòng 41, constructor lưu capacity mà không kiểm tra, nên phá vỡ invariant A: theo file contract, capacity phải là số nguyên dương. Sang cycle 2, ở dòng 63, nếu capacity không phải số nguyên, hoặc (anh nói) nhỏ hơn 0, thì code raise ValueError với thông điệp capacity phải là số nguyên dương, khớp hoàn toàn với invariant A trong contract. Trên màn hình, điều kiện ở dòng 63 là capacity <= 0, tức loại cả giá trị 0 (demo trong video đăng ngày 19/10/2026).

Code cycle 2 trong agent_cli.py với các dòng if not isinstance và raise ValueError, TypeError
Nhánh cycle 2 (demo trong video đăng ngày 19/10/2026), chú thích "Cycle 2 patch: strict validation guards enforcing task.md invariants": dòng 63 đến 66 raise ValueError khi capacity hoặc window_seconds không hợp lệ, dòng 72 raise TypeError khi tenant_id không phải chuỗi khác rỗng.

8. Checker và vòng lặp điều phối graph

Quay lại orchestrator.py, anh mở phần chạy checker CLI. Sau maker thì phải kiểm. Checker khởi động bằng một subprocess riêng, chạy unit test trên những gì có trên đĩa. Nếu test fail, nó trích dòng lỗi ra và ghi vào file review_report.json. Theo Yeyu Lab (demo trong video đăng ngày 19/10/2026), checker không xem prompt của maker; nó chỉ kiểm kết quả thực thi quan sát được của task.

Code checker: lọc các dòng AssertionError, FAILED, ValueError not raised, log Audit Verdict REJECT hoặc PASS, ghi REPORT_FILE
Phần cuối hàm checker (video đăng ngày 19/10/2026): lọc các dòng chứa "AssertionError", "FAILED" hoặc "ValueError not raised", lấy dòng đầu làm short_err, log "Audit Verdict: REJECT" hoặc "Audit Verdict: PASS (All invariants confirmed)", rồi ghi report ra file JSON. Bên dưới, hàm main khai báo các tham số --task, --test-cmd, --agent-bin, --model (mặc định "auto") và --max-cycles (mặc định 3).

Rồi vòng lặp chính điều phối state machine của graph. Lần gọi thứ nhất chạy maker, lần gọi thứ hai chạy checker. Câu lệnh if đóng vai một routing edge có điều kiện. Nếu mọi test pass, script đi tiếp tới bước người review. Nếu test fail, supervisor kích hoạt rollback edge và chỉ truyền error diagnostic có cấu trúc sang cycle sau. Anh nhấn mạnh: chỉ error diagnostic có cấu trúc, không kèm bất kỳ tin nhắn hội thoại nào khác (theo Yeyu Lab, demo trong video đăng ngày 19/10/2026).

9. Chạy supervisor trực tiếp trong terminal

Giờ anh chạy supervisor live trong terminal để xem Python giữ ranh giới context và huỷ process giữa các cycle ra sao (demo trong video đăng ngày 19/10/2026). Anh chạy thẳng orchestrator.py:

python3 demo/orchestrator.py

Ở cycle 1, khi supervisor khởi động, maker chạy như một process độc lập, ghi file xuống đĩa rồi exit ngay; memory của nó về 0 sau process này. Test runner, tức checker, bắt được lỗi ngay. Bước kiểm tra bị thiếu không lọt qua được: lỗi assertion đã bị bắt (demo trong video đăng ngày 19/10/2026).

Log terminal của Python Supervisor: Cycle 1 với Audit Verdict REJECT, Cycle 2 với Audit Verdict PASS
Log của "PYTHON SUPERVISOR: RUNNING CONTEXT-ISOLATED CLI GRAPH" (demo trong video đăng ngày 19/10/2026): ở Cycle 1, AGENT CLI PID 6354 ghi rate_limiter.py và test_rate_limiter.py rồi exit, checker báo "Audit Verdict: REJECT (AssertionError: ValueError not raised)" và supervisor kích hoạt rollback edge; ở Cycle 2, một PID mới là 6360 nhận feedback payload rồi checker báo PASS.

Sang cycle 2, ta thấy hệ thống phản ứng với lần test fail. Theo Yeyu Lab (video đăng ngày 19/10/2026), trong một cuộc hội thoại duy nhất, agent có thể viết lại test và lập luận rằng bước kiểm tra bị thiếu cũng không sao. Ở đây, supervisor route về maker chỉ với chuỗi lỗi. Cycle 2 khởi động bằng một process hoàn toàn mới, PID mới, không có bất kỳ tương tác nào với process trước. Thứ duy nhất nó nhận từ cycle 1 là một dòng trong payload: AssertionError: ValueError not raised. Anh gọi đó là rất đơn giản và thẳng (demo trong video đăng ngày 19/10/2026).

Maker ghi bản đã vá xuống đĩa, checker chạy lại trong một process sạch, và lần này pass rồi exit. Vì đã pass, supervisor ngừng lặp và chuyển sang bước người duyệt. Không có gì được merge tự động: code đã được verify nằm đó, chờ một người review (demo trong video đăng ngày 19/10/2026).

Cuối log: Verification passed, Advancing to Human Authorization Gate, khung HUMAN AUTHORIZATION GATE và dòng SUCCESS
Cuối lần chạy demo (video đăng ngày 19/10/2026): "Verification passed -> Advancing to Human Authorization Gate", khung HUMAN AUTHORIZATION GATE ghi Contract task.md, Tests Status All Passed, rồi dòng "[SUCCESS] Production artifact verified and authorized for merge."

10. Đưa script vào project thật với Cursor CLI

Đã thấy nguyên lý và cơ chế, câu hỏi tiếp theo là làm sao dùng script này trong việc phát triển hằng ngày thay cho quy trình mockup. Theo Yeyu Lab (video đăng ngày 19/10/2026), bạn không cần dựng lại từ đầu hay dùng một framework nặng; bạn có thể cắm thẳng nó vào hệ agent CLI của mình, như Cursor CLI, Claude Code, hay bất kỳ CLI nào hữu ích. Anh dùng Cursor CLI vì đã khá quen, và nói bạn có thể chọn bất kỳ CLI nào đã cài.

Anh cài nhanh Cursor CLI bằng một lệnh curl, thêm đường dẫn vào PATH của hệ thống, rồi đăng nhập (demo trong video đăng ngày 19/10/2026). Trên màn hình là hai lệnh sau:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
cursor-agent login

README của thư mục demo trên GitHub (đọc ngày 27/10/2026) ghi lệnh cài là curl -sS https://cursor.com/install | bash.

Bước tiếp theo là copy file orchestrator vào thư mục gốc repo của bạn, rồi chạy nó với ba tham số quan trọng: file markdown của task (chứa objective và contract), lệnh test (tuỳ framework bạn dùng để phát triển project), và agent binary (tuỳ AI agent bạn định dùng; anh dùng Cursor Agent). Trên màn hình là một dòng mẫu gồm python3 orchestrator.py, --task ./task.md, --test-cmd với một lệnh pytest, và --agent-bin cursor-agent (demo trong video đăng ngày 19/10/2026).

Chỗ thứ hai cần tự chỉnh là bên trong run_maker_cli: tuỳ biến lệnh cho agent CLI của bạn. Với Cursor CLI, theo Yeyu Lab (video đăng ngày 19/10/2026), có ba flag: -p chạy mà không có giao diện tương tác, --force ghi file mà không hỏi bạn duyệt từng chỉnh sửa, và --model cho bạn chọn model trong Cursor. Nếu không dùng Cursor, bạn bỏ qua phần này và thay bằng lệnh của mình.

Code danh sách cmd cho cursor-agent với các flag -p, --force, --model, --workspace
Lệnh dựng cho cursor-agent trong run_maker_cli (video đăng ngày 19/10/2026): chú thích "Official cursor-agent headless invocation flags" giải thích -p (--print), --force và --model (mặc định "auto"); danh sách cmd còn có --workspace và prompt; nhánh else bên dưới gọi agent_cli.py của demo.

Với anh, Cursor CLI ghi file xuống đĩa và tự exit, rồi Python chạy lệnh test của bạn trong một process riêng. Nếu lệnh đó fail, lỗi được đưa lại vào prompt cho một lần chạy Cursor CLI mới (theo Yeyu Lab, video đăng ngày 19/10/2026).

11. Chạy lại với Cursor CLI thật

Giờ anh chạy lệnh với Cursor CLI thật thay vì lệnh mockup, để xem cách dùng trong thực tế. Anh dán lệnh của mình: Python chạy orchestrator, vẫn task cũ, lệnh test dùng unittest của Python trên thư mục test của demo, agent binary là Cursor Agent và model auto (demo trong video đăng ngày 19/10/2026). Trên màn hình:

python3 demo/orchestrator.py \
  --task demo/task.md \
  --test-cmd "python3 -m unittest discover -s demo/tests" \
  --agent-bin cursor-agent \
  --model auto

Lần này model AI thật chạy bên trong agent. Quy trình đơn giản hơn demo trước: theo Yeyu Lab (demo trong video đăng ngày 19/10/2026), agent AI thật, dù chỉ dùng model auto trong Cursor, vẫn đủ mạnh để hoàn thành trọn vẹn ngay cycle đầu. Anh nói thêm rằng sẽ không như vậy khi codebase của project đủ lớn và các vòng làm việc với AI agent phức tạp hơn nhiều.

Log supervisor khi chạy với cursor-agent model auto: Cycle 1 pass, Advancing to Human Authorization Gate
Lần chạy với Cursor CLI thật (demo trong video đăng ngày 19/10/2026): phần đầu ghi Agent CLI cursor-agent (model: auto) và Test Cmd python3 -m unittest discover -s demo/tests; maker in ra tóm tắt các invariant A, B, C và thread safety; checker báo "Audit Verdict: PASS (All invariants confirmed)" ngay ở Cycle 1.

Không có gì nhiều để giải thích: chỉ một cycle. Maker sinh code xong, checker verify, rồi chuyển cho người duyệt khi xong mà không có lỗi nào (demo trong video đăng ngày 19/10/2026).

12. Khi nào nên dùng graph, khi nào không

Theo Yeyu Lab (video đăng ngày 19/10/2026), chạy nhiều process agent làm tăng độ tin cậy, nhưng dĩ nhiên cũng tăng overhead. Vì vậy cần quyết định khi nào dùng graph engineering cho một project. Vì chi phí review, anh khuyên không biến mọi script thành graph: với các task tuần tự thẳng, cứ dùng script đơn giản của bạn. Anh nói đó là khuyến nghị của mình.

Task tuần tự thẳng dùng script đơn giản của bạn không biến mọi script thành graph Project đủ lớn thử graph engineering nhiều process: tin cậy hơn, overhead cao hơn
Hình 12.1Khuyến nghị của Yeyu Lab về lúc nên dùng graph (video đăng ngày 19/10/2026): đổi lấy độ tin cậy là overhead và chi phí review.

Anh nói supervisor, agent harness và các template contract đều nằm trong repo đi kèm video, để đưa vào project tiếp theo và chạy verification trong một process mới. Khi project đủ lớn, anh khuyên thử đưa phương pháp graph engineering vào quy trình vibe coding của bạn (video đăng ngày 19/10/2026).

Anh kết thúc video ở đó và cảm ơn mọi người đã xem.

Nguồn và liên kết 5 nguồn

  1. Tên gốc: Stop Letting Your AI Coding Agent Review Its Own Code
  2. Sự kiện: YouTube
  3. Video gốc: https://www.youtube.com/watch?v=J16AHEKO66Q youtube.com
  4. Kênh YouTube Yeyu Lab (Yeyu Lab): youtube.com/channel/UCFosLT-CZzauB5gXQPc2a0g youtube.com
  5. Thư mục agent-context-isolation trong repo Youtube_demos của Yeyu Lab, gồm orchestrator.py, agent_cli.py, task.md, review_report.json và README mô tả Context-Isolated Graph Pattern cùng cách nối Cursor CLI (đọc ngày 27/10/2026): github.com/yeyu2/Youtube_demos/tree/main/agent-context-isolation github.com