Bạn nhờ AI xem giúp một đoạn code. Nó trả về ba đoạn khen chê chung chung, và một lỗi ở dòng 48 trong khi file chỉ có 30 dòng. Bạn thử lại với cùng câu hỏi, lần này nó bảo code ổn. Cùng một AI, hai người hỏi hai kiểu có thể nhận về hai chất lượng khác hẳn.
Chuyện này sửa được, và không cần mẹo thần kỳ nào. Bài này nói cách mình viết yêu cầu cho AI trong việc xem code, viết test và làm tài liệu, cùng một cách đơn giản để bắt AI khi nó bịa.
Viết yêu cầu giống như giao việc cho nhân viên mới
Chữ bạn gõ cho AI gọi là prompt. Hãy tưởng tượng bạn giao việc cho một bạn mới vào công ty hôm nay. Bạn ấy giỏi, nhưng không biết gì về dự án của bạn. Nếu bạn ấy đọc yêu cầu mà rối, AI cũng sẽ rối. Tài liệu của Anthropic cũng nói gần như vậy: đưa prompt cho một đồng nghiệp ít ngữ cảnh, họ không hiểu thì mô hình cũng không hiểu.
Trước khi chỉnh câu chữ, hãy có hai thứ. Thứ nhất là tiêu chí thế nào là làm tốt, đo được. Thứ hai là vài tình huống thử cố định để so trước và sau. Thiếu hai thứ này, bạn chỉ đang đoán.

Một yêu cầu tốt gồm những gì
Mình thường viết theo năm phần.
Phần đầu là vai trò và hoàn cảnh, kèm lý do. "Bạn xem thay đổi code cho một API Node.js. Kết quả sẽ do máy đọc, nên chỉ trả JSON" tốt hơn nhiều so với "đừng viết gì khác". Phần hai là luật, nói điều cần làm thay vì chỉ cấm. Phần ba là ví dụ. Ví dụ là cách chắc nhất để chốt định dạng, nhưng chọn ví dụ sát thực tế và có cả ca "không có lỗi", kẻo AI luôn tìm ra đúng một lỗi.
Phần bốn là hình dạng câu trả lời: cho sẵn khung JSON mẫu. Nếu gọi qua API, hãy dùng tính năng đầu ra có cấu trúc để ép đúng khuôn. Phần cuối là dữ liệu cần xử lý, bọc trong thẻ riêng như <diff> hay <code>, tách khỏi lời dặn. Cách này còn giúp AI không nhầm một câu nằm trong dữ liệu thành mệnh lệnh.
Làm sao để AI đừng bịa
AI bây giờ bịa ít hơn trước, nhưng vẫn bịa, nhất là khi bạn hỏi về thứ nó không nhìn thấy. Mình dùng ba lớp chặn.
Lớp đầu là cho phép nó nói "không chắc". Thêm một ô riêng cho nghi vấn và luật "không chắc thì ghi vào đó". Lớp hai là bắt nó trích nguyên văn: mỗi phát hiện phải kèm một dòng copy y nguyên từ dữ liệu. Lớp ba là lớp đáng tin nhất: chính code của bạn kiểm lại. Dòng trích có thật nằm trong dữ liệu không, mức độ có hợp lệ không, kết quả có đọc được không. Hai lớp đầu giảm bịa, lớp ba bắt được phần còn lọt.
Cho bạn nào viết code
Đây là mẫu xem code mình dùng, rút gọn, cùng hàm kiểm. Chỉ cần Python.
REVIEW_PROMPT = """\
<role>You review pull requests for a Node.js REST API.</role>
<rules>
- Report only problems that are visible in the diff below. If you are not sure, put it in "questions".
- Every finding must quote ONE line copied exactly from the diff in "quote".
- severity is one of: "bug", "security", "style". Ignore formatting.
- If there is nothing to report, return {"findings": [], "questions": []}.
</rules>
<output_format>
Return ONLY JSON, no prose:
{"findings": [{"severity": "bug|security|style", "quote": "...", "why": "...", "fix": "..."}],
"questions": ["..."]}
</output_format>
<diff>
{diff}
</diff>
"""
def validate(raw: str, diff: str) -> dict:
data = json.loads(raw) # not JSON -> exception
for i, f in enumerate(data["findings"]):
if f.get("severity") not in {"bug", "security", "style"}:
raise BadAnswer(f"finding {i}: bad severity")
if not f.get("quote") or f["quote"] not in diff: # anti-hallucination
raise BadAnswer(f"finding {i}: quote is not in the diff")
return data
def review(diff, ask_model, retries=1):
prompt = REVIEW_PROMPT.replace("{diff}", diff) # replace, not format(): the diff has braces
for _ in range(retries + 1):
raw = ask_model(prompt)
try:
return validate(raw, diff)
except (BadAnswer, ValueError) as err:
prompt += f"\n<previous_answer>{raw}</previous_answer>\n<problem>{err}. Fix it, return only JSON.</problem>\n"
raise BadAnswer("model never produced a valid answer")
Mình chạy lại hôm 21/10/2026 với một mô hình giả (hàm trả chuỗi cố định) qua 5 tình huống. Đáp án tốt qua ngay. Đáp án có dòng trích bịa bị từ chối, lỗi được đưa lại cho mô hình và lần hai được nhận. Đáp án có câu dẫn trước JSON bị từ chối rồi sửa. Đáp án sai mãi thì báo lỗi chứ không trả rác. Và diff chứa dấu ngoặc nhọn không làm hỏng mẫu. Cả năm đều qua. Cần nói rõ đây chỉ là thử phần kiểm, chưa đo chất lượng của AI thật.
Hai chi tiết nhỏ hay sai. Dùng .replace thay vì str.format, vì diff của bạn có { và }. Và khi thử lại, đưa cho AI đúng lỗi cụ thể thay vì chỉ nói "làm lại".

Với việc viết test, mình thêm vào yêu cầu hai luật: "viết lời giải tổng quát, đừng ghi cứng giá trị để vừa với đúng bản code này" và "nếu hàm trông sai hoặc yêu cầu chưa rõ, ghi vào mục <concerns> chứ đừng viết test khoá luôn cái lỗi". Không có hai luật này, AI hay viết test cho "qua" thay vì để kiểm đúng sai. Với tài liệu, luật quan trọng nhất là "điều gì không suy ra được từ code thì ghi TODO: cần xác nhận, đừng đoán". Hai mẫu này mình chưa chạy với AI thật.
Lỗi hay gặp
Có người cứ phát hiện lỗi thì thêm một luật mới vào prompt. Vài tuần sau prompt dài cả trang, và hai luật đá nhau. Hãy đọc lại định kỳ và gộp.
Một lỗi khác là cấm mà không nói cách làm. "Đừng dùng markdown" kém hơn "viết thành các đoạn văn liền mạch". Và lỗi tốn thời gian nhất là chỉnh prompt theo cảm giác. Giữ vài tình huống thử cố định, chỉnh xong chạy lại, so kết quả.
Làm gì tiếp theo
Chọn một việc bạn nhờ AI hay làm nhất. Viết lại yêu cầu theo năm phần ở trên, thêm một bước kiểm bằng code, rồi so với cách cũ trên cùng vài tình huống. Nếu cách mới không tốt hơn thì bạn biết ngay, đó chính là lợi ích của việc đo.
Khi một AI chưa đủ và bạn cần nhiều AI làm chung, các nguyên tắc này vẫn đúng với từng AI nhỏ; cách điều phối nằm ở Giao việc lớn cho nhiều AI cùng làm: cách chia việc để không hỏng. Phần gọi API thật, gồm đầu ra có cấu trúc, nằm ở Dùng Claude API trong sản phẩm của bạn: gọi hàm, hiện chữ dần và tiết kiệm tiền.



