首先,幻觉也分类型。
一个是事实性幻觉,就是LLM凭借自身能力回答问题,但是这个回答是编的,也可能有正确答案但是LLM输出错了。总之这是LLM自身原因。
另一个是忠实性幻觉,就是你要求LLM根据你给的材料给出答案,而LLM看着材料还答错了。有时候更傻,你都说了按照材料回答,而LLM就是要自己编一个。这也是不忠实的表现。
对于RAG,还有另一个幻觉,就是你给的材料不对,可能10条材料8条是无关的,LLM硬是把这些信息融到了答案里,这也是一种"幻觉"。答案确实忠诚,也是事实,但是就是和query对不上。这种错误就得依靠强大的检索和rerank功能护航了。
为了减少幻觉,要做这些事:
- 一开始就要选择强力的模型,且对数据做过预训练和微调,裸模型对问题的性能指标就要有一些。基础打好,再用RAG框架弥补性能。等你框架搭起来,再想微调LLM,那你这框架稳不稳就不知道了,所以一般LLM微调都是一个版本调一次。
- 前处理。你这个RAG要是只针对特定领域的文档,你就别放无关问题进来,在前面就意图识别滤掉那些怪问题,然后将问题规范化or拆分成子问题。
- 检索。你要是检索回来一堆和query无关的chunk,硬答肯定出幻觉,所以对齐很重要。ANCE这个方法能很好地在训练阶段加强对负样本的学习,其实也不难,正例chunk在你训练数据里,每次你找负例都找相似度和query最大的chunk且不是正例的就行。
- 检索门槛。你的每路召回都是有所谓的相似度分数的,如果你发现不相关文档和相关文档之间的相似度分数有一个明显的差距,那么你就完全可以靠设置一个门槛来滤除那些相似度过低的chunk。这得靠你对embedding模型的训练来做到,否则正负例分数拉不开差距。
- 检索的时候还能给每个chunk一个可信度标记,这个标记是靠用户反馈更新的。如果来了一批chunk,LLM输出的结果用户不满意,那么就给这一批chunk都降一点分数,这个分数是每路召回时自带的分数。
- 相关性检查。前处理也有漏网之鱼。你可以通过相关性检查,检查每个chunk是否与query相关,如果全不相关,直接导向联网搜索or日常聊天模块。
- 诚实性训练。相关性检查也会有漏网之鱼,LLM必须做诚实性训练,LLM没法从chunk中找到答案,就该说不知道答案而不是按照惯性硬答,硬答就出幻觉了。数据集也好搞,直接拿前面说的ANCE用到的数据集就行。
- 大海捞针训练。有些项目你可能要检索回来100个chunk,rerank再提取20个塞进LLM,这文本量也不少,很难说LLM能力够不够,所以要选择大海捞针性能好的LLM。
- 后处理:幻觉检测。LLM的answer符不符合query的要求?answer是否来自context?这俩问题得让幻觉检测的LLM分析一下,然后再得出是否幻觉的结论。好的RAG系统一定不需要幻觉检测,毕竟你看kimi和文心一言它们生成答案时从来没有回溯过。如果真的用上了幻觉检测模块,应该是这么个场景:本地部署7B模型作为生成模块,它的功能有限,产生幻觉的概率大,所以需要加幻觉检测模块,如果有幻觉了,则使用更大的模型or改进prompt重新生成。假如你本地部署个70B的,肯定不需要幻觉检测了,幻觉多说明你前面的工作就没做好。
- 对于answer不来自于context的问题,各厂商的解决办法是信息溯源,即训练LLM懂得在输出一段话的时候,如果它的内容来自于材料,那么就在结尾生成一个来源的特殊token,这加强了LLM基于context作答的能力。
另外记录一个比较有意义的发表。
lamini6月份发的论文Banishing LLM Hallucinations Requires Rethinking Generalization提出通过百万个memory块让LLM记住事实,可以有效控制幻觉。这个论文让关键的事实性信息计算后的loss近乎归0,而应对其他问题仍然会有一定的loss,以此让LLM兼顾了记住关键事实和具有一定创造力的能力,其原理就是对于关键信息提问的query会严格依靠cross attention找到100万个memory中对应的32个memory向量,然后融合进query的embedding,与self-attention并行计算,结果再与self-attention的结果加和。而非关键query会在找32个memory时找得驴唇不对马嘴(因为根本没对这些query训练过),所以loss仍然存在。这就是这篇论文所谓的“记住事实,也能创造”的原因。
这是一种解决rag幻觉的办法————对于关键信息,用一种特殊的微调LLM的方法使其关键信息的loss过拟合到0,而不过多影响非关键信息的loss。