ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RAG实战:从切块到重排序,彻底解决知识库问答“答非所问”

RAG实战:从切块到重排序,彻底解决知识库问答“答非所问” 我们先把话说在前面一个看起来能用的 RAG 知识库问答系统真正放进业务里跑十有八九会在第一周就被用户吐槽“答非所问”。更扎心的是当你把日志翻出来检查时经常发现模型本身没问题Prompt 写得也还行甚至召回的文档看起来也是相关的——但最终答案就是不对。这种情况我见过太多次了。这个标题之所以叫“RAG 实战”是因为我不打算跟你复述教科书里的 RAG 概念而是要聊那些真正让系统跑偏的细节数据怎么切、向量检索为什么失灵、查询改写要不要做、重排序到底值不值得上、以及如何系统性地排查“答非所问”的根因。这篇文章适合正在做知识库问答、尤其是已经被“答非所问”折磨过的工程师和技术负责人。就算你只是刚入门、想用 RAG 搭一个内部知识助手这篇文章也能帮你避开那些文档里不会写的坑。1. 先搞清楚答非所问问题到底出在哪一环1.1 瓶颈通常不在生成模型而在检索链路很多团队一开始都会怀疑“是不是大模型太笨了”于是换个更大的模型结果发现该答错还是答错。实际上在大模型能力已经够用的情况下RAG 系统的瓶颈十有八九在检索侧。你可以把整个问答过程想成“先到图书馆找资料再让一个聪明的助手根据资料写回答”。如果从图书馆拿回来的资料就是错的、碎片的、或者是无关的那助手再聪明也写不出正确答案。我遇到过的最典型情况是知识库里明明有答案但系统就是搜不到。用户问“公司年假怎么算”库里文档写的是“带薪休假天数计算规则”两者语义上有关系但向量检索却没能把它们关联起来。这种“答非所问”不是模型问题而是检索召回环节没接住用户的语言。RAG 的完整链路被拆开来看大概是这么几步文档加载、切块、向量化、索引构建、用户查询向量化、召回、重排序、组装上下文、大模型生成。每一步都会引入误差。很多教程只会带你跑通 Demo但从 Demo 到可用的产品距离就藏在这些环节里的坑里。1.2 一个常见的错误假设向量相似就代表答案正确这是我最想强调的一点。向量检索找到的是“语义相似”的文本块但“语义相似”和“包含答案”完全是两回事。举个简单例子知识库里有篇文章叫《员工手册常见问题》里面有一句“本手册不包含年假细则请参考《休假管理制度》”。如果用户问“年假有几天”这句话在语义上跟年假高度相关但它并没有给出答案。检索系统很可能把它当高相似度内容召回然后大模型基于这句话自然只能给出一个含糊甚至错误的回答。更麻烦的是如果切块的粒度太大把一个段落里包含的多个主题混在一起召回的相关性也会被稀释。比如一块文本同时讲“请假流程”和“年假计算”用户问年假时这块文本可能因为包含太多无关信息相似度被拉低反而排在了后面。这些问题的根子都在于数据进入检索系统时没有被合理结构化。所以评估一个 RAG 系统不能只看“最后答案对不对”而要分段看检索阶段有没有把包含答案的文本块召回、重排阶段有没有把最相关的块顶到前面、生成阶段有没有忠实于上下文。哪一环断了都会表现为答非所问。2. 知识库构建端的三个关键细节2.1 切块策略太大太小都是坑切块是 RAG 里最容易被轻视、却又影响最大的环节。切得太小一个完整答案被拆成两半检索只召回其中一半生成时信息残缺自然答不全切得太大块里混入大量无关内容向量表示被稀释召回精度也会下降。我踩过最深的坑是对着一份 FAQ 文档用固定 500 字符切块结果有一条问答的答案是 800 字直接被切到了两个块里。用户问的时候系统召回的是含有前半部分答案的块后半部分始终没被检索到于是模型只能给出“部分正确但明显不完整”的回答。后来我把切块策略改成了按标题和段落边界优先再辅以固定大小兜底效果立刻好了不少。一个比较实用的经验是对结构化的 FAQ 文档尽量按“一问一答”为粒度切块宁可一个块里有一个完整问答也不要强行拆开对长文章建议用递归切块按标题、段落、句子的优先级逐级切分让每个块尽量是语义完整的单元。同时要设置重叠区间一般 chunk_overlap 取 chunk_size 的 10%~20%避免关键信息刚好落在切分边界上被丢掉。2.2 向量检索的局限以及“知识库能不能存图片”先回答一个我经常被问的问题RAG 知识库能存图片吗严格来说常规的文本向量 RAG 并不能直接存图片因为 embedding 模型处理的是文本而不是图像像素。如果你只是把图片文件本身放在对象存储里再把图片的“描述文字”或“OCR 识别文本”做向量化入库那么用户是可以检索到这张图片的——但前提是你要先把图片转成文字描述。如果要做真正的“以图搜图”或多模态问答那就需要多模态 embedding 模型这是另一套方案别指望用文本 RAG 搞定。回到向量检索本身它的强项是语义召回但弱点是“关键词精确匹配”不行。比如知识库里有“CTR”用户问的是“点击率”如果 embedding 模型没有学到这个对应关系召回效果就不稳定。所以在实际项目中我更推荐做混合检索同时跑向量召回和 BM25 关键词召回再用 RRFReciprocal Rank Fusion或分数归一化加权合并。这样即使向量那边失手关键词那边也能兜底。向量化这一步还有个细节容易被忽略中文场景下 embedding 模型要选中文语料训练过的比如 bge-m3、m3e 这类英文模型直接用在中文知识库上效果会明显下降。别小看这一步我见过不少项目换了个中文 embedding 模型召回命中率直接涨了十几个点。2.3 知识库的类型文本 RAG、结构化库 RAG、知识图谱 RAG 怎么选很多同学把“知识库”理解为“一堆文档”但其实 RAG 面对的知识库形态有很多种选错类型也是答非所问的重要原因。最基础的是非结构化文本 RAG适合处理 FAQ、制度文档、产品手册这类内容第二种是结构化数据库 RAG典型做法是 Text-to-SQL用户用自然语言查询系统把问题转成 SQL 语句去数据库里取数适合“上个月华东区销售额是多少”这类精确计算问题第三种是知识图谱 RAG也叫 GraphRAG 或 Ontology RAG适合处理“A 公司的 B 业务和 C 公司是否有间接关联”这种多跳关系推理问题。这三种形态不是互斥的实际落地经常是混着用。比如一个企业内部助手制度类问题走文本 RAG经营数据类问题走结构化 RAG供应链上下游关系这类走图谱 RAG。判断的依据很简单用户的问题需要“看懂文字”回答还是“算了数字”回答还是“理清关系”回答。三种需求对应三种知识库形态硬拿文本 RAG 去回答数据统计问题能不答非所问吗这里多说一句Ontology RAG 并不是什么玄学它就是先用本体定义好实体和关系的类型再用图谱结构约束检索路径让模型沿着关系链去收集证据。对“多跳问答”场景效果比普通向量检索好得多但构建成本也高一般团队等到文本 RAG 玩明白了再上也不迟。3. 查询端的优化不是用户怎么问你就怎么查3.1 查询改写把用户的模糊话翻译成知识库的语言用户不会按照你知识库的写作风格提问这是答非所问最常见的原因之一。知识库里面写的是“发票开具流程”用户问的是“怎么开发票”关键词完全对不上知识库写“离职交接清单”用户问“我要走了要办什么手续”口语和书面语差距更大。这时候如果拿用户原始问句直接检索召回效果通常不好。一个很实用的办法是加一道查询改写让大模型先把用户问题翻译成更贴近知识库风格的关键词组合或者从问题中提取核心实体和意图再拿去检索。这个做法成本低、见效快你只需要在检索之前多调一次大模型把原始问题转成几个候选查询词。我常用的 prompt 大概是这样的你是一个知识库检索助手。请把用户的自然语言问题改写成适合文档检索的查询片段可以拆分成多个短查询用中文输出不要加多余解释。 用户问题{question}例如把“我要离职了公司有什么规定”改写成“离职流程 离职交接 相关规定”。这样原文里隐含的多个检索点就被显式拆出来了多路召回都能命中。更加进阶一点的是 HyDE 方案先让大模型根据用户问题生成一个假设性的理想答案再用这个假设答案去检索相关文档最后让大模型基于真实检索到的文档重新生成正式回答。这个思路背后的逻辑是假设答案本身就是一种更贴近知识库语言表述的查询表示因此能提高召回命中率。但 HyDE 有一次额外的大模型调用延迟和成本要考虑清楚。3.2 重排序召回 50 条不如精排 5 条向量检索阶段一般会召回数量偏多的候选块比如 top 50然后把这些候选块直接塞给大模型。但问题在于前 50 个块里可能只有前 3 个是真正有用的剩下的全是干扰信息。大模型面对一堆混淆上下文答非所问的概率会明显上升。所以一个高性能 RAG 系统里重排序这一步基本是标配。召回阶段先多拉一些候选然后用一个专门的重排序模型比如 bge-reranker、Cohere Rerank逐条计算候选块和用户问题的相关度把 top 50 压缩成 top 5 左右再组装成 Prompt 喂给大模型。我自己实测下来加了重排序之后答案的准确率提升非常明显尤其是知识库文档量大了之后这个提升几乎可以用“质的飞跃”来形容。上下文组装还有一个细节不要把多个高相关但内容重复的块都塞进去。可以用一个简单的去重逻辑相似度太高的相邻块只保留信息最完整的那一条减少上下文冗余。大模型上下文窗口再大也经不起无效信息占位。4. 典型问题排查从现象到根因4.1 五个常见“答非所问”现象的深度诊断第一个现象答案在复述文档原话但没有直接回答问题。原因通常是召回到的块太长了里面确实有相关句子但模型没找到那一句或者 Prompt 里没有强调“基于上下文提炼并回答问题”导致模型把原文直接抄了一部分出来。解决方法是缩小切块粒度并在 Prompt 里加一句“只能基于上下文内容用自己的话组织答案不要复述原文”。第二个现象知识库里有答案但系统说找不到。排查思路是先做“闭卷测试”直接把用户问题和文档块打印出来看这块到底有没有被召回。如果没被召回大概率是 embedding 模型和切块粒度的问题如果召回了但排名太靠后那就是重排序没做或模型选得不对。这个现象最常见的原因是用户问句和文档表述之间词汇差异太大向量模型没能拉近距离这时候上混合检索就能救回来。第三个现象问题简单但答案绕来绕去不切题。这通常是召回结果里出现了“看似相关但不含答案”的干扰块。前面提到的“有篇文章提到年假但不包含年假细则”就是典型例子。建议在重排序之后再加一道基于规则或小模型的过滤如果候选块里没有出现用户问题里的核心实体词整体降权。当然更治本的办法是在知识库建设时就做好数据清洗把这种“提到但没讲清”的内容和正式内容区分开。第四个现象模型一本正经地编造知识库里没有的细节。这是典型的幻觉问题根源不只是模型本身也可能是 Prompt 里让模型“自由发挥”的空间太大了。我的经验是在 Prompt 里显式声明“如果你无法从上下文中找到明确答案请回复抱歉并列出已找到的相关线索”这个约束比换个模型更直接有效。与此同时要检查召回的知识块里是否真的包含了答案如果 top 5 里都没有那再怎么约束 Prompt 也白搭。第五个现象同样的知识库换了个问题模板答案质量波动巨大。这说明系统对查询表述非常敏感因为查询改写或向量模型没有很好地泛化。建议对高频问题做一定量的“问题模板增强”也就是把同一意思的多种问法一起做向量入库让每个 FAQ 都对应多条不同措辞的查询这样用户无论怎么问都能撞上其中一种问法。4.2 排查速查表现象、根因、解决动作现象可能根因优先排查动作答案复述原文不直接回应用户问题切块过大 / Prompt 缺少提炼指令改小切块Prompt 增加“用自己的话回答”知识库有答案但系统回复找不到向量模型不适应中文 / 词汇差异大换中文 embedding 模型上 BM25 混合检索答案绕来绕去不切题召回结果含大量干扰块加重排序按核心实体词过滤候选块模型编造知识库没有的细节上下文缺少答案 / Prompt 约束太弱强约束 Prompt检查 top 5 候选块是否真含答案换一种问法答案质量波动大查询改写不稳定 / 问题模板覆盖不足对 FAQ 做多问法增强查询改写并多路召回这套速查表不是教条但它能帮你把“模糊的答非所问”拆成“具体链路里某一个环节的缺陷”然后有针对性地优化而不是瞎调参数。5. 评估与持续优化让效果可量化5.1 不要只盯着“答案对不对”要拆开评估三层指标很多团队优化 RAG 全凭感觉今天换下切块参数明天换下 Prompt但就是没建立评估闭环。我给的建议是一定要拆开三层看检索层、排序层、生成层。检索层重点关注召回率也就是“包含答案的文档块有没有出现在召回列表里”。排序层看的是重排序之后正确答案是否排进了 top 5。生成层则看两个东西一是 faithful忠实度即答案是否严格基于检索到的上下文二是 answer relevancy答案相关性即答案是否真正回应了用户问题。业界已经有一些开源评估框架比如 RAGAS直接可以算这些指标也可以自己准备一百个问答对人工打标跑回归。我自己的习惯是搭一个最小的评测集联系不需要很大五十到一百条有代表性的问答就够了但覆盖面要广包括常见问题、冷门问题、模糊口语问题、多跳问题。然后每改动任何一个环节重新跑一遍评测集把召回率、排序命中率、忠实度这些数字拉出来对比。没有这个闭环你所谓的“优化”就是瞎撞运气。5.2 一条可落地的优化路径先建基线再逐层调优如果你现在手里有一个答非所问的 RAG 系统我建议不要同时改多个环节而是按这个顺序逐步调第一步检查知识库源头把重复、过期、残缺的文档清掉这可能能解决一半的问题第二步固定切块策略和 embedding 模型跑通基线评测拿到召回率和忠实度第三步上混合检索对比向量召回和 BM25 的效果看谁拖了后腿第四步加重排序模型观察排序命中率的变化第五步做查询改写和多问法增强专门解决用户问法和文档表述不一致的问题第六步再回头调 Prompt 和上下文组织策略。这个路径的核心逻辑是“先保证系统能把正确的文档找回来再保证找回来的文档是够用的最后才是让模型把答案组织好”。很多人恰好把这个顺序做反了一开始就疯狂调 Prompt结果检索那边根本拿不到正确答案Prompt 调得再好也还是在错误的上下文里做文章。我最后分享一个真实感受做 RAG 知识库问答最容易让人挫败的倒不是技术难点而是它看起来太像“一个能跑的 Demo”了于是团队容易低估数据侧和检索侧的工作量把大量时间花在更换大模型上。换个更好的模型当然有用但它的收益会很快见顶。真正决定知识库问答系统能不能扛住真实业务压力的还是那些琐碎的、看起来一点都不酷的环节——数据清洗、切块策略、查询改写、重排序、评测闭环。把这些做扎实了答非所问的问题自然会消退大半。
返回列表