返回 AICAP-180
B12 · Day 117RLVR + 模型策略 memo

Δ 与置信区间

在 B1→B18 能力曲线上,今天是 B12 实验段的「下结论之前的最后一道数学关」:昨天(Day 116)已经把 tuned 候选(Qwen3 经 OpenRouter)在与 base 完全相同的配置下跑出 agent-evals/b12-tuned.json,于是手里有了两份按 taskId 可对齐的报告。今天要做的是把它们配对求差值 Δ,再用 bootstrap 估 95% 置信区间——只有

阶段: B12 · RLVR + 模型策略 memo(Day 111-120) 标签: #paired-bootstrap #confidence-interval #ab-compare #eval-rigor

今日导引(由浅入深)

在 B1→B18 能力曲线上,今天是 B12 实验段的「下结论之前的最后一道数学关」:昨天(Day 116)已经把 tuned 候选(Qwen3 经 OpenRouter)在与 base 完全相同的配置下跑出 agent-evals/b12-tuned.json,于是手里有了两份按 taskId 可对齐的报告。今天要做的是把它们配对求差值 Δ,再用 bootstrap 估 95% 置信区间——只有点估计的 Δ 是不够的,必须带上 CI 才能判断「这个差异是真信号还是采样噪声」。今天的最小可判定产出是一个会绿的测试 delta-ci.test.ts,它复用本仓已落地的 src/agent/eval/abCompare.ts,输出 Δ±CI 数字。这是 M5 L3 gate。明天(Day 118)才据 CI 是否跨 0 做显著性裁决。

1. 机理精读

为什么要配对(paired),而不是两组独立比较。 base 与 tuned 跑的是同一套任务集,于是每个 task 上都能算一个配对差值 Δᵢ = passᵢ(tuned) − passᵢ(base),取值 ∈ {−1, 0, +1}。 配对设计的关键好处是消除任务难度方差:同一道难题对两个模型都难,这部分共同方差在做差时被抵消掉,剩下的方差只反映「模型之间的真实差异」。 相比把 base 的所有分数当一组、tuned 当另一组做独立两样本检验,配对设计在相同样本量下功效更高、CI 更窄。 这正是 src/agent/eval/stats.ts 顶部注释写的「pairing on the same tasks removes task-difficulty variance, so the CI on the delta is tight」。 直觉上:独立比较要同时估两个均值的方差,配对比较只估一个差值序列的方差——少估一层,CI 自然窄。

bootstrap 怎么把「一份数据」变出置信区间。 我们只跑了一次实验,拿到一组配对差值 {Δ₁…Δₙ}。 bootstrap 的思路是:把这 n 个配对差值当作总体的近似,有放回地重采样 n 个、算一次均值,重复 B 次(这里 B=1000),得到 1000 个「均值的副本」。 这 1000 个副本的分布就近似了「如果重做很多次实验,Δ 均值会怎样波动」——即 Δ 均值的抽样分布。 取这 1000 个均值的 2.5% 和 97.5% 分位数,就是 95% 的 percentile CI。 它不依赖正态假设、不需要解析方差公式,对小 N、非正态的二元 pass/fail 差值特别适用——这正是评测场景的常态。

序贯停止判据决定「何时可以下结论」。 固定样本检验要求事先定 n、跑满再看;序贯检验(always-valid p-value,Statsig 2026-01)允许边跑边看而不膨胀假阳率。 在 base-vs-tuned 这种「跑一批攒一批」的离线评测里,序贯停止判据让我们能在 CI 收窄到能拒绝/接受 H0 时就停,而不必盲目跑满 n≈70。 但要警惕:用固定阈值 p 值反复偷看(peeking)会膨胀假阳——每偷看一次就多一次「碰巧越线」的机会,这正是 N=29 那次教训的根因之一。

与已落地 A/B 的关系:同一套算法、不同输入。 本仓真实跑过一次 A/B(V4-Pro vs V4-Flash),用的就是今天要复用的配对+CI 实现,产出 N=29、Δ+10.3pp、95% CI [0.0, 20.7]、3 wins / 0 losses / 26 ties。 注意三个细节:(1) CI 下界正好触 0,是「点估计可观、但不显著」的活教材;(2) wins=3、losses=0、ties=26 说明绝大多数任务两模型都对(天花板效应),真正区分两者的只有 3 道题;(3) 正因为区分信号只来自 3 道题,N=29 的功效极低,要把 CI 推离 0 就得加更多「能区分两模型」的难任务。 今天 b12 的 base-vs-tuned 走完全相同的算法,只是喂的是 b12-base/b12-tuned,所以 test 骨架与 CI 算法可以立刻绿,具体 Δ 数字则待两份报告跑出来。

2. 代码走读:abCompare + pairedBootstrap

Read 了 src/agent/eval/abCompare.tssrc/agent/eval/stats.ts,关键符号与行为:

  • abCompare(a, b, opts)(abCompare.ts)— 入参是两份 AbReportLike(各含 perTask: {taskId, judge:{label}})。流程:
    • passMap(r) 把每份报告压成 Map<taskId, 0|1>(label==='pass' → 1,否则 0)。
    • 取两份报告 taskId 的交集并排序(ids),无交集直接抛 'no common taskIds'——这是「两份报告必须同任务集」的硬约束。
    • 对齐后的 av/bvpairedBootstrapdeltaMeanci95
    • 逐 task 算 av[i]-bv[i] 统计 wins(A 过 B 败)/ losses(B 过 A 败)/ ties
    • 返回 AbResultmodelA/modelBnAlignedcompletionA/completionBdeltaMeanci95wins/losses/ties
  • pairedBootstrap(a, b, opts)(stats.ts)— iters 默认 2000(今天按 seed 用 1000)、rng 可注入(默认 Math.random,测试里注入确定性 rng 才能复现)。先算 diffs = a[i]-b[i],再循环 iters 次「有放回重采样 n 个 diff、累加求均值」,把均值排序后取 percentile(means, 2.5)percentile(means, 97.5)ci95deltaMean 是原始 diffs 的均值。
  • requiredNForDelta(delta, sdDiff)(stats.ts)— 正态近似的样本量公式 n = ((z_{α/2}+z_β)·sd/|Δ|)²(α=.05 双侧、power=.8)。这是「N=29 不够、需 ~70」估算的算法出处:把已观测的 Δ 与配对差 SD 代进去就得到目标 n。
  • 二者皆纯函数、RNG 可注入、无网络——delta-ci.test.ts 注入固定 rng 即可确定性绿,无需 API key。

走读结论:今天不需要新写 CI 算法,delta-ci.test.ts 只是把 b12-base/b12-tuned 两份 json 喂给 abCompare、断言 Δ±CI 字段,复用的就是已产出 N=29 结果的同款实现。

一个最小手算例(验证你真懂 paired bootstrap)

设只有 5 道任务,配对差值(tuned − base)为 diffs = [+1, 0, 0, +1, 0],则:

  • deltaMean = (1+0+0+1+0)/5 = 0.4(即 tuned 比 base 多对 40% 的任务)。
  • bootstrap 一次:有放回抽 5 个下标,例如抽到 [0,0,3,1,4] → [+1,+1,+1,0,0],该次均值 = 0.6;再抽 [1,2,4,2,1] → [0,0,0,0,0],该次均值 = 0.0。
  • 重复 1000 次,把 1000 个均值排序,取第 25 个(≈2.5%)与第 975 个(≈97.5%)做 ci95
  • 因为 diffs 里有 0.0 这种全抽到 0 的可能,CI 下界很容易压到 0 甚至更低——这就是小 N 下界触 0 的机制,和 N=29 那次同源。

requiredNForDelta(0.4, sd(diffs)) 则给出「要把这个 Δ 测显著需要多少配对」——SD 越大、Δ 越小,需要的 n 越多。

3. 今日实战

  1. 新建 delta-ci.test.ts:读 agent-evals/b12-base.jsonagent-evals/b12-tuned.json,构造成 AbReportLike{model, perTask:[{taskId, judge:{label}}]})。
  2. abCompare(tuned, base, { rng: <固定 seed rng>, bootstrap: 1000 }),配对求 Δ 与 95% CI。
  3. 断言:nAligned 等于两份报告 taskId 交集大小;deltaMeanci95 为有限数;wins+losses+ties === nAligned。注入固定 rng 让 CI 可复现、test 确定性绿。
  4. 在 test 里同时调 requiredNForDelta(deltaMean, sdDiff) 打印目标样本量,复刻「N=29→需 ~70」的算法路径,作为 memo 里 n 阈值的来源。
  5. 这是 M5 L3 gate——test 绿即门通过;具体 Δ 数字待 b12-base/tuned 真跑出来后填入。

4. 今日实测 / 产出

  • 产出物delta-ci.test.ts 通过 + Δ±CI 数字。
  • 状态:test 骨架与 CI 算法已可绿(复用 abCompare.ts,纯函数注入固定 rng);b12 base-vs-tuned 的具体 Δ = 待跑(需 key 跑 b12-base/tuned)
  • 已落地真实参照 A/B(V4-Pro vs V4-Flash,同款配对+CI 实现)Δ+10.3pp95% CI [0.0, 20.7]3 wins / 0 losses / 26 tiesN=29。这是 b12 之外、已经跑出的锚点数字,可写入 memo 作对照;b12 自身的 Δ 未跑出前不得臆造。

5. 常见误区 / 陷阱

  • 只报点估 Δ、不报 CI:N=29 的 +10.3pp 看着可观,但 CI 触 0([0.0, 20.7])——这是反例。Δ 必须永远带 CI。
  • bootstrap 不注入 rng:用默认 Math.random 跑 test,CI 每次不同,test 非确定性。务必注入固定 seed rng。
  • 两份报告 taskId 集合不一致abCompare 只取交集,错配会让 nAligned 缩水、CI 变宽甚至抛 'no common taskIds'。落盘前对齐任务集。
  • peeking(反复偷看固定阈值 p 值):在小 N 上边跑边用固定阈值判显著,会膨胀假阳——要么跑满预定 n,要么用 always-valid 序贯检验。
  • 把 wins 数当成显著性证据:wins=3/losses=0 看着「全胜」,但 26 ties 意味着区分信号只来自 3 道题,N 实质极小。wins/losses 是描述性辅助,定论看 CI。
  • iters 太小导致 CI 端点抖动:小 N 时 1000 次 bootstrap 的分位数本身有蒙特卡洛噪声,必要时加大 iters 至 2000+ 让 CI 稳定。

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

  • Statsig — Sequential Testing / always-valid p-values(2026-01):序贯停止判据、避免 peeking 膨胀假阳。
  • Efron & Tibshirani — An Introduction to the Bootstrap(经典方法论,配 2026 现役工程实践):percentile bootstrap CI 原理。
  • Anthropic — Demystifying evals(2026-01):Δ 必带 CI、小 N 高方差的 eval 严谨性。
  • 本仓代码:src/agent/eval/abCompare.tssrc/agent/eval/stats.tspairedBootstrap / requiredNForDelta,已 built+tested)。

7. 面试视角 / 关键要点

AISA 面试常用本日内容追问「你怎么知道模型 A 真比 B 好」,几条标准答法:

  • 「为什么配对而不是两组独立比较?」 → 同一任务集做配对,差值消除任务难度共同方差,CI 更窄、功效更高;独立比较要估两个均值方差,多一层噪声。
  • 「为什么用 bootstrap 而不是 t 检验?」 → pass/fail 差值是离散非正态、N 小,bootstrap 不依赖正态假设,对二元配对差更稳。
  • 「Δ+10.3pp 不是挺大吗,为什么说不显著?」 → 看 CI:[0.0, 20.7] 下界触 0,N=29 功效不足,区分信号只来自 3 道题;要把 CI 推离 0 需 ~70 任务。
  • 「怎么决定要跑多少任务?」requiredNForDelta(Δ, sdDiff):正态近似算目标 n(α=.05、power=.8),SD 大/Δ 小则需更多。

一句话总结:Δ 永远配 CI,配对 bootstrap 求 CI,CI 触 0 就别下结论——这是本日交付 delta-ci.test.ts 的全部精神。

SOTA检查 (2026-06 更新)

  • 现役主线:bootstrap 配对 CI + 序贯停止(Statsig 2026-01)是离线/在线模型对比的现役统计方法。配对设计消除任务难度方差、CI 收窄,是 2026 eval 严谨性标配。
  • 避免/禁用:避免只报点估 Δ 不报 CI——N=29 的 +10.3pp 触 0 即反例。避免在小 N 上用固定阈值 p 值反复偷看(peeking)。
  • 下次复查点:复查 Statsig 序贯检验文档版本(执行当周);复查 bootstrap iters(1000/2000)在 b12 实际 N 下是否足够稳定(小 N 时 CI 端点抖动,可加大 iters)。

8. 产出状态速查

状态备注
delta-ci.test.ts(骨架 + CI 算法)已可绿复用 abCompare.ts,注入固定 rng 确定性
b12 base-vs-tuned 具体 Δ待跑(需 key 跑 b12-base/tuned)两份 json 跑出后填入
abCompare / pairedBootstrap已 built+tested已产出 N=29 A/B 的同款实现
真实参照 A/B已落地Δ+10.3pp、CI[0.0,20.7]、3 wins/0 losses/26 ties、N=29

衔接

  • 昨天:Day 116 — Tuned 模型对照(Qwen3 经 OpenRouter 跑同配置,产出 agent-evals/b12-tuned.json)。
  • 今天:按 taskId 配对 base/tuned,bootstrap 1000 次求 Δ±95% CI,delta-ci.test.ts 绿(M5 L3 gate)。
  • 明天:Day 118 — 结果显著性裁决(CI 是否跨 0 + Cohen's κ 复核两套标注一致性,写 verdict.md)。