Evaluating LLMs & Agents: Golden Sets, Metrics, LLM-as-Judge, and Regression in CI
Why eval is the hardest part of shipping agents — golden datasets, offline vs online metrics, LLM-as-judge rubrics, human agreement, and regression in CI.
Bạn có thể tune sampling, viết prompt, gắn RAG, chọn model tốt nhất — vẫn deploy agent fail âm thầm trên production. Evaluation là môn khoa học cho biết mọi effort đó có thực sự cải thiện hay không. Với senior engineer xây agent, eval vừa quan trọng nhất vừa ít được đầu tư nhất trong stack.
Bài này cover cách xây golden dataset, chọn metric khớp task, tự động judge mà không tự lừa mình, và gắn regression suite vào CI. Phần 6 giải thích cách cải thiện output qua fine-tuning, prompting, RAG; phần này giải thích cách biết cải thiện đó là thật.
Mô hình tư duy:Ship agent mà không có eval giống như refactor codebase lớn mà không có test — vẫn compile, demo chạy trên máy bạn, và bạn không biết vừa làm hỏng gì cho người khác. Eval là test suite cho code không deterministic.
Mở demo đầy đủ:
Tại sao eval là phần khó nhất khi ship agent
Agent không deterministic, nhiều bước, phụ thuộc context. Demo “trông ổn” trên ba prompt chọn tay không phải bằng chứng sẵn sàng production.
| Challenge | Why it hurts |
|---|---|
| No single ground truth | Paraphrases, partial credit, multiple valid tool paths |
| Subjective quality | Tone, helpfulness, safety — hard to encode as exact match |
| Distribution shift | Eval set from March; users ask differently in June |
| Compounding errors | One wrong tool call poisons a 10-step trajectory |
| Cost of human review | Expert annotators do not scale to every PR |
Callout: Team ship agent đáng tin coi eval là infrastructure, không phải benchmark một lần trước launch. Họ duy trì golden set sống, chạy regression mỗi khi đổi prompt/model, và theo dõi metric online sau deploy.
Không có eval, bạn optimize theo cảm giác. Có eval, bạn làm eval-driven development — đổi một biến, đo delta, giữ hoặc revert.
Xây golden / eval dataset
Golden set (hay eval set) là tập input được curate kèm output mong đợi hoặc tiêu chí chấm điểm. Đó là hợp đồng cho “good trông như thế nào”.
Mỗi case nên chứa gì
{
"id": "support-refund-042",
"input": {
"messages": [{"role": "user", "content": "Can I return this after 45 days?"}],
"context": "Policy: returns within 30 days of purchase."
},
"reference": "Returns are accepted within 30 days; 45 days exceeds the window.",
"metadata": {
"category": "grounded_qa",
"difficulty": "medium",
"tags": ["policy", "hallucination_trap"]
},
"acceptance": {
"must_mention": ["30 days"],
"must_not_claim": ["full refund after 45 days"]
}
}
Nguồn case
| Source | Strength | Risk |
|---|---|---|
| Production logs (sampled, redacted) | Real distribution | Privacy, PII handling |
| Failure post-mortems | High ROI — every bug becomes a case | Reactive only |
| Synthetic generation | Scale quickly | May not match real user phrasing |
| Edge-case engineering | Catches known failure modes | Overfits to imagined threats |
| Adversarial / red-team | Finds jailbreaks, injection | Maintenance burden |
Bắt đầu 50–200 case chất lượng cao cover critical path. Một nghìn case nông thường ít giá trị hơn năm mươi case mã hóa failure mode thật. Version dataset trong git cùng prompt và model config.
Phân tầng
Gắn tag theo capability: extraction, reasoning, tool selection, multi-turn memory, refusal/safety. Báo metric theo stratum — aggregate 95% có thể che 60% trên tool call.
Offline vs online eval
| Dimension | Offline eval | Online eval |
|---|---|---|
| When | Pre-deploy, CI, local dev | Production traffic |
| Data | Golden set, held-out logs | Live user interactions |
| Cost | Compute + optional human review | Latency, user trust if wrong |
| Signal | Controlled, reproducible | Real distribution, drift |
| Speed | Fast iteration | Slow feedback loops |
Offline eval là lưới an toàn: chạy trước merge, so sánh model A vs B, bắt regression. Online eval xác nhận gain offline chuyển sang thật — A/B test, shadow mode, hàng đợi human review.
Developer change (prompt / model / RAG)
│
▼
Offline golden-set eval ──► pass threshold? ──no──► block merge
│ yes
▼
Staging / canary deploy
│
▼
Online metrics (success rate, latency, CSAT)
│
▼
Feed failures back into golden set
Vòng lặp khép kín khi failure production trở thành golden case mới.
Metric — đo gì và cái gì hỏng
Không metric nào fit mọi task agent. Chọn metric khớp success người dùng thấy được.
Exact match và n-gram overlap
Exact match (EM) — output bằng reference string. Hợp cho classification, câu trả lời factual ngắn, ID có cấu trúc. Vỡ với paraphrase: "Paris" vs "The capital is Paris." được 0 điểm.
BLEU / ROUGE — overlap n-gram với reference. Phổ biến trong benchmark summarization. Phạt diễn đạt hợp lệ; thưởng copy dài dòng. Kém fit cho agent khi task success quan trọng hơn cách diễn đạt.
Semantic similarity
Embed output và reference; chấm cosine similarity. Bắt paraphrase tốt hơn EM. Vẫn mù lỗi factual nếu embedding cluster sai — "Paris is in Germany" có thể điểm cao với "Paris is in France". Dùng như tín hiệu, không phải cổng duy nhất.
Tỷ lệ task success
Agent có hoàn thành mục tiêu không?
- Database query agent — returned rows match expected SQL result
- Support bot — ticket resolved without escalation (human label)
- Code agent — tests pass, diff applies cleanly
Task success là metric leadership quan tâm. Cũng là metric khó tự động hóa ở scale.
Groundedness và faithfulness
Khi agent có context retrieve hoặc kết quả tool, câu trả lời có bám nguồn không?
| Metric | Definition |
|---|---|
| Groundedness | Claims supported by provided context |
| Faithfulness | No contradictions with source material |
| Citation accuracy | Quoted spans exist and support the claim |
Case TC-04 trong demo là lỗi groundedness: model nói 60 ngày trong khi doc ghi 30. Xem thêm AI Hallucination and How to Spot It cho pattern phát hiện.
Tỷ lệ hallucination
Tỷ lệ output chứa claim factual không được evidence hỗ trợ so với bằng chứng có sẵn. Định nghĩa “claim” operational — entity, số, ngày, policy statement. Audit thủ công trên sample; tự động bằng NLI hoặc LLM-as-judge có human calibration.
Độ chính xác tool call
Với agent function-calling, tách thành:
tool_selection_accuracy — picked the right tool?
argument_accuracy — JSON args valid and correct?
execution_success_rate — tool ran without error?
end_to_end_success — final answer correct given tool result?
Model có thể đạt argument_accuracy nhưng fail tool_selection_accuracy khi hai tool overlap. Báo riêng.
Latency và cost
Chất lượng không miễn phí.
| Metric | Why |
|---|---|
| Time-to-first-token (TTFT) | User-perceived responsiveness |
| Total latency | End-to-end task time |
| Tokens in / out | Direct cost driver |
| Tool round-trips | Each hop adds latency and failure surface |
Model rẻ hơn kém 3% nhưng nhanh 4× có thể thắng trên SLO P99 latency. Dashboard eval nên vẽ Pareto quality vs cost.
LLM-as-judge
Khi exact match fail và human review không scale, team dùng LLM mạnh hơn (hoặc cùng model với rubric prompt) để chấm output.
Chấm theo rubric
Định nghĩa tiêu chí có trọng số và thang 1–5:
Correctness (35%) — factually accurate vs reference / context
Relevance (25%) — answers the actual question
Conciseness (15%) — no unnecessary padding
Format/Ground (25%) — valid JSON / faithful to sources
Demo tương tác cho phép gán trọng số tiêu chí và chấm thủ công, rồi bấm Simulate LLM Judge để xem aggregate chấm rubric tự động.
JUDGE_PROMPT = """You are an impartial evaluator. Score the model output 1-5 on each criterion.
## Input
{input}
## Context (if any)
{context}
## Model output
{output}
## Reference (if any)
{reference}
## Criteria
- correctness: factual accuracy
- relevance: addresses the question
- conciseness: no fluff
- format: valid structure / grounded in context
Respond JSON only:
{{"correctness": N, "relevance": N, "conciseness": N, "format": N, "rationale": "..."}}
"""
So sánh cặp
Thay vì điểm tuyệt đối, hỏi judge: “Output nào tốt hơn, A hay B?”. Pairwise thường nhất quán hơn thang 1–5 tuyệt đ đối. Dùng Bradley-Terry hoặc Elo để aggregate pairwise thành leaderboard model.
Bias đã biết và cách giảm
| Bias | Symptom | Mitigation |
|---|---|---|
| Position bias | First answer wins ~55% | Swap A/B order, average both |
| Verbosity bias | Longer answer rated higher | Rubric: penalize padding; compare length-normalized |
| Self-preference | GPT-4 prefers GPT-4 outputs | Use different judge model than candidate |
| Anchoring | Reference answer skews scores | Hide reference when testing open-ended tasks |
| Leniency drift | Scores inflate over time | Anchor with frozen calibration cases |
Callout: LLM-as-judge là proxy, không phải ground truth. Calibrate với nhãn human trên slice cố định — nếu agreement judge-human dưới ~80% Cohen’s κ, sửa rubric trước khi tin automation.
Human eval và inter-annotator agreement
Human eval vẫn là chuẩn vàng cho chất lượng chủ quan, safety, và failure mode mới.
Thiết kế human eval
- Rubric rõ kèm ví dụ mỗi mức điểm
- So sánh mù — annotator không thấy tên model
- Case trùng — cùng case được 2+ annotator chấm
- Adjudication — reviewer thứ ba giải quyết bất đồng
Agreement giữa annotator
Đo Cohen’s κ (hai rater) hoặc Fleiss’ κ (nhiều rater):
κ < 0.40 — poor agreement; rubric is ambiguous
κ 0.40–0.60 — moderate; refine definitions
κ 0.60–0.80 — substantial; usable for training judges
κ > 0.80 — strong; rubric is tight
κ thấp nghĩa là sửa rubric, không đổ lỗi annotator. Nhãn human cũng calibrate LLM-as-judge — chạy cả hai trên cùng 100 case hàng tháng.
Regression suite trong CI
Coi golden set như unit test.
1. Run agent on golden set (fixed seed where possible)
2. Score with automated metrics + LLM-as-judge
3. Compare vs baseline branch (main)
4. Fail if aggregate drops > ε OR any P0 case fails
Tab A/B Regression trong demo so sánh Model A (baseline) vs Model B (candidate) theo case — TC-04 cải thiện 2.1 → 3.8 sau sửa prompt.
# Pseudocode: CI eval gate
BASELINE = load_scores("main")
CANDIDATE = run_eval(agent_config, golden_set)
REGRESSION_TOLERANCE = 0.05 # max allowed drop on aggregate
P0_CASES = {"support-refund-042", "sql-injection-007"}
for case_id in P0_CASES:
assert CANDIDATE[case_id].passed, f"P0 regression: {case_id}"
delta = CANDIDATE.aggregate - BASELINE.aggregate
assert delta >= -REGRESSION_TOLERANCE, f"Aggregate dropped by {abs(delta):.2f}"
Lưu artifact eval (điểm, output, latency) làm CI artifact để review diff. Pin model version và prompt hash trong eval config.
Eval-driven development
Mượn vòng TDD cho agent:
1. Add failing case to golden set (from bug report or anticipated edge)
2. Run eval — confirm failure
3. Change prompt / RAG / model / tool schema
4. Re-run eval — confirm case passes without regressions elsewhere
5. Merge with CI gate
Ngăn vòng “sửa một chỗ, vỡ ba chỗ” hay gặp khi iterate prompt. Eval-driven development đi cùng chiến lược adaptation từ Fine-tuning vs Prompting vs RAG — mỗi thay đổi strategy có delta đo được.
Eval riêng cho agent
Metric QA một lượt bỏ sót hầu hết failure mode agent.
Trajectory nhiều bước
Log full trace: thought, tool call, observation, câu trả lời cuối. Chấm từng bước và end-to-end:
| Level | Question |
|---|---|
| Step | Was this tool call correct given state? |
| Trajectory | Did the path reach the goal efficiently? |
| Outcome | Is the final answer correct? |
Câu trả lời đúng qua path 12 bước lãng phí là bug cost và reliability tiềm ẩn.
Eval tool use
{
"expected_tools": ["search_policy", "format_response"],
"forbidden_tools": ["delete_user"],
"max_tool_calls": 3,
"expected_final_state": {"ticket_status": "resolved"}
}
Kiểm tra thứ tự tool sequence khi quan trọng — authenticate trước transfer_funds.
Eval memory và context
Case multi-turn test agent có giữ constraint qua các lượt không. Chèn lượt gây nhiễu để test focus. Sau context compaction (Phần 5), chạy lại case nặng memory.
Eval safety và refusal
Gồm case phải refuse — jailbreak, request ngoài scope, trích PII. Task success cao vô nghĩa nếu agent cũng comply request có hại.
Gắn lại — eval stack tối thiểu
golden_set.json — versioned cases + metadata
rubric.yaml — criteria, weights, pass threshold
run_eval.py — batch inference + scoring
judge_prompt.txt — LLM-as-judge template
ci_eval.yml — PR gate vs baseline
dashboard — aggregate + per-stratum + cost/latency
| Layer | Tooling examples |
|---|---|
| Dataset | Git, Label Studio, custom JSON |
| Inference | Your agent runner, LangSmith traces, Braintrust |
| Metrics | Custom scripts, Ragas, DeepEval |
| Judge | GPT-4o, Claude, open-weight Llama + rubric |
| CI | GitHub Actions, threshold gates |
| Online | A/B platform, human review queue |
Bắt đầu tối giản: golden set JSON, một rubric, một script, một CI job. Mở rộng khi khoảng trống metric chặn quyết định release.
Điểm chính
- Eval là infrastructure — không phải checkbox trước launch.
- Golden set mã hóa failure thật; phân tầng và version.
- Metric cổ điển (EM, BLEU) vỡ với paraphrase; dùng task success, groundedness, tool accuracy cho agent.
- LLM-as-judge scale chấm rubric — calibrate với human, giảm position/verbosity bias.
- Regression trong CI bắt drift prompt và model trước user.
- Eval agent cần chấm cấp trajectory, không chỉ câu trả lời cuối.
Lỗi thường gặp
- “Chạy ổn trên ba prompt”tự tin theo demo, không có golden set đứng sau.
- Tin LLM-as-judge mù quángchưa calibrate với nhãn human; bias vị trí và độ dài chưa kiểm soát.
- Chỉ báo số tổngtrung bình 95% lặng lẽ che stratum tool-call 60%.
- Chỉ chấm câu trả lời cuối với agentbỏ sót trajectory lãng phí hoặc thiếu an toàn mà tình cờ ra đúng.
- Eval set không bao giờ lớn lênfailure production không quay lại thành case mới, nên cùng một bug ship hai lần.
- Train hoặc judge trên eval setđiểm offline ảo, sập ngoài thực tế.
Khi nào nên dùng
Khớp đầu tư eval với mức độ ảnh hưởng:
| Stage / risk | Minimum eval |
|---|---|
| Prototype, internal, throwaway | A handful of smoke cases run by hand |
| Public feature, no tools | 50–100 golden cases + automated metrics in CI |
| Agent with tools / external data | + trajectory & tool-call scoring + safety/refusal cases |
| High-stakes (money, health, legal) | + human review queue + online A/B + calibrated judge |
Khi nào bỏ qua bộ máy nặngmột script chạy một lần hoặc demo bỏ đi ngày mai. Ngay khi user thật phụ thuộc vào output, eval hết là tuỳ chọn.
Bắt đầu nhanh
Dựng eval harness trong một buổi chiều:
- Thu 20–50 case thậtlấy từ log hoặc bug report cũ; redact PII.
- Viết
golden_set.jsoninput, reference (hoặc tiêu chí chấp nhận), và tagcategorymỗi case. - Chọn một metric khớp tasktask success cho agent, groundedness cho RAG, exact match cho classification.
- Thêm LLM-as-judge kèm rubricrồi đối chiếu 10 điểm của nó với điểm bạn tự chấm.
- Gắn vào CIfail PR nếu số tổng tụt quá ngưỡng hoặc một P0 case vỡ.
Rồi khép vòng lặp: mỗi failure production thành một golden case mới, để cùng một bug không bao giờ ship hai lần.
Tiếp theo: khi đo được chất lượng, chọn model và framework đạt ngưỡng eval với cost chấp nhận được — Choosing a Model.
Loạt bài Building AI Agents
- Tokens & Context Windows
- Sampling: temperature, top_p, top_k
- Prompt Engineering for Agents
- Stopping Criteria & Output Control
- Context Engineering & Memory
- Fine-tuning vs Prompting vs RAG
- Evaluating LLMs & Agents (current)
- Choosing a Model
- Function Calling & Tool Use
- Agent Patterns: ReAct, Reflection, Planning