"幻觉(hallucination)“是 LLM 最被诟病的问题:它会用极度自信的口吻编造不存在的 API、伪造论文标题、虚构判例条文。要缓解它,先得摆脱一个误解——幻觉不是模型"出 bug 了”,而是它正常工作的副产物。看清这一点,才能对症下药。

直觉:模型在补全,不在检索

一个自回归语言模型的全部本职工作,是建模条件概率

P(x_t \mid x_1, \dots, x_{t-1})

并据此一个 token 一个 token 地往下生成。它优化的目标是"下一个 token 的预测准确率",从来不是"事实正确性"。训练时它见过海量"流畅且通常正确"的文本,于是学会了生成流畅且统计上像真的的文本。当它对某个事实没有可靠信息时,它不会停下来说"我不知道"——因为在训练分布里,一段话戛然而止或频繁认怂是低概率的。它会用最符合语言规律的方式把句子补完整,而一个语法完美、风格自信的虚构答案,恰恰是高概率的延续。

换句话说:幻觉是流畅性与事实性目标不一致(misalignment)的必然产物。 模型是个出色的"形式补全器",不是数据库。

成因拆解:四类来源

把幻觉拆开看,至少有四条独立的来源链路,对应不同的缓解手段。

  1. 知识缺口。训练语料里就没有,或只有零星矛盾的信息(长尾实体、内部文档、训练截止日期之后的事件)。模型只能外推,外推就是编造。
  2. 参数化记忆的有损压缩。模型把整个互联网压进有限参数,本质是有损存储。细节(具体数字、人名、日期)最容易在压缩中丢失或被相邻知识"串味",于是出现张冠李戴。
  3. 采样过程的随机性。即便模型内部对正确 token 概率最高,采样仍可能选中次优 token,一旦在关键事实处选错,后续生成会自圆其说地继续编——这是自回归的放大效应:一步偏,步步偏。
  4. 对齐副作用。RLHF 让模型倾向于"有帮助、给出答案"。若奖励信号没有充分惩罚"自信地胡说",模型就会学到:给一个看似完整的答案,比诚实地说"不确定"得分更高。

缓解手段一:从采样侧降噪

最低成本的一档干预是调采样。幻觉常发生在概率分布平坦(模型本身不确定)的位置,此时随机性最危险。

  • 降低 temperature。生成 logits 经过 softmax(z/T)\text{softmax}(z / T)T0T \to 0 时分布趋近 argmax,输出更确定、更贴近高概率事实。事实问答、代码生成等场景常用 T[0,0.3]T \in [0, 0.3]
  • 配合 top-p(nucleus)截断,砍掉长尾低概率 token,避免偶发选中离谱内容。

但要清醒:采样只能减少"本可避免的随机性幻觉",治不了知识缺口。如果模型压根不知道,把 TT 调到 0 只会让它稳定地、可复现地给出同一个错误答案。

一个有用的副产品是用不确定性做信号。同一问题用 T>0T>0 采样多次(self-consistency 思路),若答案彼此发散,往往说明模型在瞎猜;若高度一致,可信度相对更高。这给了我们一个无需外部知识的"软置信度"。

缓解手段二:RAG——把事实搬到上下文里

真正治本的是改变信息来源:与其指望参数化记忆,不如检索增强生成(RAG)——先从可信知识库取回相关文档,塞进上下文,让模型"看着材料答题"。这把任务从"凭记忆背诵"降级为"阅读理解 + 摘抄",难度和出错率都大幅下降。

最小数据流如下。

1
2
3
4
5
6
query
└─> embed(query) # 查询向量化
└─> vector_search(top_k) # 在向量库里做近邻检索
└─> rerank / filter # 可选:交叉编码器精排
└─> build_prompt(query, retrieved_chunks)
└─> LLM.generate # 要求"只依据材料作答 + 标注来源"
1
2
3
4
5
6
7
8
9
def rag_answer(query, store, llm, k=5):
q_vec = embed(query)
chunks = store.search(q_vec, top_k=k) # 余弦相似度近邻
context = "\n\n".join(f"[{i}] {c.text}" for i, c in enumerate(chunks))
prompt = (
f"仅根据以下材料回答;材料中没有就回答“无法确定”,并标注引用编号。\n"
f"材料:\n{context}\n\n问题:{query}"
)
return llm.generate(prompt, temperature=0.0)

RAG 的几个关键工程点:

  • 检索质量是上限。RAG 把"模型会不会编"问题转化成了"检索器能不能召回对的材料"问题。召回错的、缺失的、过时的 chunk,模型照样会基于错误前提流畅作答——所谓 garbage in, garbage out。
  • 分块(chunking)策略直接影响召回。块太大稀释相关信号、浪费上下文;块太小切断语义、丢失上下文。需要结合文档结构和重叠窗口调。
  • 提示里必须显式授权"拒答"。明确告诉模型"材料没有就说无法确定",否则它会用参数化记忆"补全"检索没覆盖的部分,幻觉从后门溜回来。
  • 引用与可溯源。让模型标注每个论断来自哪个 chunk,既能让用户核验,也在训练/约束模型"贴着材料说话"。

其他层次的防线

RAG 之外还有几道正交的防线,可叠加使用:

  • 提示工程。要求"逐步推理后再给结论"“不确定就明说”“区分事实与推测”,能压低一部分自信型幻觉。
  • 结构化约束 / 工具调用。把能算的交给计算器,能查的交给数据库/API(function calling),让模型只负责编排,不负责硬背。
  • 后验校验。生成后用规则、第二个模型或检索做事实核查(fact-check / NLI 蕴含判断),不一致就回退或重生成。
  • 训练侧对齐。在偏好数据里显式奖励"诚实地承认不知道",惩罚自信的错误,从根上调整模型的"答题倾向"。

小结

幻觉的根因是优化目标(流畅性)与我们想要的(事实性)天然错位,再叠加知识缺口、有损记忆、采样随机和对齐副作用。对应地形成一条分层防御:采样侧(降 temperature、用一致性估置信度)压随机噪声,RAG 把权威事实搬进上下文治知识缺口,提示/工具/后验校验/训练对齐各补一刀。没有银弹——务实的系统总是把这几层叠起来,并始终假设"模型可能在自信地胡说",为关键输出保留人工或自动的核验闸门。