1. 那个让我彻底不信任模型输出概率的下午
先说一个我亲身经历的场景。去年做一套面向医疗问诊场景的辅助决策系统,模型对每个候选诊断给出一个"置信度"分数,前端按这个分数排序展示。上线第一周就出问题了:一个明显是普通上呼吸道感染的病例,模型给"急性心肌梗死"打了 0.91 的置信度,而给"上呼吸道感染"只有 0.34。医生看到这个排序直接懵了,我也懵了。
后来我把这批 case 拉出来单独分析,发现一个反直觉的事实:大语言模型输出的那个"概率",绝大多数情况下根本不是概率。它是 token 级别的生成倾向,是 softmax 之后的一个相对数值,跟"这件事为真的可能性"之间隔着一整个语义鸿沟。你拿它当置信度用,等于拿体温计去量血压——读数是有,但量的不是那回事。
这篇文章我想聊的就是这件事:为什么 LLM 的置信度在系统性地骗你,以及我后来落地的一套33ms 校准概率引擎是怎么把这个坑填上的。核心思路围绕RLCD(Reinforcement Learning from Calibration Data,基于校准数据的强化学习)展开,配合Agent场景下的实时决策需求。适合正在做 Agent 开发、LLM 应用落地、需要模型输出"可信数值"的工程师和产品同学。如果你只是拿模型聊天,这篇可能用不上;但只要你把模型输出接进了任何需要排序、阈值判断、风险分级的链路,那这些内容迟早会找上你。
2. LLM 置信度失真的三层根因
2.1 第一层:softmax 概率的语义错位
模型在生成每个 token 时,输出的是一个词表上的概率分布。比如生成"是"这个字时概率 0.8,生成"否"时概率 0.15。很多人直接把 0.8 当成"模型认为答案是'是'的概率是 80%"。这个推理链条在第一步就断了。
原因在于,这个 0.8 描述的是在当前上下文下,下一个 token 是'是'的生成倾向,而不是命题为真的后验概率。这两者的区别,类似于"我倾向于说'明天会下雨'"和"明天下雨的概率是 80%"——前者是语言习惯,后者是事实判断。模型在预训练阶段学的是"人类会怎么说",不是"世界实际是怎样的"。
更麻烦的是,这个数值对 prompt 极度敏感。同一道题,你把选项顺序换一下,或者加一句"请仔细思考",输出的概率分布可能天翻地覆。我实测过一个二分类任务,正序 prompt 下模型给"是"0.72,把选项对调后给"是"0.41。命题没变,概率变了 30 个点。这种数值你拿去接业务逻辑,不出事才怪。
2.2 第二层:RLHF 把概率分布"压平"了
经过 RLHF 对齐之后的模型,概率分布会变得更"自信"也更"扁平"。所谓自信,是模型倾向于给出高置信度的表述;所谓扁平,是不同难度的问题,输出的概率数值区间被压缩到了一个很窄的范围里。
我做过一组统计,拿 500 道难度梯度明显的题目喂给同一个模型,让它输出置信度。结果发现:简单题平均置信度 0.87,难题平均置信度 0.79。差距只有 8 个点。但实际准确率呢?简单题 94%,难题 51%。准确率差了 43 个点,置信度只差了 8 个点。这就是典型的校准失效——模型根本不知道自己在哪些题上会翻车。
这个现象的根源在于 RLHF 的奖励信号。人类标注员偏好"看起来确定"的回答,于是模型学会了在所有情况下都表现得比较确定。久而久之,置信度这个维度上的信息量就被磨掉了。
2.3 第三层:Agent 链路把误差层层放大
单轮问答里,置信度失真顶多让你排序难看。但在 Agent 场景下,这个问题会被指数级放大。
想象一个典型的 Agent 决策链:模型先判断"用户意图是什么"(置信度 0.8),再决定"调用哪个工具"(置信度 0.75),然后"工具返回结果是否可信"(置信度 0.7),最后"是否要执行写操作"(置信度 0.85)。如果每一环的置信度都是失真的,那么整条链路的可靠性就是 0.8 × 0.75 × 0.7 × 0.85 ≈ 0.36。你以为在做高置信度决策,实际上是在掷骰子。
我在一个自动化运维 Agent 项目里踩过这个坑。模型判断"这个告警是误报"的置信度 0.9,Agent 就自动关闭了告警。结果那是个真实故障,只是日志格式比较特殊。事后复盘发现,模型在类似格式的日志上历史准确率只有 60% 左右,但它给出的置信度稳定在 0.85 以上。置信度和实际准确率之间,完全没有相关性。
3. 校准概率引擎要解决的到底是什么问题
3.1 从"生成倾向"到"事实概率"的映射
校准概率引擎的核心任务,是建立一个映射函数 f,把模型原始的 token 概率 p_raw 映射到校准后的概率 p_cal,使得 p_cal 尽可能接近真实的后验概率 P(正确 | 输入)。
这个映射不是简单的线性缩放。因为失真是非线性的——在低置信度区间,模型往往高估;在高置信度区间,模型又往往低估(尤其是难题)。所以需要的是一个分段、非单调的校准曲线。
数学上,这属于概率校准(Probability Calibration)问题。经典方法有 Platt Scaling、Isotonic Regression、Temperature Scaling 等。但这些方法都是为传统分类器设计的,直接套到 LLM 上效果很差,原因有两个:一是 LLM 的输出空间是开放的文本,不是固定类别;二是 LLM 的失真模式跟传统分类器完全不同,它带有强烈的语义和上下文依赖。
3.2 为什么是 33ms 这个量级
33ms 这个数字不是拍脑袋定的。它来自 Agent 实时决策的硬约束。
在一个交互式 Agent 里,用户能感知到的延迟阈值大约是 100ms。这 100ms 要分给网络传输、工具调用、结果渲染等环节,留给校准计算的时间窗口大概就是 30-40ms。超过这个数,用户就会觉得"卡"。
33ms 意味着校准引擎必须做到:单次推理在 30ms 内完成,且不能依赖大模型的二次调用(那至少几百毫秒起步)。这就排除了"让模型自己再评估一遍"这类方案,必须走轻量级的独立校准模型路线。
我最终选的是一个参数量在百万级的小型校准网络,输入是模型原始输出的若干特征(token 概率、熵、top-k 分布、上下文长度等),输出是校准后的概率。在单张消费级显卡上,单次推理稳定在 28-33ms。这个量级刚好卡在 Agent 可接受的边界内。
3.3 RLCD 在其中的角色
RLCD 是这套引擎的训练范式。传统校准方法用的是静态数据集上的拟合,但 LLM 的失真模式会随着模型版本、prompt 风格、任务类型漂移。静态拟合出来的校准曲线,换个场景就失效。
RLCD 的思路是:把校准本身当成一个强化学习问题。校准网络是策略,校准后的概率与真实结果的偏差是奖励信号,通过持续的环境反馈来动态调整校准策略。这样校准引擎就能跟着模型和任务一起演化,而不是训练完就固化。
具体来说,奖励函数设计成负的 Brier Score(一种衡量概率预测准确度的指标),同时加入一个"过度自信惩罚项",专门压制那些高置信度但实际错误的情况。这个惩罚项很关键,因为 Agent 场景下,高置信度的错误比低置信度的错误危害大得多。
4. 校准引擎的工程实现拆解
4.1 特征工程:从原始输出里榨取信号
校准网络的输入特征设计,直接决定了校准效果的上限。我试过很多组合,最终稳定下来的是这几类:
| 特征类别 | 具体特征 | 作用 |
|---|---|---|
| 概率分布特征 | top-1 概率、top-2 概率、概率熵 | 捕捉模型的即时确定性 |
| 分布形状特征 | top-10 概率方差、长尾占比 | 区分"真确定"和"假确定" |
| 上下文特征 | 输入长度、任务类型 embedding | 建模场景依赖的失真 |
| 历史特征 | 同类任务历史准确率 | 引入外部校准信号 |
| 一致性特征 | 多次采样的答案一致率 | 用采样方差估计真实不确定性 |
其中一致性特征是我觉得最有价值的。做法很简单:对同一个输入,让模型用不同温度采样 5 次,看答案是否一致。如果 5 次答案都一样,说明模型内部对这个判断比较稳定;如果 5 次答案五花八门,那不管单次输出的概率多高,真实置信度都应该打折。
这个特征的计算成本是 5 次前向传播,但可以并行,实际增加的延迟在 10ms 以内。加上它之后,校准引擎在难题上的表现提升了将近 20 个百分点。
4.2 校准网络的架构选择
校准网络本身不需要很复杂。我试过从线性回归到 4 层 MLP 的各种规模,结论是:2 层 MLP + 残差连接是性价比最高的选择。
再深的网络会过拟合,因为校准任务的训练数据量通常不大(几千到几万条),而且特征维度不高(20-30 维)。再浅的网络(比如纯线性)又拟合不了非线性的校准曲线。
残差连接的作用是保留原始概率的信息。校准网络学的是"修正量",而不是"重新预测"。这样即使校准网络在某些样本上失效,输出也不会偏离原始概率太远,有个兜底。
激活函数用 GELU 而不是 ReLU,因为校准曲线在 0 附近需要平滑过渡,ReLU 的硬截断会导致校准后的概率在阈值附近抖动。
4.3 训练数据的构造:这是最脏最累的活
校准引擎的效果,七分靠数据,三分靠模型。训练数据的构造有几个关键点:
第一,必须覆盖真实分布。很多人图省事,用公开数据集训练校准网络,结果上线就崩。因为公开数据集的难度分布、任务类型、prompt 风格,跟你线上场景差太远。我的做法是从线上日志里采样,按任务类型分层,保证每个类型都有足够样本。
第二,标签必须是真实结果,不是模型自评。这是最容易犯的错。有人拿模型自己判断的"对错"当标签,那等于用失真的信号去校准失真,越校越歪。标签必须来自外部验证——人工标注、工具返回、用户反馈,总之得是模型之外的信息源。
第三,要包含"模型高置信度但错误"的负样本。这类样本是校准的关键,但自然分布下很少。我的做法是主动构造:用对抗性 prompt 诱导模型在难题上给出高置信度错误,然后把这些样本加权进训练集。加权系数我设的是 3.0,实测下来这个比例比较平衡。
第四,数据要持续更新。模型版本一换,失真模式就变。我设了个机制,每周从线上采样一批新数据,增量训练校准网络。这样校准引擎能跟上模型演化的节奏。
5. 在 Agent 链路里落地校准引擎的实操细节
5.1 校准点的选择:不是每个环节都要校准
Agent 链路里有很多地方会用到置信度,但不是每个点都值得接校准引擎。校准本身有成本(33ms + 计算资源),要用在刀刃上。
我的经验是,只在决策分叉点接校准。所谓决策分叉点,就是"根据置信度走不同分支"的地方。比如:置信度 > 0.9 自动执行,0.7-0.9 人工确认,< 0.7 拒绝。这种点上,置信度的准确性直接决定行为,必须校准。
而那些只是用来排序、展示、日志记录的地方,原始置信度够用了,没必要增加延迟。我见过有人给每个环节都接校准,结果整体延迟翻了三倍,收益却很小。
5.2 阈值设定:用校准后的概率反推
校准引擎上线后,阈值设定就有了依据。做法是:拿一批标注数据跑校准,画出校准后的概率 vs 实际准确率的曲线,然后根据业务能接受的风险水平反推阈值。
举个例子,如果业务要求"自动执行的操作,错误率不超过 2%",那就找校准曲线上准确率 98% 对应的概率值,假设是 0.93,那阈值就设 0.93。这个阈值是数据驱动的,比拍脑袋定 0.9 靠谱得多。
这里有个坑要注意:校准曲线是分任务类型的。同一个概率值,在简单任务上可能对应 95% 准确率,在难题上只有 70%。所以阈值也要分类型设定,不能一刀切。我在项目里维护了一张阈值表,按任务类型索引,Agent 决策时先查表再判断。
5.3 与 Agent 记忆系统的协同
校准引擎的输出,除了用于即时决策,还应该写进 Agent 的记忆系统。这样 Agent 在后续决策时,可以参考"历史上类似情况下,我的校准置信度是多少,实际结果如何"。
具体做法是:每次校准后,把 (输入特征, 校准概率, 实际结果) 三元组存进记忆库。下次遇到相似输入时,先检索历史记录,如果历史准确率和当前校准概率偏差较大,就触发告警或降级处理。
这个机制帮我抓到过好几次模型漂移。有一次模型静默更新了版本,校准引擎还没跟上,但记忆系统发现"最近 100 次校准概率 0.9 的决策,实际准确率只有 0.75",直接触发了告警。我们及时回滚了模型版本,避免了一次线上事故。
5.4 性能优化的几个实操技巧
33ms 的预算很紧,优化要抠到每一毫秒。分享几个我实测有效的技巧:
- 特征计算并行化:一致性特征需要多次采样,用 batch 推理而不是循环,能省 60% 的时间。
- 校准网络量化:把 FP32 量化到 INT8,推理速度提升约 2 倍,精度损失不到 0.5 个点。
- 结果缓存:相同输入特征的校准结果缓存起来,命中率在重复场景下能到 30% 以上。
- 预热:校准网络在首次推理时会有冷启动开销,服务启动时先跑几十次空推理预热,避免第一个请求超时。
这些优化叠加下来,我把 P99 延迟从最初的 80ms 压到了 33ms 以内。
6. 那些让我半夜爬起来改代码的坑
6.1 校准引擎自己也会漂移
这是最隐蔽的坑。校准引擎是基于历史数据训练的,但线上数据分布会变。如果校准引擎不更新,它自己就会变成新的失真源。
我遇到过一次:业务方调整了 prompt 模板,模型输出风格变了,但校准引擎还是按老数据训练的。结果校准后的概率比原始概率还离谱。排查了两天才定位到是 prompt 变更导致的分布漂移。
解决方案是加一个漂移检测模块,持续监控校准后的概率分布和实际准确率的偏差。偏差超过阈值就触发重新训练。这个模块现在是标配,每次上线新 prompt 或新模型版本,都会先跑一遍漂移检测。
6.2 别用校准概率做绝对判断
校准后的概率更准了,但它依然是概率,不是确定性。我见过有人把校准概率 0.99 当成"一定对",直接跳过所有校验。这是危险的。
概率 0.99 意味着 100 次里有 1 次错。如果这个决策是"删除生产数据库",那 1% 的错误率是不可接受的。所以校准概率要配合风险等级使用:高风险操作,即使校准概率 0.99 也要二次确认;低风险操作,0.8 就可以自动执行。
我在项目里定义了一张风险矩阵,横轴是校准概率,纵轴是操作风险等级,交叉点决定执行策略。这个矩阵是业务、风控、技术三方一起定的,不是技术单方面拍板。
6.3 采样一致性的成本陷阱
前面说一致性特征很有用,但它有个成本陷阱:采样次数越多,特征越准,但延迟越高。5 次采样是甜点,10 次采样的收益递减明显,延迟却翻倍。
而且采样本身会引入随机性。如果采样温度设得不好,一致性特征反而会误导。我的经验是温度设 0.7 左右,既能捕捉不确定性,又不会太随机。温度太高(比如 1.0),模型在简单题上也会给出不一致的答案,特征就失去区分度了。
6.4 校准数据的标注成本
真实标签的获取是有成本的。人工标注贵,工具验证覆盖不全,用户反馈稀疏。我试过几种降低成本的方案:
- 主动学习:只标注那些校准引擎最不确定的样本,标注效率提升 3-5 倍。
- 弱监督:用多个弱信号(工具返回、规则校验、历史一致性)投票生成标签,准确率能到 85% 左右,作为预训练数据够用。
- 用户隐式反馈:用户采纳/修改/拒绝 Agent 建议的行为,本身就是标签。这个信号免费且量大,但要处理噪声。
组合使用下来,标注成本降了大概 70%,校准效果只损失了 3-4 个点。
7. 校准引擎在非 Agent 场景的延展用法
7.1 内容审核的风险分级
内容审核场景下,模型需要判断"这条内容违规的概率"。原始置信度不可靠,会导致大量误杀或漏放。接校准引擎后,可以按校准概率做分级:高概率直接拦截,中概率人工复审,低概率放行。实测误杀率下降了 40% 左右。
7.2 RAG 检索结果的可信度排序
RAG 场景里,检索回来的文档质量参差不齐。模型基于这些文档生成的答案,可信度也参差。校准引擎可以对每个答案给出校准后的可信度,用于排序或过滤。这比单纯用检索相似度排序靠谱得多,因为相似度高不代表答案对。
7.3 结构化抽取的字段级置信度
从文档里抽取结构化字段时,每个字段都可以有一个校准置信度。低置信度字段触发人工校验,高置信度字段直接入库。这个用法在票据识别、合同解析等场景很实用,能把人工校验量压到 20% 以下。
8. 我在这套方案上的一些个人体会
做校准这件事,最大的心得是:不要相信任何未经校准的模型输出数值。不管是置信度、相似度、还是各种 score,只要它要参与业务决策,就必须经过校准验证。我现在的习惯是,任何模型输出的数值,上线前先跑一遍校准分析,看它和真实结果的相关性。相关性低于 0.5 的,一律不接业务逻辑。
另一个体会是,校准不是一次性工程,是持续运营。模型在变,数据在变,业务在变,校准引擎也得跟着变。我现在的团队里,校准引擎的维护是常态化工作,每周有固定的数据采样和增量训练流程。把它当成一个活系统来养,而不是一个交付完就完事的模块。
最后分享一个判断校准是否必要的小技巧:拿一批标注数据,把模型置信度分成 10 个桶,看每个桶里的实际准确率。如果准确率随置信度单调上升,且差距明显,那校准收益有限;如果准确率在各桶之间乱跳,或者高置信度桶的准确率反而不高,那校准就是刚需。这个分析半小时就能做完,能帮你快速判断要不要投入做校准引擎。
这套 33ms 校准概率引擎现在跑在我负责的几个 Agent 项目里,累计处理了上千万次决策。它没有让模型变聪明,但让模型的"自我认知"变准了。在 Agent 越来越深入业务流程的今天,我觉得这比单纯提升模型能力更重要——一个知道自己哪里不确定的 Agent,比一个盲目自信的 Agent,可靠得多。