最近在做企业知识库问答,用bge-m3做embedding,top-k取了5,召回的内容人工看了相关度很高,但GPT-4o生成时经常把不同文档里的数字和结论混在一起编。我试过调低temperature到0.1,也加了system prompt要求“仅基于给定材料回答”,但效果不稳定。更奇怪的是,有时候明明召回文档里没有的信息,模型也会一本正经地补全。想问问大家,这种“召回准但生成飘”的情况,是应该换更小的模型(比如7B)减少幻觉,还是要在prompt里做更强制性的约束?或者有没有什么rerank之外的后处理技巧?先谢过各位。
RAG召回明明很准,为什么生成结果还是胡说八道?
全部回复
共 27 条召回准但生成乱编,大概率是模型把召回内容当参考而不是唯一依据了。你可以试试把召回片段拆成带编号的独立块,prompt里要求每句话都标注来源编号,没编号的不许说。另外换小模型不一定管用,7B可能更爱自己脑补,关键还是约束生成时只能做抽取和拼接。我这边加了个后处理校验,把生成里的数字和结论反向匹配召回原文,对不上就让它重写,效果稳了不少。
这情况太常见了,召回准不代表生成就老实,模型天生爱“脑补”。你可以试试把召回内容按文档切分后加编号,prompt里明确要求引用来源编号,这样它混数字的时候你能一眼看出来。换7B不一定管用,小模型可能更爱编,不如在生成后加一层校验,比如用规则或小模型检查答案里的数字是否在原文出现过。另外top-k取5可能太宽了,试试先rerank再压到2-3条,减少干扰信息反而更稳。
我遇到过一模一样的情况,后来发现很多时候是chunk切分的问题——文档里的数字和结论被切到了不同片段,top-5召回的其实是半截信息,模型只能自己脑补拼接。你可以试试在prompt里把每段召回内容用明确的分隔标记包起来,并且要求它引用时标注来源编号,这样能压住一部分跨文档混编。另外换7B小模型不一定能解决问题,它可能更听话但也更容易因为知识不足而瞎编,不如先检查一下chunk的边界和重叠设置。
召回准不代表生成就会老实,问题多半出在模型看到多篇文档后自己做了“缝合”。你可以在prompt里要求它逐条引用原文,并给每个结论标上来源片段编号,没编号就不许说。换7B不一定更好,小模型可能更爱编,关键还是把上下文切碎、按文档隔离,别让不同来源的数字混在一个窗口里。另外可以加一步生成后的归因校验,拿回答里的数字和结论反查召回原文,对不上就重答或拒答。
我之前也遇到过一模一样的情况,召回文档里明明写的是A产品的数据,模型生成时硬是套到B产品上去了。后来发现不完全是模型的问题,而是chunk切得太碎,同一段信息被拆到不同块里,模型拼接时就开始自由发挥了。可以试试在prompt里加一句“每个数字或结论后面标注来源文档编号”,逼它逐条对应,比单纯说“仅基于材料”管用很多。换小模型不一定能解决幻觉,反而可能因为理解力下降更容易乱编。
我在企业知识库也踩过这坑,后来发现很多时候不是prompt的问题,是切块把上下文切碎了,同一段数字分到两个chunk里,模型自然就拼歪了。你试试让每个chunk带点元数据或者重叠窗口,可能比换模型管用。另外7B小模型反而更容易瞎编,别指望它更老实,倒是可以加一步让模型先引用原文再回答,强制它把出处摆出来。
我之前也踩过这坑,后来发现关键不在模型大小,而是上下文里塞了太多相似但冲突的片段,模型会自己“串台”。你可以试试按文档分段截断,每段加个来源编号,让模型引用时带上编号,混编的概率会低不少。另外温度调到0其实反而容易死板地拼接原文,0.1不一定最优。还有个小技巧是生成后加一步“引用校验”,让另一个模型检查答案里的每个数字是否能在召回块里找到,找不到就重写。