AI产品翻车实录:模型总结幻觉的三大类型与检测方案

AI产品翻车实录:模型总结幻觉的三大类型与检测方案

上回聊了 TLDR Scholar 输入端的坑------哪些论文读不了,什么格式会挂,多模态内容怎么处理。今天换个方向:模型读懂了,但输出总结的时候自己编了一套东西出来。

说个具体的。有次我拿一篇 CVPR 论文去测,原文作者是 "Zhang et al., 2024",模型生成的引用里写成了 "Zhang et al., 2019",人名都对但年份差了5年。我顺藤摸瓜去搜这篇 "2019年"的论文,压根不存在。那一刻我才意识到:模型读这篇论文确实读完了,但它输出引用的时候,不是去"查"了真实数据,而是靠概率"猜"了一个看起来合理的值。

这个问题比输入端翻车更隐蔽------用户看不到原始论文全文,只看到模型产出的总结,如果总结里夹着编造的信息,用户根本不知道。

LLM 的幻觉其实分好几个层次。按学术界给它的分法,比较常见的是事实性幻觉 (编造不存在的东西)、逻辑性幻觉 (推理链断裂)、忠实性幻觉(偏离原文意思)。跟论文总结最相关的是其中三类,也就是下面要聊的三个翻车场景。


伪造引用:模型在填空,不是在查书

现象

模型生成的引用看起来特别真------DOI 格式是对的,作者名是常见的,期刊名也真实存在。但它编出来的论文就是搜不到。这不是偶发,在早期版本的 TLDR Scholar 里,差不多每五六篇总结就会出现一次伪造引用。

根因分析

这个问题说白了,是模型本身的机制决定的。LLM 在做文本生成的时候,本质上是在概率空间里做"填空"------给定上文,预测下一个 token 最可能是什么。它见过大量的学术论文,知道引用的常见格式,知道 "et al." 后面通常跟年份,知道年份一般是四位数。但它不知道这个引用对应的论文是否存在。

我自己的理解:它不是在"回忆"数据,而是在"模仿"格式。

检测方案

对付伪造引用,我们试过几套方案,最实用的是 DOI 和 arXiv ID 交叉校验

python 复制代码
import re
import requests

def verify_reference(text):
    """
    从总结文本中摘出引用,做交叉校验。
    返回检测到的引用列表,含校验结果。
    """
    # 匹配常见的 arXiv ID 模式
    arxiv_pattern = r'arXiv:\d{4}\.\d{4,5}'
    # 匹配 DOI 模式
    doi_pattern = r'(10\.\d{4,}/[-._;()/:A-Za-z0-9]+)'
    
    arxiv_ids = re.findall(arxiv_pattern, text)
    dois = re.findall(doi_pattern, text)
    
    results = []
    for arxiv_id in arxiv_ids:
        # 调用 arXiv API 做存在性校验
        resp = requests.get(f"https://export.arxiv.org/api/query?id_list={arxiv_id.split(':')[1]}", timeout=5)
        exists = resp.status_code == 200 and len(resp.text) > 200
        results.append({"type": "arxiv", "id": arxiv_id, "verified": exists})
    
    for doi in dois:
        # 通过 doi.org 做重定向校验
        resp = requests.head(f"https://doi.org/{doi}", allow_redirects=True, timeout=5)
        results.append({"type": "doi", "id": doi, "verified": resp.status_code == 200})
    
    return results

这段代码做的事情很简单:从总结文本里用正则摘出 arXiv ID 和 DOI,然后去对应 API 校验是否存在。每次检测到伪造引用,就把对应的段落标记出来,提示用户"生成的引用可能存在偏差,建议核实原文"。

这个方案也有个问题------它只能校验有标准编号的引用。如果模型编了一个没有 DOI 的普通期刊引用,比如:

Smith, J. (2023). A new approach. Journal of AI.

就没有简单的方法验证它是否存在。我们当时的做法是对这类引用加一个"可信度较低"的标记,让用户自己判断。


结论扭曲:关键信息在传输中丢失

现象

比伪造引用更难察觉的是结论扭曲。模型读完了论文,然后给你概括了一个"看起来对但实际偏了"的结果。

举一个我们真实遇到的 case。有一篇论文的核心结论是:

提出的方法 A 在某些场景下效果不错,但有三个明显的限制------数据量要求高、训练时间长、泛化能力不足。

TLDR Scholar 生成的总结是:

方法 A 在实验中表现良好,是一种有效的解决方案。

限制条件全丢了。

乍一看这个总结没错,但实际上它传达了错误的信息:如果把这篇总结当参考,你可能会认为方法 A 可以直接用,但实际上它在你的场景下可能根本跑不通。

根因分析

这个问题出在两个环节叠加。一方面是随着输入文本变长,模型的注意力会自然衰减------开头和结尾的内容被记住了,中段细节被模糊了。另一方面是提示词本身有偏------我们写 prompt 的时候强调的是"总结核心内容",模型倾向于把"正面结论"当作"核心内容"。

检测方案

我们的做法是对比原文关键实体在总结中的覆盖度。

python 复制代码
def check_entity_coverage(original_text, summary):
    """
    对比原文和总结中的关键实体覆盖度。
    如果总结丢掉了原文中的重要描述(如限制条件、负面结论),标记出来。
    """
    # 用 NLP 抽取原文中的实体和关系
    # 这里简化展示:用关键词匹配检测"限制类"短语
    limitation_phrases = [
        "limitation", "drawback", "however", "but", "limited to",
        "does not", "fails to", "not suitable", "requires", "only works"
    ]
    
    original_has_limitations = any(
        phrase in original_text.lower() for phrase in limitation_phrases
    )
    
    summary_has_limitations = any(
        phrase in summary.lower() for phrase in limitation_phrases
    )
    
    if original_has_limitations and not summary_has_limitations:
        return {
            "status": "LIMITATION_DROPPED",
            "message": "原文包含限制性表述,但总结中未体现,建议核实"
        }
    
    return {"status": "PASS"}

这段代码看的是"原文有限制性描述,总结里却没有"的情况。逻辑很简单但效果不错------能抓到将近一半的结论扭曲问题。

局限性也很明显:阈值不好设。关键词匹配太松了误报多,太紧了漏报多。比如论文原文写了 "the method does have some constraints" 这种委婉的表达,关键词不一定能命中。后来我们换成语义相似度评分(计算原文关键句和总结句的余弦相似度),召回率提升了一些,但误报也跟着涨了。


数字篡改:当精度成为一种幻觉

现象

这个相对好懂。论文里写 "准确率从 78% 提升到 89%",模型输出 "准确率从 87% 提升到 89%"。数字变了,结论可能也跟着变了。

我印象比较深的一次:论文里实验部分写的是:

我们的方法在 5 个数据集上平均准确率达到 78%。

模型产出的总结变成了:

平均准确率达到 87%。

差了将近十个百分点。如果这是一个在做技术选型的工程师拿这个数据做决策,他可能会选择一个实际上没那么好的方法。

根因分析

这个我后来想了一下,跟数字在语言模型中的表示方式有关。数值在语义空间里是"模糊"的------模型学到的不是精确的数值,而是"某个大概的范围"。78 和 87 在语义空间中非常接近(都属于"七八十这个区间"),模型在生成的时候"猜偏"了。

检测方案

方案的核心思路是:从原文和总结里分别抽数值对,然后做比较。

python 复制代码
import re

def check_numeric_consistency(original, summary):
    """
    抽取出原文和总结中的数值,做一致性校验。
    如果同一上下文的数值偏差过大,标记出来。
    """
    # 提取数值及上下文
    pattern = r'(\d+\.?\d*%?)'  # 匹配数字及百分号
    
    original_nums = [(m.group(), original[max(0, m.start()-30):m.end()+30]) 
                     for m in re.finditer(pattern, original)]
    summary_nums = [(m.group(), summary[max(0, m.start()-30):m.end()+30]) 
                    for m in re.finditer(pattern, summary)]
    
    issues = []
    for s_val, s_ctx in summary_nums:
        matched = False
        for o_val, o_ctx in original_nums:
            # 检查上下文是否相关
            if len(set(s_ctx.split()) & set(o_ctx.split())) > 3:
                matched = True
                if s_val.replace('%', '') != o_val.replace('%', ''):
                    issues.append({
                        "original": o_val,
                        "summary": s_val,
                        "context": s_ctx.strip()
                    })
                break
    
    return issues

这个方法用在 TLDR Scholar 上之后,差不多每次跑完能抓到一两个数字偏差。我们会把它们挑出来人工确认,确实有偏差的就修正。

但这个方案也有漏洞------论文里常见的"大幅提升""显著优于"这类相对表述,没有数值可对比,检测不了。我们的做法是对这类情况保持沉默,不标记也不修正,因为强加一个数值反而会误导。


三类检测方案的对比

三类问题对应三种检测手段,各有各的适用场景和成本:

检测方案 覆盖问题 适用场景 可靠性 主要成本
DOI/arXiv 交叉校验 伪造引用 有标准编号的引用 高(有明确结果) 网络请求耗时,可能被封
实体覆盖度检查 结论扭曲 原文限制性表述明显 中等(阈值敏感) NLP 模型推理成本
数值一致性校验 数字篡改 出现具体数值的场景 中等(上下文匹配有误差) 正则+NLP 轻度计算

实际落地的时候,这三套方案不是都跑满的。按我们线上的经验,引用校验是必跑项,因为成本不高而且结果明确。实体覆盖度和数值校验放在异步离线任务里跑,跑完了把结果写入一条检测记录,前端根据记录做展示。


兜底策略:检测搞不定的事

说实话,上面这三套方案没有一个能做到 100%。我自己的感受是:检测层能把七八成的问题挑出来,剩下的得靠其他手段补。

我们在 TLDR Scholar 里做了两件事:

一个是人工抽检规则。 系统每处理 50 篇论文,随机抽 1 篇交给人工审核。审核员对照原文检查总结质量。这套抽检不是为了修 bug,而是为了发现系统性偏差------如果某段时间某个检测指标突然掉下去了,说明模型行为可能变了,需要调 prompt 或者换策略。

另一个是交互层的可信度提示。 每段总结后面加了一个小型提示标记,降低用户对 AI 产出的盲目信任:

标记 含义 条件
🟢 已验证 引用交叉校验通过,数值一致 所有检测均未发现问题
🟡 需核实 检测到可能偏差 伪造引用/遗漏限制/数值不一致
⚪ 未检测 当前无法自动验证 建议参考原文判断

这个设计不是为了装样子------用户看到 🟡 标记之后,确实会更谨慎地查看原文对照。我们后台的数据是:带 🟡 标记的内容被点击"查看原文"的概率比 🟢 标记高了将近一倍。


翻车系列写了两篇,回头来看其实是个蛮有意思的过程。输入端翻车告诉你"不是所有论文都能被 AI 读懂",输出端翻车告诉你"读懂了也不代表它能说对"。这两个问题叠在一起,才是 AI 论文阅读工具的真实水平------不是不能用,但得知道它会在什么地方犯错。

做 AI 产品就是这样,踩的坑越具体,你对产品的边界理解就越清楚。下次如果再遇到"模型编了一个看起来挺真的引用",至少你知道怎么把它揪出来了。

相关推荐
狂师1 小时前
端开发必装 Skill 清单:6 款 AI 技能,让你的开发效率原地起飞
前端·程序员·开源
3630458411 小时前
KlineChartQuant Tooltip 高频交互 200FPS 性能优化完整复盘
前端·架构
小蠢驴打代码1 小时前
AI 编程助手总是失忆?我做了一个纯 Markdown 的本地工程记忆库
ai编程
AINative软件工程1 小时前
Agent 任务别只存日志:Checkpoint Replay 才是生产排障的底座
openai
TrisighT1 小时前
Agent 流式响应你只拼 delta 就完事了?三个暗坑修完,白烧的 token 少了 68%
aigc·agent·ai编程
嘉泰姆半导体官方1 小时前
CXAR41337C 双通道数字音频功放 | 2×20W | EQ+DRC | I²S | MCLK-Less - 嘉泰姆电子
前端·javascript·数据库
PedroQue991 小时前
uni-router v2.0.0:四大功能拆分为插件,按需加载
前端·uni-app
暗不需求1 小时前
目前最火AI协议-> MCP 协议实战:从原理到落地,让 AI 拥有"超能力"
面试·ai编程·mcp
Lazy_zheng1 小时前
TDD 实战:Claude Code Superpowers 保姆级教程14 个 Skills 全解析 + 实战开发
前端·claude·vibecoding