Lecture 12 · 评估基础与 benchmark 设计 · Evaluation Fundamentals & Benchmark Design

Engineering AI Agents · Lecture 12。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 Maps to:Stanford CS329Z Engineering AI Agents(Fall 2026),Lecture 12 · Wed Nov 4 · Evaluation Fundamentals & Benchmark Design。阅读材料:Zhu et al., Establishing Best Practices for Building Rigorous Agentic Benchmarks(2025)/ Press, How to Build Good Language Modeling Benchmarks;Polo et al., tinyBenchmarks: Evaluating LLMs with Fewer Examples(ICML 2024)。 依据说明:写作时(2026-10-16)这一讲的 slides 还没有公布。本讲依据课表上的主题描述(为什么评估难、4 元组框架——请求、环境、停止条件、判分器——每一部分怎样设计、好 benchmark 的性质、贴近真实的脚手架、可靠性的维度)和阅读材料来写;tinyBenchmarks 在第 11 讲 §2 已经细讲。引用的论文和博客内容都核对过原文。全部实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:code/lecture12/(只用 Python 标准库;5 个脚本 + 2 个模块 + 1 个可选脚本;不需要 API key;每个脚本几秒以内) 预计阅读时间:3 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

学完这一讲你应该能够:

  1. 说出智能体评估比”问答评估”难在哪里:随机性、长链条、副作用、多种正确解法、依赖脚手架。
  2. 用 4 元组(请求、环境、停止条件、判分器)描述一个智能体任务,并知道每一部分有哪些设计选择、各自会怎样让分数失真。
  3. 用 ABC 检查清单的两个维度——任务有效性、结果有效性——审查一个 benchmark,识别常见漏洞(环境泄露答案、空回答也算成功、判分器太松、坏任务、步数上限太小),并用参照智能体和”谁都做不对的任务”把它们找出来。
  4. 报告可靠性的几个维度(pass^k、鲁棒性、容错、效率),而不只是一个准确率。
  5. 给评估结果配上置信区间;用配对比较判断两个系统的差别是否可信;估算需要多少道题;知道题目成簇时标准误会被低估。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面再展开 Previewed only
第 4 讲 §7:BFCL、τ-bench、按状态判分、pass^kLLM 评审、评估基础设施(第 13 讲)
第 10 讲 §5:优化数据和评估数据要分开;第 11 讲:IRT、坏题、tinyBenchmarks安全评估、红队(第 14 讲)
前置讲 P3:超时、重试;第 1 讲 §6.1:pass@k 与 pass^kSWE-bench 与编程智能体的评估(第 15 讲)

0.3 本讲地图 Map

§0.6 开场:一个分数背后的十几个决定
§1  为什么智能体的评估难                                                       ← 代码 01
§2  4 元组:请求、环境、停止条件、判分器——每一部分怎样设计                         ← 代码 02
§3  好 benchmark 的性质:Press 的三条建议、ABC 的任务有效性与结果有效性             ← 代码 03
§4  可靠性的维度:一致性、鲁棒性、容错、效率                                      ← 代码 04
§5  评估的统计:置信区间、配对比较、要多少道题、题目成簇                            ← 代码 05
§6  用真实模型试一试                                                          ← 代码 06(可选)
§7  一份 benchmark 发布前的清单
§8 小结   §9 常见误区   §10 练习   §11 延伸阅读   §12 下一讲预告

0.4 术语 Terms

术语本讲里的意思
4 元组一个任务 = 请求(给智能体的指令)+ 环境(它能操作的世界)+ 停止条件(何时结束)+ 判分器(怎样判成功)
任务有效性(task validity)任务可解,当且仅当智能体具备被测的能力——没有捷径,也没有不可能的任务
结果有效性(outcome validity)评估结果真的反映任务是否成功——判分器不太松、也不太严
参照智能体(reference agent)用来校准分数的特殊智能体:什么都不做的(“地板”)、无所不能的(“天花板”)
脚手架(scaffolding / harness)包在模型外面的那一层:工具、步数上限、重试、提示词(第 5、6 讲)
pass@k / pass^kk 次里至少成功一次 / k 次全部成功的概率
配对比较两个系统在同一批题上逐题比较(McNemar 检验),而不是把两个分数当独立样本
成簇(clustering)很多题来自同一个模板 / 仓库,彼此相关;有效样本量小于题数

0.5 本讲的代码

代码在 Orrin Grid 的客服数据库上按 4 元组搭了一个小 benchmark(bench_lab.py):20 个客户,6 类任务——查余额、查有没有停电记录、取消预约、“有停电才补偿”、“谢谢,没事了”(什么都不用做)、查一个不存在的客户——共 200 个,其中 8% 是坏任务(标准答案写错了、或者要求一件环境里做不到的事)。

智能体是模拟的,每一个代表一种行为:

智能体行为
能干的九成的任务做对,步数正常
慢但对的一样准,但要用 2.5 倍的步数
偷懒的什么都不做,回一句 “Done.”
两头下注的“yes or no""20、25 还是 30 美元”;动手的任务一半做对
偷看答案的环境里有答案文件就去读;否则一半做对
能力一般的七成做对;工具出错时不会重试;换个说法就容易出错

提醒:智能体做对的概率、需要的步数、对换说法的敏感程度是参数;环境、工具、停止条件、判分器、漏洞的效果都是真的实现——漏洞真的会让某种行为”得分”。统计部分(stats_lab.py)按 IRT 模拟每道题的结果。

0.6 开场:一个分数背后的十几个决定

“我们的智能体在某某 benchmark 上得了 62%。“这句话背后有十几个决定:题从哪来、请求怎么写、环境给哪些工具、每个任务开始前重不重置、最多允许多少步、怎样判断成功、坏题删没删、跑了几次、用的什么脚手架……每一个决定都能让这个数字上下浮动好几个点,有的能让它翻倍。

前两讲我们一直在”用”评估集:拿它挑提示词、估计成功率、判断数据好不好。这一讲正面讨论怎样造一个评估——第 13 讲再讲怎样用 LLM 当判分器、怎样搭评估的基础设施。


1. 为什么智能体的评估难 · Why evals are hard

1.1 和问答评估比

问答评估:一个问题、一个答案、一个标准答案,比较一下就行。智能体评估多了好几层难度:

  • 每次运行都不一样:LLM 采样有随机性,工具和环境也可能有(网络、时间、外部 API)。
  • 链条长:几十步里任何一步出错,结果就错;而且同一个任务往往有多种正确的做法。
  • 有副作用:智能体改了数据库、发了邮件、删了文件——判分不能只看它最后说了什么,还要看它做了什么、有没有做多余的事。
  • 依赖脚手架:同一个模型,给不同的工具、不同的步数上限、不同的提示词,表现可以差很多(第 5 讲的”harness 税”)。
  • 贵:跑一次完整的 benchmark 可能要几小时、几百美元,于是大家只跑一次、题也出得少——这又加大了不确定性。

1.2 一个任务的 4 元组

代码 01 打印了一个任务:

请求:If Nia Kovac has a logged outage, add a 20 dollar credit to the account; otherwise change nothing.
环境:20 个客户的数据库(余额、是否记录了停电、套餐、预约)+ 工具(查询、修改);每个任务开始前重置
停止条件:智能体说完了,或者用满 10 步
判分器:数据库的最终状态和期望的一致(Nia Kovac:停电 True,余额 10 → 30;其他客户不变)

1.3 运行之间的波动

同一个智能体、同一套 183 道有效题,跑 10 次:

智能体全部题,10 次运行的最低 – 最高随机 50 道题,10 次的最低 – 最高
能干的90.2% – 95.6%88% – 96%
慢但对的88.5% – 95.6%86% – 98%
能力一般的71.6% – 82.0%64% – 88%

“能力一般的”只跑一次、只用 50 道题,可能得 64%,也可能得 88%。题少、只跑一次时,几个点的差别可能只是运气(§5 讲怎样量化它)。

1.4 失败的方式不只是”答错”

“能力一般的”在修好的版本上:成功 145、回答错了 30、改了不该改的客户(副作用)7、数据库状态不对 1。在其他设置下还会出现工具出错后放弃、步数用完被截断。所以智能体的判分器通常要看最终状态,还要检查”没有做多余的事”——第 4 讲 τ-bench 按数据库状态判分就是这个道理。

1.5 脚手架改变排名

脚手架能干的慢但对的能力一般的排名
最小:最多 3 步、工具 10% 出错94.2%62.0%74.0%能干的 > 能力一般的 > 慢但对的
常见:最多 10 步、工具 10% 出错91.6%94.3%70.4%慢但对的 > 能干的 > 能力一般的
理想:最多 10 步、工具不出错93.7%92.2%76.7%能干的 > 慢但对的 > 能力一般的

只给 3 步时,“慢但对的”排在最后;给 10 步时它和”能干的”不相上下。你测的到底是模型,还是脚手架? Press 的建议是:baseline 的脚手架要贴近当前的常见做法(能执行代码、能上网、合理的步数)——太简陋的脚手架会让读者不信任结果。


2. 4 元组:每一部分怎样设计 · Designing the four components

Press 在博客里建议把每个任务定义成 4 样东西,并为每一样做出明确的选择(包括判分是二元的还是连续的)。代码 02 依次看每一部分的设计选择。

2.1 请求:写不写明格式

是 / 否题,请求里写不写 “Answer yes or no.”(20 次运行的平均):

请求 + 判分器能干的慢但对的能力一般的
写了格式,严格判分89.8%88.2%71.7%
没写格式,严格判分77.3%82.8%65.2%
没写格式,按意思判分90.3%90.7%67.0%

不写格式时,智能体常常用一句话回答(“There is a logged outage on this account.”)——它答对了,可要求出现 “yes” 的判分器判它错。请求和判分器要一起设计:要么在请求里写清楚格式,要么让判分器接受等价的说法(这正是第 13 讲 LLM 评审的用武之地,代价是它自己也会出错)。

2.2 环境:每个任务都要重置

智能体每个任务都重置不重置(修改会留下来)
能干的93.7%1.5%
慢但对的92.2%1.4%
偷懒的26.8%26.8%
两头下注的35.0%0.3%
偷看答案的67.2%1.2%
能力一般的76.7%1.2%

不重置时,上一个任务对数据库的修改留到了下一个任务,而判分器拿整个数据库和按初始状态算出的期望比较——会动手的智能体全军覆没,只有什么都不改的”偷懒的”毫发无损。环境泄漏不只是加噪声,它会系统性地偏向某种行为。真实的智能体 benchmark 要给每个任务一个干净的容器 / 数据库副本,并且在任务之间彻底清理(例如 SWE-bench 为每个任务构建独立的 Docker 环境)。

2.3 停止条件:步数上限

智能体最多 2 步最多 3 步最多 5 步最多 10 步
能干的93.4%92.2%92.8%92.2%
慢但对的62.1%62.0%93.6%91.4%
能力一般的77.6%76.5%77.8%76.4%

上限太小,测的是”快不快”而不是”会不会”。上限要按任务的合理步数留足余量,同时报告步数和成本(§4.4)——快和对是两个维度,不要用一个隐含的截断把它们混在一起。

2.4 判分器:太松就奖励钻空子

智能体严格:回答只含标准答案 + 状态一致只看数据库状态子串匹配
能干的93.7%97.3%93.2%
慢但对的92.2%97.7%93.0%
偷懒的26.8%76.5%26.8%
两头下注的35.0%90.1%77.0%
偷看答案的67.2%90.4%70.9%
能力一般的76.7%93.0%79.0%
  • 只看数据库状态:查询类任务不需要改数据库,于是什么都不说也”成功”——“偷懒的”得 76.5%。
  • 子串匹配:“yes or no”里有 “no”、“20、25 还是 30”里有 “25”——“两头下注的”从 35% 变成 77%。

判分器的设计原则:能检查状态的检查状态,需要回答的检查回答,两者都要;只接受明确的答案(不接受”列出所有可能”);用参照智能体测一测它的漏洞(§3.4)。


3. 好 benchmark 的性质 · Properties of good benchmarks

3.1 Press 的三条

Press(SWE-bench、SciCode、AssistantBench 等 benchmark 的作者之一)在《怎样造好的语言模型 benchmark》里总结了三条核心性质:

  1. 自然:任务反映人们真正在做的事——一个检验办法是”比基线做得好的系统,能不能真的帮到人”;尽量用真实用户的问题(例如真实的 bug 报告),避免多选题这种不自然的形式、避免凭空编的问题。
  2. 可自动判分:每个答案都能用程序检查(编程任务用单元测试);他特别提醒,不要让同一个语言模型既当答题者又当判分者。
  3. 有挑战:一上线就接近满分的 benchmark 没人会用。他最初建议发布时最强的模型得分在 1%–35% 之间,2025 年 1 月把这个范围改成 0.1%–9%,同年 5 月又建议把任务设计成”6 到 12 个月以后的模型还做不对”——因为 benchmark 通常一年之内就会饱和。

以及一些实用建议:答案最好不公开,防止泄露到训练数据里(SciCode 就是这样做的);一个主指标(细分结果放在分析里);baseline 要包括最强的闭源和开源模型;任务数量大约 300–500 个(至少 150 个,超过 500 个会因为跑得太久而没人用);贴近真实的脚手架(§1.5);按 4 元组定义每个任务。

3.2 ABC:任务有效性与结果有效性

Zhu et al. 从自己造 benchmark 的经验、对现有做法的调研和以往报告过的问题里,整理出 ABC(Agentic Benchmark Checklist)。它把一个智能体 benchmark 的有效性拆成两半:

  • 任务有效性:一个任务可解,当且仅当智能体具备被测的能力。违反它的有两种:有捷径(不具备能力也能”做对”,例如环境里留着答案)、不可能(具备能力也做不对,例如标准答案错了、环境缺少必要的工具)。
  • 结果有效性:评估的结果(测试、检查、判分)真的反映任务是否成功。违反它的也有两种:太松(没做成也判成功,例如空回答算成功、测试不充分)、太严(做成了也判失败,例如要求一字不差的格式)。

论文用实际的例子说明这些问题有多常见:SWE-bench Verified 用的测试用例不充分;τ-bench 把空回答算成功;这类设置和判分上的缺陷,会让智能体的表现被高估或低估,相对误差最多可达 100%。他们把 ABC 用在评估设计特别复杂的 CVE-Bench 上,把性能的高估减少了 33%。此外,ABC 也包含报告方面的要求:讲清楚 benchmark 的局限、怎样处理已知的问题、结果的不确定性。

3.3 五种漏洞,各自偏向一种行为

代码 03 在修好的版本上分别打开五种漏洞(括号里:相对真实能力的偏差;真实能力 = 修好的版本上 5 次运行的平均):

版本能干的慢但对的偷懒的两头下注的偷看答案的能力一般的排名一致性 τ
真实能力93.7%92.2%26.8%35.0%67.2%76.7%1.00
环境泄露答案92%93%27%33%90%(+34%)77%0.73
只看数据库状态97%98%77%(+186%)89%(+155%)89%93%0.86
子串匹配92%93%27%79%(+125%)69%80%0.73
保留坏任务88%87%26%31%66%73%1.00
步数上限 391%61%(−34%)27%32%69%79%0.73
五种全部打开95%66%(−29%)77%(+188%)88%(+151%)87%(+29%)90%(+18%)0.33
  • 泄露答案是任务有效性的捷径;只看状态、子串匹配是结果有效性太松;步数上限太小、坏任务是”不可能”和”太严”——它们低估能力。
  • 五种叠在一起,“偷懒的”(真实 27%)和”两头下注的”(真实 35%)都排到了”慢但对的”(真实 92%)前面,排名和真实能力的一致性只剩 τ = 0.33。ABC 论文在真实的 benchmark 上看到的相对误差最多 100%;我们刻意把几种漏洞叠在一起,偏差更大。

3.4 参照智能体:最便宜的检查

版本什么都不做的智能体无所不能的智能体
修好的版本26.8%100.0%
保留坏任务26.5%93.9%
只看数据库状态76.5%100.0%
有漏洞的版本77.0%96.5%
  • 什么都不做的给出分数的”地板”。修好的版本上它仍有 27%:有 49 个任务的正确结果恰好就是”什么都不改”(“谢谢,没事了”30 个、“有停电才补偿”但没有停电 13 个、要取消的预约本来就不存在 6 个)。这不是漏洞,但要报告出来;如果它在某个版本上高得离谱(只看状态时 77%),就说明判分器有洞。
  • 无所不能的给出”天花板”:拿不到 100%,说明有坏任务。
  • 实践中,“无所不能”可以用”把标准答案直接交上去”来代替:它必须得满分,否则判分器或任务有问题。

3.5 找坏任务

3 个老实做题的智能体各跑 5 次,从来没有人做对的任务有 12 个,全部确实是坏任务(共 17 个)。漏掉的 5 个是标准答案写错了的题(数字题多加了 15、是否题写反了),被某次答错的运行”碰巧做对”了——所以还要看”越强越错”的题(第 11 讲 IRT 的负区分度)。把这些任务拿出来人工检查,是发布前必做的一步。


4. 可靠性的维度 · Dimensions of reliability

一个准确率不能说明一个智能体”可靠”。代码 04 量了四个维度。

4.1 一致性:pass@k vs pass^k

每个任务跑 8 次,用无偏估计(第 4 讲):

智能体pass@1pass@2pass@4pass@8pass^2pass^4pass^8
能干的93.4%99.5%100.0%100.0%87.2%76.3%59.6%
慢但对的92.3%99.0%100.0%100.0%85.7%74.9%61.7%
能力一般的78.0%93.3%99.3%100.0%62.7%44.5%30.6%

“能力一般的”试 8 次总能碰上一次对的(pass@8 = 100%),可 8 次全对的概率只有 30.6%。pass@k 回答”试几次能不能碰上”——适合有验证器、可以重试的场合(第 9 讲的 best-of-N);pass^k 回答”每次都能做对吗”——适合直接面对用户的场合。报告时要说清楚是哪一个。

4.2 鲁棒性:换一种说法

智能体原来的说法换一种说法变化
能干的93.7%90.5%−3.2%
慢但对的92.2%90.5%−1.7%
能力一般的76.7%67.9%−8.9%

(掉多少是我们设的参数;要点是方法:同一个任务准备几种说法,比较成功率。)只用一种说法的 benchmark,可能测的是”对这种说法熟不熟”——这也是题目泄露到训练数据里时最常见的症状。

4.3 容错:工具会出错

智能体出错后重试不出错10% 出错30% 出错
能干的会93.7%93.1%93.4%
慢但对的会92.2%94.1%92.5%
能力一般的不会76.7%71.4%59.9%

真实的环境里 API 会超时、会限流、会返回错误(前置讲 P2、P3)。在评估里注入故障,才看得出智能体有没有恢复的能力。

4.4 效率

智能体成功率每个任务平均步数每次成功的步数
能干的92.9%1.341.44
慢但对的93.4%3.023.23
能力一般的77.0%1.341.74

“慢但对的”和”能干的”一样准,但成本和延迟是两倍多。只报告准确率,等于假设成本不重要。

4.5 汇总

智能体准确率pass^4换说法30% 工具出错每次成功的步数
能干的94%76%−3%93%1.4
慢但对的92%75%−2%92%3.2
能力一般的77%44%−9%60%1.7

没有一个数能说明”可靠”。一个好的评估报告至少给出:主指标(及置信区间)、一致性(pass^k)、在扰动和故障下的表现、成本 / 延迟。


5. 评估的统计 · Statistics for evals

“A 比 B 高 3 个点”——是真的更好,还是运气?评估分数的不确定性有三个来源:题目的抽样(这 200 道题只是所有可能的题里的一个样本)、运行的随机性、题目的成簇(很多题来自同一个模板或仓库)。代码 05 用一个按 IRT 生成结果的模拟器(stats_lab.py:每道题有难度,所有智能体共享)把它们一一量出来。

5.1 置信区间

一个真实成功率 83.2% 的智能体:

题数估计的成功率95% Wilson 区间半宽
5080.0%[67.0%, 88.8%]±10.9 个点
10075.0%[65.7%, 82.5%]±8.4 个点
20087.5%[82.2%, 91.4%]±4.6 个点
50081.6%[78.0%, 84.8%]±3.4 个点
1,00082.9%[80.4%, 85.1%]±2.3 个点

区间宽度随 1/√n 缩小。Wilson 区间比”p ± 1.96·√(p(1−p)/n)“在接近 0% 或 100% 时可靠得多(第 1 讲以来的表格一直用它)。100 道题时,同一个智能体的估计可能是 75%,也可能是 87%。

5.2 配对比较

A(真实 83.2%)和 B(真实 76.9%)差 6.3 个点。在 300 次模拟里,p < 0.05 的比例:

题数看出差别:独立 z 检验看出差别:配对 McNemar假阳性(两者一样好):z假阳性:McNemar
10019%20%3%4%
20025%30%2%2%
50069%77%3%4%
1,00094%97%3%4%
  • 差 6 个点,200 道题只有三成的把握看出来;要到 1,000 道题,McNemar 才有八成以上的把握。
  • 配对更灵敏:两个智能体在同一道题上的结果是相关的(难题对谁都难)。McNemar 检验只看”两者结果不同的题”:b = A 对 B 错的题数,c = A 错 B 对的题数,在”两者一样好”的假设下 b 服从 Binomial(b + c, 1/2)。配对把”这道题本身难不难”消掉了。
  • 两者一样好时,两种检验的假阳性都不超过 5%——配对没有让它”更容易看出不存在的差别”。

5.3 题多还是跑得多

预算固定为 400 次运行(300 次模拟,估计的标准差):

分配估计的标准差
400 道题 × 每题 1 次1.79 个点
200 道题 × 每题 2 次2.08 个点
100 道题 × 每题 4 次2.40 个点
50 道题 × 每题 8 次2.91 个点

当题和题之间的差别(难度)大于同一道题两次运行之间的差别时,多出题比多跑几次划算。多跑几次的价值在于 pass^k 和稳定性(§4.1),不在于缩小区间。

5.4 题目成簇

400 道题来自 20 个模板(同一模板的题难度相近):

标准误数值(个点)
实际的波动(模拟之间的标准差)3.51
把 400 道题当独立样本算的1.78
按模板成簇算的3.40

把题当独立样本,标准误被低估了一半。有效样本量更接近模板数,而不是题数——SWE-bench 的题来自十几个仓库、很多合成 benchmark 来自少数模板,都要用成簇的标准误(第 11 讲 SWE-smith 的去重也是在处理”同一件事考了很多遍”)。

把这些做法写成一套流程:报告平均值和(成簇的)标准误;比较两个系统时用配对差异和它的标准误;事先做检验力分析,决定需要多少道题;多次运行时分开报告”题目的波动”和”运行的波动”。Miller 的 Adding Error Bars to Evals 系统地讲了这些建议(见延伸阅读)。


6. 用真实模型试一试 · Try it on a real model

06_real_llm.py(可选,需要 pip install anthropic 和 ANTHROPIC_API_KEY,12 次调用)把客户数据库的相关几行放进系统提示,问 Claude 12 道查询题(查余额、查是否有停电记录、查不存在的客户),其中一半的是 / 否题不写 “Answer yes or no.”;同一批回答用三种判分器判:严格(bench_lab.score)、子串匹配、是 / 否题按意思判。

python3 06_real_llm.py

不联网检查脚本本身:python3 06_real_llm.py --toy。

读结果时想一想:真实模型不写格式时用什么方式回答?三种判分器在哪几道题上判得不一样——是严格的冤枉了正确的回答,还是宽松的放过了含糊的回答?查不存在的客户时,它会不会编一个套餐出来?编写时没有用真实 API 跑过这个脚本,这里不报告数字。


7. 一份 benchmark 发布前的清单 · A pre-release checklist

任务有效性

  1. 每个任务都有人确认过:可以完成、标准答案正确、环境提供了完成它需要的一切。
  2. 环境里没有捷径:答案文件、测试代码、日志、可以访问的外部资源都检查过;每个任务一个干净的环境,任务之间彻底重置。
  3. 跑过参照智能体:什么都不做的(分数的地板)、把标准答案直接交上去的(必须满分)。
  4. 看过”谁都做不对”和”越强越错”的任务,逐个人工检查。

结果有效性 5. 判分器检查状态,也检查回答;不接受”列出所有可能”的回答;要求明确的格式,或者能接受等价的说法。 6. 判分器在人工标注的一批样本上验证过(覆盖率、误报率,第 11 讲 §6)。 7. 测试足够充分:对编程类任务,做过变异测试(第 11 讲 §5.2)。

报告 8. 一个主指标 + 置信区间(题目成簇时用成簇的标准误);比较两个系统时用配对检验。 9. 一致性(pass^k)、鲁棒性、容错、成本 / 延迟。 10. 脚手架、步数上限、运行次数、模型版本写清楚;已知的局限写清楚。


8. 小结 · Summary

  1. 智能体评估难:每次运行都不一样、链条长、有副作用、多种正确解法、依赖脚手架、贵。同一个智能体只跑一次、只用 50 道题,分数可以差二十多个点;脚手架可以改变排名。
  2. 4 元组:请求、环境、停止条件、判分器——每一部分都是设计选择。请求和判分器要一起设计;环境每个任务都要重置(否则会系统性地偏向”什么都不做”);步数上限要留足余量;判分器检查状态也检查回答。
  3. 好 benchmark:自然、可自动判分、有挑战(Press);任务有效性(可解当且仅当有能力)与结果有效性(结果反映真实的成功)(ABC)。漏洞各自偏向一种行为,叠在一起可以让排名几乎失去意义。参照智能体和”谁都做不对的任务”是最便宜的检查。
  4. 可靠性有多个维度:pass@k 和 pass^k 回答不同的问题;鲁棒性、容错、效率都要单独报告。
  5. 统计:给分数配上置信区间;比较两个系统用配对检验;先做检验力分析决定题数;多出题比多跑几次划算;题目成簇时有效样本量是簇数。

9. 常见误区 · Common pitfalls

  • “我们比 baseline 高 3 个点,所以更好。” 200 道题时,差 6 个点也只有三成的把握看出来;先看置信区间和配对检验。
  • “判分器只要检查最终状态就够了。” 查询类任务不改状态,“什么都不说”也成功(ABC 指出的 τ-bench 问题)。
  • “判分宽松一点,免得冤枉模型。” 子串匹配让”两头下注”的智能体从 35% 变成 77%;要宽容的是等价的说法,不是含糊的回答。
  • “环境复用可以省时间。” 不重置环境,会动手的智能体全军覆没,什么都不做的毫发无损。
  • “步数上限越紧越能逼出效率。” 它会把”慢但对的”判成失败;效率要单独报告。
  • “满分做不到,说明题目够难。” 也可能是坏任务;交一份标准答案试试,必须满分。
  • “pass@k 很高,系统就可靠。” pass@8 = 100% 的智能体,pass^8 可能只有 30%。
  • “多跑几次能让结果更准。” 预算固定时,多出题比多跑几次更能缩小区间。
  • “1,000 道题,样本量就是 1,000。” 它们如果来自 20 个模板,有效样本量接近 20,标准误会被低估一半。
  • “benchmark 上的分数,就是模型的能力。” 它是模型 × 脚手架 × 判分器 × 题目的分数——每一项都要写清楚。

10. 练习 · Exercises

练习 1(4 元组):为”帮用户在日历里安排一个会议”写一个任务的 4 元组,并指出每一部分最容易出的有效性问题。

参考答案(之一) 请求:"下周三下午和 Alice、Bob 开 30 分钟的会,避开他们的冲突。"——问题:时区、"下周"的含义、"下午"的范围都可能含糊(任务有效性:可能有多个正确答案,也可能无解)。环境:一个有几个人日历的模拟日历服务(每个任务一份干净的副本),工具:查空闲、创建事件、发邀请——问题:环境里的"今天"要固定(否则"下周三"随运行日期变化);不能有真实的外部调用。停止条件:智能体声明完成或 20 步——问题:创建事件后还会继续发很多邀请的智能体被截断。判分器:日历里有且只有一个新事件,时间在要求的窗口内、和所有人的现有事件不冲突、参与者正确;没有修改其他事件——问题:只检查"有没有新事件"会放过时间错的;只接受唯一的正确时间会冤枉其他合法的时间(结果有效性太严)。

练习 2(找漏洞):一个 benchmark 让智能体修复代码仓库里的 bug,判分器是”运行仓库自带的测试,全部通过就算成功”。列出至少三种可能的有效性漏洞,并说明怎样检测。

参考答案 ① 测试不充分(结果有效性太松):错误的修改也能通过——用变异测试 / 额外的隐藏测试检查;② 智能体可以修改测试本身(捷径)——判分时用原始的测试文件覆盖,或检查补丁有没有动测试;③ 测试依赖网络、时间、随机数而不稳定(同一份正确的补丁时过时不过)——对标准补丁跑多次,确认它每次都通过;④ 环境里能看到修复后的代码(例如 git 历史里有未来的提交)——检查环境里能访问的东西;⑤ 标准补丁本身通不过(坏任务)——把标准补丁交上去,必须全部通过;⑥ 什么都不改也能通过(任务本身无效)——跑"什么都不做"的参照智能体。

练习 3(参照智能体):解释为什么”什么都不做”的智能体在修好的版本上仍有 27%,这算不算 benchmark 的缺陷?如果你想把这个地板降到接近 0,可以怎样改任务?

参考答案 因为有 49 个任务的正确结果恰好是"不改数据库"("谢谢,没事了"、没有停电时不该补偿、要取消的预约本来就不存在),而"Done."又被当成了一句礼貌的回复。它不一定是缺陷——现实里确实有很多请求的正确做法是"不动手"——但必须报告。如果要降低地板:要求智能体对每个请求给出明确的说明(例如"没有停电记录,所以没有补偿"),判分器同时检查状态和说明;"谢谢"类任务要求礼貌、具体的回复,而不是任何非空字符串;减少"正确做法是不动手"的任务比例,或者把它们单独报告。

练习 4(pass^k):一个智能体在某任务上每次成功的概率是 0.9。(a) pass@4 和 pass^4 各是多少?(b) 如果每天 1,000 个用户各问一次,平均有多少人遇到失败?(c) 在什么场景下你更关心 pass^k?

参考答案 (a) pass@4 = 1 − 0.1⁴ = 0.9999;pass^4 = 0.9⁴ ≈ 0.656。(b) 约 100 人——每次面对用户都是"一次机会",可靠性是 pass^1 = 0.9;同一个用户反复使用 4 次都满意的概率是 0.656。(c) 直接面对用户、没有验证器、不能重试的场景(客服、自动执行的操作),以及失败代价高的场景;pass@k 适合有可靠验证器、可以多试几次再挑的场景(代码生成 + 测试)。

练习 5(置信区间):一个智能体在 120 道题上做对 90 道。(a) 用正态近似算 95% 区间。(b) 另一个智能体在同样的题上做对 99 道;在两者结果不同的题里,A 对 B 错 6 道、A 错 B 对 15 道。用 McNemar 检验判断差别是否显著(p 用正态近似即可)。

参考答案 (a) p̂ = 0.75,标准误 √(0.75 × 0.25 / 120) ≈ 0.0395,区间 ≈ [67.3%, 82.7%]。(b) 不一致的题 n = 21,b = 6;在"一样好"的假设下 b ~ Binomial(21, 0.5),均值 10.5、标准差 √(21 × 0.25) ≈ 2.29;z = (6 − 10.5)/2.29 ≈ −1.96,双侧 p ≈ 0.05——刚好在边界上(精确的二项检验 p ≈ 0.078,不显著)。注意:两个分数分别是 75% 和 82.5%,差 7.5 个点,看起来不小,但真正提供信息的只有那 21 道结果不同的题。

练习 6(需要多少道题):你想用配对检验分辨两个真实成功率约 80% 和 75% 的智能体,并希望有 80% 的把握。参考代码 05 的结果,大概需要多少道题?如果题目来自 30 个模板,这个数字会怎样变?

参考答案 代码 05 里差 6.3 个点时,McNemar 在 500 道题时 77%、1,000 道题时 97%——差 5 个点需要更多,大约 1,000 道左右。题目成簇时,有效样本量小于题数,需要的题更多(或者说,增加同一个模板下的题收益递减,应该增加模板数);同时要用成簇的标准误来做检验。另一个办法是挑区分度高的题(第 11 讲的 IRT):对这两个水平的智能体,太简单、太难的题都不提供信息。

练习 7(题多还是跑得多):你有预算跑 800 次。智能体每次运行的随机性很大(同一道题两次运行的结果经常不同)。你会怎样分配”题数 × 运行次数”?如果你还关心 pass^k 呢?

参考答案 如果只关心平均成功率的估计精度:一般仍然是多出题更好,因为题目难度的差别通常大于运行的随机性;但当运行的随机性很大时,多跑几次的收益相对变大——可以先做一个小实验(例如 50 道题各跑 4 次),分解出"题目的方差"和"运行的方差",再按比例分配。如果关心 pass^k:至少要每题跑 k 次(例如 200 道题 × 4 次),否则无法估计"k 次都成功"的概率。

练习 8(脚手架):两个团队都声称自己的模型在同一个 benchmark 上更好:A 团队用的是 10 步上限、可以执行代码的脚手架,B 团队用的是 30 步上限、不能执行代码的。你会怎样设计一个公平的比较?

参考答案 固定脚手架,只换模型:选一个贴近常见做法的脚手架(例如能执行代码、步数上限按任务的合理需要留足余量),两个模型都在它上面跑;再报告每个模型在各自最好的脚手架上的结果作为补充。同时报告:步数 / token / 成本、pass^k、置信区间和配对检验。如果脚手架本身是被比较的对象("谁的 harness 更好"),就反过来固定模型、换脚手架。混在一起比,测出来的是"模型 × 脚手架"的组合,无法归因。

练习 9(ABC 的分类):把下面的问题归到”任务有效性”或”结果有效性”,并说明是”太松”还是”太严”(或”捷径”还是”不可能”):(a) 判分器要求答案和标准答案逐字相同;(b) 任务要求访问一个已经下线的网站;(c) 环境的日志文件里记着上一次运行的正确答案;(d) 测试只检查函数有没有返回值,不检查值对不对。

参考答案 (a) 结果有效性,太严(正确但措辞不同的回答被判错);(b) 任务有效性,不可能(有能力也做不到);(c) 任务有效性,捷径(没有能力也能做对);(d) 结果有效性,太松(错误的实现也能通过)。

练习 10(开放题:审查一个你常用的 benchmark):挑一个你看过别人报告结果的智能体 benchmark,按 §7 的清单逐条审查:它满足哪些、不满足哪些、你最怀疑哪一条会让结果失真?

参考答案(思路) 重点看:① 环境是否每个任务隔离、有没有可以访问的答案或外部资源;② 判分器是检查状态还是只看回答、有没有被验证过、有没有"空回答也成功"的任务;③ 任务数量和来源(是否成簇)、作者是否报告了置信区间;④ 发布以来是否有人报告过坏任务或捷径(很多 benchmark 后来都发布了"Verified"或修正版本);⑤ 结果用的是什么脚手架、跑了几次。写下你最怀疑的一条,并设计一个最小的实验去验证它(例如跑一个什么都不做的参照智能体)。

11. 延伸阅读 · Further reading

本讲的阅读材料

  • Y. Zhu et al., Establishing Best Practices for Building Rigorous Agentic Benchmarks, 2025(ABC 检查清单)。
  • O. Press, How to Build Good Language Modeling Benchmarks(博客,2024 年首发,之后多次更新)。
  • F. M. Polo et al., tinyBenchmarks: Evaluating LLMs with Fewer Examples, ICML 2024(第 11 讲 §2)。

相关

  • E. Miller, Adding Error Bars to Evals: A Statistical Approach to Language Model Evaluations, 2024.
  • S. Yao et al., τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains, 2024(第 4 讲)。
  • C. E. Jimenez et al., SWE-bench: Can Language Models Resolve Real-World GitHub Issues?, ICLR 2024;OpenAI, Introducing SWE-bench Verified, 2024.
  • E. B. Wilson, Probable Inference, the Law of Succession, and Statistical Inference, 1927(Wilson 区间)。

12. 下一讲预告 · Next lecture

第 13 讲 LLM-as-Judge 与评估基础设施(11/9)。这一讲里,凡是”按意思判”的地方都留了一个问号:用什么来判?最常见的答案是另一个 LLM。下一讲讨论三类判分器(代码、模型、人)各自的位置;LLM 评审的提示词怎样写;它已知的偏差——位置偏差、长度偏差、偏爱自己的回答;成对比较还是逐条打分;怎样用少量人工标签校准它(第 10、11 讲的人机分工的延续);Anthropic 的 Demystifying Evals for AI Agents 给出的评估路线图;AutoMetrics / AutoLibra 怎样从反馈里自动生成指标;以及一个评估 harness 需要的工程部件(缓存、并发、记录、可复现)。配套代码会模拟带偏差的 LLM 评审、用人工标签纠正它,并搭一个带缓存和并发的评估 harness。

← 返回课程目录