最近在做一个文档问答的RAG项目,检索模块已经调得差不多了,召回的内容基本都相关。但我发现一个问题:哪怕我明确在prompt里写了“如果检索到的文档中没有相关信息,请回答‘不知道’”,模型(用的gpt-4)还是经常自己编答案,尤其是一些细节问题。
RAG里用prompt让LLM“只回答不知道”,为什么还是乱编?
全部回复
共 184 条这个问题其实挺常见的,我也踩过类似的坑。光靠prompt里写一句“不知道”基本没用,因为模型在生成的时候,检索到的内容已经进了context,它会倾向于把context里的东西“合理化”成一个答案,哪怕只是部分相关。我后来试过一个办法,就是在prompt里要求模型先逐条判断检索到的每个片段是否真的能回答问题,明确输出“相关/不相关”,然后再决定答不答,这样稍微好一点。另外温度调低也有帮助,但别指望降到0就万事大吉,gpt-4在细节问题上还是会脑补。还有个思路是别让模型自己判断“知不知道”,而是在检索阶段加一个相关性阈值,低于阈值就直接走兜底逻辑,不把那些弱相关内容塞进context。说到底,RAG里的“拒答”是个独立模块,不能全压在prompt上,得检索、过滤、生成三层一起配合才行。
我也遇到过,后来把“不知道”改成“根据已有信息无法确认”就好多了,模型对否定指令确实不太敏感。
这种情况太常见了,光靠prompt约束真不够,得在检索后加个相关性判断,不相关就直接短路返回。
这个坑我也踩过,说实话光靠prompt真的很难完全管住模型。我后来发现问题的关键往往出在检索环节的“假相关”——你以为召回的内容相关,但其实只是语义相似度高分,里面并没有能回答问题的具体信息,模型看到一堆沾边的上下文就觉得“我应该能答”,于是开始脑补。另一个容易被忽略的点是prompt的位置和措辞,如果你把“不知道”的指令放在开头,长上下文里模型很容易把它稀释掉,我现在习惯在检索内容之后、问题之前再强调一遍,效果会好一些。还有个思路是别让模型自由发挥,改成先让它输出“检索内容中是否包含答案”的判断,再决定要不要生成答案,相当于强制它先做一次自我检查。当然gpt-4本身就有很强的“完成任务”倾向,你越问得具体,它越不甘心说不知道。所以我现在会配合一个置信度阈值,检索分数低于某个线就直接短路返回“不知道”,根本不进模型,这样反而最稳。