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 交叉校验。importreimportrequestsdefverify_reference(text): 从总结文本中摘出引用做交叉校验。 返回检测到的引用列表含校验结果。 # 匹配常见的 arXiv ID 模式arxiv_patternrarXiv:\d{4}\.\d{4,5}# 匹配 DOI 模式doi_patternr(10\.\d{4,}/[-._;()/:A-Za-z0-9])arxiv_idsre.findall(arxiv_pattern,text)doisre.findall(doi_pattern,text)results[]forarxiv_idinarxiv_ids:# 调用 arXiv API 做存在性校验resprequests.get(fhttps://export.arxiv.org/api/query?id_list{arxiv_id.split(:)[1]},timeout5)existsresp.status_code200andlen(resp.text)200results.append({type:arxiv,id:arxiv_id,verified:exists})fordoiindois:# 通过 doi.org 做重定向校验resprequests.head(fhttps://doi.org/{doi},allow_redirectsTrue,timeout5)results.append({type:doi,id:doi,verified:resp.status_code200})returnresults这段代码做的事情很简单从总结文本里用正则摘出 arXiv ID 和 DOI然后去对应 API 校验是否存在。每次检测到伪造引用就把对应的段落标记出来提示用户生成的引用可能存在偏差建议核实原文。这个方案也有个问题——它只能校验有标准编号的引用。如果模型编了一个没有 DOI 的普通期刊引用比如Smith, J. (2023). A new approach. Journal of AI.就没有简单的方法验证它是否存在。我们当时的做法是对这类引用加一个可信度较低的标记让用户自己判断。结论扭曲关键信息在传输中丢失现象比伪造引用更难察觉的是结论扭曲。模型读完了论文然后给你概括了一个看起来对但实际偏了的结果。举一个我们真实遇到的 case。有一篇论文的核心结论是提出的方法 A 在某些场景下效果不错但有三个明显的限制——数据量要求高、训练时间长、泛化能力不足。TLDR Scholar 生成的总结是方法 A 在实验中表现良好是一种有效的解决方案。限制条件全丢了。乍一看这个总结没错但实际上它传达了错误的信息如果把这篇总结当参考你可能会认为方法 A 可以直接用但实际上它在你的场景下可能根本跑不通。根因分析这个问题出在两个环节叠加。一方面是随着输入文本变长模型的注意力会自然衰减——开头和结尾的内容被记住了中段细节被模糊了。另一方面是提示词本身有偏——我们写 prompt 的时候强调的是总结核心内容模型倾向于把正面结论当作核心内容。检测方案我们的做法是对比原文关键实体在总结中的覆盖度。defcheck_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_limitationsany(phraseinoriginal_text.lower()forphraseinlimitation_phrases)summary_has_limitationsany(phraseinsummary.lower()forphraseinlimitation_phrases)iforiginal_has_limitationsandnotsummary_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 在语义空间中非常接近都属于七八十这个区间模型在生成的时候猜偏了。检测方案方案的核心思路是从原文和总结里分别抽数值对然后做比较。importredefcheck_numeric_consistency(original,summary): 抽取出原文和总结中的数值做一致性校验。 如果同一上下文的数值偏差过大标记出来。 # 提取数值及上下文patternr(\d\.?\d*%?)# 匹配数字及百分号original_nums[(m.group(),original[max(0,m.start()-30):m.end()30])forminre.finditer(pattern,original)]summary_nums[(m.group(),summary[max(0,m.start()-30):m.end()30])forminre.finditer(pattern,summary)]issues[]fors_val,s_ctxinsummary_nums:matchedFalseforo_val,o_ctxinoriginal_nums:# 检查上下文是否相关iflen(set(s_ctx.split())set(o_ctx.split()))3:matchedTrueifs_val.replace(%,)!o_val.replace(%,):issues.append({original:o_val,summary:s_val,context:s_ctx.strip()})breakreturnissues这个方法用在 TLDR Scholar 上之后差不多每次跑完能抓到一两个数字偏差。我们会把它们挑出来人工确认确实有偏差的就修正。但这个方案也有漏洞——论文里常见的大幅提升显著优于这类相对表述没有数值可对比检测不了。我们的做法是对这类情况保持沉默不标记也不修正因为强加一个数值反而会误导。三类检测方案的对比三类问题对应三种检测手段各有各的适用场景和成本检测方案覆盖问题适用场景可靠性主要成本DOI/arXiv 交叉校验伪造引用有标准编号的引用高有明确结果网络请求耗时可能被封实体覆盖度检查结论扭曲原文限制性表述明显中等阈值敏感NLP 模型推理成本数值一致性校验数字篡改出现具体数值的场景中等上下文匹配有误差正则NLP 轻度计算实际落地的时候这三套方案不是都跑满的。按我们线上的经验引用校验是必跑项因为成本不高而且结果明确。实体覆盖度和数值校验放在异步离线任务里跑跑完了把结果写入一条检测记录前端根据记录做展示。兜底策略检测搞不定的事说实话上面这三套方案没有一个能做到 100%。我自己的感受是检测层能把七八成的问题挑出来剩下的得靠其他手段补。我们在 TLDR Scholar 里做了两件事一个是人工抽检规则。系统每处理 50 篇论文随机抽 1 篇交给人工审核。审核员对照原文检查总结质量。这套抽检不是为了修 bug而是为了发现系统性偏差——如果某段时间某个检测指标突然掉下去了说明模型行为可能变了需要调 prompt 或者换策略。另一个是交互层的可信度提示。每段总结后面加了一个小型提示标记降低用户对 AI 产出的盲目信任标记含义条件 已验证引用交叉校验通过数值一致所有检测均未发现问题 需核实检测到可能偏差伪造引用/遗漏限制/数值不一致⚪ 未检测当前无法自动验证建议参考原文判断这个设计不是为了装样子——用户看到 标记之后确实会更谨慎地查看原文对照。我们后台的数据是带 标记的内容被点击查看原文的概率比 标记高了将近一倍。翻车系列写了两篇回头来看其实是个蛮有意思的过程。输入端翻车告诉你不是所有论文都能被 AI 读懂输出端翻车告诉你读懂了也不代表它能说对。这两个问题叠在一起才是 AI 论文阅读工具的真实水平——不是不能用但得知道它会在什么地方犯错。做 AI 产品就是这样踩的坑越具体你对产品的边界理解就越清楚。下次如果再遇到模型编了一个看起来挺真的引用至少你知道怎么把它揪出来了。