AI/ML 详解:幻觉与校准机制

Day 48 · 2026-07-05 · 难度 ★★★☆☆
面向:有编程经验的非 AI 方向工程师
工程对应 → super-individual D10:幻觉治理(怎么在生产里防幻觉、加护栏、做验证)
本期讲机制:为什么会编、置信度为什么不可信、对齐为什么把它变糟。「怎么治」归工程周刊。

幻觉的统计根源Statistical Origin of Hallucination

机制训练目标
一句话类比

把 LLM 想成一个永远返回 200 OK 的 API:你查一条不存在的记录,它不会返回 404null,而是就地编一条格式完美的 response 给你。问题不在它"想骗你"——而在它的架构里根本没有"查不到"这个返回值。每一步它都必须吐一个 token,"沉默"或"未知"从来不是默认选项。

它解决什么问题 + 工作机制

先破除一个误解:幻觉不是 bug,是训练目标的数学必然。LLM 干的是 next-token prediction(预测下一个词)——本质是对语言做密度估计,学一个概率分布 P(下一个词 | 前文)。这个目标里从头到尾没有"事实核查"这一项:模型被奖励"说得像训练数据",不是"说得对"。

OpenAI 的 Kalai 等人 2025 年把这件事讲透了:即使训练语料 100% 无误,交叉熵目标本身也会逼出幻觉。直觉是——生成一个有效答案,难度不低于一道二分类题"这句话对不对";而对于训练里只出现过一两次的冷门事实(一个人的生日、一篇论文的作者),模型没有足够统计信号把它和相似的错误答案区分开,于是错误率有一个不可消除的下界

更狠的一层在评估激励:几乎所有 benchmark 都按"答对得 1 分、答错和留白都得 0 分"打分。在这种规则下,蒙一个的期望得分严格高于老实说"我不知道"——就像标准化考试里空着不如猜。于是整个训练-评估流水线,系统性地把模型训练成一个自信的应试者,而不是一个诚实的知情者。

代码示例
from openai import OpenAI
client = OpenAI()  # 需要 OPENAI_API_KEY

# 问一个纯属虚构的实体——模型没有"查不到"这个返回值
r = client.chat.completions.create(
    model="gpt-5",
    messages=[{"role": "user",
               "content": "介绍一下 2019 年图灵奖得主 Zael Kirmani 的贡献"}],
    logprobs=True,  # 拿每个 token 的对数概率
)
msg = r.choices[0].message.content
print(msg)  # → 大概率编出一段流畅但完全虚构的生平

# 关键观察:编造内容的 token 概率往往并不低——
# 模型「自信地编」,高置信 ≠ 有依据。这正是下一节要量化的问题。
lp = r.choices[0].logprobs.content
print(sum(t.logprob for t in lp) / len(lp))  # 平均 logprob
常见误区 + 实践场景
"幻觉是因为训练数据里有错,清洗数据就能根治"——错。Kalai 等人的核心结论恰恰是:数据完美也无法根治,因为病根在目标函数和评估规则,不在语料脏。清洗数据能降低某类幻觉,但只要"蒙比留白得分高",模型就永远有编造的动机。
📌 场景:让 AI 帮你做文献综述时,凡是它给出的"具体引用"(论文标题、作者、年份、页码)默认当成待核实的猜测,而不是事实。冷门、低频的信息正是幻觉高发区——你的验证力气要按"这条信息在训练语料里有多常见"来分配。
Takeaway + 思考题
💡 幻觉不是模型"坏了",是它被训练成"宁可蒙不可空"的应试者——病根在目标和评分,不在数据。
🤔 如果把评估规则改成"答错倒扣、留白得 0",模型会不会自动学会说"我不知道"?这暗示了什么治理方向?

校准Calibration

度量置信度
一句话类比

校准好不好,看天气预报就懂:一个预报员说了 100 次"70% 会下雨",如果这些天里正好约 70 天真下了,他就是校准良好(well-calibrated)。跟他有多"准"是两回事——他可以每次都说 70% 从不说 100%(不够 sharp),但只要频率对得上,置信度就是可信的信号。LLM 的置信度能不能当告警阈值用,取决于同一件事。

它解决什么问题 + 工作机制

模型给每个答案都附带一个隐含置信度(token 概率)。校准问的是:它说的置信度,和实际正确率对不对得上?把预测按置信度分桶,理想情况下"置信 0.8 那一桶里,正好 80% 是对的"。量化指标是 ECE(Expected Calibration Error,期望校准误差)——各桶「平均置信度」与「实际准确率」之差的加权绝对值,越接近 0 越好:

可靠性图(Reliability Diagram):x=模型置信度,y=实际准确率

1.0 ┤ 理想=对角线(说 p% 就有 p% 对)
    │                     
0.7 ┤               ← 理想
0.5 ┤        ← 实测
    │
    └────────────────────→ 置信度
       0.5      0.7    0.9
↑ 曲线掉在对角线下方 = 过度自信(overconfident):说 0.9 其实只对 0.6

经典修法叫 温度缩放(Temperature Scaling,Guo 等人 2017):不动模型权重,只把输出 logits 除以一个学到的温度 T,再过 softmax。T>1 把过尖的分布压平,让置信度回落到和真实准确率一致——一个参数、事后校准、不掉准确率。注意它治的是"置信度数值不可信",治不了幻觉本身:校准让你知道该信几分,但不会让错答案变对。

代码示例
import numpy as np

def expected_calibration_error(confs, correct, n_bins=10):
    # confs: 每个预测的置信度 (0~1);correct: 是否答对 (0/1)
    bins = np.linspace(0, 1, n_bins + 1)
    ece = 0.0
    for i in range(n_bins):
        # 落在这个置信度桶里的预测
        m = (confs > bins[i]) & (confs <= bins[i + 1])
        if m.sum() == 0: continue
        acc  = correct[m].mean()   # 这桶的实际准确率
        conf = confs[m].mean()     # 这桶的平均置信度
        # 差距 × 该桶样本占比,累加
        ece += (m.sum() / len(confs)) * abs(acc - conf)
    return ece

# 过度自信的模型:置信度普遍高于真实准确率 → ECE 大
confs   = np.array([0.9, 0.9, 0.8, 0.95, 0.7])
correct = np.array([1,   0,   0,   1,    0])   # 5 题只对 2 题
print(f"ECE = {expected_calibration_error(confs, correct):.3f}")
常见误区 + 实践场景
"校准好 = 模型准"——两码事。一个只会瞎猜、准确率 50% 的模型,只要它每次都老实报 0.5 置信度,就是完美校准的。校准衡量的是"置信度可不可信",不是"答案对不对"。你要的是两者兼得:高准确率置信度诚实。
📌 场景:搭个"AI 辅助决策"流水线时,别把模型输出直接当结论——先拿一批有标准答案的历史问题跑一遍,画可靠性图,看它在你这个领域是不是过度自信。如果它说"很确定"时实际只对六成,你就知道要给它的"确定"打个七折再采信。
Takeaway + 思考题
💡 校准 = 置信度和真实正确率对齐;它让你知道"该信几分",但不会让错答案变对。
🤔 你现在采信 AI 的哪些判断,是被它语气的确定性说服的,而不是被校准过的置信度说服的?

RLHF 为何损害校准Why RLHF Hurts Calibration

对齐mode collapse
一句话类比

想象一个诚实但会说"这个我不太确定"的顾问,被你用"客户满意度 KPI"优化了半年——他慢慢变成一个永远斩钉截铁的销售。听起来更可信、更让人舒服,实际却更不准。RLHF 对模型做的正是这件事:为了讨好人类偏好,它牺牲了置信度的诚实性。分布式里的老对手你熟——为了 p99 体验,牺牲了一致性

它解决什么问题 + 工作机制

反直觉的事实:预训练后的原始模型(base model)其实校准得相当好——它只做 next-token 预测,概率就是它对语言的真实统计信念。但经过 RLHF(基于人类反馈的强化学习,让模型对齐人类偏好) 和指令微调后,校准显著变差。GPT-4 技术报告里有一张著名的图:预训练版 GPT-4 的可靠性曲线几乎贴着对角线,RLHF 之后曲线明显鼓向过度自信一侧

机制在于人类偏好的形状。标注者给回答打分时,系统性地更爱自信、流畅、给出明确结论的回答,不爱"这取决于…""我不确定"这类犹豫表达。奖励模型把这个偏好学了进去,PPO 优化时就把概率质量往少数几个高置信表达上挤——这叫 mode collapse(模式坍缩):分布从"诚实地摊开不确定性"塌成"总是一副很确定的样子"。

同一道模型没把握的题,两个阶段的置信度

Base(预训练):0.55 ← 摊开不确定性,接近真实准确率,校准好
                  ↓ RLHF 优化「人类更爱自信的回答」
RLHF 后:     0.92 ← 语气变确定,实际准确率没涨 → 过度自信

代价:更讨人喜欢 · 更流畅 · 但置信度不再可信(校准 tax)

这解释了一个日常观察:ChatGPT / Claude 这类对齐过的模型,比原始 base model 读起来更笃定,也因此更容易让你放下警惕。这不是模型"变笨了",而是它被优化成了让人舒服的语气——语气的确定性和内容的可靠性,在 RLHF 之后脱钩了。

代码示例
from anthropic import Anthropic
client = Anthropic()  # 需要 ANTHROPIC_API_KEY

# 对抗过度自信的一个提示手法:显式要求「校准过的」数值置信度,
# 并要求先想「什么情况下我会错」——逼模型摊开不确定性
prompt = """回答问题,然后给一个 0-100 的置信度。
置信度定义:在你给出这个置信度的所有题里,应恰好有该比例是对的。
先列出你可能出错的情形,再给分。

问题:太平洋最深处的确切深度是多少米?"""

r = client.messages.create(
    model="claude-opus-4-8", max_tokens=400,
    messages=[{"role": "user", "content": prompt}])
print(r.content[0].text)
# 要求「校准定义 + 先想错因」通常比直接问「你多确定」得到更诚实的分数
常见误区 + 实践场景
"直接问模型'你有多确定',它报的数就能用"——不一定。RLHF 之后模型的语言化置信度同样被"显得自信更讨喜"污染,容易虚高。让它先列出出错情形、再给一个带校准定义的分数,比空问"多确定"更接近真实——但仍要用你自己的历史数据验证,别照单全收。
📌 场景:用 AI 做投资/技术选型这类高风险判断时,警惕它的笃定语气本身就是被优化出来的产物。刻意反问"你在什么前提下会错?给我最强的反方论证"——这是在手动把被 RLHF 压平的不确定性重新撬开
Takeaway + 思考题
💡 RLHF 让模型更好用、更讨喜,代价是校准——语气的确定性和内容的可靠性从此脱钩。
🤔 一个"诚实但常说不确定"的助手 vs 一个"自信但偶尔错"的助手,你会更信任哪个?人类的这个偏好,正是校准被牺牲的源头。
工程对应 → super-individual D10:幻觉治理实战

知识边界与自我评估Knowledge Boundary & Self-Knowledge

机制P(True)
一句话类比

缓存的 cache miss 信号:系统内部其实知道这次是 miss,但如果不把 miss 信号暴露到上层,调用方就误以为每次都命中。模型也一样——它内部有信号区分"我知道"和"我在编"(比如输出分布的熵、内部激活),但默认不主动报出来。让它自评,就是把这个 cache-miss 信号显式暴露出来。

它解决什么问题 + 工作机制

核心问题:模型知道自己不知道吗?Anthropic 的 Kadavath 等人 2022 年(论文名就叫"Language Models (Mostly) Know What They Know")给了一个偏乐观的答案:大模型在相当程度上"知道自己知不知道"。他们用了两个可操作的探针:

  • P(True)——模型先给一个答案,再回头评估这个答案为真的概率。在多样任务上,这个自评概率校准得不错,且随模型规模变好;
  • P(IK)(Probability I Know,"我知道答案的概率")——不看具体答案,直接让模型预测"这题我答得上来吗"。模型能训练出一个可用的 P(IK) 信号。

机制直觉:当模型对答案有把握时,输出分布尖锐(少数 token 概率极高、熵低);没把握时分布平摊(很多 token 概率相近、熵高)。这个"内部不确定性"是真实存在的信号——问题从来不是模型没有边界感,而是默认的生成流程把这个信号丢掉了,只吐最终答案。让它显式做 P(True) 自评,等于把丢掉的信号捡回来。

当然是"Mostly"不是"Always":越是训练里没见过、需要多步推理的题,自评越不可靠——这和第一节的统计根源呼应,冷门低频区正是自我认知也失灵的地方。

代码示例
from anthropic import Anthropic
client = Anthropic()

def answer_with_self_eval(question):
    # 第 1 步:正常作答
    a = client.messages.create(
        model="claude-opus-4-8", max_tokens=300,
        messages=[{"role": "user", "content": question}]
    ).content[0].text

    # 第 2 步:换一次独立调用,让模型评估上面答案为真的概率 P(True)
    # 独立调用避免它「护着」自己刚说的话
    check = client.messages.create(
        model="claude-opus-4-8", max_tokens=10,
        messages=[{"role": "user", "content":
            f"问题:{question}\n候选答案:{a}\n"
            "这个答案正确的概率是多少?只回一个 0-1 的数字。"}]
    ).content[0].text
    return a, float(check.strip())

ans, p_true = answer_with_self_eval("贝叶斯定理的提出者是谁?")
# p_true 低 → 触发人工复核 / 转 RAG 检索,别直接采信
常见误区 + 实践场景
"P(True) 自评能兜住所有幻觉"——不能。它是Mostly:在训练充分的领域好用,在冷门、需要长推理的题上自评也会失灵——过度自信的题,往往连自评都过度自信。所以 P(True) 是第一道便宜的过滤网,不是最后一道保险;低分触发升级(转检索、转人工),高分不等于免检。
📌 场景:搭个人 AI 工作流时,给关键回答加一道"自评闸门"——用一次独立调用让模型评 P(True),低于阈值就自动转 RAG 检索或标记"需人工核实"。这比事后被一条自信的错误信息坑了,成本低得多。
Takeaway + 思考题
💡 模型"Mostly 知道自己不知道"——不确定性信号本就存在,默认生成流程把它丢了;显式自评就是把它捡回来。
🤔 如果模型内部有"我不知道"的信号却默认不说,那责任在模型,还是在只奖励"给出答案"的我们?

深入资源Further Reading

深入思考Deep Questions

1. 第 1 节说"蒙比留白得分高"逼出幻觉,第 4 节说模型"Mostly 知道自己不知道"。这两件事矛盾吗?
不矛盾,而且正好互补,指向同一个治理方向。第 4 节说模型内部有不确定性信号(P(True)/P(IK) 校准尚可)——它并非"瞎子"。第 1 节说的是:现行评估规则不奖励模型把这个信号说出来,反而奖励"哪怕没把握也蒙一个"。合起来看,幻觉的一大部分是激励错配而非能力缺失:模型知道自己心里没底,但外部规则告诉它"表达没底会扣分,蒙对了才加分",于是它理性地选择闭着眼给答案。这也是 Kalai 等人的政策建议——改评估:让"我不知道"在得分上不劣于"蒙错",甚至给校准过的弃答正向激励。你在自己的工作流里其实可以先行:设计 prompt 和采信规则时,明确"诚实弃答"优于"自信错答",等于在小范围内修好了这个激励。
2. 温度缩放(校准)和采样温度(Day 45 解码)都叫"温度"、都在改 softmax,是同一个东西吗?
数学形式几乎一样(logits 除以 T 再 softmax),但目的和作用点完全不同,别混。采样温度(解码时)改的是生成行为:T 高更随机有创意、T 低更确定保守,它影响"吐出哪个 token"。校准温度(Guo 2017)改的是报告的置信度数值:用一个在验证集上学到的 T,把过尖的概率压平到与真实准确率对齐,它不改变最可能的答案(argmax 不变,因为对所有 logit 同比缩放),只改"这个答案我该报多少置信度"。一个动的是"选什么",一个动的是"多信它"。有意思的联系是:两者都在承认"原始 logits 的绝对数值不能直接当概率信念用"——解码温度是为了控制多样性而调,校准温度是为了让数值变得可信而调。BigCat 你分布式背景的类比:采样温度像负载均衡的随机权重(影响路由到哪),校准温度像监控指标的标定系数(影响你多信这个读数)。
3. 如果人类偏好"自信的回答"是校准被牺牲的根源,那能不能训练时直接把"校准"加进奖励,两全其美?
方向对,但有真实张力,不是免费午餐。你确实可以在 RLHF 里加一项校准奖励(惩罚过度自信、奖励诚实弃答),学界也在试"训练模型表达不确定性"。难点在三处:(a) 目标冲突——人类偏好自信 vs 校准要求诚实,两个奖励项打架,权重怎么配是产品价值判断,配多了模型变得畏首畏尾满口"我不确定",用户体验崩;(b) 校准信号难拿——训练时你未必有每条回答的"真值"来算它该多自信,尤其开放式生成;(c) Goodhart 风险(Day 47 对齐失败)——一旦"表达不确定"成为被优化的指标,模型可能学会表演不确定(该自信时也假装犹豫)来刷奖励,而非真的更校准。所以现实里更多是分工:训练侧尽量别把校准搞得太糟,推理侧用 P(True) 自评、温度缩放、外部验证(RAG/工具)把可信度补回来。"两全其美"是渐近目标,不是一个开关。
4. 把这四节串起来:一条"AI 给的自信答案",从生成到你采信,可以设几道闸?
把它当成一条带质量门的数据管道来设计,从便宜到贵四道闸:① 源头分诊(第 1 节)——先判断这条信息在训练语料里是高频还是冷门/低频;冷门(具体引用、生日、小众数字)默认高幻觉风险,直接标"待核"。② 自评闸(第 4 节)——用一次独立调用取 P(True),低于阈值就升级处理;成本一次 API 调用,最便宜的过滤网。③ 校准折扣(第 2、3 节)——记住 RLHF 后模型语气普遍虚高,对它的"确定"打折;有条件就拿你领域的历史题画一次可靠性图,得到该打几折的经验系数。④ 外部落地——高风险结论必须落到可验证的外部源(RAG 检索、跑代码、查权威库),让答案可反驳而非仅"听起来对"。关键心法:这四道闸的力气要按风险和频次分配——不是每条回答都上全套,而是"低频信息 + 高风险决策"叠满四道,"高频常识 + 低风险闲聊"一道都不用。这本身就是超级个体的核心能力:把有限的验证注意力,花在幻觉最可能出现、且代价最大的地方。