10.2 Benchmark 与测试集
上一节我们定义了评估指标,但光有指标还不够——就像你有一把尺子,但不知道量什么。Benchmark 就是给 Agent 的"标准化考卷",它提供了统一的、可复现的、可比较的评测基准。
生活类比:Benchmark 就像是 AI 界的"高考"——所有人做同一套卷子,分数可以横向比较。没有高考,你说你家孩子学习好、他家孩子也学习好,谁也说服不了谁。
为什么需要 Benchmark?
Benchmark 是 AI 领域的"高考"——它提供了一套标准化的、可复现的、可比较的评测体系。对于 Agent 开发而言,Benchmark 的价值体现在:
┌──────────────────────────────────────────────────────────────┐
│ Benchmark 的价值 │
├──────────────────────────────────────────────────────────────┤
│ │
│ 1. 横向对比:不同模型/框架在相同任务上的表现差异 │
│ 2. 纵向追踪:同一 Agent 在迭代过程中的能力变化 │
│ 3. 能力定位:发现 Agent 在哪些能力维度上存在短板 │
│ 4. 社区共识:与学术界和工业界使用相同的评测标准 │
│ 5. 回归检测:及时发现新版本引入的能力退化 │
│ │
└──────────────────────────────────────────────────────────────┘通用 LLM 能力 Benchmark
这些 Benchmark 最初面向纯语言模型,但它们是 Agent 基础能力的重要参考——就像公务员考试的"行测"科目,考的是基础素质,不是岗位技能。
MMLU(Massive Multitask Language Understanding)
┌────────────────────────────────────────────────────────────┐
│ MMLU 概览 │
├────────────────────────────────────────────────────────────┤
│ 全称:Massive Multitask Language Understanding │
│ 题目数:约 15,908 道选择题 │
│ 领域:57 个学科(数学、历史、法律、医学、计算机等) │
│ 形式:4 选 1 选择题 │
│ 评测方式:零样本(Zero-shot)或少样本(Few-shot) │
│ 代表分数:GPT-4 (86.4%), Claude 3.5 (88.7%) │
│ │
│ 对 Agent 的意义: │
│ - 衡量 Agent 底层 LLM 的知识广度和推理能力 │
│ - 如果 Agent 依赖的模型 MMLU 很低,复杂任务会频繁出错 │
└────────────────────────────────────────────────────────────┘评测示例:
问题:在量子力学中,海森堡不确定性原理表明:
A) 能量和时间不能同时精确测量
B) 位置和动量不能同时精确测量 ← 正确答案
C) 粒子的自旋是确定的
D) 波函数在测量时坍缩生活类比:MMLU 像是"百科知识竞赛"——题海战术覆盖 57 个学科,逼模型把"通识教育"补齐。如果 Agent 底层模型在 MMLU 上分数很低,就像请了个高中没毕业的助手,专业知识再强也会在常识题上翻车。
GSM8K(Grade School Math 8K)
┌────────────────────────────────────────────────────────────┐
│ GSM8K 概览 │
├────────────────────────────────────────────────────────────┤
│ 全称:Grade School Math 8K │
│ 题目数:8,500 道小学数学应用题 │
│ 形式:多步推理数学题,需要给出最终答案 │
│ 特点:需要 Chain-of-Thought 推理 │
│ 代表分数:GPT-4 (92.0%), Claude 3.5 (96.4%) │
│ │
│ 对 Agent 的意义: │
│ - 衡量 Agent 的多步推理和数学计算能力 │
│ - 代码执行类 Agent 应在数学推理上有良好表现 │
└────────────────────────────────────────────────────────────┘生活类比:GSM8K 是"小学应用题考试"——题目不难,但需要一步步推导。就像算账:买了 3 斤苹果每斤 5 元、2 斤香蕉每斤 3 元,给 50 元找回多少?推理链断裂就全错。
HumanEval
┌────────────────────────────────────────────────────────────┐
│ HumanEval 概览 │
├────────────────────────────────────────────────────────────┤
│ 全称:HumanEval (OpenAI) │
│ 题目数:164 道 Python 编程题 │
│ 形式:给出函数签名和文档字符串,生成函数体 │
│ 评测:生成的代码通过单元测试的比例(pass@k) │
│ 代表分数:GPT-4 (87.0% pass@1) │
│ │
│ 对 Agent 的意义: │
│ - 直接衡量代码 Agent 的编程能力 │
│ - SWE-bench 的前置能力要求 │
└────────────────────────────────────────────────────────────┘Agent 专项 Benchmark
与通用 Benchmark 不同,Agent 专项 Benchmark 模拟真实世界中的 Agent 使用场景——不是考理论,而是考实操。
AgentBench
┌──────────────────────────────────────────────────────────────┐
│ AgentBench │
├──────────────────────────────────────────────────────────────┤
│ 来源:清华大学 & 智谱 AI (2023) │
│ 场景:8 个真实环境,覆盖 5 大类任务 │
│ │
│ ├─ 操作系统(OS):在真实 Linux 终端中执行操作 │
│ ├─ 数据库(DB):SQL 查询与数据分析 │
│ ├─ 知识图谱(KG):知识图谱查询与推理 │
│ ├─ 卡牌游戏(DC):数字卡牌游戏策略 │
│ ├─ 横向思维谜题(LTP):需要创造力的问题 │
│ ├─ 家居(Household):在虚拟家庭环境中操作 │
│ ├─ 网页购物(WebShopping):模拟电商网站操作 │
│ └─ 网页浏览(WebBrowsing):真实网页信息检索 │
│ │
│ 评测方式:Agent 在环境中执行动作,根据任务完成度评分 │
│ 代表分数:GPT-4 (综合 3.95/5.0) │
└──────────────────────────────────────────────────────────────┘生活类比:AgentBench 像是"职业资格实操考试"——不只是答题,而是让你在模拟工作环境中完成任务。比如考驾照,不是背交规就行,得上路开。
SWE-bench
┌──────────────────────────────────────────────────────────────┐
│ SWE-bench │
├──────────────────────────────────────────────────────────────┤
│ 来源:Princeton University (2024) │
│ 题目数:2,294 个真实 GitHub Issue │
│ 形式:给定 Issue 描述和代码仓库,Agent 自动修复 Bug │
│ 评测:生成的 Patch 通过所有测试用例 │
│ │
│ 核心流程: │
│ Issue 描述 ──► Agent 定位代码 ──► 生成 Patch ──► 运行测试 │
│ │
│ 代表分数: │
│ - Devin (13.86%) │
│ - SWE-Agent + GPT-4 (12.47%) │
│ - Claude 3.5 Sonnet + Agent (26.2%) │
│ │
│ 对 Agent 的意义: │
│ - 直接衡量代码 Agent 解决真实软件问题的能力 │
│ - 是当前最受关注的 Agent 评测基准之一 │
└──────────────────────────────────────────────────────────────┘生活类比:SWE-bench 是"程序员面试的实操题"——给你一个真实的 GitHub Issue,你需要在陌生代码库中找到问题、定位修复、保证不引入新 bug。比"写个冒泡排序"难多了。
WebArena
┌──────────────────────────────────────────────────────────────┐
│ WebArena │
├──────────────────────────────────────────────────────────────┤
│ 来源:CMU (2024) │
│ 场景:模拟真实网站(电商、社交、GitLab、地图、CMS) │
│ 任务:812 个真实世界 Web 操作任务 │
│ 形式:Agent 在浏览器中执行操作,完成指定任务 │
│ │
│ 任务示例: │
│ - "在购物网站找到最便宜的 27 寸 4K 显示器" │
│ - "在 GitLab 创建一个新的 Issue 并分配给某人" │
│ - "在 Reddit 上发布一篇帖子" │
│ │
│ 代表分数:GPT-4 (14.4%), GPT-4V (16.1%) │
│ │
│ 对 Agent 的意义: │
│ - 衡量 Web 浏览类 Agent 的真实操作能力 │
│ - 需要视觉理解 + 页面交互 + 多步规划 │
└──────────────────────────────────────────────────────────────┘Benchmark 使用流程
使用 Benchmark 评测 Agent 不是"下载个数据集跑一下"这么简单,需要一套完整的 Pipeline:
┌──────────────────────────────────────────────────────────────┐
│ Benchmark 评测 Pipeline │
├──────────────────────────────────────────────────────────────┤
│ │
│ 1. 选择 Benchmark │
│ └─ 根据 Agent 类型选择匹配的 Benchmark │
│ │
│ 2. 环境准备 │
│ └─ Docker 容器 / 沙箱 / API 权限 │
│ │
│ 3. 数据加载 │
│ └─ 下载数据集、预处理、过滤 │
│ │
│ 4. 执行评测 │
│ └─ Agent 逐题执行、记录完整日志和 Trace │
│ │
│ 5. 结果评估 │
│ └─ 自动评分 + 人工抽检验证 │
│ │
│ 6. 结果分析 │
│ └─ 生成报告、对比基线、定位问题 │
│ │
└──────────────────────────────────────────────────────────────┘自建测试集
Benchmark 虽然好,但总有"不够贴业务"的问题。就像通用驾照考试不会考你"在特定小区地库里怎么侧方停车"。自建测试集是必不可少的。
自建测试集的设计原则:
1. 代表性:覆盖真实业务场景的典型 case 和边界 case
2. 多样性:包含不同难度、不同领域的任务
3. 可评估:每个 case 都有明确的成功标准
4. 可维护:定期更新,淘汰过时的 case
5. 防泄漏:测试集不要出现在训练数据中下面是测试集构建工具的完整实现,代码逐行注释:
import json # JSON 序列化/反序列化
import hashlib # 用于生成测试用例 ID
from dataclasses import dataclass, field # 数据类装饰器
from typing import List, Optional, Dict # 类型注解
from datetime import datetime # 时间戳
@dataclass
class TestCase:
"""测试用例数据结构——一个完整的测试用例定义"""
id: str # 用例唯一标识(自动生成)
category: str # 任务类别:客服/代码/分析/...
difficulty: str # 难度:easy/medium/hard
description: str # 任务描述(给 Agent 的输入)
expected_behavior: str # 期望的行为描述
eval_criteria: Dict # 评估标准(如何判定通过)
# 对于有标准答案的任务
expected_answer: Optional[str] = None # 标准答案(可选)
# 对于需要工具调用的任务
required_tools: List[str] = field(default_factory=list) # 需要调用的工具列表
expected_tool_calls: List[Dict] = field(default_factory=list) # 期望的工具调用序列
# 元数据
created_at: str = field(default_factory=lambda: datetime.now().isoformat()) # 创建时间
tags: List[str] = field(default_factory=list) # 标签,如 ["order", "query"]
source: str = "manual" # 来源:manual/user_feedback/production_log
def __post_init__(self):
"""初始化后处理:如果未提供 ID,自动生成"""
if not self.id:
# 使用描述的 MD5 哈希前 8 位作为 ID
self.id = hashlib.md5(
self.description.encode()
).hexdigest()[:8]
class TestSetBuilder:
"""测试集构建器——管理测试用例的增删改查"""
def __init__(self, name: str, version: str = "1.0"):
"""
初始化测试集构建器
Args:
name: 测试集名称,如 "customer_service_agent"
version: 版本号
"""
self.name = name # 测试集名称
self.version = version # 版本号
self.cases: List[TestCase] = [] # 测试用例列表
def add_case(self, case: TestCase):
"""添加测试用例"""
# 检查 ID 是否重复
if any(c.id == case.id for c in self.cases):
raise ValueError(f"Duplicate case ID: {case.id}")
self.cases.append(case)
def add_from_production_log(
self, logs: List[Dict], category: str = "production"
):
"""
从生产日志中提取测试用例
生产日志包含了真实用户查询,是高质量的测试数据来源。
"""
for log in logs:
case = TestCase(
id="", # 自动生成
category=category,
difficulty=log.get("difficulty", "medium"), # 默认中等难度
description=log["user_query"], # 用户原始查询
expected_behavior=log.get("expected_behavior", ""),
expected_answer=log.get("expected_answer"),
eval_criteria=log.get("eval_criteria", {"type": "exact_match"}),
source="production_log", # 标记来源
tags=log.get("tags", []),
)
self.add_case(case)
def add_from_user_feedback(
self, feedbacks: List[Dict], category: str = "user_feedback"
):
"""
从用户反馈中提取测试用例(特别是失败 case)
用户反馈中的差评 case 是最有价值的测试数据——它们直接暴露了 Agent 的弱点。
"""
for fb in feedbacks:
if fb.get("rating", 5) <= 3: # 只收集低分反馈(1-3 分)
case = TestCase(
id="",
category=category,
difficulty=fb.get("difficulty", "hard"), # 用户投诉通常是难题
description=fb["user_query"],
expected_behavior=fb["expected_behavior"],
eval_criteria=fb.get("eval_criteria", {"type": "llm_judge"}),
source="user_feedback",
tags=["user_reported"] + fb.get("tags", []), # 标记为用户报告
)
self.add_case(case)
def get_statistics(self) -> Dict:
"""获取测试集统计信息——了解测试集的覆盖分布"""
categories = {} # 按类别统计
difficulties = {} # 按难度统计
sources = {} # 按来源统计
for case in self.cases:
categories[case.category] = categories.get(case.category, 0) + 1
difficulties[case.difficulty] = difficulties.get(case.difficulty, 0) + 1
sources[case.source] = sources.get(case.source, 0) + 1
return {
"name": self.name,
"version": self.version,
"total_cases": len(self.cases),
"by_category": categories,
"by_difficulty": difficulties,
"by_source": sources,
}
def export(self, filepath: str):
"""导出测试集为 JSON 文件——便于版本管理和团队共享"""
data = {
"name": self.name,
"version": self.version,
"created_at": datetime.now().isoformat(),
"cases": [
{
"id": c.id,
"category": c.category,
"difficulty": c.difficulty,
"description": c.description,
"expected_behavior": c.expected_behavior,
"expected_answer": c.expected_answer,
"eval_criteria": c.eval_criteria,
"required_tools": c.required_tools,
"tags": c.tags,
"source": c.source,
}
for c in self.cases
]
}
with open(filepath, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"Test set exported to {filepath}: {len(self.cases)} cases")
@classmethod
def load(cls, filepath: str) -> "TestSetBuilder":
"""从 JSON 加载测试集——便于恢复和复用"""
with open(filepath, "r", encoding="utf-8") as f:
data = json.load(f)
builder = cls(name=data["name"], version=data["version"])
for c in data["cases"]:
case = TestCase(
id=c["id"],
category=c["category"],
difficulty=c["difficulty"],
description=c["description"],
expected_behavior=c["expected_behavior"],
expected_answer=c.get("expected_answer"),
eval_criteria=c["eval_criteria"],
required_tools=c.get("required_tools", []),
tags=c.get("tags", []),
source=c.get("source", "manual"),
)
builder.add_case(case)
return builder实战演练:HumanEval 评测代码生成
下面演示如何使用 HumanEval 评测 Agent 的代码生成能力:
import subprocess # 执行子进程(运行代码)
import tempfile # 临时文件管理
import os # 文件操作
from typing import Dict, List
# HumanEval 示例题目(简化版)
HUMANEVAL_SAMPLE = [
{
"task_id": "HumanEval/0",
"prompt": '''def has_close_elements(numbers: List[float], threshold: float) -> bool:
""" Check if in given list of numbers, are any two numbers closer to
each other than given threshold.
>>> has_close_elements([1.0, 2.0, 3.0], 0.5)
False
>>> has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3)
True
"""
''',
"test": ''' # 单元测试代码
def test_has_close_elements():
assert has_close_elements([1.0, 2.0, 3.0], 0.5) == False
assert has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3) == True
assert has_close_elements([1.0, 2.0, 3.0], 1.5) == True
assert has_close_elements([], 1.0) == False
assert has_close_elements([1.0], 1.0) == False
test_has_close_elements()
print("All tests passed!")
''',
},
]
def evaluate_code(code: str, test_code: str) -> Dict:
"""
执行代码并运行测试
Args:
code: 生成的代码
test_code: 测试代码
Returns:
包含 passed、stdout、stderr 的字典
"""
# 创建临时 Python 文件
with tempfile.NamedTemporaryFile(
mode="w", suffix=".py", delete=False
) as f:
f.write("from typing import List\n\n") # 写入必要的导入
f.write(code) # 写入被测代码
f.write("\n\n")
f.write(test_code) # 写入测试代码
temp_path = f.name # 获取临时文件路径
try:
# 运行临时文件,设置 10 秒超时
result = subprocess.run(
["python", temp_path],
capture_output=True, # 捕获 stdout 和 stderr
text=True, # 以文本模式返回
timeout=10, # 超时时间
)
passed = "All tests passed!" in result.stdout # 检查是否通过
return {
"passed": passed,
"stdout": result.stdout.strip(),
"stderr": result.stderr.strip(),
}
except subprocess.TimeoutExpired: # 超时处理
return {"passed": False, "stdout": "", "stderr": "Timeout"}
finally:
os.unlink(temp_path) # 清理临时文件
def run_humaneval_eval(
model_fn, # 函数:接收 prompt,返回生成的代码
sample: List[Dict] = HUMANEVAL_SAMPLE,
) -> Dict:
"""运行 HumanEval 评测"""
results = []
for task in sample:
generated_code = model_fn(task["prompt"]) # 调用模型生成代码
eval_result = evaluate_code(generated_code, task["test"]) # 评估
results.append({
"task_id": task["task_id"],
"passed": eval_result["passed"],
"error": eval_result["stderr"] if not eval_result["passed"] else None,
})
print(f" {task['task_id']}: {'✓' if eval_result['passed'] else '✗'}")
passed = sum(1 for r in results if r["passed"]) # 统计通过数
total = len(results)
return {
"pass@1": f"{passed}/{total} = {passed/total*100:.1f}%", # pass@1 指标
"total": total,
"passed": passed,
"details": results,
}
# 模拟模型返回(实际使用中替换为真实的 API 调用)
def mock_model(prompt: str) -> str:
"""模拟模型返回——实际使用时应调用 LLM API"""
return '''
for idx, elem in enumerate(numbers):
for idx2, elem2 in enumerate(numbers):
if idx != idx2:
distance = abs(elem - elem2)
if distance < threshold:
return True
return False
'''
# 运行评测
print("HumanEval 评测示例")
print("=" * 50)
result = run_humaneval_eval(mock_model)
print(f"\n最终结果: pass@1 = {result['pass@1']}")实战演练:构建业务测试集
下面演示如何为客服 Agent 构建自定义测试集:
from test_set_builder import TestSetBuilder, TestCase # 导入上面定义的类
# 1. 创建测试集构建器
builder = TestSetBuilder(name="customer_service_agent", version="1.0")
# 2. 手动添加测试用例——覆盖核心场景、边界 case 和复杂场景
manual_cases = [
{
"category": "order_query", # 订单查询场景
"difficulty": "easy", # 简单任务
"description": "查询订单 #12345 的状态",
"expected_behavior": "调用订单查询工具,返回订单状态为'已发货'",
"expected_answer": "订单 #12345 当前状态:已发货,预计 7 月 23 日送达",
"eval_criteria": {"type": "contains", "values": ["已发货", "7 月 23 日"]},
"required_tools": ["query_order"], # 需要调用订单查询工具
"tags": ["order", "query"],
},
{
"category": "refund", # 退货场景
"difficulty": "medium", # 中等难度——多步骤
"description": "我要退掉订单 #12345 中的商品,已经收到货了但是尺码不合适",
"expected_behavior": "先查询订单状态,确认已签收,然后引导用户走退货流程",
"eval_criteria": {"type": "llm_judge"}, # 需要 LLM 判断
"required_tools": ["query_order", "initiate_refund"], # 需要两个工具
"tags": ["refund", "multi_step"],
},
{
"category": "multi_turn", # 多轮对话场景
"difficulty": "hard", # 困难——三步操作
"description": "先查询我的订单,然后帮我取消最近的一个,最后推荐一个类似商品",
"expected_behavior": "三步操作:查询订单列表 -> 取消最近订单 -> 推荐类似商品",
"eval_criteria": {"type": "llm_judge"},
"required_tools": ["query_orders", "cancel_order", "recommend_products"],
"tags": ["multi_step", "complex"],
},
{
"category": "edge_case", # 边界 case——不存在的订单
"difficulty": "hard",
"description": "帮我查询一个不存在的订单 #99999",
"expected_behavior": "调用查询工具,得到不存在的结果,友好地告知用户",
"expected_answer": "未找到订单 #99999",
"eval_criteria": {"type": "contains", "values": ["未找到", "不存在"]},
"required_tools": ["query_order"],
"tags": ["edge_case", "error_handling"],
},
{
"category": "knowledge", # 知识库查询场景
"difficulty": "easy",
"description": "你们的退货政策是什么?",
"expected_behavior": "从知识库中检索退货政策并准确回答",
"eval_criteria": {"type": "rag_faithfulness"}, # 评估 RAG 忠实度
"required_tools": ["search_knowledge_base"],
"tags": ["knowledge", "rag"],
},
]
# 逐个添加测试用例
for case_data in manual_cases:
case = TestCase(
id="", # 留空,自动生成
category=case_data["category"],
difficulty=case_data["difficulty"],
description=case_data["description"],
expected_behavior=case_data["expected_behavior"],
expected_answer=case_data.get("expected_answer"),
eval_criteria=case_data["eval_criteria"],
required_tools=case_data.get("required_tools", []),
tags=case_data.get("tags", []),
source="manual",
)
builder.add_case(case)
# 3. 查看测试集统计
stats = builder.get_statistics()
print("测试集统计:")
print(f" 总用例数: {stats['total_cases']}")
print(f" 按类别: {stats['by_category']}")
print(f" 按难度: {stats['by_difficulty']}")
print(f" 按来源: {stats['by_source']}")
# 4. 导出测试集
builder.export("./customer_service_test_set.json")
print("\n测试集已导出!")Benchmark 使用注意事项
使用 Benchmark 时有几个常见的"坑"需要警惕:
| 陷阱 | 说明 | 应对策略 |
|---|---|---|
| 数据污染 | 测试集数据出现在训练数据中 | 使用最新发布的 Benchmark、定期更新测试集 |
| 过拟合 | 针对特定 Benchmark 优化而非真实能力提升 | 在多个 Benchmark 上交叉验证 |
| 评估偏差 | 自动评分与人工判断不一致 | 定期人工抽检,校准自动评分 |
| 环境差异 | 评测环境与生产环境不一致 | 使用 Docker 标准化环境 |
| 样本偏差 | 测试集不能代表真实分布 | 从生产日志中采样构建测试集 |
生活类比:数据污染就像考试题泄露了——学生不是真学会了,而是背了答案。所以重要考试每年都换题,Benchmark 也要定期更新。
常见误区
误区一:只跑通用 Benchmark,忽略 Agent 专项 Benchmark
MMLU、GSM8K 只能说明底层模型的"基本功",但 Agent 的核心能力——工具调用、多步规划、环境交互——通用 Benchmark 完全测不到。必须配合 AgentBench、SWE-bench 等专项 Benchmark 才能全面评估。
误区二:Benchmark 分数高就等于生产表现好
Benchmark 是标准化场景,而生产环境的真实用户问题往往更加多样和不可预测。一个 Agent 在 Benchmark 上得分 90%,可能在处理真实用户的长尾问题时表现糟糕。自建测试集才是贴近业务的"试金石"。
误区三:测试集一成不变
业务在发展,用户问题在变化,测试集也需要定期更新。半年前的典型 case 可能已经不代表当前业务了。建议至少每月 review 一次测试集,淘汰过时 case,补充新的 case。
误区四:忽视评估标准的多样性
不同任务需要不同的评估标准:精确匹配(exact_match)、包含检查(contains)、LLM 判断(llm_judge)、RAG 忠实度(rag_faithfulness)各有适用场景。一刀切用精确匹配会漏掉大量"语义正确但表达不同"的好答案。
本节小结
| Benchmark | 类型 | 评测维度 | 适用场景 |
|---|---|---|---|
| MMLU | 通用 | 知识广度 | 基础模型选型 |
| GSM8K | 通用 | 数学推理 | 推理能力验证 |
| HumanEval | 通用 | 代码生成 | 代码 Agent 基础 |
| AgentBench | Agent | 多环境交互 | 综合 Agent 能力 |
| SWE-bench | Agent | 代码修复 | 编程 Agent 专项 |
| WebArena | Agent | Web 操作 | Web Agent 专项 |
关键原则:
- 通用 Benchmark 衡量基础能力,Agent Benchmark 衡量交互能力,两者缺一不可
- SWE-bench 是当前评估代码 Agent 的"金标准",但需要完整的 Docker 评测环境
- 自建测试集必须从真实业务场景出发,覆盖核心 case、边界 case 和失败 case
- 定期更新测试集,防止数据污染和过拟合
- 测试集应包含明确的评估标准(exact_match / contains / llm_judge / rag_faithfulness)
有了标准化的考题,接下来需要一位"阅卷老师"来自动评分——这正是 10.3 节 LLM-as-Judge 要解决的问题。