eval 方法论总览
这是 AICAP-180 整条能力曲线(B1→B18)的第 0 米:在动手写任何模型、tokenizer、agent loop 之前,先把「怎么判断一个 AI 系统做对了」这件事的心智框架立住。整条计划的隐性铁律是「只有笔记没有数 = 这天没学会」,而「数」从哪来、靠什么判定可信——答案就是 eval。今天不碰模型,只读一篇方法论 + 通读已在仓库里的任务套件,把每条任务拆到 task / tri
阶段: B1 · evals 方法论 + tokenization 起步(Day 1-10) 标签: #evals #outcome-over-process #aml #task-trial-outcome
今日导引(由浅入深)
这是 AICAP-180 整条能力曲线(B1→B18)的第 0 米:在动手写任何模型、tokenizer、agent loop 之前,先把「怎么判断一个 AI 系统做对了」这件事的心智框架立住。整条计划的隐性铁律是「只有笔记没有数 = 这天没学会」,而「数」从哪来、靠什么判定可信——答案就是 eval。今天不碰模型,只读一篇方法论 + 通读已在仓库里的任务套件,把每条任务拆到 task / trial / outcome 三层,并数出缺口。最小可判定产出:一张「任务 × 三层」分类表 + 缺口计数(哪些任务缺明确 outcome 判据)。
1. 机理精读
为什么从 eval 开题。AICAP-180 不是「读 180 篇论文」的笔记马拉松,而是「构建可演示、可量化的 AI 系统」的能力训练。能力要可量化,就必须先有量尺;量尺不可信,后面所有「我做到了 X」都是空话。所以 B1 的第一课不是模型、不是 agent,而是 eval——先把「怎么证明做对了」立住,整条曲线才有承重墙。这也解释了 seed 的铁律「只有笔记没有数 = 这天没学会」:数从 eval 来,eval 不立,每天都白学。
eval 的三层切分。一个评测体系可以拆成三个互相独立的层:
- task(任务定义):要被评的「问题 + 期望行为」。它是抽象的、可复用的——比如「给定一段可疑交易描述,模型应识别出 structuring 并命名 typology」。task 本身不含任何一次具体运行。
- trial(单次运行):用某个具体模型、某个具体采样配置,把 task 跑一遍,得到一条原始输出(output)。同一 task 可以跑 N 个 trial(不同模型、不同温度、不同 prompt 版本)。
- outcome(可判定的最终结果):对 trial 的 output 施加一个判据(grader),得到 pass / fail / partial / unknown。outcome 是把「主观感觉对不对」压成「可聚合的数字」的那一步。
为什么要这样三层分?因为混淆这三层是 eval 翻车的头号原因。最常见的错误是把「模型的中间推理过程看起来很顺」当成 outcome——这正是今天的核心论点要反对的。另一个常见混淆是把 trial 当 task:跑了一次某模型得到 72%,就说「这个任务的难度是 72%」——错,那只是「这个模型在这套任务上的一个 trial 结果」,换模型、换温度、换 prompt 版本都会变。task 是问题,trial 是一次作答,把两者分开才能做模型 A/B(同一批 task、不同模型的多组 trial),这正是 B17(outcome 指标仪表盘 + A/B)的地基。
OUTCOME-over-process(结果优先于过程)。Anthropic《Demystifying evals》(2026-01) 的核心主张:判分应锚定最终产物是否达标,而非中间步骤「看起来对」。理由有两个对称的失效方向:
- LLM 常常以错误路径得出正确答案——推理链里有 bug,但凑巧蒙对了最终结果。如果你判「过程」,会误杀。
- LLM 也常常以漂亮过程给出错误结论——推理读起来逻辑严密、措辞自信,最终答案却是错的(甚至是编造的)。如果你判「过程」,会误放。
所以唯一稳健的锚点是可判定的最终产物:SAR 草稿是否覆盖了 5W1H?OFAC 命中是否被 block 而非放行?PnL 在无数据时是否拒答而非编数字?这些都是「产物达标与否」的硬判据,而不是「思路顺不顺」。
关键权衡。outcome-first 不是免费的:它要求每条 task 都有一个明确、可程序化或可一致判定的 outcome 判据。没有判据的 task 是「假任务」——你能跑它,但跑完得到的 pass/fail 是噪声。这就引出今天的实战:盘点现有套件,看哪些 task 的 outcome 判据其实是缺的。
AML 语境为什么是 outcome-first 的极佳试金石。本仓任务套件刻意建在 AML/BSA 域上,而合规域天然把 outcome-first 的张力放到最大:一个模型可以写出一段措辞专业、引用了 CTR/SAR/OFAC 的「漂亮过程」,最终却把一笔 OFAC SDN 命中放行(致命错误);也可以推理磕磕绊绊,但最终正确地 block + report。在金融合规里,只有最终动作(block / file SAR / apply EDD)才有法律后果,过程再漂亮也不抵一个错误放行。所以 AML 是检验「你是否真的在判 outcome 而非过程」的硬场景——tasks.ts 里 aml-ofac-sdn、safety-hitl-sar、injection-memo-instruction 都是为此设计的 outcome 陷阱。
rubric 是 outcome 的多维展开。把 outcome 压成单一 pass/fail 太粗——一条 SAR 草稿可能「覆盖了 who/what 但漏了 why」。所以现代 eval 用 rubric(评分量规):把 outcome 拆成若干可独立判定的 facet,每个 facet 给 pass/部分分,再聚合。本仓 tasks.ts 的 aml-sar-5w1h 就是 rubric 思维的代码化:它的 codeCheck 数 6 个 5W1H facet(who/what/when/where/why/how 各一个正则),命中 ≥5 个且输出长度 >120 字符才算 pass。这比「一个正则定生死」鲁棒得多,也是 Day 17 LLM-judge rubric 的前身。
unknown 是 outcome 的第三态。二元 pass/fail 会逼判官在「信息不足」时硬猜,制造噪声。本仓 JudgeVerdict.label 是 'pass' | 'fail' | 'unknown' 三态——当信息不足以判定时显式标 unknown,并单独统计 unknownRate。这与 Day 1 的诚信底线一致:模型该拒答时拒答,判官该说不知道时说不知道,不假装确定。
与相邻概念的边界。三层切分(task/trial/outcome)回答「评什么」;明天(Day 2)的三种 grader(code / LLM-judge / human)回答「用什么判 outcome」;Day 23(评测统计基础)回答「一个 outcome 数字配多宽的误差棒」。今天先把「outcome 必须明确可判、可拆 rubric、允许 unknown」这个前提立住,明天才谈「具体由谁来判、判得准不准」。
2. 推导 / 手算 / 代码走读
今天是概念 + 代码盘点日,代码走读对象是 src/agent/eval/tasks.ts(仓库已有的任务套件)。真实函数 / 符号走读要点:
- 任务用
CategorizedTask表达:每条任务有id、category、prompt、reference、codeCheck。其中prompt是 task 层,reference是给判官(不是给被测模型)看的期望行为说明,codeCheck是 outcome 层的确定性判据。 reference即 outcome 判据的人读版:例如aml-structuring-classic的 reference 明确写「Structuring/smurfing: deposits kept just under the $10k CTR threshold」——这是一条有明确 outcome 的好任务。codeCheck是 outcome 的程序化版:如has(/structur|smurf/i)把「是否识别出 structuring」压成一个正则断言。注意这是 task 文件头注释里自己承认的「cheap heuristic first pass」——便宜但粗。- 任务分四组:
AML_DETECT(真阳性,应 flag)、AML_RESTRAINT(真阴性,不应 over-flag)、AML_COMPLIANCE(合规知识)、AGENT_CORE(format / honesty / robustness / safety / injection / reasoning / planning 失效模式)。 - 三层映射:整个
EVAL_TASKS数组是 task 层;runTaskEval(在agentEval.ts)跑一次是 trial;judge.label ∈ {pass,fail,unknown}+codeCheck.pass是 outcome 层。 - 缺口的判定标准:一条任务若
reference含糊到无法稳定判 pass/fail(例如只说「assessment?」而无明确达标线),或codeCheck用了过宽的正则(容易假阳性),就计入「缺明确 outcome 判据」。本日的人工通读就是把这类逐条标出来。 tasksByCategory()辅助函数:tasks.ts末尾导出tasksByCategory(),返回{category: count}——可直接拿来当分类表的「按 category 计数」一栏,无需手数。
分类表示例(节选三条,演示三层标注 + 缺口判定):
| task id | category | task 层 | outcome 判据(reference/codeCheck) | 是否缺判据 |
|---|---|---|---|---|
aml-structuring-classic | aml-detect | 识别 structuring + 命名 typology | reference 明确「sub-$10k CTR 结构化」;`has(/structur | smurf/i)` |
aml-sar-5w1h | aml-compliance | 写 4-6 句 SAR 叙事覆盖 5W1H | rubric:6 facet 命中 ≥5 且 len>120 | 否(rubric 已拆) |
aml-dormant-spike | aml-detect | 评估休眠账户突发活动 | `has(/suspicious | takeover |
诚实校正:seed 与
aicap-notes.ts头注都把套件记作「29 任务」,而当前tasks.ts实际导出 8(detect)+3(restraint)+5(compliance)+14(core) = 30 条。本日分类表按真实文件逐条标注,缺口计数按实际通读结果填,不臆造;29 vs 30 的差异如实记录(套件随迭代增删,seed 的 29 是某一版的锚点)。
3. 今日实战
通读时对每条任务问四个问题:
- 它的 task 意图是什么(一句话)?属于 detect / restraint / compliance / agent-core 哪组?
reference是否给出了可判定的达标线(而非含糊的「assessment?」)?codeCheck的正则是过宽(易假阳性)还是过窄(易假阴性)?还是用了 rubric 式多 facet 计数(如aml-sar-5w1h)?- code grader 能否独立判定,还是必须 LLM-judge 兜底(开放式输出)?
执行步骤:
- 打开
src/agent/eval/tasks.ts,对每条 task 标注它的三层归属,重点是 outcome 判据是否明确。 - 对每条记三列:
reference是否给出可判定达标线 /codeCheck是否过宽或过窄 / 是否需要 LLM-judge 才能判(即 code grader 覆盖不了)。 - 产出「任务 × 三层」分类表(markdown 表),末尾附缺口计数:缺明确 outcome 判据的任务数 / 总数。
- 把表与缺口计数落到本日笔记产物
dayN-evals.md(与本文件配套),不改动tasks.ts本身。
4. 今日实测 / 产出
- 产出:
dayN-evals.md+ 「任务 × 三层」分类表。 - 状态:task suite 已在 repo(按 seed 锚点记为 29 任务;测试随全量 378 绿)。缺口计数为本日人工标注产物,按实际通读结果填,不臆造。
- 不臆造任何新测量数字;本日唯一的「数」是缺口计数,且它来自人工逐条通读,不是模型跑出来的。
分类表汇总维度(产物应含的列):task id / category / task 层意图 / outcome 判据来源(reference + codeCheck)/ 是否需 judge 兜底 / 是否缺明确判据。按 category 的计数可直接调 tasksByCategory() 得到(detect 8 / restraint 3 / compliance 5 / core 14,合计 30)。缺口计数 = 「是否缺明确判据」列为「是/待判」的行数 / 总行数——这个分母用真实文件的 30,而非 seed 的 29。
一句话价值:今天的产物不是「读懂了一篇方法论」,而是「对一套真实任务套件做了 outcome 判据体检」——这是 B1 第一个可验证的人工资产,也为 Day 5 跑 harness、Day 6 失败归因提供了「哪些任务的分数本来就不可全信」的先验。
5. 常见误区 / 陷阱
- 把过程当 outcome:看模型推理「顺不顺」给分,会同时误杀(错路对果)和误放(顺路错果)。这是今天要根除的头号反模式。
- 假任务:reference 含糊到无法稳定判 pass/fail 的 task,跑出来的分是噪声——必须先补判据再统计。
- 过宽 codeCheck:正则太松会把不相关输出判 pass(假阳性),让 completion% 虚高;过窄则假阴性。盘点时两个方向都要看。
aml-dormant-spike这类宽正则就是典型,需 judge 兜底。 - 混淆 task 和 trial:一条 task 只跑一个 trial 就下结论,等于用 N=1 做统计——这条在 Day 23(评测统计基础)会被正式处理。
- only-positive 任务集:只放「应 flag」的真阳性任务,会让模型靠「全 flag」刷高分。本仓特意配了
AML_RESTRAINT(真阴性,不应 over-flag)做对照——盘点时要确认正/负样本都在。 - 把 seed 的 29 当铁律:套件随迭代增删,实际以当前
tasks.ts导出为准(现 30 条);笔记如实记差异,不强行对齐旧数字。
5b. 三层切分的反向用途:诊断「评测为什么不可信」
三层不只是分类工具,更是诊断框架。当某天 completion% 数字让你怀疑时,按层倒查:
- outcome 层有问题:判据含糊 / 正则过宽过窄 / 判官未校准 → 数字本身就是噪声。今天盘的就是这一层。
- trial 层有问题:N 太小(N=1 当结论)/ 采样温度未固定 / prompt 版本漂移 → 同 task 不同 trial 抖动大。
- task 层有问题:任务集只含真阳性(可全 flag 刷分)/ 不覆盖目标场景 / 任务本身有歧义 → 测了个寂寞。
这套「按层倒查」是 Day 6 失败归因、Day 23 评测统计、B17 A/B 的共用方法论。今天把三层立清楚,等于给后面所有「这个数能不能信」的问题装了一套体检流程。
6. 学习资源(每条带 YYYY-MM)
- Anthropic, Demystifying evals(2026-01)—— 本日 outcome-over-process 框架的来源,B1/B2 多次复用。
- Hamel Husain, AI Evals FAQ(2026-01)—— grader 与判官偏差,明天(Day 2)主线。
- Evan Miller, Adding Error Bars to Evals(2024-11)—— 「outcome 数字必须配误差棒」的依据,Day 20/23 主线(今天先埋点)。
- 仓库内交叉引用:
docs/aipa/下 P1 eval 系列笔记(AML Copilot 评测语境)。 - 仓库代码:
src/agent/eval/tasks.ts(任务套件 +tasksByCategory)、src/agent/eval/agentEval.ts(runTaskEval聚合 harness,Day 5 主走读)。
SOTA检查 (2026-06 更新)
- 当前主流:《Demystifying evals》(2026-01) 仍是当下主流的 evals 心智框架,outcome + rubric 多维评测有效;配套 Miller《Adding Error Bars to Evals》(2024-11) 的误差棒纪律仍是评审硬要求。
- 是否仍 SOTA:是。outcome-first + 显式 unknown + partial credit + bootstrap CI 是 2026 评审默认期待,未被取代。
- 过时黑名单:
- 避免回退到「单一 accuracy 分数」叙事——已被 outcome + rubric 多维评测取代。
- 避免「只报点估计、无 CI」——单一通过率无误差棒、无判定一致性(κ)的报告在 2026 评审中不予采信(CI 见 Day 20/23,κ 见 Day 19)。
- 避免「判过程不判结果」——LLM 错路对果 / 顺路错果都会让过程评分失真。
- 下次复查:复查 Anthropic evals 文档是否出 2026 下半年更新版;若出,重核三层切分与 outcome 定义是否调整。同时跟踪是否有新的 agent 失效模式类别(如 tool-call 幻觉)需要补进任务套件。
衔接
- 昨天:起点(B1→B18 全局第 0 米,无前一日)。
- 今天:eval = task/trial/outcome 三层;判分锚定可判定的最终产物,不锚过程。
- 明天:Day 2 — 三种 grader(code / LLM-judge / human),即「谁来判 outcome、判得准不准」。