Building Evals — Xây dựng hệ thống đánh giá cho Claude
Điểm nổi bật
Nhấn để đến mục tương ứng
- 1 Tận dụng Claude hiệu quả: Mỗi eval gồm 4 phần thiếu một không được: Input đầu vào: Câu hỏi, văn bản, hoặc task bạn muốn evaluate Output đầu ra: — mẹo quan trọng là cung cấp đủ ngữ cảnh để AI trả về kết quả chính xác hơn 80% so với prompt chung chung.
- 2 Không có giải pháp hoàn hảo: Nhanh nhất và rẻ nhất — dùng code Python thuần để so sánh: Exact Match def exactmatchgraderoutput: str, golden: str. Bài viết phân tích rõ trade-off giúp bạn đưa ra quyết định phù hợp với tình huống thực tế.
- 3 Không thể bỏ qua: def humangradinginterfaceresults: list: """Interface đơn giản cho human reviewer.""" humanscores = for i, result in. Đây là kiến thức nền tảng mà mọi người làm việc với AI đều cần hiểu rõ.
- 4 Khai thác tối đa công cụ AI: INPUT từ user: {input} GOLDEN ANSWER đáp án tham khảo: {golden} ACTUAL OUTPUT response cần đánh giá: {output} Đánh giá. Bí quyết nằm ở cách bạn cấu trúc yêu cầu — prompt càng rõ ràng, output càng sát nhu cầu thực tế.
- 5 Thực tế không hoàn hảo: Thay vào đó: "Response phải chứa ít nhất 3 ví dụ cụ thể" "Độ dài response phải từ 100-300 từ" "Score từ model grader. Biết trước giới hạn sẽ giúp bạn thiết lập kỳ vọng đúng và tránh thất vọng không cần thiết.
Bạn đã viết một prompt cho Claude, nhưng làm sao biết nó thực sự tốt? Cảm giác chủ quan không đủ — bạn cần một hệ thống đánh giá có thể đo lường được, tái lập được, và tự động hóa được. Đó là Evals.
Evals (evaluations) là nền tảng của mọi AI application nghiêm túc. Không có evals, bạn đang bay mù — không biết khi nào prompt regression xảy ra, không biết thay đổi nào thực sự cải thiện kết quả.
Bốn thành phần của một Eval
Mỗi eval gồm 4 phần thiếu một không được:
- Input (đầu vào): Câu hỏi, văn bản, hoặc task bạn muốn evaluate
- Output (đầu ra): Response thực tế từ Claude
- Golden answer (đáp án chuẩn): Câu trả lời "đúng" bạn mong muốn
- Score (điểm số): Kết quả so sánh output với golden answer
Ví dụ đơn giản nhất — eval phân loại sentiment:
| Input | Golden Answer | Output Claude | Score |
|---|---|---|---|
| "Sản phẩm tuyệt vời!" | POSITIVE | POSITIVE | 1.0 |
| "Giao hàng trễ quá." | NEGATIVE | NEGATIVE | 1.0 |
| "Tạm được, không quá tệ." | NEUTRAL | POSITIVE | 0.0 |
Phương pháp 1: Code-based Grading
Nhanh nhất và rẻ nhất — dùng code Python thuần để so sánh:
Exact Match
def exact_match_grader(output: str, golden: str) -> float:
"""1.0 nếu khớp chính xác, 0.0 nếu không."""
return 1.0 if output.strip().lower() == golden.strip().lower() else 0.0
# Test
score = exact_match_grader("POSITIVE", "POSITIVE") # 1.0
score = exact_match_grader("positive", "POSITIVE") # 1.0 (case-insensitive)
score = exact_match_grader("The sentiment is POSITIVE.", "POSITIVE") # 0.0
Regex Match
import re
def regex_grader(output: str, pattern: str) -> float:
"""1.0 nếu output chứa pattern, 0.0 nếu không."""
return 1.0 if re.search(pattern, output, re.IGNORECASE) else 0.0
# Linh hoạt hơn exact match
score = regex_grader("The answer is POSITIVE.", r"POSITIVE") # 1.0
score = regex_grader("sentiment: positive or neutral", r"positive") # 1.0
# Kiểm tra số trong khoảng hợp lệ
def numeric_grader(output: str, min_val: float, max_val: float) -> float:
match = re.search(r"[-+]?d*.?d+", output)
if not match:
return 0.0
value = float(match.group())
return 1.0 if min_val <= value <= max_val else 0.0
Hàm eval hoàn chỉnh
import anthropic
client = anthropic.Anthropic()
def run_eval(test_cases: list, grader_fn) -> dict:
"""Chạy eval trên danh sách test cases."""
results = []
for case in test_cases:
# Gọi Claude
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=100,
messages=[{"role": "user", "content": case["input"]}]
)
output = response.content[0].text
# Chấm điểm
score = grader_fn(output, case["golden"])
results.append({
"input": case["input"],
"output": output,
"golden": case["golden"],
"score": score,
"passed": score >= 0.5,
})
# Tổng kết
accuracy = sum(r["score"] for r in results) / len(results)
return {"accuracy": accuracy, "results": results}
# Test cases
test_cases = [
{"input": "Classify: POSITIVE, NEGATIVE, or NEUTRAL?
'Sản phẩm tuyệt vời!'", "golden": "POSITIVE"},
{"input": "Classify: POSITIVE, NEGATIVE, or NEUTRAL?
'Giao hàng rất tệ.'", "golden": "NEGATIVE"},
{"input": "Classify: POSITIVE, NEGATIVE, or NEUTRAL?
'Bình thường thôi.'", "golden": "NEUTRAL"},
]
results = run_eval(test_cases, lambda out, gold: exact_match_grader(out, gold))
print(f"Accuracy: {results['accuracy']:.1%}")
Phương pháp 2: Human Grading
Với tasks phức tạp — dịch thuật, sáng tác, tư vấn — chỉ con người mới đánh giá được chính xác. Human grading tốn kém hơn nhưng là ground truth thực sự.
def human_grading_interface(results: list):
"""Interface đơn giản cho human reviewer."""
human_scores = []
for i, result in enumerate(results):
print(f"
--- Câu {i+1}/{len(results)} ---")
print(f"INPUT: {result['input']}")
print(f"OUTPUT: {result['output']}")
print(f"GOLDEN: {result['golden']}")
print()
while True:
try:
score = float(input("Điểm (0.0 - 1.0): "))
if 0.0 <= score <= 1.0:
break
print("Vui lòng nhập số từ 0.0 đến 1.0")
except ValueError:
print("Nhập số hợp lệ")
comment = input("Nhận xét (Enter để bỏ qua): ")
human_scores.append({
**result,
"human_score": score,
"comment": comment
})
return human_scores
Tip: Dùng human grading để build dataset nhỏ (~100 cases) ban đầu, sau đó dùng dataset đó để train model-based grader.
Phương pháp 3: Model-based Grading (Claude chấm Claude)
Phương pháp mạnh nhất cho tasks phức tạp và tự động: dùng chính Claude (hoặc model mạnh hơn) để đánh giá output.
GRADER_PROMPT = """Bạn là chuyên gia đánh giá chất lượng AI. Nhiệm vụ: đánh giá response của AI.
INPUT từ user:
{input}
GOLDEN ANSWER (đáp án tham khảo):
{golden}
ACTUAL OUTPUT (response cần đánh giá):
{output}
Đánh giá output theo các tiêu chí:
1. Chính xác về thông tin (0-4 điểm)
2. Đầy đủ, không bỏ sót ý quan trọng (0-3 điểm)
3. Rõ ràng, dễ hiểu (0-3 điểm)
Trả lời theo format:
X
Giải thích ngắn gọn
(X là tổng điểm từ 0 đến 10)"""
def model_based_grader(input_text: str, output: str, golden: str) -> dict:
prompt = GRADER_PROMPT.format(
input=input_text,
golden=golden,
output=output
)
response = client.messages.create(
model="claude-sonnet-4-5", # Dùng model mạnh hơn để chấm
max_tokens=300,
messages=[{"role": "user", "content": prompt}]
)
text = response.content[0].text
# Extract score
score_match = re.search(r"(d+(?:.d+)?) ", text)
score = float(score_match.group(1)) / 10.0 if score_match else 0.0
# Extract reasoning
reasoning_match = re.search(r"(.*?) ", text, re.DOTALL)
reasoning = reasoning_match.group(1).strip() if reasoning_match else ""
return {"score": score, "reasoning": reasoning}
# Ví dụ
result = model_based_grader(
input_text="Giải thích khái niệm machine learning cho người mới.",
output="Machine learning là khi máy tính học từ dữ liệu.",
golden="Machine learning là nhánh AI giúp máy tính học từ dữ liệu mà không cần lập trình cụ thể từng bước, tìm ra patterns để dự đoán."
)
print(f"Score: {result['score']:.1f}/1.0")
print(f"Reasoning: {result['reasoning']}")
Best Practices khi xây dựng Evals
1. Eval phải cụ thể và có thể đo lường
Tránh eval chung chung như "response phải tốt". Thay vào đó:
- "Response phải chứa ít nhất 3 ví dụ cụ thể"
- "Độ dài response phải từ 100-300 từ"
- "Score từ model grader phải trên 7/10"
2. Tự động hóa hoàn toàn
import json
from datetime import datetime
def run_full_eval_suite(prompt_template: str, test_cases: list) -> dict:
"""Chạy eval đầy đủ và lưu kết quả."""
timestamp = datetime.now().isoformat()
results = []
for case in test_cases:
# Inject input vào prompt template
full_prompt = prompt_template.replace("{input}", case["input"])
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=200,
messages=[{"role": "user", "content": full_prompt}]
)
output = response.content[0].text
# Chạy nhiều graders
exact = exact_match_grader(output, case["golden"])
model = model_based_grader(case["input"], output, case["golden"])
results.append({
"case_id": case.get("id", f"case_{len(results)+1}"),
"input": case["input"],
"output": output,
"golden": case["golden"],
"exact_match": exact,
"model_score": model["score"],
"model_reasoning": model["reasoning"],
})
accuracy = sum(r["exact_match"] for r in results) / len(results)
avg_model_score = sum(r["model_score"] for r in results) / len(results)
report = {
"timestamp": timestamp,
"prompt": prompt_template,
"n_cases": len(test_cases),
"accuracy": accuracy,
"avg_model_score": avg_model_score,
"results": results,
}
# Lưu kết quả
with open(f"eval_report_{timestamp[:10]}.json", "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
return report
3. Distribution phải đại diện
Test cases không chỉ nên là "easy cases" — phân bổ theo thực tế:
- 30% easy cases: Claude xử lý tốt ngay từ đầu
- 50% normal cases: Đại diện cho traffic thực tế
- 20% edge cases: Ambiguous, long inputs, unusual formats
Ứng dụng thực tế: Theo dõi Prompt Regression
def compare_prompts(prompt_v1: str, prompt_v2: str, test_cases: list):
"""So sánh hai phiên bản prompt."""
results_v1 = run_full_eval_suite(prompt_v1, test_cases)
results_v2 = run_full_eval_suite(prompt_v2, test_cases)
print("=" * 50)
print(f"Prompt V1 accuracy: {results_v1['accuracy']:.1%}")
print(f"Prompt V2 accuracy: {results_v2['accuracy']:.1%}")
delta = results_v2['accuracy'] - results_v1['accuracy']
print(f"Delta: {'+' if delta > 0 else ''}{delta:.1%}")
if delta > 0:
print("V2 tốt hơn — an toàn deploy!")
elif delta < -0.05:
print("CẢNH BÁO: V2 kém hơn đáng kể — không deploy!")
else:
print("Tương đương — xem xét các yếu tố khác (cost, latency)")
Evals là investment quan trọng nhất bạn có thể làm cho một AI project. Bắt đầu với 20-30 test cases, chạy sau mỗi thay đổi prompt, và bạn sẽ tự tin hơn rất nhiều khi deploy lên production.
Bài viết liên quan
Bai viet co huu ich khong?
Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.






