Jean's Blog

一个专注软件测试开发技术的个人博客

0%

LLM 幻觉:为什么模型会一本正经地说错?

LLM 幻觉:为什么模型会一本正经地说错?

在前面的文章中,我们已经知道,大语言模型会根据当前上下文计算 Logits,再逐 Token 选择并生成回答。

这种机制可以产生自然、连贯的文本,但也带来一个非常常见的问题:

模型可能用非常肯定的语气,生成看起来专业、完整,实际上却错误、无依据或无法验证的内容。

这类现象通常被称为 LLM Hallucination,也就是大语言模型幻觉。NIST 的生成式 AI 风险管理资料也使用 Confabulation 描述这类自信但错误或虚构的输出,以避免与医学意义上的“幻觉”混淆。

例如:

1
2
3
4
5
用户:请介绍 2024 年发表的论文
《Quantum Coffee Networks for Large Language Models》及其作者。

模型:这篇论文由 Alice Johnson 和 Michael Chen 发表,
主要研究量子计算如何优化咖啡推荐系统……

如果这篇论文根本不存在,那么作者、发表时间和研究内容都是模型生成出来的幻觉。

image-20261012113037992

先说结论

LLM 产生幻觉的根本原因,可以概括为:

LLM 的核心目标是根据上下文生成统计上合理的下一个 Token,而不是自动查询现实世界并证明每句话为真。

模型执行的主要过程是:

1
2
3
4
5
6
7
8
9
10
11
训练数据中学到的语言与知识模式
+
当前 Prompt 与 Context
↓
预测下一个 Token 的概率分布
↓
选择一个 Token
↓
将它放回上下文并继续预测
↓
得到连贯、自然的完整回答

但默认过程里并不一定包含:

1
2
3
4
5
查询权威资料
→ 核对事实
→ 验证引用
→ 执行计算
→ 判断证据是否足够

因此:

1
2
3
语言上合理
≠
事实一定正确

什么是 LLM 幻觉?

在本文中,可以把 LLM 幻觉定义为:

模型生成了与现实事实、给定来源或可验证证据不一致,或者缺少依据却被表达为事实的内容。

这个定义里有三个重点:

  1. 输出可能与现实世界的事实不一致;
  2. 输出可能与用户提供的资料不一致;
  3. 输出也可能无法从任何可靠证据中得到支持。

幻觉不等于所有错误

“错误”和“幻觉”经常被混用,但两者并不完全相同。

情况 是否通常属于幻觉 说明
编造不存在的论文 是 无可靠依据却作为事实输出
错误引用给定文档 是 与明确来源冲突
算术计算失误 可能属于广义幻觉 也可以单独称为推理或计算错误
没遵守 JSON 格式 通常不是事实幻觉 更接近指令遵循失败
写了一篇虚构小说 不是 用户明确要求创造虚构内容
对未来进行明确标注的预测 不一定是 关键在于是否把预测冒充为已知事实

幻觉通常强调的是:输出呈现出事实性,但缺乏事实支撑。

幻觉不等于撒谎

撒谎通常意味着知道真相,却有意说出错误信息。LLM 是否具有这种主观意图不能从一次错误输出中推出。

大多数情况下,更准确的说法是:

1
模型根据概率生成了错误内容

而不是:

1
模型知道答案,但故意欺骗用户

因此在工程讨论中,应该优先分析数据、上下文、检索、解码和验证流程,而不是给模型赋予未经证明的主观动机。

两个判断维度:Factuality 与 Faithfulness

分析幻觉时,最好区分两个容易混淆的概念。

Factuality:事实性

事实性关注输出是否与现实世界中的可验证事实一致。

1
2
问题:法国的首都是哪里?
回答:巴黎。

这句话可以通过可靠外部知识验证。

Faithfulness:忠实性

忠实性关注输出是否忠于当前提供的来源、文档或结构化数据。

1
2
来源:报告显示,本季度收入增长 8%。
回答:报告显示,本季度收入增长 18%。

即使现实中企业收入碰巧增长了 18%,这个回答仍然不忠于给定报告。

两者的关系可以表示为:

输出情况 事实性 忠实性
与现实和来源都一致 正确 忠实
与现实一致,但来源没有提到 可能正确 不一定忠实
与来源一致,但来源本身错误 可能错误 忠实
与现实和来源都冲突 错误 不忠实

对于 RAG、文档问答和摘要任务,Faithfulness 尤其重要:模型应该根据当前证据回答,而不是擅自补充参数中的“印象”。

幻觉有哪些常见类型?

1. 事实捏造

模型编造不存在的人物、事件、组织、产品或数据:

1
“某公司在 2019 年获得了图灵奖。”

公司不可能获得授予个人的图灵奖,这类内容可能语法正确,却事实错误。

2. 属性与关系错误

实体本身存在,但模型把属性或关系拼错:

1
2
3
把一篇论文的作者张冠李戴;
把产品 A 的功能写到产品 B;
把事件发生年份与另一个事件混合。

这类幻觉常来自相似概念之间的错误关联。

3. 引用与来源伪造

模型生成看似规范的:

  • 论文标题;
  • DOI;
  • 法律条文;
  • 新闻链接;
  • 作者和期刊名称;
  • API 文档地址。

这些引用格式可能很像真的,但实际不存在,或者链接指向完全不同的内容。

4. 与来源冲突

用户已经提供明确资料,但模型仍然改变其中的数字、条件或结论:

1
2
来源:退款申请需在 7 天内提交。
模型:退款申请可在 30 天内提交。

这是一种典型的内在幻觉(Intrinsic Hallucination):输出与给定来源发生矛盾。

5. 无来源扩展

模型添加了来源中没有出现、外部也未验证的内容:

1
2
来源:张三于周一参加会议。
模型:张三于周一参加会议,并在会上提出了三项改革建议。

后半句没有证据支持,属于外在幻觉(Extrinsic Hallucination)的常见形式。

需要注意,来源外信息不一定事实错误,但如果任务要求“只根据资料回答”,未经支持的补充仍然是不忠实输出。

6. 推理过程幻觉

模型可能给出形式完整但实际不成立的推导:

1
2
3
错误前提
→ 看似合理的中间步骤
→ 错误结论

有时最终答案碰巧正确,中间解释却是编出来的;有时中间一个错误会让后续整条推理链偏离。

7. 工具与代码幻觉

在编程和 Agent 场景中,常见表现包括:

  • 调用不存在的函数;
  • 编造第三方库 API;
  • 使用已经废弃的参数;
  • 声称执行了实际没有执行的工具;
  • 把工具返回的失败结果描述成成功;
  • 构造不存在的文件路径或数据库字段。

这类问题不能只靠回答写得更谨慎解决,还需要真实执行、类型检查、测试和工具结果验证。

LLM 为什么会产生幻觉?

幻觉通常不是单一原因造成的,而是数据、训练目标、模型容量、上下文、检索和解码共同作用的结果。

原因一:训练目标是预测 Token,不是验证事实

预训练的典型目标是:

1
给定前面的 Token,预测下一个 Token

数学上可以写成:

1
P(x_t | x_1, x_2, ..., x_(t-1))

损失函数会奖励模型给训练文本中的下一个 Token 更高概率,却不会自动要求模型为每个陈述提供外部证据。

如果训练数据中经常出现:

1
“这项研究由……提出,并发表于……”

模型就会学会这种论文介绍模式。面对一个不存在的论文标题,它仍可能继续生成常见作者名、年份和研究结论,因为这些 Token 在语言结构上非常合理。

这解释了一个关键现象:

模型可以非常擅长生成“答案的样子”,但这不等于它拥有答案的证据。

原因二:训练数据包含错误、冲突与过时内容

LLM 的训练数据通常来自大量文本,其中可能同时存在:

  • 真实事实与网络谣言;
  • 新版本文档与旧版本文档;
  • 权威来源与低质量转载;
  • 不同时间点的冲突信息;
  • 讽刺、虚构作品与真实报道;
  • 人类普遍相信但实际错误的说法。

模型学习的是这些文本的统计分布,不会天然知道哪一份来源最权威。

TruthfulQA 的研究也表明,模型可能复现训练文本中常见的人类误解。单纯扩大参数量,并不自动保证模型在所有问题上更加真实。

原因三:模型参数不是精确数据库

模型不会把每条知识保存成简单的键值对:

1
2
key = "某论文作者"
value = "某个人"

知识以分布式方式编码在大量参数中。多个概念、名称和语言模式共享参数表示,因此可能出现:

  • 相似实体相互混淆;
  • 两段真实信息被错误拼接;
  • 记住大致结论,却记错数字;
  • 记住某个 API 的旧版本;
  • 用常见模式填补具体细节。

参数化知识适合进行语言理解和模式泛化,却不是具有事务一致性和实时更新能力的数据库。

原因四:模型存在知识边界,但仍能继续生成

当模型不知道答案时,词表中的每个候选 Token 仍然会得到一个 Logit:

1
2
3
不知道事实
≠
无法计算下一个 Token

Softmax 仍然可以产生总和为 1 的概率分布,解码器仍然可以选出一个 Token。除非模型学会在证据不足时拒答,否则它可能继续补全一个听起来合理的答案。

可以把它理解为:

1
2
3
4
5
6
7
知识置信不足
↓
语言生成机制仍然正常工作
↓
使用相似模式填补缺失信息
↓
形成流畅但无依据的内容

原因五:对“有帮助”的训练可能鼓励猜测

经过 SFT 或偏好对齐后,模型通常更愿意直接、完整地回答用户。如果训练数据持续奖励“给出一个答案”,却没有充分奖励:

  • 承认不知道;
  • 请求更多信息;
  • 区分事实与推测;
  • 引用可验证证据;
  • 拒绝错误前提;

模型就可能在“有帮助”和“真实可靠”之间偏向前者。

这不是说对齐训练必然增加幻觉,而是训练目标需要同时平衡 Helpful、Honest 和 Harmless。只奖励语言质量和用户满意度是不够的。

原因六:Prompt 可能包含错误前提

考虑这个问题:

1
请解释爱因斯坦在 1969 年登月任务中的贡献。

问题已经包含错误前提。模型可能有两种行为:

1
2
行为 A:指出爱因斯坦于 1955 年去世,无法参与 1969 年任务
行为 B:接受错误前提,并编造他的贡献

如果模型过度迎合用户,就可能沿错误前提继续生成。这类行为也与 Sycophancy,也就是迎合倾向有关。

因此,可靠 Prompt 应明确允许模型纠正用户:

1
如果问题包含错误前提,请先指出错误,不要沿错误前提继续推测。

原因七:上下文过长、缺失或互相冲突

即使正确答案已经写在 Context 中,模型仍可能回答错误,原因包括:

  • 关键内容被截断;
  • 信息位于很长上下文的中间,未被有效关注;
  • 大量无关内容产生干扰;
  • 多份资料给出冲突结论;
  • Chat Template 没有清晰标识资料边界;
  • System、User 和检索资料的优先级不清楚;
  • 历史对话中的旧信息没有更新。

更长的上下文窗口只能让模型接收更多 Token,不保证模型一定能正确使用每个 Token。

原因八:逐 Token 生成会累积错误

自回归生成会把刚刚生成的 Token 重新加入上下文:

1
2
3
4
5
6
7
错误的第一个实体
↓
后续 Token 把它当作已有上下文
↓
继续补充日期、身份和事件
↓
形成内部连贯的错误叙述

例如模型一开始误选了某个作者名,后续就可能根据这个作者的真实研究领域继续编造,使整段回答看起来更加可信。

这类错误具有路径依赖:越早发生,影响的后续 Token 通常越多。

原因九:检索和工具也可能出错

引入 RAG、搜索和工具并不意味着幻觉自动消失。外部系统可能出现:

  • 检索到不相关文档;
  • 权威资料没有进入 Top-k;
  • 搜索结果已经过时;
  • 文档解析丢失表格或单位;
  • 工具调用失败;
  • 模型误读工具返回值;
  • 引用编号与正文证据错位;
  • 模型在证据之外继续扩写。

因此系统可能形成新的错误链路:

1
2
3
4
错误检索
→ 错误上下文
→ 忠实总结错误资料
→ 得到事实错误的答案

在这种情况下,模型可能对来源是忠实的,但来源本身不真实。

Temperature 会导致幻觉吗?

Temperature 会改变 Token 概率分布的集中程度:

1
2
较低 Temperature → 更偏向高概率 Token
较高 Temperature → 更多低概率候选有机会被选中

较高 Temperature 往往增加输出多样性,也可能增加不稳定细节和无依据内容出现的机会。但不能简单写成:

1
2
Temperature 高 = 一定幻觉
Temperature 低 = 一定真实

原因是:

  1. 最高概率 Token 本身也可能对应错误事实;
  2. Greedy Decoding 可以每次稳定地产生同一个错误答案;
  3. 某些推理模型对过低 Temperature 也可能出现重复或性能下降;
  4. 事实正确性主要取决于知识、上下文、证据和验证,而不是单个采样参数。

更准确的说法是:

解码参数会影响幻觉的表现形式和发生概率,但无法从根本上保证事实正确。

为什么高概率不等于事实正确?

假设模型对三个候选 Token 给出:

1
2
3
候选 A:90%
候选 B:8%
候选 C:2%

这组概率表达的是:

1
在当前模型和当前上下文中,A 最符合模型学到的生成分布

它不是:

1
A 经过外部事实核验后有 90% 的概率为真

如果训练数据错误、问题前提错误,或者模型把两个实体混淆,那么错误 Token 也可能获得最高概率。

所以:

  • Token Probability 是语言模型内部的生成偏好;
  • Factual Confidence 应建立在证据、校准和外部验证上;
  • 两者有关联,但不能直接画等号。

RAG 能消除幻觉吗?

不能。RAG 的作用是给模型提供与当前问题相关的外部证据,从而减少模型完全依赖参数记忆:

1
2
3
4
5
6
7
用户问题
↓
检索相关资料
↓
把资料放入 Context
↓
要求模型根据资料回答

它能显著改善以下问题:

  • 模型缺少私有领域知识;
  • 模型知识已经过时;
  • 回答需要引用具体文档;
  • 需要追溯答案来源。

但 RAG 仍可能失败:

阶段 可能的问题
文档采集 来源本身不可靠或已过时
文档切分 关键条件被切到另一个 Chunk
Embedding 语义表示没有捕捉关键差异
Retrieval 正确文档未进入候选集合
Rerank 不相关片段被排到前面
Generation 模型忽略证据或在证据外扩写
Citation 引用编号与实际结论不对应

因此,更准确的表达是:

RAG 可以降低知识缺失和来源不可追溯导致的幻觉,但不能保证答案百分之百正确。

如何检测幻觉?

没有一种方法可以在所有任务中完美识别幻觉。实际系统通常组合多种手段。

1. 来源核对

对每个可验证陈述检查:

1
2
3
4
5
回答中的 Claim
↓
是否能在给定来源中找到支持?
↓
支持 / 冲突 / 未提及

这是文档问答和 RAG 最重要的检测方式之一。

2. 外部事实核验

使用权威数据库、搜索引擎、知识图谱或官方 API 验证:

  • 人名与机构;
  • 时间和地点;
  • 产品版本;
  • 法律条款;
  • 医疗与金融信息;
  • 论文 DOI;
  • 实时价格和状态。

关键点是让外部系统提供证据,而不是让同一个模型仅凭参数再次判断自己是否正确。

3. 多次采样检查一致性

对同一问题生成多个回答:

1
2
3
回答 A:作者是张三
回答 B:作者是李四
回答 C:作者是王五

如果关键事实高度不一致,说明模型可能处于不稳定或知识不足状态。SelfCheckGPT 就利用了类似思想:事实性较强的内容在多次采样中通常更一致,而幻觉内容可能出现分歧。

但必须注意:

1
多次回答一致 ≠ 一定真实

模型也可能稳定复现同一个训练数据误解。

4. 使用 NLI 或验证模型

Natural Language Inference 可以判断某个 Claim 与来源之间属于:

  • Entailment:来源支持;
  • Contradiction:来源冲突;
  • Neutral:来源没有足够信息。

验证模型本身也会出错,所以高风险场景不能只依赖另一个 LLM 给出的单次评分。

5. 确定性程序校验

能用程序确定的问题,优先使用程序:

内容 适合的验证方式
数学计算 计算器或代码执行
JSON 格式 JSON Schema
日期关系 日期库
SQL 查询 只读数据库执行
API 参数 类型系统和官方 Schema
引用编号 程序检查编号是否存在
代码正确性 编译、单元测试和静态分析

不要让模型用自然语言“保证”代码可以运行,应该真正执行代码。

6. 人工审核

医疗、法律、金融、安全控制等高风险任务,需要领域专家审核关键结论。自动检测只能降低成本,不能把责任完全交给模型。

如何降低幻觉?

治理幻觉最好采用分层防御,而不是只改一句 Prompt。

生成前:改善输入与证据

  • 使用可靠、及时、去重的数据源;
  • 通过 RAG 提供与问题相关的证据;
  • 对检索结果进行 Rerank;
  • 清晰标注来源边界、时间和版本;
  • 删除互相冲突或无关的上下文;
  • 对用户问题中的错误前提进行检查;
  • 为外部事实提供搜索、数据库和计算工具。

生成中:限制模型的自由度

可以在 Prompt 中明确:

1
2
3
4
5
只根据给定资料回答。
如果资料没有提供答案,请回答“根据现有资料无法确定”。
不要补充资料之外的人名、数字、日期或引用。
每个关键结论都需要标明来源编号。
如果问题包含错误前提,请先指出错误。

还可以使用:

  • 结构化输出;
  • 枚举或受限解码;
  • 合理的 Temperature;
  • Function Calling;
  • 允许 Abstention,也就是拒答;
  • 先提取证据,再生成结论。

生成后:验证与拦截

  • 将回答拆成原子 Claim;
  • 检查每个 Claim 是否有证据;
  • 验证引用是否存在且真正支持结论;
  • 对数字、日期和代码使用确定性工具;
  • 对高风险内容设置人工审批;
  • 证据不足时删除结论或降级为不确定表述;
  • 记录失败案例,加入持续评测集。

可以形成下面的治理流程:

1
2
3
4
5
6
7
8
9
10
11
12
用户问题
↓
检索与工具获取证据
↓
模型生成带引用的候选回答
↓
Claim 拆分
↓
证据与程序验证
↓
通过 → 返回答案
失败 → 重试、拒答或人工审核

Prompt 应该怎样写?

不够可靠的写法

1
请准确回答下面的问题,不要产生幻觉。

“不要幻觉”没有告诉模型证据是什么,也没有定义信息不足时应该怎么办。

更可靠的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
你是一个基于资料回答问题的助手。

规则:
1. 只使用 <sources> 中的信息回答;
2. 每个事实性结论后标注来源编号,例如 [S1];
3. 如果来源没有提供答案,回答“根据现有资料无法确定”;
4. 如果来源之间冲突,明确列出冲突,不要自行选择;
5. 不要编造人名、数字、日期、链接或引用。

<sources>
[S1] ……
[S2] ……
</sources>

问题:……

这类 Prompt 不能保证零幻觉,但它给出了:

  • 允许使用的信息边界;
  • 证据表达方式;
  • 信息不足时的行为;
  • 来源冲突时的处理规则;
  • 明确禁止编造的字段。

实战一:观察模型如何面对不存在的事实

下面使用本地小模型,对一个虚构论文提问,并对比普通 Prompt 与允许拒答的 Prompt。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"

tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(MODEL_ID)
model.eval()


def ask(system_prompt: str, question: str) -> str:
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": question},
]

inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_tensors="pt",
return_dict=True,
)

with torch.inference_mode():
output_ids = model.generate(
**inputs,
max_new_tokens=160,
do_sample=False,
)

new_tokens = output_ids[0, inputs["input_ids"].shape[1]:]
return tokenizer.decode(new_tokens, skip_special_tokens=True)


question = (
"请介绍论文《Quantum Coffee Networks for Large Language Models》,"
"包括作者、发表年份和主要贡献。"
)

normal_answer = ask(
"你是一名乐于助人的人工智能助手。",
question,
)

cautious_answer = ask(
"""你是一名事实核查助手。
如果无法从可靠资料确认某个实体存在,必须明确回答无法确认。
不要根据标题编造作者、年份、期刊或研究内容。
请区分已知事实与推测。""",
question,
)

print("=== 普通 Prompt ===")
print(normal_answer)

print("\n=== 允许拒答的 Prompt ===")
print(cautious_answer)

不同模型可能给出不同结果。这个实验的目的不是证明某个 Prompt 可以彻底消除幻觉,而是观察:

  • 模型面对不存在或无法确认的实体时是否会补全细节;
  • 明确允许拒答后,行为是否发生变化;
  • 小模型的指令遵循能力是否足以执行这些约束。

即使模型回答“无法确认”,也不能反向证明论文一定不存在。真正验证仍需要查询可信论文数据库。

实战二:用多次采样观察回答稳定性

下面对同一个问题采样多次,并用 Python 标准库计算回答之间的文本相似度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from difflib import SequenceMatcher

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"

tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(MODEL_ID)
model.eval()

messages = [
{
"role": "user",
"content": (
"请介绍论文《Quantum Coffee Networks for Large Language Models》,"
"包括作者、发表年份和主要贡献。"
),
}
]

inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_tensors="pt",
return_dict=True,
)

answers = []

for seed in range(5):
torch.manual_seed(seed)

with torch.inference_mode():
output_ids = model.generate(
**inputs,
max_new_tokens=160,
do_sample=True,
temperature=0.9,
top_p=0.9,
)

new_tokens = output_ids[0, inputs["input_ids"].shape[1]:]
answer = tokenizer.decode(new_tokens, skip_special_tokens=True)
answers.append(answer)


def similarity(a: str, b: str) -> float:
return SequenceMatcher(None, a, b).ratio()


for index, answer in enumerate(answers, 1):
print(f"\n=== 回答 {index} ===")
print(answer)

scores = []
for i in range(len(answers)):
for j in range(i + 1, len(answers)):
scores.append(similarity(answers[i], answers[j]))

average_similarity = sum(scores) / len(scores)
print(f"\n回答两两平均文本相似度:{average_similarity:.3f}")

如果作者、年份和内容在多次回答中不断变化,这是一个明显风险信号。但这个简单脚本只比较字符串,不理解语义;即使所有回答完全一致,也不能证明它们是真实的。

SelfCheckGPT 等方法会使用更强的语义判断,但“自洽”始终不能替代外部证据。

实战三:验证回答中的引用编号

对于 RAG,可以要求模型只能引用已有来源编号,再使用程序检查它是否编造编号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import re


def validate_citation_ids(answer: str, valid_ids: set[str]) -> dict:
cited_ids = set(re.findall(r"\[(S\d+)]", answer))

return {
"cited_ids": sorted(cited_ids),
"invalid_ids": sorted(cited_ids - valid_ids),
"has_invalid_citation": bool(cited_ids - valid_ids),
}


sources = {
"S1": "退款申请需要在签收后 7 天内提交。",
"S2": "定制商品不支持无理由退款。",
}

answer = (
"普通商品应在签收后 7 天内提交退款申请 [S1]。"
"所有商品都可以无理由退款 [S3]。"
)

result = validate_citation_ids(answer, set(sources))
print(result)

输出为:

1
2
3
4
5
{
'cited_ids': ['S1', 'S3'],
'invalid_ids': ['S3'],
'has_invalid_citation': True
}

这能发现不存在的 [S3],却仍然不能证明 [S1] 真的支持前面的结论。完整验证还需要检查:

1
2
3
4
5
引用是否存在
+
引用内容是否支持对应 Claim
+
来源本身是否可信和最新

实战四:把回答拆成可验证 Claim

复杂回答如果整段核验,很容易漏掉局部错误。更实用的方法是先要求模型输出原子化 Claim,再逐条验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
claims = [
{
"id": "C1",
"text": "退款申请需要在签收后 7 天内提交。",
"source_ids": ["S1"],
},
{
"id": "C2",
"text": "定制商品支持无理由退款。",
"source_ids": ["S2"],
},
]

sources = {
"S1": "退款申请需要在签收后 7 天内提交。",
"S2": "定制商品不支持无理由退款。",
}

for claim in claims:
evidence = [
sources[source_id]
for source_id in claim["source_ids"]
if source_id in sources
]

print("Claim:", claim["text"])
print("Evidence:", evidence)
print("需要进一步判断:支持、冲突还是证据不足")
print()

在真实系统中,最后一步可以交给:

  • 规则程序;
  • NLI 模型;
  • 另一个验证模型;
  • 权威数据库;
  • 人工审核者。

不要只让原生成模型在没有证据的情况下回答“我刚才是否产生了幻觉”,因为它可能再次生成一个听起来合理的判断。

如何评估一个系统的幻觉率?

一个可靠的评测流程至少需要:

1
2
3
4
5
6
7
8
9
10
11
固定评测问题
↓
准备可验证的参考答案或证据
↓
运行完整的 Prompt、RAG 和工具链
↓
把回答拆成 Claim
↓
标注 Supported / Contradicted / Unsupported
↓
统计不同错误类型

可以关注以下指标:

指标 含义
Claim Precision 生成的事实性 Claim 中有多少得到支持
Citation Precision 引用有多少真正支持对应结论
Citation Recall 应该引用的关键结论有多少提供了引用
Abstention Accuracy 证据不足时是否正确拒答
Contradiction Rate 回答与来源直接冲突的比例
Unsupported Rate 回答中缺少来源支持的比例
Task Accuracy 最终任务答案是否正确

只评估“回答是否流畅”或“用户是否喜欢”,无法充分衡量幻觉。

评测集必须包含困难情况

除了普通问题,还应该主动加入:

  • 不存在的实体;
  • 带错误前提的问题;
  • 来源互相冲突的问题;
  • 来源没有答案的问题;
  • 数字和单位非常接近的问题;
  • 过时信息与新信息混合的问题;
  • 需要调用工具才能回答的问题;
  • 长上下文中间位置的信息;
  • 诱导模型编造引用的问题。

系统是否可靠,不只看“知道时能否答对”,还要看“不知道时能否承认不知道”。

不同场景需要不同的风险控制

场景 幻觉的主要影响 建议控制方式
创意写作 通常较低 明确区分虚构与事实即可
日常问答 中等 引用来源、允许不确定表达
企业知识库 中高 RAG、权限过滤、Claim 验证
编程助手 中高 官方文档、编译、测试、静态分析
数据分析 高 使用真实查询和计算工具
医疗、法律、金融 很高 权威来源、专业审核、明确责任边界
自动执行 Agent 很高 最小权限、参数校验、审批和回滚

同一个幻觉,在闲聊中可能只是体验问题,在自动转账、修改生产配置或提供医疗建议时,可能造成严重后果。

常见误区

误区一:模型越大就不会幻觉

更大的模型通常拥有更强知识和推理能力,但仍可能生成错误内容。模型规模不是事实保证机制。

误区二:Temperature 设置为 0 就没有幻觉

Greedy Decoding 只是稳定选择当前最高分 Token。如果最高分答案是错误的,模型会稳定地重复同一个错误。

误区三:回答越详细越可信

模型可以同时编造人物、日期、论文和链接。细节越多,有时只是可核验的错误点越多。

误区四:模型说“我很确定”就代表置信度高

自然语言中的肯定语气也是生成结果,不是经过校准的事实概率。

误区五:有引用就不是幻觉

引用可能不存在、指向错误页面,或者根本不支持对应结论。必须验证引用内容。

误区六:RAG 可以彻底消除幻觉

RAG 仍可能发生错误检索、来源过时、上下文冲突、证据误读和无来源扩写。

误区七:同一个问题多问几次,答案一致就是真的

一致性只能说明模型输出稳定,不能证明答案符合现实。

误区八:让另一个 LLM 审核就一定可靠

验证模型也会幻觉、受提示影响或与生成模型共享相同误解。高风险内容需要确定性工具和人工审核。

误区九:只要 Prompt 写得足够好,就能实现零幻觉

Prompt 可以明确行为边界,但无法补充模型没有的实时知识,也无法替代外部验证。

误区十:幻觉只是模型的问题

完整系统中的数据源、检索、文档解析、工具、缓存、Prompt 和后处理都可能引入错误。治理对象应该是整条应用链路。

工程实践建议

  1. 先定义哪些输出属于事实性 Claim,哪些允许创造;
  2. 对需要事实的任务提供可靠且及时的外部证据;
  3. 明确要求证据不足时拒答,不要强迫模型必须给结论;
  4. 把复杂回答拆成原子 Claim,逐条验证;
  5. 要求引用来源,同时验证引用是否真实支持结论;
  6. 数学、代码、SQL、日期和结构化数据优先交给工具执行;
  7. 不要把 Token Probability 直接当成事实置信度;
  8. 同时评估事实性、忠实性、引用质量和拒答能力;
  9. 保存线上失败案例,持续加入回归评测;
  10. 根据风险等级设置自动返回、降级、拒答或人工审核;
  11. 给 Agent 设置最小权限、审批点和可回滚机制;
  12. 向最终用户清楚标明生成内容、来源和不确定性。

小结

本文的核心结论可以总结为:

  1. LLM 幻觉是指模型生成与事实、来源或可验证证据不一致,或者缺少依据却被表达为事实的内容;
  2. 幻觉不等于所有错误,也不等于模型在有意撒谎;
  3. Factuality 关注现实正确性,Faithfulness 关注是否忠于给定来源;
  4. LLM 的核心训练目标是预测下一个 Token,而不是自动完成事实验证;
  5. 数据噪声、参数化知识、知识边界、错误前提、长上下文和逐 Token 累积都可能造成幻觉;
  6. 高概率只代表模型的生成偏好,不等于事实正确率;
  7. 降低 Temperature 不能从根本上消除幻觉;
  8. RAG 能提供外部证据,但检索、来源和生成阶段仍可能出错;
  9. 多次采样的一致性只能提供风险信号,不能代替外部事实核验;
  10. 可靠系统需要检索、工具、Claim 验证、拒答、评测和人工审核组成分层防御。

模型生成文本的能力与验证事实的能力不是同一件事。真正可靠的 LLM 应用,不是要求模型“永远不要犯错”,而是让系统能够:

1
2
3
4
有证据时给出可追溯答案
证据冲突时明确说明冲突
证据不足时承认无法确定
高风险时交给工具或人类审核

下一篇文章将进入模型内部,介绍 Transformer 如何通过 Self-Attention、残差连接和前馈网络处理上下文,并最终产生下一个 Token 的 Logits。

参考资料