LLM 6 — Đánh giá & kiểm thử ứng dụng LLM
LLM 6 — Đánh giá & kiểm thử ứng dụng LLM
Bạn đã dựng xong một trợ lý hỏi đáp bằng LLM. Bạn gõ vài câu hỏi, thấy nó trả lời trôi chảy và hợp lý, rồi kết luận: "ổn rồi, đưa lên production". Vài tuần sau bạn đổi prompt để sửa một lỗi nhỏ, hoặc nâng model lên phiên bản mới — và bỗng nhiên hệ thống bắt đầu bịa số liệu, trả lời lạc đề, hoặc từ chối những câu hoàn toàn hợp lệ. Không ai phát hiện cho đến khi khách hàng phàn nàn.
Đây là câu chuyện quen thuộc của mọi đội làm ứng dụng LLM chưa có quy trình đánh giá (evaluation) có hệ thống. Bài này bàn về cách biến "cảm giác ổn" thành con số đo được, để mỗi lần thay đổi bạn biết mình đang tiến bộ hay thụt lùi.
Vì sao "chạy thử thấy ổn" là chưa đủ
Ba đặc điểm của LLM khiến việc kiểm thử thủ công trở nên nguy hiểm:
- Không tất định (non-deterministic): Cùng một prompt, model có thể trả lời khác nhau giữa các lần gọi. Một lần thử thành công không đảm bảo lần sau cũng vậy. Bạn cần đo trên nhiều mẫu để có tín hiệu đáng tin.
- Nhạy cảm với thay đổi: Đổi một câu trong system prompt, nâng model, tinh chỉnh nhiệt độ tạo sinh, thay đổi chunk trong RAG — bất kỳ thay đổi nào cũng có thể gây hồi quy (regression) ở những case bạn không ngờ tới. Sửa được A nhưng làm hỏng B là chuyện thường xuyên.
- "Cảm giác ổn" không đo được: Con người kiểm 5-10 câu rồi mệt, và có xu hướng chỉ thử những câu dễ. Cảm giác chủ quan không so sánh được giữa hai phiên bản, không chạy lại được, không phát hiện được suy giảm 3%.
Kết luận: bạn cần một bộ eval — tập câu hỏi cố định kèm tiêu chí chấm — chạy được lặp lại, cho ra con số, trước khi lên production và mỗi khi thay đổi bất cứ thứ gì. Tài liệu Anthropic mô tả đây là một vòng lặp trung tâm: định nghĩa tiêu chí thành công → xây eval → tinh chỉnh → validate → ship.
Định nghĩa tiêu chí thành công trước khi đo
Trước khi viết một dòng code eval, hãy trả lời: "tốt" nghĩa là gì? Anthropic gợi ý một tiêu chí thành công tốt phải là:
- Cụ thể (Specific): Thay vì "phân loại tốt", hãy viết "phân loại đúng cảm xúc tích cực/tiêu cực/trung tính".
- Đo được (Measurable): Dùng con số hoặc thang đo định tính nhất quán. Ngay cả chủ đề "mơ hồ" như an toàn cũng lượng hoá được — ví dụ "dưới 0.1% output trong 10,000 lần thử bị bộ lọc gắn cờ độc hại" thay vì "output an toàn".
- Khả thi (Achievable): Đặt mục tiêu dựa trên benchmark ngành hoặc thử nghiệm trước, không mơ mộng vượt khả năng model hiện tại.
- Liên quan (Relevant): Độ chính xác trích dẫn cực kỳ quan trọng với app y tế nhưng ít quan trọng với chatbot giải trí.
Một ví dụ tốt: "Trên tập test giữ riêng gồm 10,000 bài đăng, mô hình phải đạt F1 ≥ 0.85, 99.5% output không độc hại, thời gian phản hồi < 200ms cho 95% request." Hầu hết use case thực tế cần đánh giá đa chiều trên nhiều tiêu chí cùng lúc.
Bộ eval (eval set)
Bộ eval là trái tim của mọi quy trình. Nó gồm:
- Tập input đại diện: những câu hỏi/ngữ cảnh phản ánh đúng phân bố thực tế người dùng sẽ gặp.
- Kỳ vọng hoặc tiêu chí chấm: đáp án đúng (golden answer), hoặc rubric mô tả thế nào là đạt.
Nguyên tắc thiết kế theo Anthropic:
- Bám sát tác vụ thật (task-specific): eval phải phản ánh phân bố công việc thực tế, không phải toàn câu dễ.
- Bao phủ case biên và đối kháng: input rỗng/không liên quan, input quá dài, câu hỏi độc hại hoặc gài bẫy, và cả những case mà chính con người cũng khó thống nhất đáp án.
- Tự động hoá khi có thể: cấu trúc câu hỏi để chấm tự động (multiple-choice, string match, code-graded, LLM-graded).
- Ưu tiên số lượng hơn độ hoàn hảo: nhiều câu hỏi với tín hiệu chấm tự động hơi thấp vẫn tốt hơn ít câu chấm tay hoàn hảo — vì tín hiệu tổng hợp mới quan trọng.
Lời khuyên thực tế: bắt đầu nhỏ (20-50 case cũng đủ có tín hiệu), rồi mở rộng từ lỗi thực tế. Mỗi khi production gặp lỗi thật, hãy biến nó thành một case eval mới — để lỗi đó không bao giờ tái diễn mà không bị phát hiện.
Các cách chấm điểm
Anthropic xếp hạng ba phương pháp chấm theo tốc độ và độ tin cậy: code-based (nhanh nhất, đáng tin nhất, dễ mở rộng nhưng thiếu tinh tế) → human (linh hoạt, chất lượng cao nhất nhưng chậm và đắt, tránh nếu được) → LLM-based (nhanh, linh hoạt, phù hợp phán đoán phức tạp — nhưng phải kiểm tra độ tin cậy trước khi mở rộng).
Chấm tất định (deterministic)
Khi có đáp án rõ ràng, hãy dùng code:
- Exact match:
output.strip().lower() == đáp_án— hoàn hảo cho phân loại (positive/negative/neutral). - Chứa từ khoá:
"Acme Inc." in output. - Regex: kiểm tra định dạng mã, số điện thoại, ngày tháng.
- JSON schema hợp lệ: parse được và đúng schema.
Chấm bằng code / heuristic
Không cần đáp án tuyệt đối nhưng vẫn đo bằng luật: độ dài phản hồi trong khoảng cho phép, đúng định dạng markdown, gọi đúng tool với đúng tham số (xem Tool use & agents).
LLM-as-judge
Với tiêu chí tinh tế — đúng đắn, liên quan, không bịa, giọng điệu — dùng chính một LLM (Claude) làm giám khảo. Vài nguyên tắc từ Anthropic để prompt judge tốt:
- Rubric chi tiết, rõ ràng: "Câu trả lời phải nhắc 'Acme Inc.' ở câu đầu. Nếu không, tự động chấm 'incorrect'."
- Cho điểm cụ thể, thực nghiệm: yêu cầu output chỉ 'correct'/'incorrect' hoặc thang 1-5, tránh đánh giá thuần định tính khó tổng hợp.
- Khuyến khích suy luận trước, chấm sau: cho LLM lý luận trong thẻ
<thinking>rồi mới ra điểm trong<result>— cách này tăng chất lượng chấm cho tác vụ cần phán đoán phức tạp. - Dùng model khác để chấm so với model tạo output khi có thể, để giảm thiên lệch tự-ưu-ái.
Cảnh báo quan trọng: LLM-judge có thiên lệch (thiên vị câu dài, thiên vị vị trí, tự thích phong cách của mình). Vì vậy phải calibrate với nhãn người: lấy vài chục case đã chấm tay, chạy judge, đo mức đồng thuận. Nếu judge lệch nhiều với người, sửa rubric rồi lặp lại — chỉ khi judge đủ tin cậy mới mở rộng ra toàn bộ. Judge không phải chân lý; nó là một công cụ đo cần được hiệu chuẩn.
Human eval
Vẫn cần con người cho những phán đoán khó nhất (chất lượng viết dài, sắc thái đạo đức) và để làm "vàng chuẩn" hiệu chuẩn cho judge. Nhưng dùng tiết kiệm vì chậm và đắt.
Ví dụ code: một LLM-as-judge rút gọn
# LLM-as-judge dùng Anthropic SDK, chấm faithfulness (không bịa ngoài ngữ cảnh)
import anthropic
client = anthropic.Anthropic()
JUDGE_RUBRIC = """Bạn là giám khảo nghiêm khắc. Chấm câu trả lời theo tiêu chí:
- 'correct': mọi khẳng định đều được HỖ TRỢ bởi ngữ cảnh cho sẵn.
- 'incorrect': có ít nhất một khẳng định bịa ra, không có trong ngữ cảnh.
Bỏ qua khác biệt về cách diễn đạt; chỉ xét nội dung có bị bịa hay không."""
def build_judge_prompt(context: str, answer: str) -> str:
return f"""{JUDGE_RUBRIC}
<ngu_canh>{context}</ngu_canh>
<cau_tra_loi>{answer}</cau_tra_loi>
Suy luận trong thẻ <thinking>, sau đó xuất 'correct' hoặc 'incorrect' trong thẻ <result>."""
def judge_faithfulness(context: str, answer: str) -> bool:
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
thinking={"type": "adaptive"}, # cho model suy luận trước khi chấm
messages=[{"role": "user", "content": build_judge_prompt(context, answer)}],
)
text = "".join(b.text for b in resp.content if b.type == "text").lower()
return "<result>correct</result>" in text
Và một eval case minh hoạ — dạng dữ liệu bạn tích lũy dần trong bộ eval:
(minh hoạ) Một eval case cho chatbot RAG
id: refund-policy-01
loai: faithfulness + relevance
cau_hoi: "Tôi mua áo tuần trước, chính sách đổi trả thế nào?"
ngu_canh_lay_ra:
- "Chính sách đổi trả: trong vòng 30 ngày kể từ ngày mua, còn nguyên tem mác."
ky_vong:
- phai_nhac: ["30 ngày", "nguyên tem mác"]
- khong_duoc_bia: true # không được tự chế ra điều kiện khác
- relevance: >= 4 # thang 1-5, chấm bằng LLM-judge
Các tiêu chí phổ biến
Tùy use case, bạn thường đo một tập con của:
- Accuracy / correctness: trả lời có đúng sự thật không.
- Relevance: có trả lời đúng câu hỏi không, hay lạc đề.
- Faithfulness / groundedness: không bịa ngoài ngữ cảnh cho sẵn — tiêu chí then chốt của RAG. Model chỉ được khẳng định những gì có trong tài liệu truy xuất.
- Completeness: có bỏ sót ý quan trọng không.
- Tone / format: đúng giọng điệu và định dạng mong đợi.
- An toàn (safety): không rò rỉ dữ liệu nhạy cảm, không sinh nội dung độc hại. Anthropic khuyến nghị lượng hoá cả tiêu chí này (ví dụ tỷ lệ output bị gắn cờ).
Phân biệt hallucination và faithfulness: hallucination là model bịa thông tin sai; faithfulness là mức độ output bám sát ngữ cảnh được cung cấp. Trong RAG, một câu trả lời có thể đúng sự thật (accurate) nhưng không faithful nếu nó dùng kiến thức nền thay vì tài liệu truy xuất — và ngược lại. Cả hai đều cần đo riêng.
Đánh giá RAG: tách thành hai tầng
Sai lầm phổ biến khi đánh giá RAG là chỉ nhìn câu trả lời cuối. Khi nó sai, bạn không biết lỗi ở đâu: retrieval lấy sai tài liệu, hay generation bịa dù tài liệu đúng? Giải pháp: đánh giá hai tầng độc lập.
Tầng retrieval — đo chất lượng tài liệu lấy về (chưa quan tâm câu trả lời):
- Recall@k: trong top-k tài liệu lấy ra, có bao nhiêu phần trăm tài liệu liên quan thực sự được lấy.
- Precision@k: trong top-k lấy ra, bao nhiêu phần trăm thực sự liên quan.
- Hit rate: tỷ lệ câu hỏi mà ít nhất một tài liệu đúng nằm trong top-k.
Tầng generation — cho ngữ cảnh cố định, đo câu trả lời:
- Faithfulness với ngữ cảnh: câu trả lời có bịa ngoài tài liệu không (dùng LLM-judge như ví dụ trên).
- Answer relevance: câu trả lời có đúng trọng tâm câu hỏi không.
Việc tách tầng cho bạn biết chính xác nên sửa gì. Recall@k thấp → cải thiện embedding, chunking, hoặc thêm re-ranking. Faithfulness thấp trong khi retrieval tốt → sửa prompt generation, buộc model chỉ dùng ngữ cảnh cho sẵn.
Sơ đồ: pipeline eval
Quy trình: offline → A/B → online → CI
Một quy trình eval trưởng thành đi qua bốn giai đoạn:
1. Offline eval. Chạy bộ eval cố định, ra con số theo từng tiêu chí. Đây là nền tảng — làm được bước này bạn đã hơn 90% dự án chỉ thử tay.
2. So sánh model/prompt (A/B). Khi cân nhắc nâng model hay đổi prompt, chạy cả hai phiên bản trên cùng bộ eval và so điểm. Anthropic khuyến nghị A/B testing như một phương pháp đo định lượng. Đây là lúc bạn phát hiện: "prompt mới cải thiện relevance 4% nhưng làm faithfulness giảm 6%" — thông tin không thể có bằng cảm giác. Xem thêm Prompt về cách tinh chỉnh prompt có kỷ luật.
3. Theo dõi online. Sau khi ship, thu thập tín hiệu thực tế: nút thumbs up/down, tỷ lệ hoàn thành tác vụ, log đầy đủ input-output. Người dùng thật sẽ gặp phân bố câu hỏi mà bộ eval offline không lường trước — biến những case lỗi đó thành eval mới.
4. Regression test trong CI. Đây là bước biến eval thành lưới an toàn tự động. Đưa bộ eval vào pipeline CI: mỗi khi ai đó đổi prompt hay bump version model, CI chạy eval và chặn merge nếu điểm tụt dưới ngưỡng.
(minh hoạ) Ngưỡng regression trong CI
Chạy 60 eval case, so với baseline đã lưu:
faithfulness: 0.94 (baseline 0.95, ngưỡng >= 0.93) → PASS
relevance: 0.91 (baseline 0.88, ngưỡng >= 0.85) → PASS (cải thiện)
recall@5: 0.79 (baseline 0.86, ngưỡng >= 0.85) → FAIL → CHẶN MERGE
Kết luận: thay đổi làm suy giảm retrieval → không cho merge.
Vì eval LLM có tính ngẫu nhiên, ngưỡng nên đặt hơi thấp hơn baseline một chút (ví dụ baseline 0.95, ngưỡng 0.93) để tránh false alarm do nhiễu, đồng thời vẫn bắt được suy giảm thật.
Công cụ (nhắc trung lập)
Bạn không phải tự viết mọi thứ. Có các framework eval chuyên dụng để quản lý dataset, chạy chấm và tổng hợp báo cáo; cũng như các công cụ tracing/observability để log và phân tích từng request LLM trong production. Chọn công cụ phù hợp với hạ tầng của bạn — nguyên tắc và tư duy trong bài này áp dụng bất kể công cụ nào.
Use case thực tế: eval cho chatbot RAG trước khi đổi prompt/model
Bạn vận hành một chatbot hỏi đáp nội bộ dựa trên RAG. Sếp yêu cầu nâng model lên phiên bản mới để tiết kiệm chi phí. Không có eval, bạn chỉ có thể "thử vài câu rồi cầu nguyện". Với eval, quy trình là:
- Xây bộ eval 50 case từ log câu hỏi thật, mỗi case gồm câu hỏi, ngữ cảnh đúng, và kỳ vọng (từ khoá phải nhắc, không được bịa, điểm relevance mục tiêu).
- Chạy baseline với model hiện tại, lưu điểm: faithfulness 0.95, relevance 0.88, recall@5 0.86.
- Chạy model mới trên cùng 50 case đó. Kết quả: faithfulness tụt xuống 0.89 — model mới bịa nhiều hơn ở các câu hỏi ngoài phạm vi tài liệu.
- Quyết định dựa trên số liệu: hoặc giữ model cũ, hoặc gia cố prompt generation (buộc model chỉ dùng ngữ cảnh, từ chối khi không đủ thông tin) rồi chạy lại eval cho đến khi faithfulness đạt ngưỡng.
- Đưa bộ eval vào CI để lần nâng cấp sau tự động được bảo vệ.
Điều bạn vừa tránh được: một lần đổi model tưởng vô hại làm chatbot bắt đầu bịa thông tin cho khách hàng — mà không ai biết cho đến khi quá muộn. Đây cũng là nền tảng cho việc vận hành ổn định trên production.
Ghi nhớ
- LLM không tất định + nhạy với thay đổi ⇒ kiểm thử tay không đủ tin cậy. Bạn cần eval đo được, chạy lại được.
- Bắt đầu nhỏ, mở rộng từ lỗi thật. 20-50 case đủ có tín hiệu; mỗi lỗi production biến thành một case eval mới.
- Định nghĩa "tốt" trước: tiêu chí phải cụ thể, đo được, khả thi, liên quan.
- Chọn phương pháp chấm nhanh và tin cậy nhất: code-based khi có đáp án rõ; LLM-as-judge cho phán đoán tinh tế — nhưng phải calibrate với nhãn người và cảnh giác thiên lệch.
- RAG đánh giá hai tầng: tách retrieval (recall@k, precision, hit rate) khỏi generation (faithfulness, answer relevance) để biết lỗi nằm ở đâu.
- Faithfulness là tiêu chí sống còn của RAG: không bịa ngoài ngữ cảnh cho sẵn.
- Đưa eval vào CI như regression test: mỗi thay đổi prompt/model đều phải qua cửa eval trước khi merge; đặt ngưỡng hơi thấp hơn baseline để chịu nhiễu.
- Đóng vòng lặp offline → A/B → online → CI: feedback thực tế nuôi lại bộ eval, khiến hệ thống ngày càng khó hồi quy.
Bài viết liên quan
Phân biệt AI/ML/DL, các kiểu học máy, quy trình ML end-to-end và thuật ngữ nền tảng.
Chất lượng dữ liệu, xử lý thiếu/ngoại lai, mã hoá, chuẩn hoá, tạo đặc trưng và tránh data leakage.
Mô hình ngôn ngữ lớn hoạt động ra sao, token, context window, tham số sinh, và kỹ thuật viết prompt.
Retrieval-Augmented Generation, vector database, tool calling, agent và MCP để xây ứng dụng LLM thực tế.