跳转至

第 14 章 可复现评测系统:Evaluation Harness

开场问题:同一个模型、同一个 benchmark,两个团队为什么能跑出相差 8 分的结果?

14.1 harness 是实验协议,不只是脚本

一项任务应被封装为:

  1. 数据加载和版本。
  2. prompt/chat template 构造。
  3. 生成参数。
  4. 输出解析。
  5. 评分函数。
  6. 聚合和置信区间。
  7. 缓存、日志和可重放记录。

只有数据集名称相同远远不够。few-shot 示例、答案顺序、system prompt、是否要求 CoT 都能带来数分差异。

14.2 Task、Document、Request、Metric

一个清晰的 harness 把原始样本 Document 转成一个或多个 Request:生成文本、计算候选 log-likelihood、调用工具或运行 Agent 环境。模型产生 Response,再由 Metric 聚合。

分层的好处是同一任务可切换本地模型、API 模型和不同后端;评分逻辑不依赖执行方式。任务协议一旦和某个 SDK 写死,后续很难复现。

14.3 log-likelihood 与 generation

多选题可比较每个候选的条件 log-likelihood,不必真的生成;这种方法稳定、便宜,但长度不同的候选要考虑归一化。真实产品是生成答案,因此还应补 generation 评测,测试格式遵循和解释能力。

两种设置回答不同问题,不应拿 likelihood 结果冒充端到端生成效果。

14.4 缓存与可重放

模型调用昂贵,应按“模型制品哈希 + 模板版本 + 生成参数 + 输入”缓存原始响应。缓存原始输出,不只缓存分数,这样解析器或评分规则更新时不必重新推理。

每条结果要能追溯到完整请求和响应。只保留总分会让错误分析和 judge 复核无从进行。

14.5 并发、重试与 API 评测

外部 API 会限流、超时和返回瞬时错误。重试必须区分幂等错误与内容错误;不能因为解析失败就重新采样到一个能过解析的答案,这会暗中把 pass@1 变成 pass@k。

记录实际重试次数、模型版本和服务端可能变化的日期。闭源模型名称相同也可能滚动更新,结果无法永久复现。

14.6 Agent harness 为什么更难

普通评测是 prompt → response;Agent 评测是策略与环境多轮交互。harness 还要固定:

  • 初始环境快照。
  • 可用工具和权限。
  • 每步观察格式。
  • 最大步数、token 和时间预算。
  • 环境状态转移。
  • 成功判定和副作用清理。

若环境不确定,同一 Agent 的分数波动可能来自网页变化或服务故障,而不是模型。需要容器、模拟器或可重置 sandbox。

14.7 一个最小结果记录

每条样本至少保存:

  • task/sample ID 与数据版本。
  • 完整渲染 prompt/messages。
  • 原始输出或完整轨迹。
  • token 用量、延迟、工具次数。
  • 解析结果、各指标分量。
  • 模型、模板、推理配置和代码 commit。

这不是日志洁癖,而是未来能够解释“为什么这版涨了”的最低条件。

核心问答

Q:harness 与普通评测脚本的区别? harness 把任务协议、执行后端、解析和指标分离,并保证版本化、缓存和重放。

Q:为什么缓存原始输出而不是最终分数? 评分器和解析器会修复;有原始输出即可重算,没有就必须重新调用模型且结果可能变化。

Q:解析失败可以自动重试吗? 通常不可以。格式失败本身是模型失败,重试会把单次成功率偷偷变成多次尝试成功率。

Q:Agent 评测为什么需要环境快照? 环境变化会改变任务难度和结果,无法区分模型变化与外部变化。