Tháng nào cũng có model mới. Mỗi model đều có “we beat GPT-4 on benchmark X”. Một thời gian sau model khác lại beat tiếp. Cuối cùng dev không biết tin ai.

Câu hỏi sống còn của AI engineering: làm sao đánh giá LLM đúng cách? Benchmark public có giá trị tới đâu, contamination nguy hiểm thế nào, và quan trọng nhất, làm sao build benchmark cho use case của riêng bạn để biết model nào thực sự phù hợp.

Đây là bài cuối series. Sau 30 bài đi qua từ tokenization đến reasoning model, evaluation là kỹ năng đóng vai trò “thước đo” cho tất cả: bạn không biết kết quả nếu không có cách đo.

Dành cho: dev hoàn thành 29 bài trước hoặc đang ở vị trí cần đánh giá / chọn LLM cho project thật.

Mental model: evaluation là gì

Evaluation = trả lời câu hỏi “model X tốt thế nào cho task Y?”

Có ba loại đánh giá chính:

1. Benchmark public (academic): MMLU, GSM8K, HumanEval, GPQA, etc. Dataset cố định, metric chuẩn, cho phép so sánh model qua thời gian. Lợi cho research, hạn chế cho production decision.

2. Benchmark custom (production): dataset từ use case thực, metric phù hợp business. Lợi cho production, đắt để build và maintain.

3. Human evaluation: human đánh giá output. Thước đo “vàng” cho task subjective (writing, design). Đắt, chậm, không scalable.

Production system tốt: dùng custom benchmark là chính, public benchmark làm reference, human eval làm spot check.

Phần 1: Public benchmark phổ biến

MMLU (Massive Multitask Language Understanding, 2020): 57 chủ đề từ math, history, law, biology. Mỗi câu là multiple choice 4 options.

Question: What is the powerhouse of the cell?
A) Nucleus
B) Mitochondria
C) Ribosome
D) Endoplasmic reticulum

Đo: knowledge breadth. Score = % câu đúng.

Model 2026: GPT-4o ~87%, Claude-3.5 ~88%, Llama-3.1-405B ~85%, Llama-3-8B ~69%, R1 ~91%.

GSM8K (Grade School Math 8K, 2021): 8500 bài toán cấp 2-3 (multi-step arithmetic).

Question: Jen earns $20 per hour. She works 8 hours a day, 5 days a week. After 2 weeks, she spends 30% on rent. How much does she have left?

Đo: multi-step reasoning. Score = % câu đúng (cần verify final number, allow CoT).

Model 2026: GPT-4o ~93%, Claude-3.5 ~95%, Llama-3.1-405B ~96%, Llama-3-8B ~84%, R1 ~97%.

HumanEval (2021): 164 bài code Python. Mỗi bài có docstring + signature, model phải implement function. Verify bằng test cases.

def has_close_elements(numbers, threshold):
    """Check if any two numbers in given list are closer than threshold."""
    # Model phải implement

Đo: code generation. Score = pass@1 (% bài pass test ngay lần đầu).

Model 2026: GPT-4o ~90%, Claude-3.5 ~92%, Llama-3.1-405B ~89%, Llama-3-8B ~62%, R1 ~93%.

MMLU-Pro (2024): harder version của MMLU, 10 options thay vì 4, câu hỏi phức tạp hơn. Số reliable hơn cho model mạnh.

GPQA (Graduate Physics, Chem, Bio, 2023): câu hỏi PhD-level. Rất khó.

Codeforces (competitive programming): benchmark đánh giá code generation ở level olympiad. Reasoning model ưu thế ở đây.

Chatbot Arena (LMSYS): Elo rating dựa trên blind A/B vote từ human. Khó game nhất, sát với perceived quality nhất.

Phần 2: Contamination, vấn đề căn cốt của benchmark public

Mọi benchmark public đều chia sẻ vấn đề: train data có thể chứa benchmark data. Model học đáp án trong training, làm “đúng” ở benchmark mà không thực sự hiểu.

Vd: GSM8K dataset đã trôi khắp internet từ 2021. Model train trên CommonCrawl scrape của internet sẽ thấy nó. Khi test trên GSM8K, model có thể nhớ đáp án thay vì tính.

Bằng chứng contamination:

  • DeepMind nghiên cứu (2024): điểm MMLU của một số model giảm ~10% khi test trên paraphrase câu hỏi.
  • Nhiều model đạt 100% trên một số benchmark cũ (đáng nghi).

Hậu quả: benchmark score 95% không có nghĩa model “biết 95%”. Có thể “nhớ 90% và biết 5%”.

Cách handle:

  • Tin fresh benchmark hơn benchmark cũ (vd MMLU-Pro mới hơn MMLU)
  • Tin private benchmark hơn public (test set ẩn)
  • Tin dynamic benchmark (Chatbot Arena, mỗi câu hỏi unique)
  • Đặc biệt nghi ngờ “near 100%” score

Phần 3: Metric đo sai cách

Ngay cả khi benchmark sạch, metric chọn sai gây hiểu nhầm:

Accuracy: % câu đúng. Đơn giản, hợp cho multiple choice. Không phản ánh được “gần đúng” (math 0.99 ≠ 1.0).

Pass@K (code): % bài pass test trong K attempts. Pass@1 strict, Pass@10 dễ hơn. Đừng so model X Pass@1 vs model Y Pass@10.

Exact match (string): model output phải khớp y hệt expected. Quá strict cho freeform answer.

BLEU, ROUGE (translation, summarization): n-gram overlap. Không phản ánh được semantic correctness.

BERTScore, embedding similarity: dùng embedding model đo similarity. Tốt hơn BLEU cho semantic.

LLM-as-judge: dùng LLM khác (vd GPT-4) đánh giá output. Phổ biến nhưng có bias (judge thiên vị style của chính nó).

Win rate (pairwise): show 2 output cho human / LLM, hỏi cái nào tốt hơn. Ổn định hơn absolute score.

Quy tắc: metric phải phản ánh thực tế. Translation chấm BLEU nghe ổn nhưng có thể model A BLEU 35 dịch tự nhiên hơn model B BLEU 38. Human eval mới biết.

Phần 4: Build custom benchmark cho use case

Đây là phần quan trọng nhất cho production. Quy trình:

Bước 1: Định nghĩa task cụ thể.

Sai: “đo model trả lời câu hỏi customer”. Đúng: “đo model trả lời câu hỏi về policy hoàn tiền của công ty, dựa trên 50 câu hỏi thật + expected answer + expected source chunk từ tài liệu”.

Bước 2: Build test set.

Lượng tối thiểu: 50 câu. Khuyến nghị: 200-500 câu.

Sources:

  • Logs production: query thật từ user
  • Edge cases: case khó user hay hỏi
  • Synthetic: LLM sinh câu hỏi từ tài liệu (cẩn thận vì có thể quá dễ)

Cho mỗi câu, label:

  • Expected answer (hoặc multiple acceptable answers)
  • Expected behavior (vd: phải refuse, phải cite source)
  • Difficulty (easy / medium / hard)
  • Category (vd: pricing question, troubleshooting, refund)

Bước 3: Chọn metric.

Cho factual QA: accuracy với grader (rule-based hoặc LLM judge). Cho summarization: ROUGE + human eval mẫu nhỏ. Cho code: pass test cases. Cho creative: win rate (pairwise vs baseline).

Bước 4: Run baseline.

Test model bạn đang dùng. Đây là baseline. Mọi cải tiến (đổi model, đổi prompt) compare với baseline này.

Bước 5: Track over time.

Mỗi lần đổi code / prompt / model, run benchmark. Lưu kết quả. Nhìn xu hướng theo thời gian. Nếu metric tụt sau một change, revert.

Code framework đơn giản:

import json
from openai import OpenAI

client = OpenAI()

def run_benchmark(test_set, model_name, score_fn):
    results = []
    for item in test_set:
        response = client.chat.completions.create(
            model=model_name,
            messages=[{"role": "user", "content": item['question']}]
        )
        actual = response.choices[0].message.content
        score = score_fn(actual, item['expected'])
        results.append({
            'id': item['id'],
            'question': item['question'],
            'expected': item['expected'],
            'actual': actual,
            'score': score,
            'category': item.get('category', ''),
            'difficulty': item.get('difficulty', '')
        })
    return results

def exact_match(actual, expected):
    return 1.0 if expected.lower().strip() in actual.lower() else 0.0

def llm_judge(actual, expected):
    prompt = f"""Câu trả lời mong đợi: {expected}
Câu trả lời thực tế: {actual}
Câu trả lời thực tế có thể hiện đúng ý không? Chỉ trả lời 'yes' hoặc 'no'."""
    resp = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}]
    )
    return 1.0 if 'yes' in resp.choices[0].message.content.lower() else 0.0

# Sử dụng
with open('test_set.json') as f:
    test_set = json.load(f)

results = run_benchmark(test_set, "gpt-4o-mini", llm_judge)
accuracy = sum(r['score'] for r in results) / len(results)
print(f"Accuracy: {accuracy:.2%}")

# Breakdown by category
by_cat = {}
for r in results:
    by_cat.setdefault(r['category'], []).append(r['score'])
for cat, scores in by_cat.items():
    print(f"{cat}: {sum(scores)/len(scores):.2%} ({len(scores)} samples)")

50 dòng. Đây là MVP eval framework cho production.

Phần 5: LLM-as-judge, tận dụng cẩn thận

Human eval chậm và đắt. LLM judge nhanh và rẻ. Tin được không?

Có, nhưng cẩn thận:

Bias 1: Position bias. LLM judge thiên về câu trả lời đứng trước. Fix: randomize order, hoặc test cả 2 order, lấy trung bình.

Bias 2: Length bias. LLM judge thường thích câu trả lời dài. Fix: nói rõ trong prompt “ngắn gọn tốt hơn nếu đủ thông tin”.

Bias 3: Self-preference. GPT-4 judge thiên về output của GPT-4. Fix: dùng judge model khác family với evaluation target. Hoặc dùng nhiều judge khác nhau, lấy consensus.

Bias 4: Prompt sensitivity. Đổi nhỏ trong judge prompt -> score khác nhiều. Fix: lock judge prompt, version control.

Best practice:

  • Calibrate judge bằng human-labeled sample (vài chục câu). Đo agreement giữa judge và human.
  • Nếu agreement >85%, judge OK cho metric tracking.
  • Nếu thấp hơn, refine prompt hoặc switch judge.

Phần 6: Evaluation cho RAG, agent, structured output

Mỗi use case cần metric riêng.

RAG eval:

  • Retrieval recall@K (top-K chunks có chứa expected source không?)
  • Answer faithfulness (LLM có dựa vào chunks không, hay bịa?)
  • Answer relevance (LLM có trả lời đúng câu hỏi không?)

Tool: Ragas, TruLens.

Agent eval:

  • Task completion rate (% task hoàn thành)
  • Tool call accuracy (gọi đúng tool với đúng args không?)
  • Number of steps (efficient không?)
  • Cost (tokens / wall-clock)

Tool: AgentBench, custom.

Structured output eval:

  • Schema compliance (JSON valid không?)
  • Field accuracy (field nào đúng, field nào sai?)
  • Type correctness

Tool: pydantic validation + custom assertion.

Phần 7: Pitfall thực tế

Pitfall 1: Test set too small.

50 sample dao động ngẫu nhiên ±5%. Một change “cải thiện 3%” có thể chỉ là noise. Tăng test set lên 200-500 cho metric ổn định, hoặc dùng confidence interval.

Pitfall 2: Overfit prompt vào test set.

Tinh chỉnh prompt cho đến khi pass 100% test set. Production có queries khác, performance tệ. Test set là held-out, không tune trên nó.

Quy tắc: chia data thành dev set (tune) và test set (đo cuối). Test set chỉ chạy mỗi 1-2 tuần, không phải mỗi commit.

Pitfall 3: Benchmark không cập nhật.

Production data drift theo thời gian (user hỏi khác, content thay đổi). Test set 6 tháng cũ có thể không phản ánh thực tế hiện tại. Refresh test set định kỳ.

Pitfall 4: Confuse model swap với prompt change.

Đổi prompt thấy benchmark tăng 5%, đổi model thấy tăng 8%. Nghĩ model B tốt hơn? Không chắc, có thể prompt mới hợp model B hơn model A. Test fair: cùng prompt cho cả hai model, hoặc tune prompt cho mỗi model riêng.

Pitfall 5: Bỏ qua latency và cost trong eval.

Model A accuracy 90%, model B 88%. A tốt hơn? Nếu A đắt gấp 10 và chậm gấp 5, B có thể là lựa chọn đúng cho production. Đo cả accuracy lẫn latency, cost.

Cheatsheet

Câu hỏiTrả lời nhanh
Trust benchmark public?Có với fresh, large model; nghi ngờ với near 100% hoặc cũ
Build test set bao nhiêu?Min 50, khuyến nghị 200-500
LLM-as-judge dùng được?Có, calibrate với human sample trước
Metric cho RAG?Recall@K + faithfulness + relevance
Metric cho agent?Task completion + tool accuracy + cost
Eval frequency?Mỗi commit major, snapshot tuần
Bias of LLM judge?Position, length, self-preference, prompt sensitivity
Compare model nào?Same prompt or each tuned, log everything

Quy tắc 80/20:

  • 80% chất lượng production phụ thuộc custom benchmark + iterate
  • 20% phụ thuộc public benchmark / model choice
  • Không có eval = không có cải thiện
  • “If you can’t measure it, you can’t improve it”

Lời kết, đóng series 30 bài

Bạn vừa đi qua 30 bài. Từ mental model LLM đầu tiên (bài 1), qua nền toán (bài 2-5), tokenization và embeddings (bài 6-8), attention và Transformer (bài 9-13), training (bài 14-17), fine-tuning (bài 18-21), inference và production (bài 22-26), tới các hướng advanced (bài 27-30).

Nếu bạn đã làm hands-on song song, bạn đã:

  • Code được nanoGPT từ 300 dòng PyTorch
  • Train BPE tokenizer từ đầu
  • Fine-tune Llama-3-8B với dataset tiếng Việt trên GPU thuê ~$20
  • Quantize model xuống Q4 và deploy với vLLM hoặc llama.cpp
  • Build RAG pipeline end-to-end
  • Hiểu MoE và reasoning model đủ để đọc paper mới
  • Build evaluation framework cho project của riêng mình

Đây là cuộc hành trình dài. Cảm ơn bạn đã đi cùng tới đây.

Một vài suy nghĩ riêng để đóng series.

LLM không phải kết thúc. Field này thay đổi mỗi tháng. Sau khi đọc xong series này, bạn sẽ thấy paper mới mỗi tuần. Phần quan trọng là bạn có mental model vững để parse paper mới một cách critical, không bị shock bởi marketing.

Code mới là thước đo hiểu biết. Đọc 30 bài blog mà không chạy code, bạn hiểu 30%. Code + đọc, bạn hiểu 80%. Code + đọc + giải thích lại cho người khác, bạn hiểu 95%. Đây là lý do series này nhấn mạnh hands-on.

Hiểu để build, không chỉ để dùng. Tiêu đề series. Sự khác biệt giữa dev dùng OpenAI API và dev có thể fine-tune model, build agent, deploy inference engine, là sự khác biệt giữa “user” và “engineer”. Bạn vừa step qua sang phía thứ hai.

Field này cần nhiều người Việt. Đa số content LLM bằng tiếng Anh, đa số contributors là người Mỹ / Trung. Việt Nam có rất nhiều dev giỏi nhưng ít người contribute paper, ít người publish kết quả. Nếu bạn build được gì đáng kể từ series này, share lại. Cho cộng đồng.

Series 30 bài kết thúc ở đây nhưng learning không kết thúc. Tôi đang lên kế hoạch series tiếp theo về AI infrastructure (Kubernetes for AI, GPU clusters, distributed training systems). Nếu bạn quan tâm hoặc có suggest, drop comment, gửi email, ping tôi qua kênh nào bạn thoải mái.

Nếu bài nào trong series có lỗi, có chỗ chưa rõ, hoặc có chủ đề bạn muốn tôi đào sâu hơn: feedback luôn welcome. Series này là working notes của một dev đang học như đã nói ở landing. Mỗi feedback giúp nó tốt hơn.

Chúc bạn build được những thứ thú vị.