文档目录
置信度
TypeSafe 如何报告确定性、与概率的区别,以及如何用它来控制系统行为。
非官方中文翻译 · 内容以 英文原文 ↗ 为准 · 同步于 2026-10-15
TypeSafe 返回的所有 Score(打分题)和 Choice(选择题)答案都包含一个 probabilities 属性,表示跨选项(Choice)或档位(Score)的概率分布。该分布的形状能告诉你模型有多大把握:集中在某一个结果上表示答案有把握,分布均匀则表示答案不确定。
答案的 confidence 属性将该形状压缩为一个 0 到 1 之间的数字,让你无需自己计算就能基于 confidence 设置阈值。当所有概率都集中在一个结果上时它为 1,当概率均匀分布时它为 0。(Noul(是非题)答案不附带该属性,详见下文 Noul。)
置信度由概率派生
confidence 是一个由答案已给出的概率分布计算得到的统计量。TypeSafe 为你计算它,并在每个 Choice 和 Score 答案中返回,所以常见场景下你无需额外工作。
对于 Choice,分布就是跨选项的 probabilities。对于 Score,分布则是跨档位的 probabilities。两种情况下,分布越平坦,置信度越低:Choice 上的低置信度通常意味着没有任何一个选项明显胜出,而 Score 上的低置信度通常意味着档位本身模糊、涉及多个维度,或是 state(上下文状态)中包含的信息不足以作出判断。
每种题型对应的精确公式见 置信度是如何计算的,你可以从中看到任何 confidence 值是如何由答案自身的 probabilities 推导出来的。
"我不知道"是有用的信号
如果一个智能系统——无论人还是机器——无法诚实地表达不确定性,那么这个系统就无法被信任。
置信度为模型提供了一个内置的机制,让它可以说"我对此不太确定"。这让你的代码可以根据不同的确定程度实现不同的行为,这是构建真正可靠系统的基础。
在代码中使用置信度的三条路径
一个有用的起始模式是将置信度划分为三个区间,每个区间对应不同的系统行为:
高置信度: 自动执行。模型有明确的判断,无需人工参与即可继续。
中等置信度: 谨慎推进。模型给出的答案合理,但并不确定。根据上下文,你可以让用户确认、标记为待复核,或在执行前收集更多信息。
低置信度: 不执行。转人工、请求澄清,或回退到另一个系统。模型在告诉你它的信息不足,或这个问题并不适合由它回答。
这些边界的具体位置取决于风险大小。
阈值随风险而变化
置信度阈值不是一个数字。同一系统中的不同操作应根据出错的后果,在不同的置信度水平上进行门控。
response = client.system_one(
state=user_message,
questions={
"action": Choice(
instructions="What is the user trying to do?",
criteria={
"check_balance": "View account balance",
"approve_transfer": "Approve the pending withdrawal request",
"support": "Get help with an issue",
},
),
},
)
action = response.answers["action"]
confidence = action.confidence
if confidence < 0.5:
# Model is genuinely unsure. Don't guess.
route_to_human(user_message)
elif action.choice == "check_balance":
# Low stakes. Showing the wrong screen is recoverable.
show_balance(account_id)
elif action.choice == "approve_transfer":
if confidence > 0.9:
# High stakes, high confidence. Proceed with confirmation.
confirm_then_execute(account_id)
else:
# High stakes, moderate confidence. Verify first.
ask_user_to_confirm(account_id)0.5 这一置信度下限会拦截模型报告的所有真正不确定的情况。在此之上,对于破坏性操作,未经确认就执行的阈值要高于只读操作。你的代码承载着风险偏好。
置信度是如何计算的
每种题型对其概率分布的汇总方式略有不同。Noul 有两个结果,Choice 有任意数量的选项且无特定顺序,而 Score 的档位是有序的,因此下面的每个公式都建立在前一个公式的基础上。
TypeSafe 的 confidence 是汇总分布的一种合理方式,但不是唯一的方式。我们返回一个固定的度量,这样每个答案都会附带一个合理的默认值:你从第一次调用起就能基于 confidence 设置门控,所有题目使用同一个 0 到 1 的量表,而无需先自行选择并验证某个统计量。由于下面的公式都是精确的,并且每个答案都包含完整的 probabilities,你也可以改为计算对你应用而言最重要的度量。
Noul
Noul 答案是一个表示答案为 yes 的单一概率 $p$,TypeSafe 不为其返回单独的 confidence。概率本身已经承载了不确定性:接近 0.5 的值表示模型在说它不确定,Noul 页面介绍了如何直接基于它设置阈值。
如果你无论如何都想要一个置信度风格的数字(例如用同一段代码同时门控 Noul 和 Choice),可以使用与 0.5 的距离:
$$ \text{confidence} = |2p - 1| $$
在 $p = 0.5$ 时它为 0,在 $p = 0$ 或 $p = 1$ 时它为 1。它也是将下面的 Choice 公式应用到一个 yes/no Choice 上得到的,因此与 Choice 置信度处于同一量表。
Choice
Choice 将同样的思路推广到任意数量的选项。对于一个有 $n$ 个选项的 Choice,其中 $p_{\max}$ 是被选中的选项的概率:
$$ \text{confidence} = \frac{p_{\max} - \frac{1}{n}}{1 - \frac{1}{n}} $$
它衡量的是最高概率在均匀分布 $\frac{1}{n}$ 之上偏离了多少,其中均匀分布对应 0、确定对应 1。由于只有最高概率起作用,$(0.6, 0.3, 0.1)$ 和 $(0.6, 0.2, 0.2)$ 的置信度都是 0.4。
def choice_confidence(probabilities: list[float]) -> float:
n = len(probabilities)
return (max(probabilities) - 1 / n) / (1 - 1 / n)
choice_confidence(list(answer.probabilities.values()))本页开头的可视化工具 使用的是这个公式,并配有三个选项。
还有两种更简单的度量,它们同样从 probabilities 出发计算,在实践中往往非常有效,值得与 confidence 一起尝试:
- 最高概率,$p_{\max}$。它可以直接理解为"被选中的选项有多大的可能性",使阈值易于推理。其含义取决于选项的数量:在两个选项中 0.5 是个弱答案,而在十个选项中 0.5 是一个很强的答案,因此其阈值应按题目分别设置。
- 最高与次高之比,$p_{\max} / p_{\text{second}}$。它衡量的是被选中的选项领先次高选项多少,而忽略其余概率如何分布。许多实际决策归根结底取决于前两个候选选项,这个比值正好针对这种情况。
Score
Score 的档位是有序的,因此其公式还计算了概率距离最可能档位有多远。对于一个有 $n$ 个档位(编号为 $0$ 到 $n - 1$)的 Score,其中 $p_i$ 是档位 $i$ 的概率,$m$ 是最可能的档位:
$$ \text{confidence} = \max\left(0,\ 1 - \frac{\sum_i p_i , |i - m|}{\text{MAD}{\text{unif}}}\right) \qquad \text{MAD}{\text{unif}} = \frac{1}{n} \sum_i \left| i - \frac{n - 1}{2} \right| $$
分子中的求和是答案与最可能档位之间按概率加权的平均距离(以档位为单位)。$\text{MAD}_{\text{unif}}$ 是均匀分布到所有档位上时,按相同方式计算的、从中间档位出发的平均距离。置信度对两者进行比较,当答案的分布至少和均匀分布一样分散时,它会被截断到 0。
相邻档位上的概率对置信度的削减小于更远档位上相同概率的影响。在三个档位的情况下,$(0, 0.5, 0.5)$ 的置信度为 0.25,因为模型在两个相邻档位之间摇摆。$(0.5, 0, 0.5)$ 的置信度为 0,因为它在相对的两端之间摇摆。Choice 公式会给这两种分布都给出 0.25。
def score_confidence(probabilities: list[float]) -> float:
n = len(probabilities)
m = probabilities.index(max(probabilities))
spread = sum(p * abs(i - m) for i, p in enumerate(probabilities))
even_spread = sum(abs(i - (n - 1) / 2) for i in range(n)) / n
return max(0.0, 1 - spread / even_spread)
levels = sorted(answer.probabilities)
score_confidence([answer.probabilities[level] for level in levels])Score 响应示例 中的 bug_severity 答案具有概率 $(0, 0.57, 0.43)$。最可能的档位是 1,spread 为 $0.43$,三个档位对应的 $\text{MAD}_{\text{unif}}$ 为 $\frac{2}{3}$,因此置信度为 $1 - 0.43 / \frac{2}{3} \approx 0.35$。
本文档由 Mintlify 构建并托管。Mintlify 是一个开发者文档平台。