Skip to content

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. 防泄漏:测试集不要出现在训练数据中

下面是测试集构建工具的完整实现,代码逐行注释:

python
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 的代码生成能力:

python
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 构建自定义测试集:

python
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 基础
AgentBenchAgent多环境交互综合 Agent 能力
SWE-benchAgent代码修复编程 Agent 专项
WebArenaAgentWeb 操作Web Agent 专项

关键原则

  • 通用 Benchmark 衡量基础能力,Agent Benchmark 衡量交互能力,两者缺一不可
  • SWE-bench 是当前评估代码 Agent 的"金标准",但需要完整的 Docker 评测环境
  • 自建测试集必须从真实业务场景出发,覆盖核心 case、边界 case 和失败 case
  • 定期更新测试集,防止数据污染和过拟合
  • 测试集应包含明确的评估标准(exact_match / contains / llm_judge / rag_faithfulness)

有了标准化的考题,接下来需要一位"阅卷老师"来自动评分——这正是 10.3 节 LLM-as-Judge 要解决的问题。