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

Base 模型基线

昨天(Day 114)把 base-vs-tuned 的因果实验框架搭好了——H0/H1、唯一变量、n≈70。今天落地这个框架的第一块砖:固化 base 基线。在 B1→B18 曲线上,这是「设计实验」走向「跑出可复现锚点」的一跳。核心纪律一句话:基线分必须先于任何调优固化存档,且固定 seed/温度/prompt/模型 id/grader 版本,否则后续一切 Δ 都无法归因到模型。今天还要避一个

阶段: B12 · RLVR + 模型策略 memo(Day 111-120) 标签: #reproducibility #baseline #eval-rigor #deepseek

今日导引(由浅入深)

昨天(Day 114)把 base-vs-tuned 的因果实验框架搭好了——H0/H1、唯一变量、n≈70。今天落地这个框架的第一块砖:固化 base 基线。在 B1→B18 曲线上,这是「设计实验」走向「跑出可复现锚点」的一跳。核心纪律一句话:基线分必须先于任何调优固化存档,且固定 seed/温度/prompt/模型 id/grader 版本,否则后续一切 Δ 都无法归因到模型。今天还要避一个坑——基线绝不能绑会退役的 legacy 模型 id,否则基线一过期就再也复现不出来。最小可判定产出:agent-evals/b12-base.json + base 准确率数字(固定配置下产出)。

1. 机理精读

为什么基线要先固化。 base 基线是「后续一切对照的锚」。明天 Day 116 的 tuned、Day 117 的 Δ±CI,都是相对 base 测量的。如果 base 没在调优之前存档,或者存档时配置没固定,那么当你拿到 tuned 结果时,根本无法判断 Δ 来自模型还是来自「base 那次恰好用了不同的温度/prompt」。

先存基线、再调优是因果链上不可逆的顺序,有两个原因:

  1. 防未来知识污染:调优之后再去补 base,你已经知道 tuned 的成绩,会下意识挑对自己有利的 base 配置(哪怕只是无意识地选了某个 prompt 版本),这等于偷偷给实验注入了确认偏误。
  2. 可审计性:基线存档是一个时间戳锚点,commit 进 agent-evals/ 后任何人都能复算并验证「这个 base 分确实在调优之前产生」。没有这个锚,整条 Δ 链条无法被外部审计。

复现性五要素。 一次 eval 要能被任何人在任何时间复算出同一个数字,必须钉死五项:

#要素不固定的后果推荐值
1seed同 prompt 每次输出不同,准确率随机波动固定整数
2温度采样噪声淹没能力差异0(贪心)
3prompt 模板测的是「模型+prompt」联合效应锁版本
4模型 id别名随时间指向不同权重显式 deepseek-v4-pro
5grader 版本codeCheck/judge prompt/tasks 改了分不可比锁 git commit
  1. seed:采样随机性的种子。不固定 → 同一 prompt 每次输出不同 → 准确率随机波动。
  2. 温度:建议 0(贪心解码)。温度 >0 引入采样噪声,会把模型能力差异淹没在随机性里;评测要测「能力」就该关掉采样噪声。
  3. prompt 模板:同一套 system/user 模板。prompt 变了,测的就是「模型 + prompt」的联合效应。
  4. 模型 id:精确到版本(如 deepseek-v4-pro),不能用会随时间指向不同权重的别名。
  5. grader 版本:codeCheck 逻辑 + LLM-judge prompt + 任务集(tasks.ts)的版本。grader 改了,分数不可比——最稳妥是把 grader 的 git commit hash 也记进 b12-base.json

模型 id 必须显式且不绑退役 id。 这是今天最硬的一条坑。deepseek-chat / deepseek-reasoner 这两个 legacy id 将于 2026-07-24 退役——一旦把基线绑在它们上,退役后基线就永远无法复现(id 失效或被重定向到不同权重)。所以基线必须用显式的 deepseek-v4-pro,并在协议里标注「禁用 legacy id」。这与顶层全局时效性硬规则「版本号必须显式」一致。

基线分的两个口径。 本仓 harness(src/agent/eval/agentEval.ts)对每个任务产出两层评判:(1) 便宜的确定性 codeCheck(启发式首过),(2) LLM-judge 的 label(pass/fail/unknown)+ score(partial credit)。聚合后 TaskEvalReportcompletionRate = judge.label==='pass' 的占比,partialCreditMean = judge.score 均值。已有真实参照:V4-Flash completion 79.3%(judge=pass)、V4-Pro 89.7%、partial-credit 0.900、$0.0139/run——这些是同 harness 下已测得的锚点。

基线 ≠ 已是 SOTA,但必须诚实。 基线的价值不在于「高」,而在于「可复现 + 先于调优」。一个固定配置下诚实存档的 base 分,哪怕只有 79.3%,也比一个配置漂移、事后挑出来的「90%+」有用——因为只有前者能让 Δ 干净归因。

与 Day 114 协议的接口。 Day 114 的 exp-protocol.md 规定了「固定哪些变量、n≈70」;Day 115 是把这套协议的 base 半边实际落盘。两者的接口就是:协议里写的「固定 seed/温度=0/prompt/模型 id/grader 版本」这串约束,必须一字不差地体现在 b12-base.jsonconfig 块里——否则明天 Day 116 的 tuned 跑批就无法与 base「只换权重」对齐。基线是协议从纸面落到磁盘的第一步。

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

src/agent/eval/agentEval.ts 走读(base 跑批的引擎):

  • EvalTask(第 20-28 行):{id, category?, prompt, reference?, codeCheck?}。注释第 24 行强调 reference 只给 judge 看、不给被测模型看——防止把答案泄露给被测模型(否则基线虚高、不可复现地虚高)。
  • JudgeVerdict(第 30-35 行):{label: 'pass'|'fail'|'unknown', score, rationale?}。注释第 6 行点明遵循 Anthropic「Demystifying evals」——grade the OUTCOME、允许显式 unknown、给 partial credit。unknown 这一档很关键:它让 judge 在证据不足时不被迫二选一,避免污染 completionRate。
  • GenerateFn / JudgeFn(第 42-43 行):模型调用是可注入的,所以聚合逻辑能用 fake 单测、无网络。scripts/run-agent-eval.ts 把真实 OpenRouter / deepseek 模型接进来(文件头注释第 9-11 行)。
  • TaskEvalReport(第 55-59 行):modelncompletionRate(label==='pass' 占比)、partialCreditMean(judge.score 均值)、unknownRate。→ base 跑批存进 b12-base.json 的就是这个结构。
  • 第 13-16 行 imports:generateText(ai SDK)、createOpenAICompatible(deepseek/OpenRouter 兼容层)、cohensKappaWithCI(judge↔human κ 校准)、estimateCost(成本,$0.0139/run 的来源口径)。
  • 注释第 5-7 行点明设计哲学:「report the judge↔human Cohen's kappa with a bootstrap CI so the judge itself is calibrated, not trusted」——judge 不是被信任的、而是被校准的。这与基线复现性是一体两面:基线分要可复现,judge 要可校准,两者都不能「拍脑袋相信」。
  • 第 9-11 行注释:模型调用件可注入(GenerateFn/JudgeFn),所以聚合逻辑用 fake 单测、无网络。这是为什么 agentEval.ts 本身已 built+tested,而真实 base 跑批仍需 key——测的是聚合逻辑,不是模型。

复现性手算检查(为什么温度=0 重要): 设某任务模型在温度 T=0 时贪心输出固定答案 → 多次跑 completionRate 完全一致(可复现)。在 T=0.7 时同一任务每次采样不同 → 假设单任务 pass 概率 0.8,跑 29 个任务,completionRate 的二项标准差 ≈ √(0.8×0.2/29) ≈ 0.074 → 单次跑批就可能在 72%~88% 间随机摆动。这点随机噪声(±7pp 量级)足以淹没明天要测的模型差异(Δ+10.3pp),所以基线必须 T=0。

存档动作:pnpm eval:agent(经 scripts/run-agent-eval.ts 接真实模型)→ 得 TaskEvalReport → 落 agent-evals/b12-base.json,配置块里写死 seed/温度=0/prompt 版本/模型 id=deepseek-v4-pro/tasks.ts 版本。期望落盘结构(口径示意,数字待真实跑批回填):

{
  "config": {
    "model": "deepseek-v4-pro",
    "temperature": 0,
    "seed": 42,
    "promptVersion": "p1-v1",
    "graderCommit": "<git-sha>",
    "taskSet": "tasks.ts@<sha> (n=29)"
  },
  "report": {
    "model": "deepseek-v4-pro",
    "n": 29,
    "completionRate": "<待跑>",
    "partialCreditMean": "<待跑>",
    "unknownRate": "<待跑>"
  }
}

注意 completionRate/partialCreditMean 标注「待跑」——本日不臆造数字,只把可复现的配置块写死。已有的 V4-Pro 89.7% / V4-Flash 79.3% / partial-credit 0.900 / $0.0139/run 是别处同 harness 已测得的参照锚,不等于 b12-base 这次跑批的结果。

3. 今日实战

  1. src/agent/eval 的 κ-harness(pnpm eval:agent,经 scripts/run-agent-eval.ts 接真实模型)跑 base 模型过 P1 任务集(tasks.ts,29 条)。
  2. 模型 id 用 deepseek-v4-prolegacy deepseek-chat / deepseek-reasoner 2026-07-24 退役,禁用)。
  3. 固定 温度(建议 0)/ seed、prompt 模板、grader 版本。
  4. TaskEvalReport 结果存 agent-evals/b12-base.json,配置块写死全部复现性五要素。
  5. 记录 base completionRate / partialCreditMean 作为后续 tuned 对照的锚。

4. 今日实测 / 产出

  • 产出agent-evals/b12-base.json + base 准确率数字。
  • 已有真实参照(同 harness 下已测得):V4-Flash completion 79.3%(judge=pass)、V4-Pro 89.7%、partial-credit 0.900、$0.0139/run
  • b12-base.json 的具体跑批 = 待跑(需 key 跑),将产出固定配置下的 base 准确率。
  • 模型 id 显式 deepseek-v4-pro;legacy deepseek-chat / deepseek-reasoner 2026-07-24 退役、禁用
  • harness(agentEval.ts)为可注入设计、已 built+tested(fake 无网络单测);本日不臆造新测量数字,b12-base 真实跑批待 key。

5. 常见误区 / 陷阱

  1. 调优之后再补 base。基线必须先于一切调优固化——事后补 base 会被「未来知识」污染(你会挑对 tuned 有利的配置)。顺序不可逆。
  2. 基线绑会退役的 legacy 模型 iddeepseek-chat / deepseek-reasoner 2026-07-24 退役,一旦基线绑过期 id,复现即失效。必须用显式 deepseek-v4-pro
  3. 温度 >0 跑基线。采样噪声(±7pp 量级)会淹没模型差异(Δ+10.3pp)。评测能力要 T=0 关掉随机性。
  4. 把 reference 喂给被测模型reference 只给 judge 看;泄露给被测模型会让基线虚高且不可复现地虚高。
  5. 不记 grader 版本。codeCheck/judge prompt/tasks.ts 任何改动都会让分数不可比。基线存档必须连 grader 的 git commit 一起钉死。
  6. 把别处的参照锚当成本次基线。V4-Pro 89.7% 是同 harness 别处已测的锚,不是 b12-base 这次跑批结果——混用会让基线失真。

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

  • Anthropic《Demystifying evals》— 2026-01(复现性纪律、grade the outcome、显式 unknown、partial credit、judge κ 校准)
  • DeepSeek 模型生命周期公告 — 2026(deepseek-chat/deepseek-reasoner 2026-07-24 退役;deepseek-v4-pro 为现役 id)
  • 顶层全局时效性硬规则(CLAUDE.md,2026)—「版本号必须显式」与「禁止引用已停服项目」直接约束基线模型 id 选择
  • 本仓实现:src/agent/eval/agentEval.ts(harness:EvalTask/JudgeVerdict/TaskEvalReport,可注入)、scripts/run-agent-eval.ts(接真实模型)、src/agent/eval/cohensKappa.ts(judge↔human κ)

SOTA检查 (2026-06 更新)

  • 当前主流:Demystifying evals(Anthropic 2026-01)的复现性纪律仍是当前 best practice——固定 seed/温度/prompt/模型 id/grader 版本、基线先于调优固化、judge 配 κ 校准。
  • 是否仍 SOTA:是。可复现 + 显式版本 + judge 校准是 2026 严谨评测的底线。
  • 过时黑名单
    • 禁用会退役的 legacy 模型 id 当基线(deepseek-chat / deepseek-reasoner 2026-07-24 retire——基线一旦绑过期 id,复现即失效);
    • 禁止温度 >0 跑能力基线(采样噪声淹没差异);
    • 禁止把 reference 泄露给被测模型(基线虚高且不可复现);
    • 禁止调优后补 base(未来知识污染);
    • 禁止不记 grader 版本就存基线(分数不可比)。
  • 下次复查点:2026-07-24 deepseek legacy id 退役日——届时复查所有基线是否已迁到 deepseek-v4-pro;复查 Demystifying evals 是否有更新版本;待 key 跑出 b12-base.json 后回填真实 base 准确率。

衔接

  • 昨天:Day 114 — 实验设计基础(H0/H1、唯一变量、n≈70、序贯 vs 固定检验)
  • 今天:固化 base 基线——复现性五要素(seed/温度0/prompt/模型 id/grader 版本),先于调优存档,禁用退役 legacy id;b12-base.json 真实跑批待 key。
  • 明天:Day 116 — Tuned 模型对照(除模型外全锁死,用 Qwen3 经 OpenRouter 路由跑同一任务集,存 b12-tuned.json),随后 Day 117 配对求 Δ±CI(M5 L3 gate)。

114→115→116→117 是一条完整链:定协议(114)→ 落 base(115)→ 落 tuned(116)→ 配对出 Δ±CI(117)。今天是这条链的第二环,也是「让评测可复现、可审计」从原则变成磁盘上一个 commit 的那一步。