最近在搭一个简单的RAG问答系统,用的是LangChain + OpenAI的embedding,检索效果还行,但LLM回答时总喜欢“自由发挥”——比如用户问“张三在2023年说过什么政策”,明明库里只有一段原文,它非要自己总结一遍,甚至加些原文没有的细节。我试过在system prompt里写“请严格引用原文回答”,但效果不稳定,有时候还是乱编。想请教下大家,有没有什么prompt技巧或者模板能让模型更“死板”一点?另外,如果原文很长,是不是应该把检索到的片段分段塞进prompt,还是直接整段放进去比较好?感谢!
RAG系统里prompt怎么写才能让LLM更准确引用原文?
全部回复
共 154 条这个问题我也踩过坑,说点实际经验。“严格引用原文”这种指令太软了,模型该编还是编,得把约束落到格式上才管用。我现在的做法是要求它每句话后面必须跟一个引用标记,比如直接标注来自哪个chunk,然后prompt里明确写“如果检索内容里没有相关信息,就回答不知道,禁止自行补充”。这招比单纯说“别乱编”有用得多,因为模型一旦被逼着给出来源,它瞎编的成本就高了,很多情况下它会老老实实照抄。
另外你提到的分段还是整段,我倾向于按语义切分后放top 3到5个片段,别一股脑全塞进去。塞太多反而稀释注意力,模型容易抓错重点,而且长上下文里它更倾向于“总结”而不是“引用”。可以在每个片段前加个编号或者来源标识,prompt里让它引用编号,这样追溯起来也方便。
还有个小技巧是few-shot,给它一两个“用户问—正确引用回答”的示例,比干巴巴的规则管用。温度也可以调低点,0或者0.1,别让它有太多发挥空间。不过话说回来,检索本身如果召回不准,prompt再怎么写也救不回来,可以先看看是不是chunk切分或者embedding的问题。
你这个情况挺典型的,我一开始搭RAG也踩过一模一样的坑。光靠system prompt里喊“严格引用原文”基本没用,模型该编还是编,因为它根本分不清哪句是检索来的、哪句是自己脑补的。后来我改成在user prompt里把检索片段用明确标签包起来,比如
我之前也碰到过类似情况,后来在prompt里加了一句“如果原文没有明确提到,就直接回答‘未找到相关信息’”,效果好了不少。另外可以在回答里要求它先摘抄原文句子再解释,这样它就不太敢乱编了。片段长度的话,我一般会控制在500字以内,太长反而容易让模型忽略中间的内容。
我之前也碰到过这个问题,后来在prompt里加了一句“只允许使用检索内容中的原句作答,找不到就直说没有”,效果好了不少。另外可以试试让模型先输出引用片段再给答案,这样它不太敢瞎编。长文本的话我一般按语义切段塞进去,整段放容易稀释重点。
试试在prompt里加一句“若原文没写就回答不知道”,比单纯说“严格引用”管用多了。
这个坑我也踩过,光在system prompt里写“严格引用原文”确实不太管用,模型该编还是编。后来我改成在prompt里明确要求“每个回答必须附上原文片段作为依据,找不到就说不知道”,效果好了不少,关键是让它有“举证”的压力。另外温度调到0或者0.1也很重要,默认值下模型太爱发挥了。原文片段的话,我建议还是分段放,整段塞进去容易超token,而且中间信息容易被忽略,可以按段落加个编号,让模型引用时带上编号,这样能追溯也更能约束它。还有个偏方是在prompt里加一句“如果原文没有明确提到,请直接回答‘原文未提及’”,比单纯说“不要编造”管用。不过说实话,prompt只能缓解,真要稳定还是得在检索层和rerank上多下功夫,检索准了模型乱编的空间自然就小了。
可以试试在prompt里加一句“如果原文没有明确提到,就回答‘根据现有资料无法确定’”,这句比单纯说“严格引用”管用很多。还有个歪招是把temperature调到0,能压一压它自由发挥的毛病。长文本的话我一般按语义切成小块分别喂进去,整段塞反而容易让模型忽略中间部分。你检索出来的片段最好带上原文的句子编号或者出处标记,让它引用时有“锚点”可抓。
这个问题我也踩过坑,说实话光靠“请严格引用原文”这种指令确实不太稳,模型该编还是会编。我后来改成在prompt里明确要求它先摘出原文句子、再基于摘录作答,格式上逼它走两步,幻觉明显少了。另外可以试试让它输出时带上引用标记,比如“根据片段1”,这样它自己也会收敛一点。至于长文本,我一般会把检索片段按相关性排序后分段塞进去,每段加个小标题或编号,整段硬塞反而容易让模型忽略中间部分。温度调到0或者0.2也有帮助,别让它太有创造力。还有个歪招是让它在回答末尾加一句“以上内容均来自给定片段”,虽然听起来傻,但确实能压一压乱发挥的倾向。
我一般会在prompt里直接要求模型“只允许用检索内容中的原句回答,如果找不到就回答不知道”,比单纯说“严格引用”管用不少。长文本的话我倾向分段塞,每段前面加个编号,再让模型引用时带上编号,这样它更难瞎编。还有个歪招是把temperature调到0,虽然不能根治但确实稳一些。你检索回来的片段如果本身有噪声,也会让模型忍不住自己脑补,可以试试加个重排序再喂进去。
我也踩过这个坑,光写“严格引用”基本没用,模型该编还是编。后来改成让它先摘抄原文句子再回答,并且明确说“找不到就回答不知道”,幻觉明显少了。长文本建议按语义切短一点塞进去,整段放反而容易让模型抓不住重点。另外可以在prompt里加一句“不要改写、不要总结,只允许基于以下片段回答”,比单纯强调“准确”管用。
这个思路不错,收藏了。
这个思路不错,收藏了。
写得挺好,建议补充一些性能数据。
我一般会在prompt里直接把检索到的片段用编号标好,然后要求模型每个结论后面标上对应的片段号,不加编号的句子就当无效输出。另外“严格引用”这种话太虚了,换成“只允许使用片段中出现的事实,不确定就回答不知道”会稳不少。长原文的话我倾向分段塞,段落之间加个小标题或者摘要句,模型定位起来准很多。还有个偏方是temperature调到0,虽然不能根治但能少很多自由发挥。