当评测器比模型更不靠谱:Agent 评测管道的 18.5% 幻觉率与工程自救指南
最新研究发现 Agent 工具调用评测的误对齐率高达 18.5%,同一配置重复跑分差 18.9 个百分点。本文拆解评测器的五种失灵模式,给出从污染检测、可复现管道到分解式评测的三层工程自救方案。
一、你看到的排行榜,有 1/5 是评测器的幻觉
2026 年 6 月 30 日,一篇来自 Bhat、Vaghasiya、Mohsin 和 Aali 的论文(arXiv:2607.02577)给 Agent 评测领域投下了一枚”元评测炸弹”。研究团队对 BFCL v4、τ2-Bench、LiveMCPBench 和 MCP-Atlas 四大主流工具调用评测基准进行了 496 个任务的人工复核审计,结论令人不安:
18.5% 的评测分数与人类专家判断不一致。
这不是个例,不是某个特定评测的 bug。这是当前 Agent 评测基础设施的系统性脆弱。
更令人震惊的是 LiveMCPBench 的发现:相同的 Agent + 相同的任务 + 相同的配置,重复运行 23 次,分数从 57.9% 波动到 76.8%——18.9 个百分点的差距,足以改变整个排行榜的排名结论。
想象一下这个场景:你花了两周时间调优 Agent,模型从 v1 换到 v2,benchmark 分数涨了 10 个百分点。你准备写周报了——但你可能不知道,这 10 个百分点的提升里,有一大半根本不是模型变强了,而是评测器那天心情好。
二、评测器失灵的五种模式
这篇论文的价值,不仅在于发现了问题,更在于它给出了系统性的故障分类学。评测器的失灵不是随机的——它有清晰可分类的模式。
确定性评测器的三种”硬伤”
1. 脆弱状态匹配(Brittle State Matching)
确定性评测器依赖于对 Agent 执行后系统状态的精确比对。问题在于,出题人定义”正确状态”时往往漏掉了合法但不同的实现路径。Agent 用一个稍有不同的文件名存储了结果——功能完全 OK,但字符串匹配失败,判负。
// 评测器预期的输出文件名
expected_output: "report_2026-07-23.csv"
// Agent 实际输出
actual_output: "report_20260723.csv"
// 判决:FAIL(功能正确,但命名格式不同)
2. 轨迹锁定(Trajectory Lock-in)
评测器预先定义了”正确”的工具调用序列。Agent 分两步调用 API 完成了任务(第一步查参数、第二步创建资源),而标注者预期的是三步(查参数、验证、创建)。缺少”验证”步骤导致整个任务被判失败——但两步方案在实际生产中更快且无误。
3. 基础事实错误(Incorrect Ground Truths)
连出题人自己也会把标注搞错。论文中发现多起 ground truth 本身无法完成任务的情况——Agent 不可能通过,因为”正确答案”本身就是错的。
LLM-Judge 评测器的两种”软偏”
4. 评分标准漂移(Rubric Drift)
LLM 做 Judge 时,对同一评分标准的理解会在不同运行时漂移。上次跑认为”基本可用”给 70 分,这次同样的输出给 55 分——因为 Judge 模型先看到了一个更好的输出做对比。
5. 幻觉补全(Hallucinated Completion)
LLM-Judge 在判断任务是否完成时,会”脑补”Agent 没有执行但应该已经完成的步骤。Agent 实际上只做了三件事,Judge 报告里写了五件——后两件是 Judge 自己合理推断出来的。这不是恶意,但结果完全不可靠。
三、工程自救方案一:污染检测前置
在相信任何公开评测分数之前,首先要确认一件事:模型有没有见过考题。
CoDeC:给模型做个”测谎”
CoDeC(Contamination Detection via Context,ICLR 2026)是目前最实用的检测方法。它的核心思想很简单:如果模型真的理解了一个题目,给它多一点上下文(比如一个相似的示例),它的置信度应该基本不变。但如果模型是背答案的,上下文会干扰它的记忆提取——置信度下降。
# CoDeC 的核心思路:对比有无上下文时的 token 概率
import numpy as np
from vllm import LLM, SamplingParams
def codec_score(model, benchmark_items, context_examples):
"""
返回 0-100 的污染嫌疑度。
> 80:高度可疑(可能被污染)
60-80:灰色地带
< 60:大概率干净
"""
llm = LLM(model=model, dtype="bfloat16", max_model_len=4096)
params = SamplingParams(max_tokens=1, prompt_logprobs=1)
baseline = []
with_context = []
for item in benchmark_items:
# 基线:只给题目
b_out = llm.generate([item["prompt"]], params)
baseline.append(_extract_confidence(b_out))
# 加一个上下文示例再问
ctx_prompt = context_examples[item["topic"]] + "\n" + item["prompt"]
c_out = llm.generate([ctx_prompt], params)
with_context.append(_extract_confidence(c_out))
# 上下文导致置信度下降的比例
drops = sum(1 for b, c in zip(baseline, with_context) if c < b * 0.9)
return (drops / len(benchmark_items)) * 100
def _extract_confidence(outputs):
"""从 vLLM prompt_logprobs 提取平均置信度"""
logprobs = outputs[0].prompt_logprobs
# 跳过前 10 个 token(噪声大),取剩余的平均
return np.exp(np.mean([lp[list(lp.keys())[0]].logprob
for lp in logprobs[10:] if lp]))
重要警告:CoDeC 对经过了 RL 后训练的推理模型可能失效。ASTRAL Group(UIUC + UW,Han Wang, Haoyu Li, Brian Ko, Huan Zhang)在 ICLR 2026 的研究(arXiv:2510.02386)表明,GRPO 强化学习可以”抹去”污染的检测信号——同一个模型在 RL 前 CoDeC 得分 85%(染污),RL 训练 64 步后降到 55%(看起来干净)。不要因为 CoDeC 没报警就放心。
CCV:让模型重做五遍
Cross-Context Verification(CCV)是污染检测的另一条路径:让模型在温度 0 下独立重复 5 次相同任务,检查解的多样性。
# 5 次独立运行的结果对比
Run 1: def solve(grid): return bfs(grid, (0,0), (n-1,m-1))
Run 2: def solve(grid): return bfs(grid, (0,0), (n-1,m-1))
Run 3: def solve(grid): return bfs(grid, (0,0), (n-1,m-1))
Run 4: def solve(grid): return bfs(grid, (0,0), (n-1,m-1))
Run 5: def solve(grid): return bfs(grid, (0,0), (n-1,m-1))
# AST 相似度: 99.8%(五份复制粘贴 → 极度可疑)
真实理解问题的模型应该会产生变量命名、实现路径上的自然变化。五份一模一样的输出是记忆复现,不是推理。
四、工程自救方案二:让评测可以复现
Tool-Veritas 论文提出的 Harness Lab 概念,给出了评测可复现性的工程解法。核心思想很简单——评测本身应该是一个可审计、可重放、可对比的系统,而不是一个”跑完出分就完事”的黑箱。
Harness Lab 的设计原则
┌─────────────────────────────────────────────────┐
│ Harness Lab │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ 任务定义 │→│ 执行引擎 │→│ 评测器(多选) │ │
│ │ (YAML) │ │ (Docker) │ │ - 确定性检查 │ │
│ │ │ │ │ │ - LLM Judge │ │
│ │ │ │ │ │ - 人工复核标记 │ │
│ └──────────┘ └──────────┘ └───────────────┘ │
│ ↓ ↓ │
│ ┌──────────────────────────┐ │
│ │ Trace Store(完整审计) │ │
│ │ - 每个 step 的输入/输出 │ │
│ │ - 工具调用原始日志 │ │
│ │ - 评测器判断 + 置信度 │ │
│ │ - 运行环境 hash │ │
│ └──────────────────────────┘ │
└─────────────────────────────────────────────────┘
最小可执行的评测管道
# eval-pipeline.yaml — 一个强调可复现性的评测定义
name: "agent-tool-calling-smoke"
version: "1.0.0"
environment:
image: "eval-runner:v2.4"
hash: "sha256:a1b2c3..."
tasks:
- id: "mcp-file-read-001"
description: "读取 /data/config.json 并解析 API endpoint"
setup:
docker: "mcp-testbed:file-ops"
pre_state:
files:
- path: "/data/config.json"
content_hash: "sha256:def456..."
expected:
# 分解式评估:分别检查工具调用、任务完成、结果验证
tool_invocation:
- tool: "read_file"
args: { path: "/data/config.json" }
required: true
task_completion:
evaluator: "deterministic"
check:
type: "json_contains_key"
key: "api_endpoint"
value_type: "string"
outcome_verification:
evaluator: "llm_judge"
model: "claude-sonnet-4.5"
prompt_template: "verify_config_read.jinja2"
# 多次运行取均值,减少方差
runs: 3
execution:
repeats: 5 # 5 次重复运行
timeout_per_task: 300 # 秒
seed: 42 # 固定种子——降方差
capture_traces: true # 保存完整执行链路
reporting:
metrics:
- "tool_invocation_accuracy"
- "task_completion_rate"
- "outcome_verification_agreement"
output:
format: ["json", "html"]
include_trace: true
这里的关键设计选择是多次重复和分解式指标。单次运行的分数在大多数 Agent 评测中是不可靠的——5 次重复、取中位数、报告标准差应该成为标配。
评测管道的 CI 集成
# eval_ci.py — 在 CI 中加入评测可靠性校验
import json
import sys
from pathlib import Path
def check_eval_reliability(results_dir: str, threshold: float = 0.05):
"""
校验评测结果的可靠性。
如果评分方差超过阈值,CI 失败——评测本身不可信。
"""
with open(Path(results_dir) / "summary.json") as f:
data = json.load(f)
for task_id, stats in data["tasks"].items():
mean = stats["mean_score"]
std = stats["std_score"]
# 18.9pp 的方差是不可接受的——参考 Tool-Veritas 的发现
if std > threshold * 100:
print(f"❌ {task_id}: std={std:.1f}pp > {threshold*100:.1f}pp 阈值")
print(f" 分数: {stats['scores']}")
print(f" 该评测不可靠,CI 阻断。")
sys.exit(1)
# 额外检查:是否有 run-to-run 方向性差异
if stats["max_score"] - stats["min_score"] > 15:
print(f"⚠️ {task_id}: range={stats['max_score'] - stats['min_score']:.1f}pp")
print(f" 评测方差过大,建议人工复核后再引用分数。")
print("✅ 所有评测可靠性检查通过")
if __name__ == "__main__":
check_eval_reliability(sys.argv[1])
把这段校验嵌入 CI 管道的一个直接效果是:你不会再被一个碰巧跑出高分的模型骗进生产环境。
五、工程自救方案三:分解式评测
Tool-Veritas 论文最核心的方法论贡献,是将单一的”通过/失败”评判决,拆分为三个独立可测的维度:
| 维度 | 测的是什么 | 评测方式 | 典型陷阱 |
|---|---|---|---|
| 工具调用 | Agent 是否调用了正确的工具?参数是否正确? | 确定性匹配(工具名 + 参数签名) | 轨迹锁定——合法但不相同的调用序列被判错 |
| 任务完成 | Agent 是否达成了用户的最终目标? | 状态验证(环境状态检查点) | 状态匹配过于脆弱,忽略等效结果 |
| 结果验证 | 输出是否满足定性要求? | LLM Judge(有约束)+ 人工抽样 | 评分标准漂移,单次运行不具代表性 |
拆分之后,你可以回答一些过去被单一大分数掩盖的关键问题:
- 模型 A 的工具调用准确率 92%,但任务完成率只有 65%?→ 它每次都能调对工具,但是用错参数或调用顺序导致任务失败。
- 模型 B 的任务完成率 80%,但结果验证只有 55%?→ 它能”形式上”完成任务,但输出质量达不到生产标准。
这类诊断,过去需要工程师手动翻 trace 才能发现。分解式指标让它自动化。
生产实践:评分模板
# 生产环境评测配置的关键片段
evaluators:
tool_call:
type: "deterministic"
match_mode: "structural" # 不强制精确顺序
ignore_fields: ["timestamp", "request_id"] # 忽略非确定性字段
task_completion:
type: "state_checkpoint"
checks:
- type: "file_exists"
path: "/output/report.csv"
- type: "file_contains"
path: "/output/report.csv"
pattern: "total_revenue"
- type: "http_status"
url: "http://api:8080/health"
expected: 200
outcome_quality:
type: "llm_judge"
model: "claude-sonnet-4.5"
runs: 3 # 跑三次取中位数
rubric: |
评估输出是否满足以下要求:
1. CSV 文件包含表头
2. 数值精度 ±1%
3. 不包含调试信息或中间输出
评分: 0-100
constraints:
- "如果 CSV 包含 Markdown 格式标记,扣 20 分"
- "如果输出中引用了评测提示词原文,评分为 0"
六、开箱即用的评测可靠性自查清单
如果你现在负责一个 Agent 系统,以下是今天就能执行的 7 项自查:
- 评测结果是否报告了标准差? 如果只报告均值不报告分布,分数无效。
- 是否至少重复运行了 3 次? 单次运行的分数在大多数 Agent 评测中是不可靠的。Tool-Veritas 显示 LiveMCPBench 单次分数方差可达 18.9pp。
- 是否对评测器本身做过人工审计抽样? 随机抽 50 个任务,让人看 Agent 的实际输出和评测器的判断——你会发现 15-20% 左右的误判率。
- LLM-Judge 是否运行了多次并报告了一致性? 单次 LLM-Judge 判断受 position bias、verbosity bias 和 rubric drift 三重污染。
- 是否有基于训练截止日期的污染检测? 如果模型声称在某个 benchmark 上表现优秀,先确认 benchmark 的题目发布时间是否在模型训练截止之后(LiveCodeBench 和 LiveBench 是黄金标准)。
- 确定性评测的 ground truth 是否经过人工验证? 别信出题人的——OpenAI 审计发现 SWE-bench Pro 约 30% 的题目本身就有问题。
- 评测环境是否 Docker 化且有版本 hash? 跑分结果无法复现的头号原因就是环境不一致。每一个评测管道都应该有一个 commit hash 绑定的 Docker 镜像。
七、结论:评测不是 QA 的最后一环,而是工程质量的一部分
Tool-Veritas 这篇论文给我们的教训远不止”有些 benchmark 有问题”这么浅。它在传达一个更深层的信号:
评测基础设施本身的工程质量,已经成为 Agent 研发流程中最被低估的技术债。
过去我们花 80% 的时间调模型,20% 的时间看分数。现在是时候把这个比例倒过来——在确认评测管道本身可靠之前,任何”涨点”都可能是评测器的随机抖动。
三个立即可执行的动作:
- 给每个评测管道加上
repeats: 5和标准差报告——这是最小改动,最大收益。 - 从分解式评测的三个维度(工具调用/任务完成/结果验证)各抽 20 个 case 做人工审计——你会对自己过去信以为真的分数产生怀疑。
- 把 CoDeC 污染检测纳入新模型接入流程的必选步骤——别看排行榜,先测是否见过题。
评测不是为了证明自己做得对,而是为了发现自己错在哪里。当评测器自己都在犯错的时候,诚实比准确更重要。