起因#
之前写 Next-Token Prediction的时候,我把条件概率链式分解、Softmax 输出概率分布这些东西理了一遍。当时觉得逻辑非常自洽:模型在每个位置输出整个词表上的概率分布,概率最高的那个 token 就是模型最有信心的预测。
顺着这个想法,我产生了一个看起来很自然的推论:
如果模型对某个答案给出了 99% 的概率,那是不是意味着这个答案有 99% 的可能性符合事实?
这个推论在直觉上很有说服力。毕竟概率都 99% 了。但继续看 MIT 6.S191 Lecture 6(New Frontiers)关于 LLM Limitations 的部分时,我发现这个推论混淆了两个完全不同的东西。
这篇笔记就是从这个混淆开始,把我在学习过程中遇到的几个问题理清楚。
Token 概率高,不等于事实正确#
先回到 NTP 的基本设定。语言模型在每个时间步输出的是:
$$ P_\theta(x_{t+1} \mid x_1, \ldots, x_t) $$这个概率分布是模型参数 \(\theta\) 在给定 context 下,对词表中每个 token 出现可能性的估计。NTP 那篇已经推导过这个条件概率的来源和训练目标,这里不重复。
我需要搞清楚的是:这个概率到底在说什么?
仔细想,这里其实有三个层次的"概率",它们看起来相关,但含义完全不同:
- Token 条件概率:给定上文,某个 token 在下一个位置出现的模型概率。
- 序列生成概率:一整段文本被模型生成出来的联合概率——各个 token 条件概率的连乘。
- 事实正确概率:这段文本所表达的事实陈述,在真实世界中为真的概率。
第一个和第二个之间有明确的数学关系(概率链式法则)。但第二个和第三个之间没有这种关系。
为什么?
模型的参数 \(\theta\) 是通过在训练文本上最小化 cross entropy loss 学出来的。它学到的是训练数据中的统计规律:在什么样的 context 之后,什么样的 token 更可能出现。
这里有一个很容易忽略的前提:训练数据本身不一定全是正确的事实。
构造一个极端但有说明意义的例子(以下是为了解释概念虚构的场景,不是真实数据):假设互联网上有大量网页错误地记载"某国首都是 B 城",但事实上首都是 C 城。模型在这些文本上训练之后,看到"某国的首都是"这个 context,很可能给 B 赋予远高于 C 的概率。
这不是模型的 Bug。从优化目标来看,模型忠实地学到了训练数据中的统计分布——这正是 cross entropy loss 鼓励它做的事。但统计分布和事实真值是两回事。
即使退一步,假设训练数据中的每一条事实都是正确的,问题也不会消失。自回归生成是逐 token 进行的。每一步都是条件概率最大化,但连续多步高概率的 token 组合在一起,最终形成的完整陈述未必对应一个真实的事实。模型可能把"作者 A 发表过关于 X 主题的论文"和"Y 会议发表过关于 X 主题的论文"这两条各自正确的信息,拼接成"作者 A 在 Y 会议上发表了关于 X 主题的论文"——一个不存在的事实。
不过我想在这里加一个澄清,因为"LLM 只是在预测下一个 token"这句话经常被用来得出一个过于强烈的结论。
“预测下一个 token"作为训练目标,并不意味着模型不可能学到事实知识或推理能力。 Pre-training 那篇讨论过,为了在各种 context 下都降低 prediction loss,模型会被迫捕获语言中广泛存在的统计规律——包括事实关联、语义结构、甚至一定程度的推理模式。关键在于:这个训练目标能够促使模型学习知识,但不提供事实正确性的无条件保证。模型可以在绝大多数常见知识问题上答对,同时在某些长尾事实上输出高置信度的错误答案。
把 Temperature 调到 0 就不会幻觉了?#
这是我学到这里时想到的第一个"解决方案”。
既然概率分布中可能有低概率的正确答案和高概率的错误答案,那随机采样就有可能抽到更离谱的结果。如果我把 Temperature 设成 0,强制每一步都选概率最高的 token(Greedy Decoding),是不是就能避免生成错误内容?
先看 Temperature 到底在做什么。标准的 Softmax 输出是:
$$ P_i = \frac{\exp(z_i)}{\sum_j \exp(z_j)} $$引入 Temperature 参数 \(T\) 后变成:
$$ P_i(T) = \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)} $$\(T\) 的作用是缩放 logits。当 \(T \gt 1\) 时,所有 logits 被压缩,概率分布变得更均匀,低概率选项获得更多机会。当 \(T \lt 1\) 时,logits 差异被放大,概率集中到最高的那几个选项上。
用一个具体例子来看。假设模型对某个问题有三个候选答案(以下是为了说明概念构造的示例数据,不是真实模型输出):
| 候选答案 | 原始 Logits | 事实 |
|---|---|---|
| B | 最高 | 错误 |
| C | 中等 | 正确 |
| D | 最低 | 错误 |
不同 Temperature 下的概率分布大致变化如下:
| 候选 | T = 0.3(低) | T = 1.0(标准) | T = 2.0(高) |
|---|---|---|---|
| B(错误) | ~95% | ~70% | ~50% |
| C(正确) | ~4% | ~20% | ~30% |
| D(错误) | ~1% | ~10% | ~20% |
当 \(T\) 很小的时候,概率几乎全部集中在 B 上。Greedy Decoding 会稳定地选择 B。
但 B 是错误的。
需要说明一下 \(T = 0\) 的含义。严格地说,不能直接把 \(T = 0\) 代入上面的公式(分母会出现 \(\exp(z/0)\) 这种未定义的表达式)。\(T \to 0\) 是一个极限:在这个极限下,概率分布退化成一个只在最大 logit 位置为 1、其余为 0 的分布。实际实现中,“Temperature = 0"通常就是 Greedy Decoding——每一步直接选 argmax,跳过 Softmax 采样。
还有一个相关但独立的问题:Greedy Decoding 每一步选的是当前位置概率最高的 token,但这不保证整个生成序列的联合概率是全局最大的。涌现能力那篇讨论过 Greedy Decoding 的离散化效应——这里是另一个侧面:逐步局部最优不等于全局最优。不过这个问题跟幻觉的关系不大,主要影响的是生成文本的整体质量。
回到核心问题。Temperature 改变的是采样分布的形状,不是模型参数中存储的知识。如果模型的 logits 本身就把错误答案排在第一位,降低 Temperature 只会让模型更确定地选择那个错误答案。
我从这里得到的一个认识是:一致性不等于正确性(Consistency ≠ Correctness)。 模型连续十次给出相同的答案,不意味着这个答案就是事实。
当然也不能反过来说"低 Temperature 一定更差”。在很多任务上,降低 Temperature 确实能减少随机采样带来的噪声,提高输出的稳定性和在常见问题上的准确率。问题在于它不能从根本上修正模型知识中已有的错误。
模型为什么会编造看似真实的内容#
想通了"高概率不等于正确"之后,下一个问题自然就是:那些看起来非常像模像样、但完全是编造的内容,到底是怎么产生的?
举一个贴近技术工作的场景(以下是为了演示 Hallucination 构造的虚构例子,不要当成真实文献引用):
假设你让一个 LLM 推荐几篇关于 CUDA Graph 和 GPU Kernel Fusion 的论文。模型可能会返回:
“Zhang et al. (2024), ‘Efficient Kernel Fusion via Graph-Level Scheduling on Modern GPUs’, NeurIPS 2024. 提出了基于依赖图的 kernel 合并策略,在 A100 上实现了 2.3 倍推理加速。”
标题、作者、会议、年份、甚至实验指标——全部一本正经,但这篇论文根本不存在。
这种现象通常被叫做 Hallucination。我在学习过程中理解到的几个促成因素:
训练目标的本质。 语言模型的训练目标是在给定 context 下预测下一个 token 的分布,不是对每一条事实进行独立核验。训练信号那篇讨论过,self-supervised pretraining 的监督信号来自文本本身的结构,不来自外部的事实标注。模型学到的是"什么样的文本在统计上更可能出现",而不是"什么样的事实在逻辑上为真"。
知识的错误组合。 即使训练数据中每一条信息单独来看都是正确的,模型在生成时也可能把它们错误地拼接在一起。训练语料里确实有大量 NeurIPS 论文、确实有关于 Kernel Fusion 的研究、确实有在 A100 上做实验的工作——模型把这些独立正确的模式组合成了一个不存在的整体。
数据覆盖与长尾问题。 训练语料对不同领域的覆盖程度差异很大。热门主题(比如 ImageNet 分类)的相关文本可能有成千上万篇,模型对这类问题的回答准确率很高。但到了长尾领域(比如某个特定硬件平台上的某个特定编译器 Bug),训练数据可能极其稀疏,模型只能基于有限的上下文模式进行"合理猜测"。
猜测与拒答的激励不对称。 这一点比较微妙。如果模型的训练和评估方式更多地奖励"给出一个看起来合理的回答",而不太惩罚"在不确定时编造内容"或奖励"承认不知道",那模型就会倾向于猜测而不是拒答。这不是说模型"选择"了撒谎——它没有这种意图——而是训练信号的结构在统计上鼓励了生成行为而非沉默行为。
这四个因素不是 Hallucination 的完整因果解释。实际的机制可能更复杂,学术界对此仍有活跃的研究。但它们帮助我理解了一件事:Hallucination 不是采样随机性带来的偶发失误,而是模型训练目标和知识表示方式的结构性特征。
目前业界针对这个问题的工程手段主要包括 RAG(让模型基于检索到的真实文档回答)、Tool Calling(让模型调用外部工具获取确定性结果)、外部验证(对模型输出进行独立的事实核查)、以及训练模型在不确定时拒答(Abstention)。这些方向各有局限,这里不展开。
那 Calibration 能帮上忙吗?#
Token 概率不等于事实正确率,Temperature 也解决不了这个问题。那我们能不能换一个角度:不去直接相信模型的原始概率,而是想办法让模型的置信度变得可靠?
这是我学到这里时自然产生的第二个想法。如果我们能让模型"说 90% 的时候真的有 90% 的概率是对的",那至少可以知道什么时候该信它、什么时候不该信。
这个想法指向的概念叫 Calibration(概率校准)。
先用一个简单的对比来说明 Calibration 到底在衡量什么(以下是为了说明概念构造的示例):
假设两个模型都回答了 100 道题,都答对了 80 道。
- 模型 A 对每道题都报告 99% 的置信度。
- 模型 B 对每道题都报告 80% 的置信度。
两个模型的准确率相同(都是 80%)。但模型 B 的置信度更符合实际情况——它说自己 80% 确定,实际上也确实答对了 80%。模型 A 说自己 99% 确定,但实际只对了 80%。
用更正式的语言:一个模型是 well-calibrated 的,如果:
$$ P(\text{Correct} \mid \hat{c} = 0.9) \approx 0.9 $$也就是说,在模型报告置信度为 0.9 的那些样本中,大约有 90% 是正确的。
这里有一个很容易混淆的点,我花了一些时间才想清楚:Calibration 和 Accuracy 是两个独立的维度。
Calibration 衡量的是"模型对自己正确性的估计是否可靠"。Accuracy 衡量的是"模型实际答对了多少"。一个模型可以准确率很高但校准很差(对每个预测都过度自信),也可以准确率不高但校准良好(它知道自己大概能对多少)。
Calibration 不会自动修正模型掌握的错误事实。 一个校准良好的模型在回答"某国首都是哪里"时,如果它的知识里存储的就是错误答案,校准好只意味着它能准确地告诉你"我有 60% 的把握觉得答案是 B"——而不是把 B 变成正确答案 C。
这里需要严格区分两种 Temperature,因为它们在名字上容易混淆:
- Decoding Temperature:生成时调整 Token 采样分布的 \(T\),就是上一节讨论的那个。
- Temperature Scaling(用于 Calibration):经典分类设置中,在训练好的模型的 logits 后面加一个可学习的标量 \(T\),通过在验证集上优化这个 \(T\) 来改善概率输出的校准度。
后者是一种 post-hoc 校准方法。它通常不会改变 logits 之间的相对排序——如果原来 argmax 指向 B,Temperature Scaling 之后 argmax 大概率还是 B。它改变的是概率值的绝对大小,让它更接近真实的正确概率。
还有一点需要说明:不能简单地认为对 LLM 的 token-level logits 做一次 Temperature Scaling,就自动得到了答案级别的事实正确概率。Token-level 的校准和 answer-level 的校准是不同粒度的问题,后者要复杂得多。
那 Calibration 有什么用?它支持一种叫 Selective Prediction 的策略:
- 置信度高于某个阈值时,直接输出答案。
- 置信度低于阈值时,拒绝回答,或者标记为"不确定,建议人工核实",或者触发外部检索。
这样做的本质是在回答覆盖率和可靠性之间做权衡。阈值设得越高,回答的可靠性越高,但会有更多问题被拒答。
Calibration 在分布变化下还靠得住吗#
这是顺着上面的思路自然冒出来的第三个问题。
假设一个 LLM 在通用知识测试集上校准良好——它说 90% 的时候,确实有大约 90% 是对的。然后我们把它部署到一个技术支持场景,用户大量询问的是 CUDA Kernel 兼容性、特定 GPU 架构上的编译器 Bug、某个版本的 Driver 与某个版本的 NCCL 之间的交互问题。
这些都是模型训练数据中可能极度稀疏的长尾知识。即使模型仍然报告 90% 的置信度,实际正确率可能远低于这个数字。
用符号写出来就是:
$$ P_{\text{test}}(\text{Correct} \mid \hat{c} = 0.9) \approx 0.9 $$不一定意味着:
$$ P_{\text{prod}}(\text{Correct} \mid \hat{c} = 0.9) \approx 0.9 $$Distribution Shift 那篇详细讨论过这个问题——测试集和生产环境的数据分布可能有本质差异,而测试集上的评估指标不能无条件平移到生产环境。这里是同一个逻辑在 Calibration 上的体现。
不过要避免一个过度推论:Distribution Shift 不必然导致 Calibration 失效。如果新环境的问题虽然不同但难度分布相似,或者模型的不确定性估计在新领域也恰好保持一致,校准可能仍然大致成立。关键在于:Calibration 是相对于某个评估分布定义的统计性质,不是模型的固有属性。 分布变了,校准是否还成立需要重新验证。
这里有两个概念值得分开:
Accuracy Generalization:模型能否在新环境中保持预测准确率?
Calibration Generalization:模型对自己正确性的估计,能否在新环境中保持可靠?
这两者不等价。一个模型可能在新环境中准确率下降但校准仍然合理(它知道自己在新领域表现变差了),也可能准确率不变但校准崩了(它在新领域过度自信)。
其他几个 LLM 的局限#
MIT 6.S191 Lecture 6 在 LLM Limitations 这个话题下还提到了另外两点,简单记一下。
Guardrails 与 Jailbreaks。 Guardrails 是指通过训练或系统层面施加的行为约束,比如让模型拒绝回答有害内容。Jailbreak 是指通过精心构造的输入,绕过这些约束让模型产生本不该产生的输出。Agent Safety 那篇讨论过一个相关的工程原则:从训练中学到的指令遵循能力,本质上是软约束而非硬边界。真正的安全边界需要在系统层面(权限控制、工具白名单、操作审计)而非仅靠模型行为来保证。
逻辑与数值推理。 LLM 在语言理解和推理上的能力不需要质疑,但这种能力基于统计学习得到的模式匹配,而不是执行确定性计算程序。让模型做 \(17 \times 38\) 的计算,它可能给出一个接近但不完全正确的结果——因为它是在"预测一个看起来合理的数字",而不是在执行乘法指令。这就是为什么实践中会让 LLM 生成代码、调用计算器或外部工具,然后用确定性的程序来执行计算、再把结果返回给模型——让擅长推理的部分做推理,让擅长精确计算的部分做计算。
写在最后#
回头看这篇笔记走过的路径:从"Token 概率高是不是就意味着正确"这个最初的疑问出发,一路追问下去,每个"解决方案"都引出了新的问题。
降低 Temperature?改变的是采样行为,不是模型存储的知识。
靠 Calibration?衡量的是置信度的可靠性,不是提升模型的准确率。
在测试集上校准好?校准是相对于特定分布的统计性质,换了环境可能不再成立。
这些问题之间有一条暗线:模型能够生成流畅、合理、高概率的文本,和我们是否有充分理由相信这段文本所陈述的事实为真,是两个必须分开对待的问题。
从工程角度来说,这意味着在使用 LLM 的输出时,不能只看"模型是否给出了一个答案",还需要独立的手段来评估"这个答案是否值得信任"。具体的手段——外部检索、工具调用、人工审核、置信度过滤——取决于场景和风险容忍度。但把"生成"和"信任"这两件事分开,是所有后续工程决策的起点。
参考资料#
- MIT 6.S191 Lecture 6: New Frontiers — https://introtodeeplearning.com/slides/6S191_MIT_DeepLearning_L6.pdf
- MIT 6.S191 课程主页 — https://introtodeeplearning.com/
- Next-Token Prediction:语言模型的训练目标从哪来
- 为什么测试集表现很好,模型上线后仍然可能失败?——从 Distribution Shift 到 Extrapolation
- 训练信号从哪里来:重新理解有监督、无监督、半监督与自监督学习
- 从 Pre-training 到 Post-training:为什么大模型需要分阶段训练?
- LLM 的涌现能力是真的吗?从 49% 到 51% 的思考
- 为什么模型准确率达到 99.9%,AI Agent 仍然可能不安全?