TypeSafe 自洽性测试:多问几次会不会变
决策系统上线前,最该追问的不是“它答得顺不顺”,而是“同一个输入多问几次,答案会不会变”。如果会变,而且变化跨越阈值,次级不确定性就会变成路由抖动。TypeSafe 官方有两篇 cookbook,分别覆盖离散选择与概率判断题的稳定性。本文把两篇放在一起看:测什么、怎么算钱、结果怎么读、替代不了什么。
先说结论
- 官方两篇 cookbook 有明确分工:Choice 版测固定标签集里的选项是否稳定选中;Noul 版测 True/False 题的
P(true)概率在多轮里是否稳定。 - 落地成本:同一 state 重复 N 次,成本基本线性放大。官方 cookbook 采用 N=15;按官方首页
$42 Per Billion input tokens,可以做人天级预算推算,但本文只标量级。 - 一致率高 ≠ 正确率高。自洽性只回答“稳不稳”,不回答“对不对”;必须和带标注评测集放在一起看。
- 工程上建议每次调用都落盘,失败重试、幂等记录;社区二手提到“约 240 次调用出现 1 次瞬时错误、重试后答案一致”,但原始出处未核实。
- 最小脚本只需要 N 次调用 → 一致率 → 不一致样本落盘三件事。
官方两篇 cookbook 的差异
选择类测试对应 官方 cookbook:Self-consistency(choice)。该篇开头这样写:
This cookbook takes one borderline user post, runs a moderation rubric over it 15 times, and checks whether each answer holds still across the repeats. Every check is a Choice, so each answer is one label from a fixed set.
这句话点出关键对象:一条边界用户帖子、15 次重复调用、每次检查是 Choice、答案是固定集合中的一个标签。因此要统计的是一致率,也就是多数标签在重复中是否变化。
概率类测试对应 官方 cookbook:Self-consistency(noul)。它的开篇原句是:
This cookbook takes one auto-insurance claim, runs a 14-question rubric over it 15 times, and checks whether each answer holds still across the repeats. Every check is a Noul, so each answer is P(true) for one True/False question.
这里每个输出不是标签,而是 P(true),取值天然在 0~1。因此稳定性要看的不是“是否选同一个类别”,而是概率值散不散。官方在 noul 版报告了一次采样结果,原句是:
TypeSafe’s mean per-question probability standard deviation is 0.0102, below all LLM probability conditions here.
这属于官方数据,但它只是一次运行结果,不是普适保证。
在 choice 版里,官方也报告了运行结果:LLM 分布设置的 plurality label 重复比例从 87.5% 到 100%,TypeSafe 为 90.8%。原句是:
In this run the LLM distribution settings repeat their plurality labels 87.5% to 100% of the time, compared with TypeSafe’s 90.8%. TypeSafe has lower mean probability variation than five of the six LLM distribution conditions; Haiku at temperature 0 varies less.
这些数字也是官方 cookbook 的一次运行数据,不能当作模型永远的水平。
怎么落地:重复 N 次与成本
两篇官方 cookbook 的 setup 都用 15 次重复,因为 NUM_SAMPLES = 15。每次调用都是一次 system_one 调用,一次回答全部 8 个 Choice 或 14 个 Noul,不是逐题散打。这影响成本估算:重复 15 次,不是 15×题目数。
官方 cookbook 还写明每次调用带新的 uid 字段,原句是:
with a fresh uid field (a throwaway unique value) on each call, matching the noul cookbook setup.
我的工程理解是:这是为了防止采样被缓存或请求复用,但每次仍需要落盘原始结果。
成本方面,官方首页把 Jev 输入价格写成:
$42 Per Billion input tokens.
官方 cookbook 代码里也有:
TYPESAFE_PRICE = ( 0.042 , 0.00 ) # Historical TypeSafe rate, as of 2026-08
后面的 LLM_PRICES 注释单位是 $ per 1M tokens。两者可互相印证:$0.042/百万 token = $42/十亿 token。这是官方数据。按这个价格做一次自己的推算:设单次输入 token 数为 T,N 次自洽性测试的输入成本约为 N × T / 1e6 × 0.042 美元。注意输出价格在 cookbook 代码里写成 0,属于历史费率;只应该用于量级估计,不该作为采购依据。
统计口径上,Choice 版适合计算 plurality agreement;Noul 版适合对每个问题计算概率标准差,再取均值。如果自己做,可以先只做一致率,再按需加入分布方差。
结果怎么读:稳定不等于正确
官方 choice 版报告了一个重要现象,原句是:
Close probabilities still permit routing changes: TypeSafe flips on 2 of the 8 questions.
意思是即使概率变化不大,只要跨过阈值,路由就会变。官方还用 0.60 作为示例自动动作阈值,代码注释原文是:
MIN_CHOICE_PROBABILITY = 0.60 # illustrative automatic-action threshold
这是说明性阈值,不是通用推荐。noul 版则把 0.30 到 0.70 的概率划为显式不确定区间,用于人工复核。
官方 Confidence 文档进一步解释了概率与 confidence 的关系,原句是:
All Score and Choice answers from TypeSafe include a probabilities property representing the probability distribution across the options (for Choice) or levels (for Score). The shape of that distribution is what tells you how certain the model is: concentrated on one outcome means a confident answer, spread out means an uncertain one.
并且:
confidence is a statistic computed from the probability distribution the answer already gives you.
同时 Noul answers don’t carry one. 这说明 confidence 只是对概率分布形状的压缩,不是外部正确性。
我的判断是:自洽性测试属于稳定性测试,不应单独用作正确率指标。一个模型可能 15 次全部选择同一个错误答案,一致率 100%,但正确率是 0%。要验证正确性,必须把同一批 state 放到带人工标注的评测集里,比较模型多数答案与标注答案。官方 Confidence 文档也说:“Start with conservative thresholds, test with your own data, and adjust as you observe results.” 这正是要把稳定性和真实数据表现分开看。
社区二手的瞬时错误
工单提到一个社区二手观察:在某个 60 例基准中,约 240 次调用出现 1 次瞬时错误,重试后答案一致。这个数字本次没有原始链接,未能核实,所以不作为结论依据。它只提示工程上必须把失败请求单独记录,不要混进一致率。可参照的思路是:每次调用带 request_id、样本 ID、是否重试、是否成功;失败重试不能改变原样本的幂等记录。
最小自洽性测试脚本骨架
下面的骨架是通用实践,不依赖官方 SDK。run_once 可以是 TypeSafe 调用或任意模型调用,返回 dict。核心分三块:N 次调用、一致率计算、不一致样本落盘。
from collections import Counter
import json
def self_consistency_check(run_once, state, n=15, value_key="label"):
successes, failures = [], []
for i in range(n):
try:
raw = run_once(state)
assert value_key in raw, "missing key in model result"
successes.append({"attempt": i, "raw": raw})
except Exception as exc:
failures.append({"attempt": i, "error": str(exc)})
values = [r["raw"][value_key] for r in successes]
dist = Counter(values)
plurality = dist.most_common(1)[0][0] if dist else None
agreement = dist[plurality] / len(values) if values else None
ambiguous = [r for r in successes if r["raw"][value_key] != plurality]
if ambiguous:
with open("ambiguous_samples.jsonl", "a", encoding="utf-8") as f:
for item in ambiguous:
f.write(json.dumps(item, ensure_ascii=False) + "n")
return {
"n": n,
"successful": len(values),
"failed": len(failures),
"agreement": agreement,
"distribution": dict(dist),
"failures": failures,
}
这个骨架没有处理重试、超时、限流,也没有做概率方差;但足以先把“稳不稳”这件事跑起来。
自己的判断与落地清单
- 先判断题型再选指标:离散选项用 plurality agreement;True/False 概率题用每问题概率标准差或方差。
- 固定输入 state,每次 fresh uid,N=15 起步;但不要只写死 15,成本允许可以上调。
- 把一致率和标注准确率分开报告。只有两者同时达标,才适合自动执行。
- 阈值必须按业务风险定。官方 Confidence 文档里 High/Medium/Low 三段划分是工程框架,不是固定参数。
- 对失败样本、重试、不一致样本留痕;人工抽检不一致样本,往往能暴露 prompt 或 rubric 的模糊处。
这次没核实的
- “约 240 次调用出现 1 次瞬时错误、重试后答案一致”是社区二手,本次没有原始链接,未能核实。
- 官方首页
$42 Per Billion input tokens未注明价格截止时间,是否涵盖输出/缓存未进一步确认。 - 官方 cookbook 使用的
jev-latest与模型名称gpt-5.5、claude-opus-4-8等未验证是否为当前可购模型版本。 - Noul 版
mean per-question probability standard deviation的具体统计口径,未能从页面完全确认。
参考来源
评论区
登录后可评论。