Eval & golden set — đo AI feature thay vì tin demo
Demo chạy được không phải bằng chứng. Golden set vài chục case + cách chấm lặp lại được là eval tối thiểu để biết AI feature tốt lên hay tệ đi.
TL;DR: Demo chạy được không phải bằng chứng — vài case chọn thuận tay, không lặp lại được, không so sánh nổi giữa hai phiên bản prompt hay model. Golden set là bộ case chốt (vài chục case đủ để bắt đầu), lấy từ traffic thật, case biên, và case bắt buộc phải từ chối trả lời; mỗi case có đáp án mong đợi hoặc tiêu chí chấm. Cách chấm khớp loại output: exact-match/schema, rubric chấm tay, hoặc LLM-as-judge — judge cũng có thể bịa nên luôn phải spot-check tay. Eval chạy bằng script, lặp lại y hệt mỗi lần, và không bao giờ chỉnh prompt cho tới khi vừa khít đúng bộ case đó.
Một kỹ sư đội dev/UAT ngân hàng build tính năng tóm tắt ticket sự cố nội bộ: dán ticket vào, model trả về 3 dòng tóm tắt. Demo trước leader dùng 3 ticket chọn tay — cả ba gọn, đúng ý. Leader gật đầu, tính năng lên UAT.
Hai tuần sau, tester phàn nàn: model gộp nhầm hai sự cố thành một. Kỹ sư thêm câu chỉ dẫn "chỉ tóm tắt đúng một sự cố mỗi lần", ticket lỗi đó chạy đúng. Nhưng không ai chạy lại ba ticket demo cũ, và không ai biết prompt mới ảnh hưởng gì tới hơn 150 ticket đội trực xử lý mỗi ngày — "sửa xong" chỉ được xác nhận bằng đúng một ticket vừa gây lỗi.
Một tính năng AI có thể demo hoàn hảo mà vẫn không có bằng chứng nào cho biết nó tốt lên hay tệ đi sau mỗi lần đổi. Cách sửa là dựng một bộ đo cố định, chạy lại được, trước khi đổi bất cứ thứ gì.
Test chỉ giữ giá trị "chưa từng thấy" nếu không bị dùng để chọn cấu hình — nhìn rồi quay lại chỉnh biến nó thành validation trá hình, và tính thống kê trên toàn bộ dữ liệu rồi mới tách là rò rỉ dữ liệu. Chỉnh prompt cho tới khi golden set báo điểm cao là cùng một lỗi rò rỉ, chỉ khác chỗ rò rỉ vào prompt chứ không phải trọng số model.
Negative rejection là khi đáp án không tồn tại trong kho tài liệu và hệ đúng lẽ phải từ chối thay vì bịa. Golden set của bất kỳ feature AI nào cũng cần loại case tương tự: tình huống đáp án đúng là "tôi không biết", để bắt được model bịa khi không nên bịa.
1. Analogy — merge bằng tự tay click qua app, hay để CI chạy test suite?
Cách A — tự tay click qua app: mở vài màn hình quen thuộc, thấy ổn thì merge. Nhanh, nhưng bạn chỉ thử đúng những gì nghĩ ra lúc đó, và lần sau phải click lại từ đầu.
Cách B — CI chạy test suite: mỗi lần push, một bộ test cố định chạy lại y hệt, so actual với expected, báo xanh/đỏ rõ ràng — mỗi bug production tìm được thêm thành một test case mới.
Đánh giá một AI feature đứng trước đúng lựa chọn đó, chỉ khác ở chỗ "expected" không phải lúc nào cũng là một chuỗi so khớp tuyệt đối.
| Xác nhận code (bạn đã quen) | Eval AI feature |
|---|---|
| Tự tay click qua vài màn hình trước khi merge | Demo chạy vài case chọn thuận tay |
| CI chạy test suite cố định mỗi lần push | Golden set script chạy mỗi lần đổi prompt/model/chunking |
Assertion so expected với actual | Case golden set so đáp án mong đợi (hoặc tiêu chí chấp nhận) với output model |
| Bug production được thêm thành test case mới | Ticket lỗi thật từ log được thêm thành golden case mới |
Demo là bạn tự tay click qua app trước khi merge. Golden set là CI chạy test suite của bạn — chỉ khác chỗ "assertion" đôi khi là một rubric, không phải một chuỗi so khớp tuyệt đối.
2. Vì sao "demo chạy được" không phải bằng chứng
Ba lỗ hổng của demo là hệ quả tất yếu của việc nó không có cấu trúc cố định, không phải do "chọn case sai". Chọn thuận tay: người demo có xu hướng chọn case mình tin sẽ chạy tốt — ba ticket demo đại diện cho "loại ticket kỹ sư nghĩ tới lúc demo", không phải 150 ticket một ngày. Không lặp lại được: không ai ghi lại input đã dùng để chạy lại y hệt sau khi đổi prompt — biết prompt mới có hỏng case cũ không chỉ còn là cảm giác. Không so sánh được: không điểm số cố định trên tập case cố định thì "tốt hơn"/"tệ hơn" không có nghĩa để so sánh giữa hai phiên bản.
Hệ quả: feature có thể ngày càng tệ đi qua nhiều lần "sửa nhanh", và không ai biết cho tới khi người dùng phàn nàn đủ nhiều.
3. Golden set là gì — bộ case chốt thay cho vài case thuận tay
Golden set là một tập case đánh giá cố định, chọn có chủ đích và giữ nguyên qua nhiều lần chạy. Vài chục case đủ để bắt đầu — không cần lớn bằng toàn bộ traffic, chỉ cần cố định và đại diện.
Case nên lấy từ ba nguồn, không nghĩ ra tùy hứng:
- Traffic/log thật — input thật đã đi qua hệ thống, không phải input kỹ sư tưởng tượng.
- Case biên — input dài bất thường, thiếu thông tin, chạm đúng giới hạn feature từng gãy trong quá khứ, giống ticket "gộp nhầm hai sự cố" ở đầu bài.
- Case phải từ chối trả lời — đáp án đúng là "không đủ thông tin", nối thẳng negative rejection ở Recall trên. Thiếu loại case này, golden set không bao giờ bắt được lúc model bịa khi lẽ ra phải im lặng.
Mỗi case gồm input và đáp án mong đợi hoặc tiêu chí chấp nhận — một chuỗi cố định để so khớp, hoặc một danh sách điều kiện, tùy loại output (mục 5).

4. Bài tập — tự phác golden set cho tính năng tóm tắt ticket
Đề bài
Feature ở đầu bài: nhận nội dung một ticket sự cố nội bộ, trả về bản tóm tắt 3 dòng cho người trực ca sau. Trước khi viết script eval, tự phác:
- 5–6 case cho golden set — mỗi case chỉ cần mô tả ngắn input là loại ticket gì.
- Với mỗi case, cách chấm: so khớp đáp án cố định, hay chấm theo tiêu chí? Tiêu chí đó là gì?
Viết ra trước khi đọc Gợi ý.
Gợi ý
Bắt đầu từ ba nguồn ở mục 3, không phải "nghĩ ra case gì hay":
- Loại ticket nào chiếm phần lớn traffic hàng ngày? Nên chiếm số đông trong golden set.
- Loại ticket nào từng gây lỗi thật hoặc bất thường — dài, thiếu thông tin, gộp nhiều sự cố? Đó là case biên.
- Có input nào mà câu trả lời đúng lại là một dạng từ chối, không phải một bản tóm tắt? Thử nghĩ xem những input như thế đến từ đâu trong hệ thống của bạn.
- Với output tự do, một chuỗi so khớp tuyệt đối gần như không khả thi — nghĩ bằng danh sách điều kiện (đúng số sự cố, không thêm thông tin ngoài ticket) thay vì một đáp án duy nhất.
Lời giải
| # | Input (mô tả ticket) | Cách chấm |
|---|---|---|
| 1 | Ticket điển hình: một lỗi, mô tả rõ, có log | Rubric: đúng 3 dòng, đúng loại lỗi, không bịa thêm nguyên nhân |
| 2 | Ticket rất dài, log dán nguyên khối | Rubric: vẫn đúng 3 dòng, không bỏ sót lỗi chính ở giữa log |
| 3 | Ticket gộp hai sự cố khác nhau (case gây lỗi thật ở đầu bài) | Rubric: tách rõ hai sự cố, không gộp chung |
| 4 | Ticket thiếu thông tin — chỉ có tiêu đề | Tiêu chí: phải nêu "thiếu thông tin", không tự suy diễn |
| 5 | Ticket test nội bộ, không mang sự cố thật | Case phải từ chối: đáp án đúng là "không tóm tắt" — model KHÔNG được bịa sự cố |
| 6 | Ticket có đính kèm số tài khoản khách hàng | Tiêu chí: tóm tắt không được lặp lại số tài khoản |
Case 5 là ví dụ "case phải từ chối" — thiếu nó, một model luôn cố tóm tắt bất kể input gì sẽ không bao giờ bị bắt lỗi, cho tới khi người trực nhận một bản tóm tắt bịa từ dữ liệu test rỗng.
5. Cách chấm theo loại output
Cách chấm phải khớp hình dạng output. Exact-match/schema cho output có cấu trúc (JSON, nhãn phân loại): so khớp trực tiếp, rẻ và chắc chắn nhất. Rubric chấm tay cho output tự do (tóm tắt, hội thoại): danh sách tiêu chí cụ thể, người chấm theo đúng danh sách đó — chậm hơn nhưng đáng tin nhất. LLM-as-judge dùng thận trọng: một model chấm thay người, rẻ và nhanh hơn — nhưng judge cũng là model, có thể bịa điểm hoặc thiên vị câu trả lời dài/giống văn phong chính nó (Deep Dive). Dùng judge cho số đông case, nhưng luôn spot-check tay phần kết quả, đặc biệt case biên và case phải từ chối.
6. Kỷ luật vận hành
Golden set chỉ có giá trị nếu vận hành đúng ba kỷ luật. Chạy bằng script, lặp lại được: đọc golden set, gọi feature với từng input, chấm theo mục 5, in điểm tổng hợp — không bước nào cần click tay. Chạy trước mỗi lần đổi prompt/model/chunking, như regression test: đổi gì cũng chạy lại toàn bộ eval, không chỉ case vừa gây lỗi — chạy cả golden set sẽ lộ ngay nếu chỉ dẫn mới ảnh hưởng ngược tới case khác. Đừng "train trên golden set": chỉnh prompt tới khi golden set báo điểm tuyệt đối là cùng cơ chế rò rỉ ở Recall đầu bài — điểm cao không còn chứng minh gì về case chưa nghĩ tới. Giữ sạch bằng cách thêm case mới định kỳ từ log thật.
7. Pitfall tổng hợp
❌ Nhầm 1 — coi vài case demo đẹp là đủ bằng chứng để ship: ✅ Dựng golden set cố định, chạy script, so điểm.
❌ Nhầm 2 — chỉ dùng LLM-as-judge, không bao giờ spot-check tay: ✅ Judge cũng là model, có thể bịa điểm. Luôn chấm tay một phần, đặc biệt case biên.
❌ Nhầm 3 — chỉnh prompt liên tục cho tới khi golden set báo điểm gần tuyệt đối: ✅ Đó là "train" trên chính bộ đo. Thêm case mới định kỳ từ log thật.
8. 📚 Deep Dive
- Zheng, Chiang, Sheng et al. — Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena, arXiv:2306.05685 — một judge mạnh (GPT-4 trong nghiên cứu này) khớp đánh giá con người trên 80%, nhưng đi kèm position, verbosity và self-enhancement bias — đúng lý do bài này nhắc "phải spot-check tay".
Ghi chú: con số hơn 80% là benchmark cụ thể của paper, không phải hằng số áp dụng chung mọi judge/model/ngôn ngữ — tự đo lại trên golden set của bạn.
9. Liên hệ các bài khác
- Bài 05 — Cost & latency — sau khi đo chất lượng bằng golden set, bài tiếp theo đo chi phí và độ trễ cùng feature.
- Bài 07 — Mini-challenge: ship checklist — checklist ship dùng chính golden set làm tiêu chí bắt buộc.
- Data leakage — train/val/test — cùng cơ chế rò rỉ, áp cho prompt thay vì trọng số model.
- Bốn failure mode của RAG — negative rejection là lý do cần "case phải từ chối".
10. Tóm tắt
- Demo chạy được không phải bằng chứng: case chọn thuận tay, không lặp lại được, không so sánh nổi giữa hai phiên bản.
- Golden set là bộ case chốt, cố định, vài chục case đủ để bắt đầu — lấy từ traffic thật, case biên, và case bắt buộc phải từ chối.
- Mỗi case gồm input và một đáp án mong đợi hoặc tiêu chí chấp nhận rõ ràng.
- Cách chấm khớp loại output: exact-match/schema, rubric chấm tay, hoặc LLM-as-judge — judge luôn cần spot-check tay.
- Eval chạy bằng script lặp lại được, chạy trước mỗi lần đổi prompt/model/chunking như regression test.
- Không bao giờ chỉnh prompt cho tới khi vừa khít đúng golden set — đó là rò rỉ dữ liệu vào prompt.
11. Tự kiểm tra
Q1Vì sao một demo chạy tốt trước leader không chứng minh được tính năng đã sẵn sàng ship, dù không case nào lỗi?▸
Case demo thường bị chọn thuận tay nên không đại diện cho phân bố input thật. Ngay cả khi cả ba case đều đúng, không ai lưu input để chạy lại sau khi đổi prompt, và không có điểm số cố định để so sánh phiên bản cũ với mới — "demo tốt" không tích luỹ thành bằng chứng qua thời gian.
Q2Golden set nên lấy case từ ba nguồn nào, và vì sao thiếu case 'phải từ chối trả lời' là lỗ hổng nghiêm trọng?▸
Ba nguồn: traffic/log thật, case biên, và case mà đáp án đúng là từ chối hoặc "không đủ thông tin". Thiếu loại case thứ ba, golden set không bao giờ bắt được lúc model có xu hướng luôn cố trả lời — một model bịa khi lẽ ra phải từ chối sẽ được điểm cao mãi, vì không case nào bắt đúng tình huống đó.
Q3Khi nào dùng exact-match/schema, khi nào dùng rubric chấm tay, và rủi ro lớn nhất khi chuyển sang LLM-as-judge là gì?▸
Exact-match/schema khi output có cấu trúc cố định — rẻ, chắc chắn. Rubric chấm tay cho output tự do, nơi không có một đáp án đúng duy nhất. Rủi ro lớn nhất của LLM-as-judge: nó cũng là model, có thể bịa điểm hoặc thiên vị câu trả lời dài/giống văn phong chính nó, nên luôn cần spot-check tay.
Q4Vì sao chỉnh prompt liên tục cho tới khi golden set báo điểm gần tuyệt đối lại nguy hiểm?▸
Đó là cùng cơ chế rò rỉ dữ liệu ở bài train/validation/test: golden set không còn là "chưa từng thấy" một khi được dùng để tối ưu trực tiếp, nên điểm cao chỉ chứng minh prompt khớp đặc thù của chính bộ case đó — feature vẫn có thể hỏng trên input thật chưa từng đưa vào golden set.
Q5Đội bạn vừa đổi sang model khác cho tính năng tóm tắt ticket. Làm sao biết model mới tốt hơn hay tệ hơn mà không cần đợi phàn nàn?▸
Chạy script eval golden set với model mới, so điểm tổng hợp trực tiếp với điểm của model cũ trên cùng bộ case — golden set đã mô phỏng sẵn traffic, case biên, case phải từ chối nên không cần đợi phản hồi thật. Baseline chỉ có ý nghĩa khi đo trên đúng một bộ case cố định cho cả hai model.
Bài tiếp theo: Cost & latency — tính từ token
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên