返回 AICAP-180
B1 · Day 6evals 方法论 + tokenization 起步

解析首跑结果

在 B1→B18 整条能力曲线里,B1 解决的是最底层的问题:怎么判一个 AI 输出对不对、贵不贵。

阶段: B1 · evals 方法论 + tokenization 起步(Day 1-10) 标签: #evals #failure-taxonomy #attribution #agent-eval

今日导引(由浅入深)

在 B1→B18 整条能力曲线里,B1 解决的是最底层的问题:怎么判一个 AI 输出对不对、贵不贵

Day 1-5 已经把方法论铺到能跑——task/trial/outcome 三层(Day 1)→ 三种 grader(Day 2)→ BPE 原理(Day 3)→ OpenRouter 接入(Day 4)→ harness 首跑出数(Day 5)。

Day 5 跑出了第一份自产报告(completion% + cost + commit),但报告只是原料,不会自己告诉你下一步该改什么

今天的任务就是把这份原料「读懂」——把失败逐条归因到一个稳定的失败分类法(failure taxonomy),统计 top-3 失败类型及各自占比,让「失败」从一团噪声变成可迭代的结构化信号。

最小可判定产出:一张失败归因表(top-3 类型 + 各自占比%)。明天起转去手写 BPE 编码器(Day 7-9),所以今天也是 evals 方法论这条支线的一个临时收束点。

1. 机理精读

读自产报告,本质是做「错误分析(error analysis)」,不是看一个总分。

Day 5 的 agentEval.ts 给出的 completionRate(源码字段名,注释写 fraction with judge.label === 'pass')是一个聚合数——它告诉你「整体多少任务过了」,但不告诉你为什么没过的那些没过

一个 79% 的 completion 和另一个 79% 可以是完全不同的两个系统:一个是 21% 都栽在工具超时上,另一个是 21% 全是幻觉。这两种 79% 的修法南辕北辙。

所以读报告的第一性原理是:把聚合数拆回到单条失败,再把单条失败归到可复用的类别。 没有这一步,迭代就是盲目的。

读一份报告要盯三件事,三件事对应三种迭代动作:

  1. 哪些 task fail —— 定位到具体任务 id,看是不是集中在某一类任务(比如全是 multi-hop layering 任务挂,说明检索/推理深度不够)。
  2. cost 分布 —— 哪几条吃掉大头。Agent 任务的 cost 长尾极重:少数任务因为多轮 tool-call + 长 context 会吃掉总成本的大半。只看 totalCostUsd 均值会被长尾骗。
  3. 判定噪声来源 —— 是 code grader 漏判(确定性检查覆盖不到的语义错),还是 LLM-judge 抖动(同一条输出两次判分不一致)。这一条决定你该信哪个 grader,也呼应 Day 2 的「三种 grader」。

为什么必须归因到结构化类别才能迭代?

因为没有类别,你只能「fail 了就重跑」——而重跑对系统性错误(比如 prompt 缺一段约束)毫无帮助,只会把同样的错以同样的概率再犯一遍。

结构化 taxonomy 把「这条错了」升级成「这条属于 hallucination / 这条属于 format_violation」,于是修法立刻清晰:

  • critical 类先修;
  • code-checkable 的类用确定性断言兜底(不浪费 LLM-judge 预算);
  • 纯语义类才动 prompt 或换模型。

关键权衡:taxonomy 的颗粒度。 太粗(只有「对/错」)等于没归因;太细(每个错一个类)无法统计、无法复用。

本仓 failureTaxonomy.ts 选了 6 类,并给每类配了 severity(critical/high/medium)做排错优先级——这是经验上「够用且能进看板」的颗粒度。

出处方法论是 Hamel Husain + Shreya Shankar 的 evals 工作流:人工错误分析 → open coding(开放编码)→ axial coding(轴向编码)→ LLM-as-judge → 代码型检查(Lenny's Newsletter 2025-09 / hamel.dev evals-faq)。「先人工开放编码、再归并成稳定类别」正是结构化 taxonomy 的来历。

与相邻概念的边界:failure taxonomy 不是 grader(Day 2)。

  • grader 判「过没过」,taxonomy 判「没过是哪种没过」;
  • outcome(Day 1)是单任务的达标线,taxonomy 是跨任务的失败聚类。

三者串起来才是一条完整的 eval 闭环:outcome 定线 → grader 打分 → taxonomy 归因 → 迭代。

2. 推导 / 手算 / 代码走读

今天 seed 指向 src/aml/failureTaxonomy.ts(已在 repo,18.7KB),是确定性的分类 schema,非 LLM。真实符号走读:

  • FailureClassId(type):6 个稳定 id —— tool_failure / hallucination / context_pollution / retrieval_miss / format_violation / typology_misjudge。注释明确「进 CI / 看板的 key,勿改名」,这就是归因表的列。
  • FAILURE_TAXONOMY(readonly 数组):6 个 FailureClass 对象,每个带 definition(是什么)、decisionRule(人工/代码据此归类,可执行可复现)、severity、可选 exampleCaseId
  • exampleCaseId 的妙用typology_misjudgeexampleCaseId: 'C049',注释说这是金标 v1 第 1 个 normal 案件(现金密集型商户),已知会被规则误报为 structuring——把「已知坑」钉死在代码里,便于回归定位。
  • severity 三档 + SEVERITY_WEIGHT(Record)critical:3 / high:2 / medium:1,给排错优先级提供可排序的数值权重。
  • 谁是 criticaltool_failure(下游工具抛错/超时/返回结构不合法 → 无有效产物)与 hallucination(引用案件交易集中不存在的 txId/金额/对手 → 凭空捏造证据)。AML 场景 hallucination 最危险,因为 SAR 必须可溯源到真实交易。
  • isBenignNoise(memo, channel)(工具谓词)channel === 'card' 直接判良性;否则看 memo 是否在 ['工资代发','账单代扣','日常消费'] 里。这是 context_pollution 类的判定底座——识别「真实存在但不该引用」的噪声交易。
  • suggestFailureClasses(c, assessment, sar)(建议器):注释诚实写「非自动判定,仅给标注者建议」。它把 4 条 decisionRule 串起来返回可能命中的 classId[]
    • sar.citedTxIds.some(id => !txIds.has(id))hallucination
    • ② 引用了 isBenignNoise 的交易 → context_pollution
    • sar.sections.length < 5format_violation
    • assessment.topTypology ?? 'normal'c.labeltypology_misjudge
  • 关键边界:真正的 critical 判定走 evalChecks 的确定性检查,suggestFailureClasses 只做 UI 提示。把建议器当判官就错了。
  • FailureLabel(interface):人工标注落盘契约,字段含 annotator: 'human' | 'llm-judge',注释引「LLM 模拟用户是不可靠代理 (2026-01),关键评分保留人工」——与 Day 2 的 self-preference 警示一脉相承。

走读结论:归因不是拍脑袋,而是有可执行 decisionRule 兜底的。

其中 hallucination / context_pollution / format_violation / typology_misjudge 这 4 类有 code 侧近似判定;retrieval_miss 精确判定「需金标证据集」(源码注释直说,目前只有「citedTxIds 非空 + 段落完整」的下界守卫)。

6 类的修法分流(归因后立刻知道怎么改):

  • tool_failure(critical)→ 不是 prompt 问题,是工程问题:加重试/超时/契约校验,归 SRE 而非提示词。
  • hallucination(critical)→ 收紧「只能引用证据集内 txId」的约束,或加 cited_tx_exist 代码型 grader 硬卡。
  • context_pollution(high)→ 用 isBenignNoise 在喂给模型前过滤噪声渠道,做 context engineering(呼应 B5)。
  • retrieval_miss(high)→ 调规则引擎召回 / recall@k,属检索层,不是生成层。
  • format_violation(medium)→ 纯确定性代码检查兜底(evalChecks),完全不用 LLM-judge 预算。
  • typology_misjudge(high)→ 分类层语义错,动 prompt/few-shot 或换更强模型。

为什么 format_violation 是 medium 而 hallucination 是 critical? 因为前者「结构错但可一眼发现、可代码兜底」,后者「内容假但表面合规、会骗过人工复核」——AML 场景里「看起来对的假证据」比「明显坏的格式」危险得多,这是 severity 排序的金融语义依据。

3. 今日实战

把 Day 5 的失败任务逐条归因到 failureTaxonomy.ts 的 6 类,统计 top-3:

  1. 打开 Day 5 落到 agent-evals/reports/ 的自产报告,列出所有 judge.label !== 'pass' 的任务(或离线 fixture 下 code-grader 判负的任务)。
  2. 对每条失败任务,跑 suggestFailureClasses 拿候选类,再人工核对 decisionRule 定档(建议器只给候选,最终归类是人工动作——见上文边界)。
  3. FailureClassId 计数,算每类占比% = 该类条数 / 总失败条数,按 SEVERITY_WEIGHT 给同占比的类排序,取 top-3。
  4. 落表到 dayN-evals.md 旁,列 classId | count | pct% | severity | 代表 caseId

4. 今日实测 / 产出

  • 失败归因表(top-3 类型 + 各自占比%):依赖 Day 5 报告。
  • 若仅离线 fixture 跑通,则先对 code-grader 可判的失败归因,LLM-judge 相关失败标「待跑(需 key)」。 占比按实际归类结果填,不臆造。
  • failureTaxonomy.ts 已在 repo(6 类 + suggestFailureClasses + isBenignNoise,确定性 schema,非 LLM)。
  • 状态:归因表为本日人工产物(待按 Day 5 实际报告落数);其中 LLM-judge 维度待跑(需 OPENROUTER_API_KEY)

5. 常见误区 / 陷阱

  • 「fail 了就重跑」无归因循环:对系统性错误无效,只会重复犯错。必须先归类再决定修法。
  • suggestFailureClasses 当自动判官:它注释明写「仅给标注者建议」,critical 判定走 evalChecks。误用会把 UI 提示当成判定结论。
  • 只看 completionRate/totalCostUsd 均值不看分布:agent cost 长尾极重,少数任务吃掉大头,均值会骗人。
  • retrieval_miss 当已能精确判定:源码注释说精确判定需金标证据集,当前只有下界守卫,别夸大。

6. 学习资源(每条带 YYYY-MM)

  • Hamel Husain + Shreya Shankar《AI Evals FAQ》(hamel.dev / evals-faq, 2026-01) — 三种 grader + self-preference 偏差,本批次 Day 2/6 共用。
  • Hamel + Shreya, error analysis 工作流(open coding → axial coding → LLM-judge → code check, Lenny's Newsletter 2025-09)— 本仓 failureTaxonomy.ts 头注引用的方法论出处。
  • Anthropic《Demystifying evals》(2026-01) — outcome-over-process,Day 1 主线,归因表的 outcome 判据来源。
  • 本仓 src/aml/failureTaxonomy.ts(2026-06,repo 内)— 6 类失败 schema + decisionRule + suggestFailureClasses

SOTA检查 (2026-06 更新)

  • 当前主流:结构化 failure taxonomy 归因是 2026 agent-eval 的主流做法(与 Hamel/Shreya 的 error-analysis 工作流一致),仍 SOTA,有效。
  • 过时黑名单:避免「fail 了就重跑」无归因循环;避免只报单一 accuracy 总分而不拆失败类别(已被 outcome + rubric + taxonomy 多维评测取代)。
  • 下次复查点:是否需新增 2026 agent 失效模式类别——如 tool-call 幻觉(模型臆造不存在的工具/参数)、long-context 上下文丢失。当前 6 类覆盖 AML Copilot 场景,但 agent 域半衰期 ~6 个月,下次复查随 B3(agent loop)和 B4(multi-agent)实测扩类。

衔接

  • 昨天:Day 5 — 跑通 eval harness(agentEval.ts completionRate + cohensKappa.ts κ,离线 fixture 出数)。
  • 今天:把 Day 5 的失败逐条归因到 6 类 failure taxonomy,统计 top-3 占比,让失败从噪声变成可迭代的结构化信号。
  • 明天:Day 7 — byte-level 编码器 (1),转去手写 BPE 三件套(vocab/merge 表/encode 主循环),把 Day 3 的原理落成 tokenizer.ts 代码。