RAG 答错了,先把检索结果摊开看

以相机手册问答为例,分开检查召回、上下文与回答,避免盲目更换模型。

目录

给知识库换一个更大的模型,答案还是错。此时很容易继续改提示词:必须准确、必须引用、没有依据不要回答。可如果正确的那段资料根本没被取回来,这几句要求没有多少发挥空间。

排查 RAG,我会先暂时关掉最后的回答,只看检索到底找到了什么。

用一个足够具体的问题

假设知识库里有三台相机的说明书,问题是:“A 相机能不能自动对焦?”这是假设的资料集,不是在比较真实机型。

检索返回了一段“本机支持自动对焦”,看似完美,却来自 B 相机。模型如果没看到机型信息,就可能把答案写得非常肯定。

这类错误不是句子理解不够好,而是证据丢了身份。每个片段至少应带文档标题、所属机型或版本、章节、来源定位。文章标题放在另一块,而正文片段只有“本机”,检索时就很容易拆散。

Anthropic 的 Contextual Retrieval 讨论了片段脱离原文语境的问题,也说明了关键词检索和语义检索的互补性。对型号、错误码这类精确字符串,我会保留词面匹配作为基线,不直接假定向量检索更合适。

三个环节,分别留一份结果

第一份是候选片段:检索词是什么、命中了哪个文档、排在第几位。第二份是最终送给模型的上下文:有没有被截断、同一文档是否重复占位、版本信息是否还在。第三份才是回答和引用。

这三份记录可以把问题拆开:

  • 正确片段没进入候选,查检索和资料覆盖。
  • 候选里有,但没进入上下文,查排序、去重和截断。
  • 上下文里有,答案仍然错,查推理、问题歧义和输出约束。
  • 答案正确但引用错误,单独修引用关联,不把它算作完全成功。

日志里只保存排查必需的片段和标识;如果资料敏感,不要为了方便调试就把整库写进日志。这个限制应该在日志层做。

先做十个能人工判定的问题

不需要一开始就搭庞大评测平台。可以从手册写十个问题,每题列出支持答案的具体段落。再补几个知识库根本回答不了的问题,例如它没有收录的机型。

每次修改只比较同一组问题。最直观的指标是,正确证据有没有出现在前几个候选里;然后再看最后答案是否忠于证据。不要把答案里出现一个相关词就当成成功。

资料版本也要固定。如果今天新增了一份文档,明天修改检索算法,后天又换模型,结果改善了却不知道是哪一步起效。

片段长一点也有代价

把完整章节都放进去,可以少丢一些语境,但也会带来无关内容。同样的上下文预算下,一篇长文可能挤掉其他证据。遇到表格则更麻烦:表头在上一块,数值在下一块,任何一块单独看都可能被误读。

我会先检查正文结构:让标题和正文一起保存,表格尽量保留表头,引用时能回到原始位置。固定每隔若干字符切一刀可以作为起点,却不应该成为无法调整的规则。

如果只有几十篇短文,全文搜索甚至直接选出两三篇给模型,可能已经足够。先把这个简单版本的表现记下来,再增加向量、重排等步骤。多一个组件,就多一个需要证明有用的环节。