AI不确定性推理:让模型知道何时该说“不知道”

发布时间:2026/8/31 11:16:30
AI不确定性推理:让模型知道何时该说“不知道” 当模型答错的时候展示给用户的语调和它答对时往往一模一样。这是当前大量 AI 应用卡在“演示可行、生产不敢用”的根本原因模型只会输出一个结果很少输出这个结果的可信度。近期与 DeepMind 相关的技术讨论里有一个信号越来越清晰AI 下一阶段的能力分水岭也许不是生成文字更流畅、图片更像真人而是模型能不能“知道自己不知道”。这个方向在业界被称作不确定性推理uncertainty reasoning。它要回答的问题很朴素模型给出的答案到底有多可信这篇文章从一个普通开发者的视角拆解这个议题。我会先讲不确定性推理是什么、不确定性从哪来再讲工程上量化和表达不确定性的主流手段然后给出可以直接运行的回归预测区间、分类置信度校准代码最后聊一聊如何把它接到大模型和 Agent 应用里。读完你会明白让 AI 学会表达不确定不是让它变得“吞吞吐吐”而是给系统加一个真正的可靠性开关。1. 这篇文章真正要解决的问题如果你做过基于大模型的业务系统大概率经历过这种时刻模型一本正经地给出了一个错误答案而且配套的说明文字还很流畅。用户最终投诉客服团队复盘而技术团队把日志翻了个底朝天也找不到一个“模型自己也没把握”的信号。这个问题在 Agent 场景里会被放大。一个 Agent 往往要调用好几步工具、拼接多次生成结果只要其中一个环节判断错了后续所有步骤都在错误基础上继续。更麻烦的是如果每一步都以极其自信的姿态向后传递整个错误链路几乎不会被发现。很多人第一时间想到的解法是修改提示词让模型“如果拿不准就直说”。这种思路在演示里偶尔有效在生产环境却不稳定语言模型擅长模仿“表达不确定性”的措辞但这并不代表它的真实置信度真的降低了。换句话说让模型口头承认不确定和让它在概率层面表达不确定是两件完全不同的事。这篇文章要解决的问题就是帮你建立一套工程视角的不确定性处理能力。你会看到如何为一个普通分类或回归模型追加置信度估计如何用温度缩放把过热概率校准回来又如何把不确定性作为决策信号接进业务系统。适合的读者包括正在做大模型应用的开发同学、Agent 链路设计者以及任何对“AI 什么时候不该自动回答”这个问题头疼的工程师。2. AI 不确定性推理概念、来源与为什么重要2.1 一句话理解不确定性推理不确定性推理不是让模型变得优柔寡断而是让模型的每个输出都附带一个可以被统计验证的可信度估计。用一个天气预报的类比最容易讲明白。气象台说“明天降水概率 70%”单看某一天你可能觉得这个预测很含糊。但如果把一年里所有“70%”的预报日拉出来统计其中大约 70% 的日子确实下雨了我们就说这个预报系统是校准良好的。AI 的不确定性推理也想达到同样的效果模型说“这个分类有 90% 置信度”那么在大量同类样本上正确率应该真的在 90% 左右。这个视角和深度学习默认的训练目标有本质区别。传统分类模型输出 softmax 概率但 softmax 概率并不天然等于真实置信度它只是模型内部的相对得分。很多研究发现深度神经网络容易过度自信即使预测错了softmax 概率依然很高。不确定性推理要做的就是校正这种失真并进一步把不确定性拆分成可以解释的组成部分。2.2 不确定性从哪来三种主要来源在工程里讨论不确定性先要分清楚它来自哪里。通常可以分成三类偶然不确定性、认知不确定性和分布偏移。这里的常见误区是把它们混为一谈导致后续的排查方向完全错误。不确定性来源通俗解释典型例子偶然不确定性数据本身存在噪声同一个输入可能对应不同输出两张图片肉眼几乎一样但一张有猫一张没有认知不确定性模型掌握的样本不足以支撑判断属于“没见过”训练数据里根本没有这类样本模型在强行外推分布偏移训练时和部署时的数据分布不同训练集来自白天拍摄线上输入却大量来自夜间偶然不确定性通常无法通过加数据消除它是任务本身的难度的体现。认知不确定性则可以靠增加覆盖更全面的训练数据来降低。分布偏移最隐蔽它让模型在不该自信的场景里表现得很有把握也是生产事故的重要来源。2.3 为什么“知道自己在不知道”如此重要从 DeepMind 近年的技术分享和公开讨论来看团队对“模型应该知道自己不知道”的强调越来越明显。这背后其实有一整套技术逻辑强化学习需要探索与利用的权衡Agent 系统需要判断下一步该继续尝试还是退回去重新规划搜索类方法需要在分支之间计算可靠的概率估计。这些都绕不开不确定性推理。更贴近普通开发者的解释是AI 进入关键生产场景的门槛已经从“能不能答”变成了“答错了能不能被及时发现”。在低风险场景里模型偶尔犯错可以接受但在医疗辅助、金融审核、设备自动控制等场景中一个自信的错误可能导致很高的代价。不确定性推理的意义并不是让模型永远正确而是让系统在模型可能出错的时候有足够的信号触发人工接管或回退流程。需要补充一点不确定性推理并不是一个新词。在符号 AI 时代它指的是知识不完整条件下的推理方法比如概率推理、证据理论、模糊推理。现在大模型把这个话题重新推上了议题中心但今天的侧重点更偏向深度学习的概率表达和可靠决策讨论整个生命周期里如何处理不可靠的信息。2.4 小结不确定性推理的价值可以概括成一句话它把“模型的回答”从单一结论变成“结论 可信度 不确定来源”让下游系统有了做风险管理的能力。接下来要进入原理和方法部分。3. 从点到分布不确定性推理的核心原理3.1 点估计与分布输出传统深度学习模型的预测过程可以理解成 y f(x)输入一个 x输出一个 y。这个 y 是一个点不带任何概率信息。不确定性推理的第一步是把输出从“一个点”改成“一个分布”。以回归任务为例。确定性模型直接输出一个房价预测值而概率模型输出的是“预测均值为 200 万标准差为 30 万”。标准差就是不确定性信号预测可能是 170 万到 230 万之间的任意值。在分类任务里分布输出则是每个类别一个概率但关键不是看概率的绝对值而是看这个概率是否被校准过。贝叶斯定理是不确定性推理最核心的底层公式P(A|B) P(B|A) × P(A) / P(B)把它放到模型训练里A 是模型参数B 是观测数据。P(A) 是先验训练前我们对参数的假设P(B|A) 是似然当前参数下数据出现的概率P(A|B) 是后验看到数据之后我们对参数的信念。深度学习训练通常只能学到一组参数贝叶斯方法则试图估计整个参数分布所以它能表达“模型对参数有多确定”。3.2 从模型的不确定性到预测的不确定性工程上真正使用的往往是预测分布即给定输入 x输出 y 的完整分布 p(y|x)。预测分布同时包含了偶然不确定性和认知不确定性数据噪声越大分布越宽模型越没把握分布也会越宽。这里需要解释一下“不确定性估计”和“校准”的区别。不确定性估计关注分布的宽度校准关注分布是否准确。一个病弱的模型可能给出的区间非常宽把不确定性域覆盖住了但毫无决策价值另一个模型可能区间宽度刚好但置信水平完全错误。好的不确定性推理需要同时关注这两个维度。3.3 校准说 80% 就真的是 80%校准是判断概率质量最直接的指标。如果模型在一批样本上都输出“置信度 80%”且这批样本的实际正确率也是 80%那它就是校准良好的。常用评估指标包括 Expected Calibration ErrorECE和 Brier Score。实际观察时可以把样本按置信度分桶比如 0 到 0.1、0.1 到 0.2 这样分 10 个桶然后统计每个桶里的实际正确率。如果模型过度自信高置信度桶里的实际正确率会明显低于置信度如果模型过于保守则会出现反向偏差。这个可靠性图是排查模型置信度问题最直观的工具。3.4 不确定性如何影响业务决策不确定性信息进入业务决策时最常见的方式是设置阈值。置信度高于阈值就自动处理低于阈值就转人工或回退。它本质上改变了系统的错误模式从“自动答错”变成了“在不确定时保持沉默”。但阈值本身不是拍脑袋定的它取决于错误代价。比如自动审核漏过一个坏账的代价远高于把一个好客户转给人工的成本那么阈值就应该设置得偏高。不确定性推理的工程落地从来不是“把概率加进 API 返回”这么简单而是要围绕业务的错误代价设计决策规则。4. 工程上量化和表达不确定性的主流方法深度学习模型的不确定性估计并没有一个“唯一正确解法”。不同方法在效果、实现难度和推理成本之间各有取舍。下面介绍工程上最常见的五类方法。方法原理实现成本推理成本适用场景概率头输出网络直接输出概率分布参数低低回归、简单分类蒙特卡洛 Dropout推理时保留 Dropout多次前向取统计量低中已训练模型的改造深度集成训练多个模型统计预测差异高高高可靠性任务贝叶斯近似估计参数后验分布中高中高学术研究与高价值场景温度缩放对 softmax 做后处理校正极低无额外成本分类模型校准4.1 概率头输出概率头输出的思路很直接不直接回归一个数值而是让网络输出分布的参数。回归任务输出均值和方差分类任务输出每个类别的概率分布。这种方法实现简单缺点是它只能刻画偶然不确定性很难处理“没见过”导致的认知不确定性。4.2 蒙特卡洛 Dropout蒙特卡洛 Dropout 是一个巧妙的小技巧。标准 Dropout 在训练时随机丢弃神经元推理时关闭。MC Dropout 则在推理时也保留 Dropout并对同一个输入做多次前向得到一系列不同的预测结果。这些结果的离散程度就是不确定性信号如果多次预测高度一致说明模型对此很稳如果结果起伏很大说明模型对输入并不确定。它的优势是几乎不用改模型结构可以直接复用一个已经训练好的网络。4.3 深度集成深度集成是另一种被广泛验证的方法。用不同随机种子训练多个模型推理时让所有模型都做预测然后综合结果。模型之间分歧越大认知不确定性越高。它的效果通常优于 MC Dropout但训练和推理成本都成倍增长在线上实时预测场景里需要谨慎评估。4.4 贝叶斯近似贝叶斯近似方法试图估计模型参数的后验分布代表性方法包括变分推断、马尔可夫链蒙特卡洛等。它能提供理论上更完备的不确定性估计但实现复杂、计算成本高在大多数业务系统里并不实用。不过它是理解不确定性推理理论框架的必经之路。4.5 温度缩放温度缩放是一个比直觉更简单的后处理校准方法。它在 softmax 函数里引入一个温度参数 Tsoftmax(z / T)训练完成后在验证集上优化一个 T。当 T 1 时概率分布会变得更平缓相当于给模型“降温”抑制过度自信当 T 1 时分布更尖锐让原本模糊的预测变得更极端。这个方法不改变预测的类别排序只影响概率数值因此非常适合作为上线前的最后一道校准工序。5. 最小可运行示例回归任务预测区间理解原理之后我们用代码把不确定性推理跑通。第一个示例是回归任务训练一个输出均值和方差的小网络让模型不仅能给出预测值还能给出 95% 预测区间。5.1 环境准备示例使用 Python 和 PyTorch需要安装 torch 和 numpy。版本以你本机实际安装为准本文不限定具体版本号重点是跑通建模思路。pip install torch numpy准备一个uncertainty_regression.py文件输入下面的代码。5.2 构建带异方差噪声的数据集为了让预测区间更有展示效果我在正弦函数上叠加了随 x 变化的噪声右侧区域噪声更大形成异方差分布。这样训练好的模型会发现区间宽度在不同区域有不同的变化。# uncertainty_regression.py import torch import torch.nn as nn import numpy as np torch.manual_seed(0) # 生成带异方差噪声的正弦数据 n 2000 X torch.linspace(-3, 3, n).reshape(-1, 1) y torch.sin(X) 0.2 * torch.randn_like(X) # 在 x 1 的区域额外增加噪声 mask X 1.0 y y 0.4 * mask.float() * torch.randn_like(X)5.3 定义输出均值和方差的小网络网络结构是两个隐藏层的 MLP输出头分为两个分支mean_head 输出预测均值logvar_head 输出对数方差。使用对数方差而不是直接输出方差是为了避免训练过程中出现负方差。class MeanVarNet(nn.Module): def __init__(self): super().__init__() self.fc1 nn.Linear(1, 64) self.fc2 nn.Linear(64, 64) self.mean_head nn.Linear(64, 1) self.logvar_head nn.Linear(64, 1) def forward(self, x): h torch.relu(self.fc1(x)) h torch.relu(self.fc2(h)) mu self.mean_head(h) log_var self.logvar_head(h) return mu, log_var5.4 使用负对数似然作为损失函数高斯负对数似然损失的形式是 log sigma 加上平方误差与方差的比值。这个损失函数会让模型在误差大的区域自动调大方差从而在拟合均值的同时学会表达不确定性。def nll_loss(mu, log_var, y): # 使用 exp 恢复方差加一个极小值防止除零 var torch.exp(log_var) 1e-6 return torch.mean(log_var (y - mu) ** 2 / (2 * var)) model MeanVarNet() optimizer torch.optim.Adam(model.parameters(), lr1e-2) for step in range(3000): optimizer.zero_grad() mu, log_var model(X) loss nll_loss(mu, log_var, y) loss.backward() optimizer.step() if step % 500 0: print(fstep {step}, loss {loss.item():.4f})5.5 推理并输出预测区间训练完成后模型对每个输入 x 都能输出一个均值 mu 和一个标准差 sigma。按照正态分布的近似95% 预测区间大约是 mu ± 1.96 * sigma。# 推理并输出预测区间 with torch.no_grad(): mu, log_var model(X) sigma torch.exp(log_var * 0.5).squeeze().numpy() mu mu.squeeze().numpy() x_np X.squeeze().numpy() sort_idx np.argsort(x_np) lower mu - 1.96 * sigma upper mu 1.96 * sigma print(\n抽样输出预测区间) for i in sort_idx[::400]: print(fx{x_np[i]:.2f}, mean{mu[i]:.2f}, 95% interval[{lower[i]:.2f}, {upper[i]:.2f}])5.6 运行结果与验证方式在命令行执行python uncertainty_regression.py预期会看到 loss 逐步下降最后输出类似下面这样格式的结果x-3.00, mean-0.14, 95% interval[-0.53, 0.25] x-1.51, mean-1.00, 95% interval[-1.40, -0.60] x1.51, mean1.00, 95% interval[0.50, 1.51]注意 x 越大越接近右侧噪声区域区间宽度会明显变大。如果 interval 宽度在所有位置都一样说明模型没有真正学会异方差建模可以检查学习率是否合适或者把训练步数增加到 6000。6. 分类任务中的置信度与校准实战第二个示例更贴近业务训练一个三分类模型检验 softmax 概率是否过度自信并用温度缩放修正。6.1 生成三分类数据并训练模型用 make_blobs 生成三个簇数据重叠度较高让模型天然存在不确定性。这里用两个隐藏层的 MLP 训练分类器。# calibration_demo.py import torch import torch.nn as nn import numpy as np from sklearn.datasets import make_blobs from sklearn.model_selection import train_test_split # 生成三分类合成数据 X, y make_blobs(n_samples3000, centers3, cluster_std2.5, random_state42) X_train, X_val, y_train, y_val train_test_split(X, y, test_size0.3, random_state42) X_train torch.tensor(X_train, dtypetorch.float32) y_train torch.tensor(y_train, dtypetorch.long) X_val torch.tensor(X_val, dtypetorch.float32) y_val torch.tensor(y_val, dtypetorch.long) class Net(nn.Module): def __init__(self, in_dim2, out_dim3): super().__init__() self.net nn.Sequential( nn.Linear(in_dim, 32), nn.ReLU(), nn.Linear(32, 32), nn.ReLU(), nn.Linear(32, out_dim) ) def forward(self, x): return self.net(x) model Net() opt torch.optim.Adam(model.parameters(), lr1e-2) loss_fn nn.CrossEntropyLoss() for step in range(2000): opt.zero_grad() logits model(X_train) loss loss_fn(logits, y_train) loss.backward() opt.step() with torch.no_grad(): val_logits model(X_val) val_preds val_logits.argmax(dim1).numpy() val_labels y_val.numpy() print(accuracy:, (val_preds val_labels).mean())6.2 实现温度缩放校准先实现 ECE 计算函数和温度缩放函数。温度缩放的核心是在验证集上优化一个温度参数 T让校准后的负对数似然最低。from scipy.optimize import minimize def ece(logits, labels, n_bins10): probs torch.softmax(logits, dim1).numpy() conf probs.max(axis1) pred probs.argmax(axis1) acc (pred labels).astype(np.float64) bin_boundaries np.linspace(0, 1, n_bins 1) ece 0.0 for i in range(n_bins): mask (conf bin_boundaries[i]) (conf bin_boundaries[i 1]) if mask.sum() 0: continue bin_acc acc[mask].mean() bin_conf conf[mask].mean() ece (mask.sum() / len(conf)) * abs(bin_acc - bin_conf) return ece def temperature_scaling(logits, labels): logits logits.numpy() labels labels.numpy() def nll(t): logits_t logits / t max_logit logits_t.max(axis1, keepdimsTrue) softmax np.exp(logits_t - max_logit) softmax / softmax.sum(axis1, keepdimsTrue) prob softmax[np.arange(len(labels)), labels] return -np.mean(np.log(prob 1e-12)) res minimize(nll, x01.0, bounds[(0.05, 10.0)], methodL-BFGS-B) return res.x[0]6.3 计算校准前后的 ECE把验证集 logits 传入温度缩放得到最优 T然后分别计算校准前后的 ECE。t temperature_scaling(val_logits, y_val) with torch.no_grad(): calibrated_logits val_logits / t print(temperature:, round(t, 4)) print(ECE before:, round(ece(val_logits, y_val), 4)) print(ECE after:, round(ece(calibrated_logits, y_val), 4))运行python calibration_demo.py这里的关键判断是看温度 T 是否明显大于 1。如果 T 1说明模型校准前过度自信softmax 概率整体偏高T 1 则说明模型过于保守。ECE 数值越低说明概率越接近真实正确率。这个示例改造成本极低只需拿验证集计算一个 T上线时把 logits 除以 T 再走 softmax 即可。对于大多数分类模型这通常是收益最明显、成本最低的不确定性校准手段。7. 如何把不确定性接入大模型与 Agent 应用7.1 为什么不能直接相信大模型说“我不确定”在大模型应用里最简单也最无效的做法是让模型在回答里写一句“我有 90% 把握”。这不是不确定性推理而是“口头置信度”。语言模型被训练成最像人类、最有说服力的助手它非常擅长模仿“表达不确定”的语言风格。但研究表明口头置信度和回答的正确率之间相关性很弱。真正可靠的不确定性信号往往来自模型内部比如 logits 的熵、embedding 与训练数据的距离、多次采样答案的一致性或者一个独立训练的判断模型。7.2 落地方式一检索环节的不确定性触发如果你做一个基于 RAG 的问答系统一个重要信号是 query 与检索到文档的相似度。当用户问题明显偏离知识库覆盖范围时最相似的文档分往往也很低。此时即使大模型能根据检索片段拼出一个流畅的回答这个答案的可靠性也是非常低的。更稳妥的做法是设置一个文档相似度阈值低于阈值时不直接回答而是返回“这个问题需要更专业的资料”或转人工。这个机制把不确定性拦截在了生成之前比事后检测省力得多。7.3 落地方式二答案一致性自检另一个实用手段是多次采样一致性判断。让模型对同一个问题生成 3 到 5 次答案然后比较这些答案是否一致。如果每次回答的核心结论都不同说明模型在这个问题上没有稳定的判断。这里的实现不复杂同一个 prompt 多次调用取回答的语义相似度或关键实体是否一致作为置信度信号。它比 prompt 里的“我很有把握”可信得多但要注意调用成本会成倍增加适合用在需要高可靠性判断的场景。7.4 落地方式三决策层的阈值门控不确定性推理的最终出口通常是一个决策函数。下面是一个最小示例把置信度和业务动作分开class GateDecision: def __init__(self, confidence_threshold0.75): self.threshold confidence_threshold def decide(self, answer, confidence): if confidence self.threshold: return { action: human_handoff, message: 自动回答置信度不足请人工介入, answer: answer, confidence: confidence, } return { action: auto_reply, answer: answer, confidence: confidence, } gate GateDecision(confidence_threshold0.75) result gate.decide(建议按时还款, 0.62) print(result)这段代码的意义不在于实现复杂逻辑而在于把“模型生成”和“业务决策”解耦。上游模型判断每没把握不重要重要的是下游系统拿到置信度后能做出统一的、可审计的决策。生产环境里这个函数可以替换成更复杂的策略引擎例如根据用户等级动态调整阈值、根据业务线区分拒绝策略等。8. 常见问题与排查思路工程里引入不确定性推理后最容易遇到的问题往往不在模型本身而在数据、校准和决策链路。下面列出几类高频问题。问题现象可能原因排查方式解决方案softmax 概率普遍接近 1模型过拟合或数据太容易区分画可靠性图计算 ECE温度缩放、标签平滑、增加正则温度缩放后 ECE 依然很高校准集和线上数据分布不一致对比验证集与线上特征分布用更贴近线上分布的数据重新校准预测区间过宽没有决策价值模型未收敛或噪声建模不当检查损失曲线和残差分布调整模型结构、增加训练步数蒙特卡洛 Dropout 推理慢需要多次前向传播统计单次请求耗时限制采样次数或用轻量集成替代大模型口头置信度与准确率无关语言模型学会了模仿表达风格的自信统计分析自报置信度与真实准确率改用内部信号或多次采样一致性模型对没见过的问题依然给出高置信度认知不确定性没有被建模检查向量检索相似度增加检索阈值设置拒绝策略排查的第一原则是先确认不确定性来自哪一层。是模型层还是数据层是训练阶段还是后处理阶段。不要一上来就换更复杂的模型先看校准集的数据分布是否已经偏离线上。9. 最佳实践与工程建议把不确定性推理接入真实系统有几条经验值得沉淀下来。9.1 先分场景再选方法不是所有业务都需要完整的贝叶斯建模。如果只是做一个知识库问答机器人检索相似度加答案一致性检查通常就够用。如果是风险敏感业务比如金融审核、医疗建议才需要投入训练多模型集成或使用更严格的校准流程。方法的复杂度和业务风险应该匹配。9.2 校准是一次性的也是持续的线上数据分布会随时间漂移模型也会被重新训练。校准参数不是上线之后就不用管了。更合理的做法是把校准和模型监控放在一起定期用新的验证集计算 ECE如果校准质量明显下滑就要触发重新校准或告警。9.3 不只盯 ECE还要盯业务代价ECE 是技术指标业务方真正关心的是漏报和误报带来的实际损失。一个模型即使在统计上校准良好它所对应的业务代价也可能不可接受。因此在调阈值时不能只看置信度分布还要模拟不同阈值下的收益和成本选择一个业务最优的决策边界。9.4 日志里记录置信度上线后一定要在日志里记录每次自动回答的置信度、阈值是否命中、最终动作是什么。否则当你需要复盘一次线上事故时会发现根本没有数据能说明“为什么这次模型如此自信”。把不确定性信号纳入日志体系是 AI 系统可审计的基础。9.5 从最小闭环开始灰度不要一开始就把所有流量切到自动决策。可以先挑选一个低风险技能或 API加上置信度阈值和人工兜底观察一段时间。确认不确定性信号稳定后再逐步放大自动处理比例。灰度期间要保留一键回滚机制保证模型判断失误时可以快速撤回。总结与后续学习方向DeepMind 对不确定性推理的关注本质上反映了 AI 行业从“追求生成能力”到“追求可靠能力”的转变。对一个普通开发者而言不需要立刻上手复杂的贝叶斯深度学习可以先从两个地方开始第一为现有分类模型加温度缩放看看 ECE 是否下降第二在 Agent 链路里加一个置信度门控让低置信度请求走人工。这两个改动都很小但效果立竿见影它们让系统第一次拥有了“承认自己没把握”的能力。之后如果想深入可以继续学习贝叶斯深度学习、MC Dropout 的变体、深度集成在实践中的优化以及强化学习中的不确定性估计。最后想给一个提醒不确定性推理不是让模型变得更谦虚而是让系统在模型犯错之前有机会停下来。你不需要让 AI 完美无缺但当你为它加上可靠的不确定性判断时它才真正从演示工具变成了值得信赖的生产系统。