Chapter 08

推理模型评估:基准与自定义测试

不会评估的模型选型是瞎猜。理解主流基准的含义,构建贴近业务的自定义评估体系。

为什么评估对推理模型尤为重要

推理模型的"推理 Token"是黑箱——模型声称"思考了很多",但思考过程可能包含大量无效探索,甚至绕圈子。没有系统的评估,你无法判断:增加 budget_tokens 是否真的提升了质量?模型 A 是否真的比模型 B 更适合你的业务?推理模型的高额成本是否带来了相应的价值回报?

主流推理基准解读

MATH(Henderson et al. 2021)
12500 道竞赛数学题,覆盖代数、几何、概率、数论等 7 个子领域,难度分 1-5 级。MATH-500 是精选的 500 题子集,是目前最标准的数学推理基准。o1 在 MATH-500 上达到 92.4%,GPT-4o 约 74%。对于 RAG/Agent 系统,MATH 可以测试多步推导的准确性。
AIME(美国数学邀请赛)
美国顶尖高中数学竞赛,每题答案为 0-999 的整数(自动验证)。极高难度,人类平均分约 5/15(33%)。o1 在 AIME 2024 上达到 83%,DeepSeek-R1 达到 83.9%,标志性突破指标。如果你的业务需要专业级数学推导,AIME 是最有区分度的基准。
GSM8K(Cobbe et al. 2021)
8500 道小学水平数学应用题,解题需要 2-8 步基础运算。曾经是重要基准,但现代大模型基本接近满分(GPT-4o 95%+),区分度很低。现在主要用于验证"基础推理是否正常",而非比较不同模型的高级能力。
HumanEval / MBPP / LiveCodeBench
编程能力基准。HumanEval:164 道 Python 函数编写题,用单元测试验证;MBPP:374 道,更多样。LiveCodeBench(2024-):持续从 Codeforces、LeetCode 抓取新题,避免数据污染。代码推理能力的核心基准,推理模型在此类基准上提升显著(o1 在 Codeforces 达到 89 百分位)。
GPQA Diamond(Rein et al. 2023)
448 道博士级科学题(物理、化学、生物),由活跃的领域专家设计,并经过多人交叉验证。普通人准确率约 34%,非领域专家约 54%,领域专家约 74%。o1 达到 78%,首次超越专家——这是 AI 在严谨科学推理上的历史性突破。
ARC-AGI(Chollet 2019)
通用推理能力测试,要求从少量示例中推导出规则并应用到新情况。GPT-4 只有约 5% 的准确率,o3 达到 75.7%(接近人类 85%)。被认为是衡量"真正智能"最接近的基准之一,未来几年将持续重要。

pass@k 采样策略详解

对于有确定性答案的任务(数学、代码),pass@k 是标准的采样评估策略,它测量"在 k 次机会内至少答对一次"的概率:

import numpy as np
from typing import List, Callable

def estimate_pass_at_k(n: int, c: int, k: int) -> float:
    """
    无偏估计 pass@k
    n: 总采样次数(推荐 10-20)
    c: 正确答案的数量(0 ≤ c ≤ n)
    k: 给定的机会数(pass@1 = 直接正确率, pass@10 = 10次中至少一次正确)
    原理:1 - P(全部失败) = 1 - C(n-c, k) / C(n, k)
    """
    if n - c < k:
        return 1.0  # 正确数量足够,必然 pass
    return 1.0 - np.prod(
        1.0 - k / np.arange(n - c + 1, n + 1)
    )

# 实际意义:
print(f"10次采样中4次正确 → pass@1: {estimate_pass_at_k(10, 4, 1):.1%}")  # 40%
print(f"10次采样中4次正确 → pass@3: {estimate_pass_at_k(10, 4, 3):.1%}")  # ~73%
print(f"10次采样中4次正确 → pass@5: {estimate_pass_at_k(10, 4, 5):.1%}")  # ~87%

def evaluate_with_pass_at_k(
    problems: List[dict],
    model_fn: Callable,
    n_samples: int = 10,
    k_values: List[int] = [1, 3, 10]
) -> dict:
    """对问题集进行 pass@k 评估"""
    all_results = {k: [] for k in k_values}

    for problem in problems:
        # 采样 n 个输出
        outputs = [model_fn(problem["question"]) for _ in range(n_samples)]

        # 统计正确数量
        correct_count = sum(
            verify_answer(problem["correct_answer"], output)
            for output in outputs
        )

        # 计算每个 k 的 pass 概率
        for k in k_values:
            score = estimate_pass_at_k(n_samples, correct_count, k)
            all_results[k].append(score)

    # 返回平均 pass@k
    return {
        f"pass@{k}": np.mean(scores)
        for k, scores in all_results.items()
    }

# 不同 k 值的业务含义:
# pass@1:用户一次查询的准确率(直接部署场景)
# pass@3:用户选择最好的3个答案之一的准确率(多选场景)
# pass@10:验证模型"是否能解决这类问题"(研究场景)

LLM-as-Judge:评估开放性推理回答

数学和代码可以自动验证,但开放性推理任务(策略分析、科学解释、法律推导)需要 LLM 作为评判者:

from pydantic import BaseModel

class JudgmentResult(BaseModel):
    score: int               # 1-10 总分
    accuracy: int            # 准确性 1-10
    completeness: int        # 完整性 1-10
    reasoning_quality: int  # 推理质量 1-10(推理模型特有)
    reason: str              # 评分理由(50字以内)

JUDGE_SYSTEM = """你是一个严格、客观的 AI 回答评估者。
评估维度:
1. accuracy(准确性):核心信息是否正确
2. completeness(完整性):是否覆盖了所有必要方面
3. reasoning_quality(推理质量):推理过程是否严谨、有逻辑
4. score(总分):综合评估

评分标准:
1-3:严重错误或缺失  4-5:部分正确  6-7:基本正确
8-9:优秀  10:完美

只输出 JSON,不要其他内容。"""

def llm_judge_reasoning(
    question: str,
    reference_answer: str,
    model_answer: str,
    judge_model: str = "claude-opus-4-6"  # 用更强的模型作为评判者
) -> JudgmentResult:
    response = client.messages.create(
        model=judge_model,
        max_tokens=512,
        system=JUDGE_SYSTEM,
        messages=[{"role": "user", "content": f"""
问题:{question}

参考答案(标准答案):{reference_answer}

被评估的答案:{model_answer}

请按上述标准评估被评估答案的质量:"""}]
    )
    return JudgmentResult.model_validate_json(response.content[0].text)

# 批量评估并生成报告
def batch_reasoning_evaluation(
    test_cases: list,
    model_fn: Callable
) -> dict:
    judgments = []
    for case in test_cases:
        answer = model_fn(case["question"])
        judgment = llm_judge_reasoning(
            case["question"],
            case["reference"],
            answer
        )
        judgments.append(judgment)

    # 计算各维度均值
    n = len(judgments)
    return {
        "n_samples": n,
        "avg_score": sum(j.score for j in judgments) / n,
        "avg_accuracy": sum(j.accuracy for j in judgments) / n,
        "avg_completeness": sum(j.completeness for j in judgments) / n,
        "avg_reasoning_quality": sum(j.reasoning_quality for j in judgments) / n,
    }

构建业务自定义评估集

公开基准衡量通用能力,但只有业务自定义评估集才能告诉你:模型在你的实际场景中表现如何。

自定义评估集构建步骤: Step 1: 数据收集 ───────────────────────────────────────────── 来源 A:从生产日志中抽取真实用户查询(去隐私化) 来源 B:与业务专家共同设计边界情况测试 来源 C:历史上出现过错误/失败的案例(回归测试集) 目标规模:至少 100 题(小),理想 500+ 题(中) 难度分布:简单 30% / 中等 50% / 困难 20% Step 2: 标注标准答案 ───────────────────────────────────────────── 方式 A(有唯一正确答案):专家撰写标准答案 方式 B(开放性):标注"评估维度 + 关键要素清单" 方式 C(代码类):编写自动化测试用例 注意:标注质量直接决定评估质量,值得投入 Step 3: 定义评估维度 ───────────────────────────────────────────── 必选:准确性(核心答案是否正确) 按业务需求选择: - 完整性(是否覆盖了所有要点) - 安全性(有无有害内容) - 格式合规性(是否符合输出格式要求) - 溯源性(引用是否可验证) Step 4: 持续维护 ───────────────────────────────────────────── 纳入版本控制(Git) 每次模型版本更新都运行全量评估 定期添加新的边界情况(每季度更新 20%) 当线上发现新错误时,立即添加回归用例
import json
from pathlib import Path
from dataclasses import dataclass
from datetime import datetime

@dataclass
class EvalCase:
    """单个评估用例"""
    id: str
    question: str
    reference_answer: str
    difficulty: str         # easy / medium / hard
    category: str           # 业务分类(如 math / code / analysis)
    eval_method: str        # exact_match / llm_judge / unit_test
    tags: list[str]         # 标签(如 regression、edge_case)

class EvalSuite:
    """业务评估套件"""

    def __init__(self, path: str):
        self.path = Path(path)
        self.cases: list[EvalCase] = self.load()

    def run(self, model_fn: Callable, tag_filter: str = None) -> dict:
        """运行评估,返回各维度分数"""
        cases = self.cases
        if tag_filter:
            cases = [c for c in cases if tag_filter in c.tags]

        results = []
        for case in cases:
            answer = model_fn(case.question)

            if case.eval_method == "exact_match":
                score = 1.0 if case.reference_answer.strip() == answer.strip() else 0.0
            elif case.eval_method == "llm_judge":
                judgment = llm_judge_reasoning(case.question, case.reference_answer, answer)
                score = judgment.score / 10.0
            elif case.eval_method == "unit_test":
                score = run_unit_tests(answer, case.reference_answer)

            results.append({
                "case_id": case.id,
                "difficulty": case.difficulty,
                "score": score
            })

        # 按难度和总体统计分数
        return {
            "total": sum(r["score"] for r in results) / len(results),
            "by_difficulty": {
                d: np.mean([r["score"] for r in results if r["difficulty"] == d])
                for d in ["easy", "medium", "hard"]
            },
            "timestamp": datetime.now().isoformat()
        }
基准污染(Benchmark Contamination)风险

公开基准(GSM8K、HumanEval、MATH)的题目可能已经被包含在模型的训练数据中(训练集泄露)。当你看到模型在这些基准上得高分时,不代表实际业务性能也同样优秀。这个问题在 2024-2025 年越来越严重。

缓解措施:优先使用 LiveCodeBench(持续抓取新题)和 AIME 最新年份(每年新题)这类动态基准;或构建你自己的私有评估集(绝对不会污染)。

本章小结

推理模型评估体系:公开基准了解相对能力(MATH、AIME、HumanEval、GPQA Diamond),pass@k 评估有确定答案的推理任务,LLM-as-Judge 评估开放性推理质量。最重要的是构建自己的业务评估集——只有这个才能真正告诉你模型对你的业务有多大价值。注意基准污染风险,优先使用动态基准或私有测试集。下一章进入成本控制策略——让推理模型在生产中具备可行性。