为什么 LLM 会"一本正经地胡说八道":幻觉的工程视角
做 AI 系统最常被问的一个问题:模型为什么会犯错?"幻觉"这个词听起来玄乎,拆开看其实是几件很具体的事。

为什么 LLM 会"一本正经地胡说八道":幻觉的工程视角
做 AI 系统最常被问的一个问题:模型为什么会犯错?"幻觉"这个词听起来玄乎,拆开看其实是几件很具体的事。
先说清楚的:幻觉不是 bug,是训练方式的副产品。大模型是在海量文本上学习"下一个词最可能是什么",它优化的是语言流畅度,不是事实一致性。文本里"说得通"的句子滚着多,它就更倾向于生成说得通的内容——哪怕内容本身是编的。所以越是流畅的语言,越容易把错误信息包装得像真知识。
具体来看,文本幻觉有几个常见来源:
第一,训练数据稀疏事实。模型见过的数据里,"李白的《静夜诗》写于 726 年"这种细粒度事实往往没有交叉验证,参数里没有可靠的存储路径,生成时就被语言先验拽走了。
第二,**上下文张力**。用户给了一个错误前提,比如"法国首都是里昂",模型为了把对话连贯地接下去,大概率会顺着这个错误前提把它输出,而不是纠正它。这不是智商问题,是继续匹配的分布更平。
第三,温度。temperature 调高后,生成会更意外,也就更容易偏离事实。生产上对事实密集型任务,文本要保持低温。
文档场景下还有一个经典误区:给 RAG 塞了文档,幻觉就消失了吗?并不一定。模型可能忽略文档,改用它预训练的参数知识补全信息;也可能文档本身不全,它就用填充。你验证检索命中了,不代表模型用了检索。
能做什么?几条实践中比较有用的方向。
**事实型任务上做显式校验**。让模型先复述"我看到的事实是 X,依据是文档 Y",再回答。把"依据"这个字段填不掉,就会触发拒绝回答的分支。这比调 prompt 语气管用得多,本质上是在结构上强制文本执行一个"检索"的动作。
**给文本一个"不知道"的节奏**。很多模型默认倾向把空白填上,因为训练数据里"我不知道"几乎不出现。你要么在文本里直接写"如果你不知道,请回答'根据现有信息无法得出此结论'",要么用微调,加一条专门训练不确定性输出的数据。
**校验在文本侧,不在模型侧**。把代码跑一遍比信任模型的文本计算可靠得多。把一个生精子 JSON 过 JSON schema 验证,比告诉模型"请务必输出合法的 JSON"便宜得多——这也是为什么有 reason、calibrate 这种"后校验"的存在理由。
**别用"请记住"来修真相**。很多团队会在 prompt 里加一大段"请记住事实 A/B/C",短期内有效,长文本下会被注意力稀释。更稳的做法是把文本直接挂在系统参数里,然后用"长对话摘要"把相关约束再压缩一遍。
一句话收束:文本能做的事很少,大多数文本系统的问题不出在"模型文",而出在没有给文本结构化的质控手段——校验、回退、不确定性的拒绝回答。
**验证也要分层做**。不是所有错误都需要重新建模。事实层面的断裂(日期、名字、数字)可以后置校验:生成完再调一个轻量工具核查其中一个字段。整个编造的段落(不存在的API、看起来像真的引用)需要用检索覆盖、引用追溯来消解。两类错误对应成本不同的修复路径,混在一起看"幻觉率"这个数字,会一直让修复方向偏向通用方案。
**把否定也用正例表达**。很多团队在 prompt 里写"不要编造事实",效果有限,因为模型对"不要"的执行更多取决于上下文分布,而不是指令措辞。更有效的写法是给出"不知道时的示例回复",让模型握住一个具体的、可模仿的形式,而不是一个抽象禁止。
**监控长短不一的失败模式**。上线后,把幻觉分成"小事实错"(日期、数字)和"整段编造"(条纹不存在的API)两类分别埋点。前者的修复方案是 schema 校验 + 低文本,后者的修复方案是 RAG 覆盖率 + 重试,只用一个总体"幻觉率"指标,会看不到这两种差异。
留言区
欢迎分享你的想法!
加载留言中…