决策置信度工作台
从 TypeSafe 文档里提取出的 Choice confidence 公式,做成交互工具。
它想回答一个具体问题:为什么你的置信度阈值不能跨问题复用。
一、公式
来源:docs.typesafe.ai 的 confidence 页面内嵌组件,未改动一行。
function choiceConfidence(values) {
const count = values.length;
const peak = Math.max(...values) / 100;
return Math.max(0, Math.min(1,
(count * peak - 1) / (count - 1)));
}
翻译成人话:把「均匀分布」当作 0 基准,看峰值比基准高出多少。 完全均匀 → 0;某一项独占 → 1。
二、拖动看看
拖动滑块改变概率分布,观察 confidence 如何变化。总和自动保持 100%。
confidence
0.000
落点分区
峰值 / 均匀基准
1.00×
三、⚠️ 官方文档没提的性质
固定峰值 = 90%,只改变选项数量 —— 看 confidence 怎么变。
| 选项数 | 峰值 | 其余选项 | confidence |
|---|
同样的峰值概率,选项越多,confidence 越高。
因为公式以「均匀分布」为 0 基准 —— 选项越多,那个基准(1/n)越低, 于是同样的峰值离基准越远,confidence 就被算得越大。
这不是 bug,是定义使然。但它的实践后果是: 你的 0.8 阈值,在 2 选项题和 10 选项题上要求的实际把握程度并不相同。
因为公式以「均匀分布」为 0 基准 —— 选项越多,那个基准(1/n)越低, 于是同样的峰值离基准越远,confidence 就被算得越大。
这不是 bug,是定义使然。但它的实践后果是: 你的 0.8 阈值,在 2 选项题和 10 选项题上要求的实际把握程度并不相同。
四、阈值反解器
给定「想要多少 confidence」和「有多少选项」,反解出峰值概率需要达到多少。
反解公式:peak = (c × (n−1) + 1) / n
| 选项数 n | 峰值需达到 | 若峰值恰为此值 | 校验 |
|---|
上表最后两列是把反解结果代回原公式验算的 —— 都精确回到目标值,
说明反解正确。这一栏你可以自己核对。
五、三区路由:怎么用这个数字
文档建议把 confidence 分成三段,每段对应不同的系统行为。
| 区间 | 含义 | 系统行为 |
|---|---|---|
| 高 | 模型读得很清 | 直接执行 |
| 中 | 有答案但不确定 | 请用户确认 / 标记复核 / 补充信息 |
| 低 | 证据不足或问题不适配 | 不要行动 —— 转人工或换路径 |
关键:阈值随风险变化,不是一个数
文档给的示例很能说明问题 —— 同一个系统里,只读操作和高风险操作的门槛不同:
if confidence < 0.5:
route_to_human() # 模型真的不确定,别猜
elif action == "check_balance":
show_balance() # 低风险:显示错页面也能挽回
elif action == "approve_transfer":
if confidence > 0.9:
confirm_then_execute() # 高风险 + 高把握
else:
ask_user_to_confirm() # 高风险 + 一般把握 → 先核实
注意 0.5 这个「地板」的位置不是随口定的。
在上面的公式里,2 选项题 conf=0.5 对应峰值 75%;5 选项题只对应 60%;
10 选项题更低。同一个 0.5,背后要求的把握程度随选项数一路下降。
六、设计判断题时的检查清单
来自 TypeSafe 官方的设计指引,我按原文归纳,没有加料。
| 要做的事 | 原因 |
|---|---|
| 规则、计算、精确查表留在代码里 | 模型只负责需要语义理解的那一步 |
| 一个问题只问一件窄而连贯的事 | 拆开独立维度,但别破坏被判断的关系 |
| 把判断写进 instructions,把可选答案写进 criteria | 两者职责不同,混着写会含糊 |
| 给出「都不匹配」的出口 | 否则模型被迫在坏选项里选一个 |
| 选值类问题要检查候选覆盖 | 模型无法选中一个没被列出来的值 |
| 独立问题一次发出去并行 | 省往返;但它们互相看不见彼此的答案 |
| 阈值必须在自己的数据上验证 | 文档明说:cookbook 的阈值只是示例,不是通用规则 |
| Web 应用里凭据只放服务端 | 原文明确要求 |
三种原语怎么选
| 你需要什么 | 原语 | 要注意的区别 |
|---|---|---|
| 从既定集合里选一个 | Choice | 它的分布是拿来比较候选之间的 |
| 某个条件是否成立 | Noul | 只给「是」的概率,没有单独的 confidence;多个条件各问一次 |
| 沿某个维度打几分 | Score | 要排序就得保证各次 Score 可比 |
一条容易误解的:Noul 接近 0.5 表示「是/否概率相当」,不是「程度中等」。
另一条:低 confidence 不一定意味着答案没用 —— 几个都还行的选项会摊薄概率,但选哪个都无所谓时,低 confidence 完全无害。
另一条:低 confidence 不一定意味着答案没用 —— 几个都还行的选项会摊薄概率,但选哪个都无所谓时,低 confidence 完全无害。
六、实测:confidence 会漂
下面是用真实 API 跑出来的(每例 n=20,模型 jev-latest)。
choice 一次都没变,但 confidence 在动。
| 用例 | confidence 区间 | 极差 | choice 稳定 |
|---|---|---|---|
| 中等把握(4 选 1) | 0.580 – 0.730 | 0.150 | ✅ 20/20 |
| 较高把握(4 选 1) | 0.810 – 0.870 | 0.060 | ✅ 20/20 |
| 高把握(3 选 1) | 1.000 – 1.000 | 0.000 | ✅ 20/20 |
把握越"中等",抖得越厉害。高把握用例极差为 0,
中等把握用例极差 0.150 —— 是最宽的。
这意味着:你不能用「多问几次看答案是否一致」来判断模型有没有把握 —— 答案永远一致,不确定性只存在于分布里。
这意味着:你不能用「多问几次看答案是否一致」来判断模型有没有把握 —— 答案永远一致,不确定性只存在于分布里。
七、⚠️ 阈值漂移区
同一批 30 个真实样本,扫不同阈值时的通过率。看中间那段。
| 阈值 | 通过率 | 分布 | 稳定性 |
|---|
阈值 < 0.60 或 > 0.75 都很稳(全过 / 全不过)。
但落在 0.60–0.75 这段漂移区里,通过率会从 100% 一路崩到 0%。
所以正确做法不是"挑一个优雅的数",而是 —— 先测出你这个用例的漂移区,再把阈值放到漂移区外面。 哪怕 0.58 看起来不如 0.7 好看,它才真的可靠。
所以正确做法不是"挑一个优雅的数",而是 —— 先测出你这个用例的漂移区,再把阈值放到漂移区外面。 哪怕 0.58 看起来不如 0.7 好看,它才真的可靠。
八、删掉「都不匹配」出口,模型反而更自信
拿一段信息量极低的输入做对照(真实调用结果):
「关于那个,我觉得可能有点问题,你看怎么弄」
| 条件 | 选中 | confidence | 分布 |
|---|---|---|---|
候选含 unclear 出口 |
unclear | 0.92 | unclear 94% / complain 6% |
| 删掉出口,只剩 4 个具体诉求 | complain | 0.96 ↑ | complain 98% / ask_policy 2% |
把出口拿掉,模型不会"降低置信度表示为难" ——
它会基于剩下的选项给一个更集中的分布。
推论:置信度的高低,部分取决于你提供了哪些选项。 一个坏的问题设计,会让模型在错误答案上更自信。
推论:置信度的高低,部分取决于你提供了哪些选项。 一个坏的问题设计,会让模型在错误答案上更自信。