self-consistency 机制
Day 33 立了非确定性的统计底座(pass@k / pass^k / variance),并建了 runNTimes 复跑封装。今天把这个封装用起来,落地第一个降方差技术:self-consistency——同 prompt 多采样再多数投票。它在能力曲线上的位置是「方差控制」:不是让模型更聪明,而是把偶发错误样本稀释掉。最小可判定产出:用 DeepSeek-V3 对 8 任务跑 single
阶段: B4 · reasoning/planning/multi-agent + 何时不用 agent(Day 31-40) 标签: #self-consistency #majority-vote #variance-reduction #cost-curve
今日导引(由浅入深)
Day 33 立了非确定性的统计底座(pass@k / pass^k / variance),并建了 runNTimes 复跑封装。今天把这个封装用起来,落地第一个降方差技术:self-consistency——同 prompt 多采样再多数投票。它在能力曲线上的位置是「方差控制」:不是让模型更聪明,而是把偶发错误样本稀释掉。最小可判定产出:用 DeepSeek-V3 对 8 任务跑 single-shot vs k=5 self-consistency,记 Δaccuracy 与成本曲线(数字待 key)。
1. 机理精读
self-consistency 是方差缩减,不是能力提升。 机制三步:(1) 对同一 prompt 在温度>0 下采样 k 次,得到 k 个可能不同的答案;(2) 把答案归一化(数值/分类/是否);(3) 多数投票取众数作为最终答案。直觉来自 Self-Consistency (arXiv:2203.11171):正确答案往往是「多条不同推理路径的共同终点」,而错误是分散的偶发样本——投票把分散的错稀释、把集中的对放大。
为什么有效,依赖什么前提。 它成立的前提是「单次正确率 > 随机」且「错误彼此独立分散」。在这个前提下,多数票的准确率高于单次,且随 k 上升。但它只对可投票的输出有效——数值(reasoning-numeric-sum 答 $29,000)、分类(structuring/layering/integration)、是/否(restraint 类「是否 flag」)能投票;开放式长文(aml-sar-5w1h 的叙事)不能直接多数投票,需先抽取可比较的关键字段再投。
代价是 token×k 与延迟。 k=5 意味着 5 倍生成 token 和(若串行)约 5 倍延迟。准确率随 k 边际递减:从 1→3 提升明显,3→5、5→7 收益迅速变小。因此必须把 accuracy 和 cost 一起画成成本曲线找拐点——这正是 Karpathy Zero-to-Hero 里「采样直觉」的工程化:采样是有价的随机性,要为收益付费而非无脑堆 k。
关键权衡与边界。 self-consistency 是「用更多 token 换更低方差」的经典基线。它和 Day 33 的 variance 是一体两面:variance 大的任务,self-consistency 收益大;variance 已经很小(模型每次都对或每次都错)的任务,投票几乎无用。重要边界(2026 现实):带 extended thinking 的推理模型在内部已经走了多条路径并自洽,外部再叠 self-consistency 的边际收益变小——对 reasoning model 要先验证收益是否还在,不能照搬 2022 的经验。这条会进 Day 38(成本/延迟多维度量)和 Day 40(gate)的取舍。
与 Day 33 的接力。 Day 33 把 variance 量化成 per-task std;今天 self-consistency 正是「对高 std 任务定向投药」——只对那些 std 大、单次不稳的任务开 k 采样,对 std≈0 的稳定任务保持 single-shot 省钱。换句话说,self-consistency 不该全量开,而该按 Day 33 的 std 列有选择地开,这本身就是一条成本优化策略。
2. 推导 / 手算 / 代码走读
为什么这一步对 AISA 重要。 self-consistency 是「可靠性可以花钱买」的最直接证据——它把「准确率不够」翻译成「再花 k 倍 token 能买回多少 pp」,让可靠性和成本进同一张账。架构评审里你能据此回答「为什么这条链路用 k=3 投票」:因为它的 std 大(Day 33)、k=3 把 Δaccuracy 抬到 CI 不跨 0(Day 35),且 token 成本仍在预算内(Day 38)。这比「加一层投票更稳」的空话能落到数字上。
手算多数投票降错的直觉(设单次正确率 p=0.6,错误均匀分散到 2 个错误答案各 0.2,k=5 投票):
- 5 次里正确答案的期望出现次数 = 5×0.6 = 3,往往是众数 → 投票后正确概率明显 > 0.6。
- 直觉公式(二选一简化版,单次 p>0.5 时):多数票正确率 =
Σ_{i>k/2} C(k,i) p^i (1-p)^(k-i),p=0.6、k=5 时 ≈ 0.683 > 0.6。提升约 +8pp,但 k 再加到 7、9 提升迅速收窄——这就是边际递减,要在曲线拐点停。
代码走读(本日复用/挂接):
- 复用 Day 33 的
runNTimes(task, n):对每任务采样 k=5,拿到 k 个输出。 - 多数投票聚合器(本日新增逻辑):对 k 个输出按可比较字段归一化后取众数;single-shot 则取 k=1。两者都过同一
judge/codeCheck算 accuracy。 - 投票逻辑用 fake 输出离线单测(如喂
['A','A','B','A','B']验证众数=A),离线单测绿,不触网。 - 脚本挂到
scripts/run-agent-eval.ts:该 runner 现状是--provider deepseek默认、读EVAL_TASKS、无 key 时打印 dry-run 并 exit 0(见文件 68-89 行main())。本日要做的是让它支持「k-run + 投票」模式跑真实 DeepSeek-V3(OpenRouter),但无 key 时仍走 dry-run,与现有行为一致。 - 真实模型经
makeModelGenerate计 token 与(若modelName在MODEL_PRICES)真实 cost,成本曲线的 token 数据由此而来。
makeModelGenerate 的成本细节(走读 agentEval.ts 150-165 行):
- 它对每个 task 调
generateText,从r.usage取inputTokens/outputTokens(兼容promptTokens/completionTokens旧字段名)。 - 仅当
opts.modelName存在且命中MODEL_PRICES且 in/out token 都是数字时,才用estimateCost(modelName, inTok, outTok)算costUsd;否则costUsd留undefined——绝不静默记 0。这保证成本曲线里没有「假装免费」的点。 - 因此 self-consistency 的真实 token 成本 = k 次每次的
inTok+outTok累加,可直接从 per-call 结果聚合,无需另估。
多数投票聚合的伪代码(本日新增逻辑,离线可单测):
function majorityVote(outputs): # outputs = k 个被测输出
keys = outputs.map(normalize) # 抽可比较字段(数值/分类/是否)
return mode(keys) # 取众数;平票按预设 tiebreak
# single-shot = majorityVote([outputs[0]]);k=5 = majorityVote(全部 5 个)
测试:喂 ['structuring','structuring','layering','structuring','layering'] → 众数 structuring,离线断言即可,不触网。
成本曲线读法速查表
| k | 相对 token 成本 | accuracy 走势 | 何时停 |
|---|---|---|---|
| 1 | 1× | 基线 | 稳定任务(std≈0)停在此 |
| 3 | 3× | 提升明显 | 多数任务的甜点区 |
| 5 | 5× | 提升收窄 | 高方差任务可到此 |
| 7+ | 7×+ | 边际趋平 | 几乎不值得,除非任务极脆弱 |
口诀:accuracy 抬升边际递减、token 成本线性上涨,拐点(通常 k=3~5)就是该停的地方;reasoning model 上拐点更靠前(内部已多路径)。
3. 今日实战
- 用 DeepSeek-V3(OpenRouter provider,runner 默认 provider 可切到 openrouter)对 8 任务跑 single-shot。
- 同 8 任务跑 k=5 self-consistency:复用 Day 33
runNTimes采样 + 本日多数投票聚合。 - 记两组 accuracy 与 Δ(k=5 − single-shot)。
- 把投票模式脚本挂到
scripts/run-agent-eval.ts。 - 画 accuracy-vs-k 成本曲线(k=1,3,5),找边际递减拐点。
- 离线 fixture 模式:喂确定性 fake 输出验证投票聚合 + completion% 能产出并 commit;真实 single vs k=5 的 Δaccuracy 留待 key。
- 把每任务的 token 成本(k 次累加)并列记入,作为 Day 38 成本/延迟矩阵的输入之一。
4. 今日实测 / 产出
- 「待跑(需 OPENROUTER_API_KEY);可先用离线 fixture 跑通 harness 出 completion%+commit」。
- 将产出 Δaccuracy(k=5 − single-shot)数字 + 成本曲线。
- 投票逻辑离线单测绿。
- 状态:投票聚合器+离线单测属可建/可验;Δaccuracy 与成本曲线的真实数字属待跑(需 key),不臆造数值。
与 Day 33/35 的接力
- 输入来自 Day 33 的
runNTimes+ per-task std:std 大的任务才是 self-consistency 的投药对象。 - 输出交给 Day 35:single vs k=5 的两组 accuracy 喂
pairedBootstrap,判 Δ 的 95% CI 是否跨 0——只有 CI 不跨 0,才有统计依据说「投票真的更好、值这 k 倍 token」。 - token 成本列再喂 Day 38 的 cost/latency/variance 三维矩阵。
5. 常见误区 / 陷阱
- 对不可投票输出硬投票:开放式叙事(SAR narrative)直接投票无意义,需先抽取可比较字段再投。
- 无脑堆大 k:准确率边际递减但 token×k 线性涨,不画成本曲线就会在 k=9 付 9 倍钱换 +1pp。
- 对 reasoning model 照搬收益:extended thinking 模型已内化多路径,外叠 self-consistency 收益变小,要先测再上。
- 把离线投票单测绿当真实 Δ:fixture 只验众数逻辑,真实 Δaccuracy 仍需 key——状态不可升级。
- 全量开 self-consistency:对 std≈0 的稳定任务也投票纯属浪费;应按 Day 33 的 std 列定向只对高方差任务开。
- 平票无 tiebreak:偶数 k 或多分类下可能平票,聚合器必须有确定性 tiebreak(如按 codeCheck 或保守取「更安全」选项),否则结果不可复现。
自测题(面试演练)
- Q:self-consistency 提升的是能力还是方差? A:方差。它不让模型更聪明,而是把分散的偶发错误样本投票稀释掉;前提是单次正确率 > 随机且错误彼此独立分散。
- Q:为什么不能无脑把 k 调大? A:accuracy 随 k 边际递减,但 token×k 与(串行)延迟×k 线性上涨;不画成本曲线就会在 k=9 付 9 倍钱换 +1pp。要在拐点(常 k=3~5)停。
- Q:reasoning model 上还要叠 self-consistency 吗? A:先测。extended thinking 模型内部已走多路径并自洽,外叠收益变小甚至接近 0,要用实测确认收益是否还在,别照搬 2022 经验。
- Q:开放式 SAR 叙事怎么投票? A:不能直接投。先从每次输出抽出可比较的关键字段(典型学标签、是否含 5W1H facet、风险结论),对字段投票,而非对整段文本投票。
6. 学习资源(每条带 YYYY-MM)
- Self-Consistency Improves Chain of Thought Reasoning, Wang et al. (arXiv:2203.11171, 2022-03) — 多采样投票降方差原始论文。
- Karpathy《Neural Networks: Zero to Hero》(2023, 持续更新) — 采样/温度直觉的教学黄金路径。
- 本仓代码
scripts/run-agent-eval.ts+src/agent/eval/agentEval.ts(makeModelGenerate计 token/cost)— 真实跑与成本数据来源。 - 本仓代码
src/agent/eval/stats.ts— accuracy 聚合的统计原语。
SOTA检查 (2026-06 更新)
- 当前主流:self-consistency 仍是降方差基线,现行有效。
- 重要折扣:2026 推理模型(带 extended thinking)部分内化了多路径,需注意对 reasoning model 收益变小——上线前先验证收益是否仍在。
- 版本核对:DeepSeek-V3 版本号执行当周复验(OpenRouter slug 可能变更)。
- 下次复查点:是否有 self-consistency 的「自适应 k」方法(按 variance 动态决定采样数)成为新基线。
衔接
- 昨天:Day 33 — 非确定性统计基础(pass@k/pass^k/variance +
runNTimes封装)。 - 今天:self-consistency 多采样投票降方差,single-shot vs k=5 对比 + 成本曲线。
- 明天:Day 35 — bootstrap 置信区间(给今天两组 single vs k=5 结果算 Δ 的 95% CI,判是否跨 0)。