大语言模型在数学推理、多步逻辑分析这类任务上表现出色,但它有一个致命弱点:当它不知道答案时,往往不会沉默,而是流畅地编造一个看似合理的结论。这种幻觉现象在推理链中尤其危险,因为一步错误的中间结论会污染后续所有推导,最终输出一个完全错误却逻辑自洽的答案。解决这个问题的核心思路并不是把模型变得更强,而是让模型学会暴露自己的不确定性,也就是识别出低置信度区域,并在这些区域引入人工干预。

幻觉产生的根本原因:模型为什么不知道自己不知道
要有效检测幻觉,首先需要理解它的成因。大模型的训练目标是最大化下一个token的预测概率,它学到的是文本的统计规律而非事实本身。当一个问题触及训练数据中的稀疏区域时,模型并没有一个明确的“我不知道”机制,它会继续按照语言习惯补全最可能的词序列。这就像一个学生考试时遇到不会的题,不是留白,而是把记得的公式东拼西凑写上去,写得还挺像回事。
更麻烦的是推理任务的级联放大效应。假设一个十步的推理链,每一步的正确率是95%,十步下来整体正确率只剩不到60%。如果模型在第二步就产生了一个幻觉性的中间结论,后面的步骤会在这个错误地基上继续推导,而且越推越“自信”。这就是为什么很多推理模型的最终答案看起来逻辑严密,实际却完全错误——错误不在逻辑,而在某个被当作公理使用的虚假前提。
还有一个容易被忽视的因素是采样策略。使用temperature大于0的采样时,模型每次输出都可能不同,低概率的错误token有机会被选中。即使temperature设为0的贪心解码,也只保证局部最优,不保证全局正确。所以幻觉不是偶发的bug,而是这类模型生成机制的内生属性,只能管理,无法根除。
低置信度区域检测:从token概率到语义熵
最直接的置信度信号是token级别的概率。现代推理模型在生成时,每个token都有一个softmax概率分布,如果输出序列中存在大量概率低于阈值的token,说明模型对这些位置并不确定。实现上可以通过输出logprobs参数获取每个token的对数概率,然后计算整个序列的平均负对数似然或者困惑度作为置信度指标。
import math
def detect_low_confidence(logprobs, token_threshold=-1.5, window=5):
"""检测连续低概率token区域
logprobs: [(token, logprob), ...]
token_threshold: 单token对数概率阈值
window: 连续低概率token数量触发告警
"""
low_regions = []
streak = 0
start = None
for i, (token, lp) in enumerate(logprobs):
if lp < token_threshold:
if streak == 0:
start = i
streak += 1
else:
if streak >= window:
low_regions.append((start, i,
sum(lp for _, lp in logprobs[start:i]) / streak))
streak = 0
return low_regions不过token概率有一个明显局限:它是词汇层面的不确定性,不是语义层面的。模型可能对某个事实给出两种措辞完全不同的表述,每个token的概率都很高,但两个表述互相矛盾,这时候逐token看概率是发现不了问题的。语义熵方法正是为了解决这个问题:让模型对同一个问题采样多个回答,把这些回答聚类成若干语义等价类,然后计算语义层面的熵。如果多个回答指向不同的结论,语义熵就高,说明模型内部对答案本身就摇摆不定。
与语义熵思路相近的是自一致性采样,在数学推理场景中特别实用。让模型用较高温度采样多条推理路径,分别得出最终答案,然后统计答案的一致性比例。如果10次采样里有9次得到同一个数值,置信度就高;如果答案五花八门,这个结果大概率不可靠。这个方法不需要访问模型内部概率,只依赖API就能实现,工程上门槛很低。
from collections import Counter
def self_consistency(answers):
"""answers为多次采样的最终答案列表"""
counter = Counter(answers)
top_answer, count = counter.most_common(1)[0]
confidence = count / len(answers)
if confidence < 0.7:
return None, confidence # 标记为需人工复核
return top_answer, confidence人工干预机制的设计:分级路由与证据校验
检测出低置信度区域之后,接下来的问题是怎么处理。粗暴地把所有不确定的请求都转给人工,在业务量大时根本不可行。更合理的做法是分级路由:根据置信度分数把请求分成三档。高置信度的直接采信模型输出;中置信度的走自动校验流程,比如用检索增强补充事实依据,或者让模型对自己的推理链做一次批判性复查;低置信度的才进入人工审核队列。这样人工只需要处理最关键的百分之几的请求,成本可控。
对于推理任务,人工干预的重点不应该是检查最终答案,而是审查推理链中的关键节点。实践经验表明,让审核者通读整段推理再判断对错,效率低且容易顺着模型的思路被带偏。更有效的做法是把推理链拆解成若干可独立验证的断言,自动标注出低置信度对应的那些断言,让人工只需验证这几句话。比如一条十步的推导,系统提示第三步和第七步置信度偏低,审核者只需要核对这两步涉及的计算或事实,工作量可能只需要原来的十分之一。
证据校验是人工干预之前可以再加的一道自动防线。对推理链中的事实性断言,可以先用检索系统从知识库或权威文档中找支撑材料,找不到证据支撑的断言直接标记为待验证。这相当于把幻觉检测从概率信号扩展到了事实验证信号,两种信号交叉印证能显著降低误报率。只有既概率低又缺乏证据的断言,才真正需要人工介入。
落地实践中的几个关键问题
第一个问题是阈值的设定。置信度阈值定得太高,大量正常请求被转给人工,效率优势消失;定得太低,幻觉漏网。实践中不建议用固定的全局阈值,而应该根据任务类型和历史误报率动态调整。可以先用历史数据做离线评估,画出置信度分数与实际正确率的关系曲线(类似可靠性图),找到错误率开始明显上升的分数区间作为干预阈值,再上线后根据人工审核的反馈持续校准。
第二个问题是置信度校准本身可能有偏差。有研究发现,推理模型在经过强化学习训练后,其表达出的自信程度与实际正确率的相关性会变差——模型经常在错误答案上表现出很高的确定度。所以不能只依赖模型自身的概率信号,语义熵和自一致性这类基于多次采样的外部信号要配合使用。多种信号综合打分,比单一指标稳健得多。
第三个问题是人工干预的反馈闭环。人工纠正的结果不应该只是修掉当前这条输出,而应该回流到系统中:错误的案例可以整理成few-shot示例加入提示词,高频出错的领域可以在检索库中补充权威文档,甚至可以用来微调模型让其在该领域更谨慎。一个没有反馈闭环的人工干预系统,本质上只是给幻觉打了补丁,而一个有闭环的系统会让干预量随着时间持续下降,这才是这套方案真正的长期价值。