先说结论:大部分 RAG 项目做出来效果不理想,问题不是出在大模型“不会答”,而是出在“喂进去的东西不对”。检索端决定了模型能看到什么,内容不准、不精、不完整,模型再聪明也是徒劳。我这两年帮人调过的 RAG 系统不少,从企业内部知识库到电商客服问答都有。凡是那种“测试的时候回答挺好,一上线就胡说八道”“多问几个问题就答非所问”“答案跟文档内容对不上”的场景,十次里有八次,根因都在检索链路,而不是生成链路。很多人第一反应是换更大的模型、加提示词、做微调,这些都是绕远路。真正该做的是把检索端当成独立的子系统去优化,从数据切分、向量召回、排序策略到查询改写,一步步排雷。这篇文章不写教科书式原理,就按实际踩坑的顺序来,把 RAG 为什么容易输在检索端、怎么快速定位问题、怎么系统性优化,一条条讲清楚。适合正在调试 RAG 应用、被效果问题折磨得头大的工程师,也适合刚接触 RAG、想看明白“症结到底在哪”的入门者。1. RAG 效果差到底差在哪:先给问题定性1.1 常见的“效果差”表现有哪些很多人说“RAG 效果差”的时候,其实描述的是完全不同的现象。我复盘过几十个案例,基本可以归成三类:第一类:答案与文档内容无关,或者直接编造。用户问的是文档里根本没有的信息,系统却一本正经地给了一个答案。这个叫“幻觉”,但本质上是检索结果里没有相关信息,模型只能靠训练记忆瞎猜。第二类:答案有相关片段,但融合得支离破碎。你打开检索到的片段,发现每条都有些相关,但放到一起却是东一榔头西一棒子,没有形成完整答案。这个典型是召回数量不足或排序有问题,关键上下文被漏掉了。第三类:回答“没错但没用”。检索到了正确主题的段落,却答不到用户问题的点上。比如用户问“退款多久到账”,检索回来的段落讲的是“退款申请流程”,主题相关,但缺了时间承诺这个核心信息点。这种问题最隐蔽,也是最容易被误判成“模型理解能力不行”的。这三类现象对应的根因方向完全不同。第一类多是索引覆盖不全或查询召回为空,第二类多是分块策略和召回配置不合理,第三类多是查询改写不足、排序策略太粗糙。如果上来就盲目调提示词,往往一个问题都解决不了。1.2 判断问题侧的最快方法:人工看检索结果遇到“效果差”的反馈,我的第一个动作从来不是改代码,而是把实际检索结果打印出来人工看一眼。这个动作虽然土,但是效率极高,五分钟就能定位侧别。操作很简单:取几条用户问得最多、效果最差的 query,直接调用检索模块,不管生成模块,把 Top 10 检索片段连同相关性打分打出来。然后你逐条问自己三个问题:这些片段里有没有存在能回答用户问题的关键信息?如果有,它排在什么位置?排在前三吗?排序靠前的片段质量怎么样?是有用的,还是标题相近但内容跑偏的?只要记录十几条 query 的结果,就足够看出规律。如果检索回来的片段里根本没有能回答问题的内容,那是检索侧的问题,生成侧不必管。如果片段里明明有答案,但最终回答还是错了,那才有可能是生成侧的融合和提炼出了问题。这个手工诊断法我推荐每个 RAG 项目都做一遍,而且要持续做。检索质量不是评完一次就结束,数据更新、用户提问分布变化,都会让问题重新出现。1.3 端到端指标掩盖了多少真相正规一点的团队会用端到端指标评估 RAG,比如回答准确率、相关性打分、忠实度。但端到端指标有个致命问题:它把检索和生成混在一起,你只知道结果差,不知道差在哪一环。举个例子,你用大模型逐条打分,问“这个回答是否忠实于给定文档”,得了 0.6 分。这个分数能说明生成器没有忠实引用文档,但完全没告诉你检索器有没有把该引的文档找回来。如果检索的召回就是空的,那生成器想忠实也没东西可忠实。所以我在团队里定了一个保守原则:所有 RAG 评估都必须分两层做。第一层叫检索评估,只看 Top-K 召回率、命中率、排序质量,跟生成完全脱钩。第二层才是端到端评估,看最终回答质量。只有两层分开看,才能知道优化该投在哪一侧。这个习惯帮我在很多项目里省了冤枉钱。有个项目曾想微调模型解决“答不对”的问题,我看完检索日志后发现 Top 10 里根本没有答案片段,果断建议先把索引建好。结果只调了清理数据和重排逻辑,效果直接翻番,微调白省了。2. 为什么问题多半在检索端:链路里的六道坎2.1 数据清洗和切分的锅,比想象中大得多很多团队搭建 RAG 时,最不重视的就是数据准备,觉得“直接切块塞进去就行”。这是第一个坑,而且是最深的坑。本地文档质量参差不齐,PDF 转出来带页眉页脚,表格被拆得七零八落,同一份文档在新旧版本里互相冲突,这些数据问题会原封不动地传导到检索结果上。再就是分块策略。切块大小、重叠长度、分隔符选择,每个参数都直接影响检索粒度。切太大,块内主题混杂,向量表示被平均化,检索精度下降;切太小,语义不完整,关键信息被切断,又召不回上下文。没有万能参数,但有个基准值得参考:通用文本最好控制在 300 到 800 token 之间,重叠 50 到 100 token;代码或表格这类结构化内容,则要顺着逻辑边界去切,不能死记 token 数。我见过最多的问题是把几个主题混在一块切,或者一个完整表格被拦腰切断,导致用户查“某型号故障代码”时,召回出来的片段只有表格的表头部分。这种问题靠换模型解决不了,只能回到切分环节,按标题层级和段落边界重切。2.2 嵌入模型选型与领域漂移嵌入模型的选型对检索质量的影响是全局性的,怎么强调都不过分。很多人直接套用开源社区默认模型,完全不考虑自己的文档领域和语言分布,结果检索效果自然不稳定。嵌入模型的核心问题是表征空间的适配性。通用模型在大规模语料上训练,对网络文本、新闻语料表现好,但换到专业领域,比如医疗器械说明书、法律合同、金融研报,词表和表达风格就存在明显漂移。你想一下,通用嵌入模型见过的是“手机屏幕坏了怎么修”,而你的用户问的是“YY/T 标准下三类医疗器械的注册变更流程”,这两者的向量空间根本不是一回事。处理办法有三层:第一,优先挑选在目标领域语料上做过训练的模型;第二,用少量典型 query 对几个候选模型做对比测试,哪个命中率高用哪个;第三,条件允许的话,用领域语料对嵌入模型做继续预训练或对比学习微调。多数项目做到第二层就够用了,不需要复杂化。2.3 查询与文档的语义鸿沟被低估了这是检索端最隐蔽的问题。用户自然语言提问和文档中的陈述句式往往存在巨大差异,用户不会按照文档作者的表述习惯去提问。举个常见的例子:文档里写的是“本产品适用于海拔三千米以下环境”,用户的提问可能是“去拉萨用会不会出问题”。两句话指涉同一个内容,但字面上几乎没有重合。检索模型通常只能捕捉词汇和浅层语义的相似性,真碰上这种“概念等价”的转换就抓瞎。这也是为什么我一直强调查询改写的重要性。检索前先把用户 query 改写成更贴近文档表述的检索式,是性价比最高的优化手段之一。常见的做法是根据对话上下文做指代消解,比如用户先说“我买的那个耳机坏了”,后一句问“怎么退换”,检索时就要补全成“耳机 退换流程”。还可以对同一个 query 生成多个改写变体同时检索,再合并去重,提高召回的覆盖面。我在实际项目里,只加了一个基于大模型的轻量改写,检索命中率就抬升了二十个百分点上下,这个投入产出比非常可观。2.4 向量检索的固有局限:只有相似,没有精准向量检索本身是近似语义搜索,它找的是“语义相近”,不是“事实精准”。这意味着它是召回的优秀工具,但不是排序的最终答案。大量项目里,我把向量召回和 BM25 混合检索都拉通测试一遍,发现很多专业 query 下,传统的关键词召回竟然更准。原因不复杂:向量检索擅长处理同义表达、模糊描述,但对专有名词、精确 ID、版本号、型号编码等强标识符信息不敏感。你检索一个“H3C S5130-52S-EI 固件升级失败”,向量模型可能给你召回一堆“交换机升级”“固件资料”的大类内容,精确型号反而被淹没了。所以现在稍微成熟一点的架构都采用混合检索:向量召回负责宽口子语义召回,BM25 负责精确词匹配召回,再把两路结果合并统一排序。这一层加完,检索命中率通常会有明显提升,而且成本几乎可以忽略。2.5 Rerank 缺失或形同虚设如果检索端一定要挑一个最值得投资的组件,我会毫不犹豫选重排模型。向量检索的目的是“宽进”,宁可错杀也不能漏掉,所以 Top 20 或 Top 50 里常常混杂大量低质片段。如果直接把这些结果一股脑丢给大模型,上下文里噪声太多,回答质量必然下降。重排模型的作用就是在宽召回的基础上做精细排序,把真正对当前 query 有用的片段压到最前面,把无关片段清出去。它和嵌入模型最大的区别在于:重排模型直接计算 query 与文档的交互相关性,而不是双塔式的相似度。这种交互式建模,对“问题与片段是不是真的匹配”的判断要可靠得多。很多团队没有做 rerank,或者做了但只把它当成一个排序函数摆在那里,没有细调输入输出。我在多个项目里的经验总结是:先让向量检索和 BM25 各自召回 Top 50 甚至 Top 100,合并后交给 rerank 取 Top 5 到 Top 8,再进生成环节。这个流程调好之后,回答质量通常会有肉眼可见的提升。2.6 排序后的上下文构造:数量与顺序都是变量最后一个环节容易被忽略:排序选出的片段以什么顺序、什么形式拼接成提示词,对生成质量影响不小。很多人直接把 Top N 依次拼接,第一个位置塞的是与查询最相关的,其他片段按序排布。但这个顺序未必最优。片段顺序会影响模型的信息整合方式。有些模型在长上下文中对中间位置的内容关注度更弱,所以务必要把最关键、最直接回答问题的信息放到靠前位置。另一些场景下,同一主题的碎片应该相邻放置,方便模型把零散信息拼装成完整答案。另外,Top N 不是越大越好。给模型塞 20 个片段,远不如精选 5 个高质量片段。上下文里的垃圾信息会产生注意力干扰,甚至直接盖过真正的答案。我给的建议是:先暴力召回,再严选进入上下文,宁可给模型少而精的素材。3. 检索端优化的实操流程:六步排查与修复3.1 第一步:建立查询镜像集优化检索端之前,必须得有一个足够有代表性的测试查询集。没有固定测试集,你根本不知道改了什么、效果是变好还是变坏。我习惯建立一个“查询镜像集”,维护了项目里真实用户最高频的 50 到 200 条 query,覆盖各类提问模式和困难案例。每一条 query 我都手工标注了标准答案片段或相关文档 ID。这个标注工作繁琐,但值得认真做。没有真实数据做支撑,后面做的每一项优化都是盲人摸象。建好之后,每次索引或检索逻辑改动,都拿这套查询集回归一遍,用命中率指标快速反馈。热门的开源库里有专门的检索引擎评测手册,各大采集器也支持构建自定义评测集。也可以自己写脚本,只需记录检索结果、让助手给相关性打分、按阈值归入命中或未命中,就能形成一套轻量评测。3.2 第二步:筛出“零召回”和“低排位”两类硬伤查询镜像集跑过一次之后,立刻能发现两类硬伤,它们的处理方式完全不同。零召回指 Top 50 里完全没有正确答案,这种问题基本指向数据与切分环节,需要检查文档有没有进索引、字段映射是否正确、切分是否切断了关键片段。低排位则指正确答案存在但排在十名开外,这种情况大概率是排序和重排环节不够强。排查零召回的常见手段是下拉原始文档,直接搜关键词,确认内容到底在不在库里。很多时候你会发现所谓的“零召回”只是文档格式太乱,比如扫描件没有 OCR、表格内容被转成了图片,这些内容根本没进索引。这一类问题占的比例相当高,排查后先别急着调模型,先解决数据入库问题。3.3 第三步:围绕切分策略做对照实验切分是检索质量的基础,值得专门花一轮时间做对比实验。我的做法是搭一个小型实验环境,对同一批数据分别用几种切分策略跑一遍,然后在查询镜像集上对比召回率。比如对技术文档,我会对比“固定 512 token 不重叠”“512 token 加 64 重叠”“按 Markdown 标题切”“按语义边界工具切”这几种方案。结果往往差异明显,尤其在文档结构清晰的情况下,按结构切分的效果要远好于固定长度硬切。原因也好理解,标题本身就是天然的语义边界,RAG 切分顺着它走,才能保住主题的完整性。重叠的意义在于把边界信息多保留一份,避免关键信息恰好卡在切分缝上。但重叠不是越多越好,太多重叠会导致内容冗余,降低检索精度。常规区间在 50 到 100 token。3.4 第四步:引入混合召回再加粗排如果单纯向量检索的命中率偏低,下一步就是接混合召回。比较通用的实现是向量检索和 BM25 各跑一路,对结果做加权融合。权重如何设置要用查询集调,先从 50/50 起步,然后分别观察偏好精确词还是偏好语义的查询类型的表现,再微调,不过大多数情况下最终结果都在 40/60 到 60/40 之间。然后是提醒了一百遍的加粗排。粗排的输入就是混合召回的 Top 50,输出是整理后的 Top 8。粗排模型一般以排序阶段微调的多任务模型为基座,部署时先用 CPU 推理也够用,如果延迟敏感再考虑压缩或上 GPU。重排层不建议省。我唯一见过重排意义不大的情况,是语料只有一两百条、用户提问都非常模板化。只要语料规模上千条,查询模式分散,重排对效果的影响基本都是决定性的。3.5 第五步:查询改写与多路召回查询改写的价值经常被低估,因为它让人觉得“不就是在提示词里加两句话”,但实测效果常常出人意料。最简单的方式是构造一个改写提示词,把用户问题、历史对话、期望的检索式格式都喂给模型,让模型输出一到三个候选检索式。这里有个细节很多人忽略:改写后的查询不要直接替换原查询,而是和原查询一起并行检索,最后合并结果。因为大模型改写存在过度概括的风险,可能把“iPhone 14 电池更换价格”写成了“苹果手机维修费用”,反而丢失了精确信息。多路并行检索再加去重,才能既扩大覆盖又不丢失精确词。3.6 第六步:元数据过滤与精细化路由到这一步,检索端的基本优化已经到位,但还有一个锦上添花的动作:元数据过滤。如果你的文档带有来源、时间、分类、部门等字段,可以在检索时强制过滤,把搜索范围缩小到相关子集,质量和速度都会提升。比如企业知识库里既有技术文档又有行政制度,用户问“请假流程”时,如果系统能先按文档类型过滤掉技术文档,检索精度会明显上升。这类过滤规则有的写在索引阶段,有的写在查询阶段,实现成本都不高。还可以做查询路由:先判断 query 属于哪个领域,再路由到对应的专业索引。比起一套通用索引打天下,这在多业务线的知识库场景下效果更可控。4. 评估与回归:怎么验证“检索端修好了”4.1 检索侧指标怎么设做了这么多优化,得有量化手段确认真的有效。我常用的指标有三类,每个都有明确含义:召回率@K:正确答案是否出现在前 K 个结果里。这是最核心的指标,因为 RAG 的底线是信息能不能被找到。命中位置:正确答案平均排在什么位置。方案从“找到”到“排前面”还有距离。排序相关性:用粗排后的得分均值或人工标注的相关性分数来评估粗排质量。这些都建议画成曲线看。只看单一数值容易忽略部分查询变差、部分查询变好的抵消效应。按查询类型分组统计是更细的做法,比如分为“专有名词型”“描写描述型”“多跳复合型”,分别看指标变化,能更精准判断优化方向。4.2 端到端效果对比:必须用同一批真实问题最后一步是回到端到端效果对比。不要用几条测试样例口头判断“好像好多了”,要用一组固定问题、固定参考答案反复测同一版本。我习惯将查询集分成两个部分:一部分优化调参时看效果,一部分留作盲测,避免过度拟合到测试集上。一般迭代三轮以后,前测集指标会上升而盲测集指标可能不动,这时就要考虑是不是调参过拟合了。此时回归到数据层面,重新检查是否有更合理的路线。4.3 生成侧什么时候才需要介入判断完检索侧之后,还有少部分问题确实在生成侧。典型表现为:检索结果里已经给出了完整答案,但模型回答时仍然漏了要点、或者自作主张补充了文档里没有的额外信息。这种情况才需要动生成逻辑。常见介入方式包括:在提示词里明确要求“只根据提供文档回答,不要凭记忆补充”;把整体答案拆成“先简述再分条”的输出结构;或者对输出段落做忠实度校验,检测是否有与文档事实不符的表述。我接触的项目里,真到了需要针对生成侧动手的比例大概只有两成。其余八成,优化检索端之后就基本能解决问题。5. 实战问题与避坑清单5.1 高频问题速查表我在多个项目里反复遇到的几类问题,整理成了一个表,给读者们留个备份。遇到类似症状可以直接按图索骥。症状表现可能根因优先排查方向答案凭空捏造,看不出出处检索零召回或上下文无相关内容检查索引是否缺失、切分是否切断回答只覆盖问题一半召回不全或排序靠后的关键片段丢失提升 召回深度、加粗排答非所问但片段“相关”向量召回相似语义跑偏混合召回、查询改写型号/编号类查询总是找不到向量模型对强标识符不敏感加入 BM25 精确词匹配修一次好一次,换问题又崩测试查询集覆盖太窄扩充查询镜像集加了粗排反而变差粗排模型与领域不匹配微调粗排数据或换推理策略这张表不能解决所有问题,但它能帮你把优化精力集中在正确的方向,避免无头苍蝇式调试。5.2 几个容易忽略的细节第一个细节:索引更新频率。文档更新后,索引要重新构建或增量更新,很多测试环境的“效果差”其实是索引没跟上新文档,旧数据一直占着查询结果席位。第二个细节:检索日志一定要留全。当初没留日志,后面想复盘某个 query 为什么坏了,只能重新复现,效率极低。现在所有关键 RAG 请求里都保留 query、检索到的片段 ID、排序得分、最终输出这几个字段,出了任何效果问题都能快速回溯。第三个细节:粗排时别追求全准确率。粗排应该比“哪个绝对更相关”,而是“哪个明显更不相关”,把噪声压下去即可,因为用模型解决两可情况会放大它的幻觉。容忍模糊排序,把可靠排序做对,往往比追求满分更稳。第四个细节:别把嵌入模型和粗排模型混为一谈。它们的训练目标不同、交互模式不同、改变其中一个,整个召回链路的特性就会变。升级嵌入模型之后一定要重跑全链路评估,不能只看单点改进。5.3 迭代秩序:先窄后宽,先冷后热最后一条经验是优化节奏。我的建议是先用固定测试集把线上影响大、现象明显的 query 一条条优化过去,再做全量回归。这跟练拳一样,先把动作一招一式纠正,再打整套,才不容易把坏习惯固化。冷门但重要的知识段落和管理逻辑也不能忽略,哪怕用户提问频率不高,一旦被问错,后果很严重。先优化这部分,再来处理热门问题的性能优化,整体的稳定性和满意度都会更高。6. 一点个人体会:把检索端当产品来做技术在调参里越陷越深之前,我建议先退一步整体看一遍 RAG 架构。检索端不是一个“写条检索逻辑就完事”的功能,它直接决定了整个系统能力的上限。换模型、调提示词、做微调,全都是在有限召回结果上做后处理,回天乏力。所以我每一版 RAG 设计,检索端永远先做“数据检查”“查询集镜像”“指标基线”这三件事。数据检查让脏数据不过夜,查询集镜像让每一次改动都能量化,指标基线让优化方向有据可循。做好了这三件事,后面的调参自然就变得清醒。如果你现在正被某个 RAG 效果差的问题折磨,我的建议是:从今天起,不要再反复折腾大模型那一侧了。去查你的索引切分是否合理,去把那个“看一遍检索结果”的日志功能加上,去问自己“这一段检索回来的内容,到底有没有覆盖用户真正的问题”。把答案找出来,你离解决这个问题的距离,就不会远了。
先说结论:大部分 RAG 项目做出来效果不理想,问题不是出在大模型“不会答”,而是出在“喂进去的东西不对”。检索端决定了模型能看到什么,内容不准、不精、不完整,模型再聪明也是徒劳。我这两年帮人调过的 RAG 系统不少,从企业内部知识库到电商客服问答都有。凡是那种“测试的时候回答挺好,一上线就胡说八道”“多问几个问题就答非所问”“答案跟文档内容对不上”的场景,十次里有八次,根因都在检索链路,而不是生成链路。很多人第一反应是换更大的模型、加提示词、做微调,这些都是绕远路。真正该做的是把检索端当成独立的子系统去优化,从数据切分、向量召回、排序策略到查询改写,一步步排雷。这篇文章不写教科书式原理,就按实际踩坑的顺序来,把 RAG 为什么容易输在检索端、怎么快速定位问题、怎么系统性优化,一条条讲清楚。适合正在调试 RAG 应用、被效果问题折磨得头大的工程师,也适合刚接触 RAG、想看明白“症结到底在哪”的入门者。1. RAG 效果差到底差在哪:先给问题定性1.1 常见的“效果差”表现有哪些很多人说“RAG 效果差”的时候,其实描述的是完全不同的现象。我复盘过几十个案例,基本可以归成三类:第一类:答案与文档内容无关,或者直接编造。用户问的是文档里根本没有的信息,系统却一本正经地给了一个答案。这个叫“幻觉”,但本质上是检索结果里没有相关信息,模型只能靠训练记忆瞎猜。第二类:答案有相关片段,但融合得支离破碎。你打开检索到的片段,发现每条都有些相关,但放到一起却是东一榔头西一棒子,没有形成完整答案。这个典型是召回数量不足或排序有问题,关键上下文被漏掉了。第三类:回答“没错但没用”。检索到了正确主题的段落,却答不到用户问题的点上。比如用户问“退款多久到账”,检索回来的段落讲的是“退款申请流程”,主题相关,但缺了时间承诺这个核心信息点。这种问题最隐蔽,也是最容易被误判成“模型理解能力不行”的。这三类现象对应的根因方向完全不同。第一类多是索引覆盖不全或查询召回为空,第二类多是分块策略和召回配置不合理,第三类多是查询改写不足、排序策略太粗糙。如果上来就盲目调提示词,往往一个问题都解决不了。1.2 判断问题侧的最快方法:人工看检索结果遇到“效果差”的反馈,我的第一个动作从来不是改代码,而是把实际检索结果打印出来人工看一眼。这个动作虽然土,但是效率极高,五分钟就能定位侧别。操作很简单:取几条用户问得最多、效果最差的 query,直接调用检索模块,不管生成模块,把 Top 10 检索片段连同相关性打分打出来。然后你逐条问自己三个问题:这些片段里有没有存在能回答用户问题的关键信息?如果有,它排在什么位置?排在前三吗?排序靠前的片段质量怎么样?是有用的,还是标题相近但内容跑偏的?只要记录十几条 query 的结果,就足够看出规律。如果检索回来的片段里根本没有能回答问题的内容,那是检索侧的问题,生成侧不必管。如果片段里明明有答案,但最终回答还是错了,那才有可能是生成侧的融合和提炼出了问题。这个手工诊断法我推荐每个 RAG 项目都做一遍,而且要持续做。检索质量不是评完一次就结束,数据更新、用户提问分布变化,都会让问题重新出现。1.3 端到端指标掩盖了多少真相正规一点的团队会用端到端指标评估 RAG,比如回答准确率、相关性打分、忠实度。但端到端指标有个致命问题:它把检索和生成混在一起,你只知道结果差,不知道差在哪一环。举个例子,你用大模型逐条打分,问“这个回答是否忠实于给定文档”,得了 0.6 分。这个分数能说明生成器没有忠实引用文档,但完全没告诉你检索器有没有把该引的文档找回来。如果检索的召回就是空的,那生成器想忠实也没东西可忠实。所以我在团队里定了一个保守原则:所有 RAG 评估都必须分两层做。第一层叫检索评估,只看 Top-K 召回率、命中率、排序质量,跟生成完全脱钩。第二层才是端到端评估,看最终回答质量。只有两层分开看,才能知道优化该投在哪一侧。这个习惯帮我在很多项目里省了冤枉钱。有个项目曾想微调模型解决“答不对”的问题,我看完检索日志后发现 Top 10 里根本没有答案片段,果断建议先把索引建好。结果只调了清理数据和重排逻辑,效果直接翻番,微调白省了。2. 为什么问题多半在检索端:链路里的六道坎2.1 数据清洗和切分的锅,比想象中大得多很多团队搭建 RAG 时,最不重视的就是数据准备,觉得“直接切块塞进去就行”。这是第一个坑,而且是最深的坑。本地文档质量参差不齐,PDF 转出来带页眉页脚,表格被拆得七零八落,同一份文档在新旧版本里互相冲突,这些数据问题会原封不动地传导到检索结果上。再就是分块策略。切块大小、重叠长度、分隔符选择,每个参数都直接影响检索粒度。切太大,块内主题混杂,向量表示被平均化,检索精度下降;切太小,语义不完整,关键信息被切断,又召不回上下文。没有万能参数,但有个基准值得参考:通用文本最好控制在 300 到 800 token 之间,重叠 50 到 100 token;代码或表格这类结构化内容,则要顺着逻辑边界去切,不能死记 token 数。我见过最多的问题是把几个主题混在一块切,或者一个完整表格被拦腰切断,导致用户查“某型号故障代码”时,召回出来的片段只有表格的表头部分。这种问题靠换模型解决不了,只能回到切分环节,按标题层级和段落边界重切。2.2 嵌入模型选型与领域漂移嵌入模型的选型对检索质量的影响是全局性的,怎么强调都不过分。很多人直接套用开源社区默认模型,完全不考虑自己的文档领域和语言分布,结果检索效果自然不稳定。嵌入模型的核心问题是表征空间的适配性。通用模型在大规模语料上训练,对网络文本、新闻语料表现好,但换到专业领域,比如医疗器械说明书、法律合同、金融研报,词表和表达风格就存在明显漂移。你想一下,通用嵌入模型见过的是“手机屏幕坏了怎么修”,而你的用户问的是“YY/T 标准下三类医疗器械的注册变更流程”,这两者的向量空间根本不是一回事。处理办法有三层:第一,优先挑选在目标领域语料上做过训练的模型;第二,用少量典型 query 对几个候选模型做对比测试,哪个命中率高用哪个;第三,条件允许的话,用领域语料对嵌入模型做继续预训练或对比学习微调。多数项目做到第二层就够用了,不需要复杂化。2.3 查询与文档的语义鸿沟被低估了这是检索端最隐蔽的问题。用户自然语言提问和文档中的陈述句式往往存在巨大差异,用户不会按照文档作者的表述习惯去提问。举个常见的例子:文档里写的是“本产品适用于海拔三千米以下环境”,用户的提问可能是“去拉萨用会不会出问题”。两句话指涉同一个内容,但字面上几乎没有重合。检索模型通常只能捕捉词汇和浅层语义的相似性,真碰上这种“概念等价”的转换就抓瞎。这也是为什么我一直强调查询改写的重要性。检索前先把用户 query 改写成更贴近文档表述的检索式,是性价比最高的优化手段之一。常见的做法是根据对话上下文做指代消解,比如用户先说“我买的那个耳机坏了”,后一句问“怎么退换”,检索时就要补全成“耳机 退换流程”。还可以对同一个 query 生成多个改写变体同时检索,再合并去重,提高召回的覆盖面。我在实际项目里,只加了一个基于大模型的轻量改写,检索命中率就抬升了二十个百分点上下,这个投入产出比非常可观。2.4 向量检索的固有局限:只有相似,没有精准向量检索本身是近似语义搜索,它找的是“语义相近”,不是“事实精准”。这意味着它是召回的优秀工具,但不是排序的最终答案。大量项目里,我把向量召回和 BM25 混合检索都拉通测试一遍,发现很多专业 query 下,传统的关键词召回竟然更准。原因不复杂:向量检索擅长处理同义表达、模糊描述,但对专有名词、精确 ID、版本号、型号编码等强标识符信息不敏感。你检索一个“H3C S5130-52S-EI 固件升级失败”,向量模型可能给你召回一堆“交换机升级”“固件资料”的大类内容,精确型号反而被淹没了。所以现在稍微成熟一点的架构都采用混合检索:向量召回负责宽口子语义召回,BM25 负责精确词匹配召回,再把两路结果合并统一排序。这一层加完,检索命中率通常会有明显提升,而且成本几乎可以忽略。2.5 Rerank 缺失或形同虚设如果检索端一定要挑一个最值得投资的组件,我会毫不犹豫选重排模型。向量检索的目的是“宽进”,宁可错杀也不能漏掉,所以 Top 20 或 Top 50 里常常混杂大量低质片段。如果直接把这些结果一股脑丢给大模型,上下文里噪声太多,回答质量必然下降。重排模型的作用就是在宽召回的基础上做精细排序,把真正对当前 query 有用的片段压到最前面,把无关片段清出去。它和嵌入模型最大的区别在于:重排模型直接计算 query 与文档的交互相关性,而不是双塔式的相似度。这种交互式建模,对“问题与片段是不是真的匹配”的判断要可靠得多。很多团队没有做 rerank,或者做了但只把它当成一个排序函数摆在那里,没有细调输入输出。我在多个项目里的经验总结是:先让向量检索和 BM25 各自召回 Top 50 甚至 Top 100,合并后交给 rerank 取 Top 5 到 Top 8,再进生成环节。这个流程调好之后,回答质量通常会有肉眼可见的提升。2.6 排序后的上下文构造:数量与顺序都是变量最后一个环节容易被忽略:排序选出的片段以什么顺序、什么形式拼接成提示词,对生成质量影响不小。很多人直接把 Top N 依次拼接,第一个位置塞的是与查询最相关的,其他片段按序排布。但这个顺序未必最优。片段顺序会影响模型的信息整合方式。有些模型在长上下文中对中间位置的内容关注度更弱,所以务必要把最关键、最直接回答问题的信息放到靠前位置。另一些场景下,同一主题的碎片应该相邻放置,方便模型把零散信息拼装成完整答案。另外,Top N 不是越大越好。给模型塞 20 个片段,远不如精选 5 个高质量片段。上下文里的垃圾信息会产生注意力干扰,甚至直接盖过真正的答案。我给的建议是:先暴力召回,再严选进入上下文,宁可给模型少而精的素材。3. 检索端优化的实操流程:六步排查与修复3.1 第一步:建立查询镜像集优化检索端之前,必须得有一个足够有代表性的测试查询集。没有固定测试集,你根本不知道改了什么、效果是变好还是变坏。我习惯建立一个“查询镜像集”,维护了项目里真实用户最高频的 50 到 200 条 query,覆盖各类提问模式和困难案例。每一条 query 我都手工标注了标准答案片段或相关文档 ID。这个标注工作繁琐,但值得认真做。没有真实数据做支撑,后面做的每一项优化都是盲人摸象。建好之后,每次索引或检索逻辑改动,都拿这套查询集回归一遍,用命中率指标快速反馈。热门的开源库里有专门的检索引擎评测手册,各大采集器也支持构建自定义评测集。也可以自己写脚本,只需记录检索结果、让助手给相关性打分、按阈值归入命中或未命中,就能形成一套轻量评测。3.2 第二步:筛出“零召回”和“低排位”两类硬伤查询镜像集跑过一次之后,立刻能发现两类硬伤,它们的处理方式完全不同。零召回指 Top 50 里完全没有正确答案,这种问题基本指向数据与切分环节,需要检查文档有没有进索引、字段映射是否正确、切分是否切断了关键片段。低排位则指正确答案存在但排在十名开外,这种情况大概率是排序和重排环节不够强。排查零召回的常见手段是下拉原始文档,直接搜关键词,确认内容到底在不在库里。很多时候你会发现所谓的“零召回”只是文档格式太乱,比如扫描件没有 OCR、表格内容被转成了图片,这些内容根本没进索引。这一类问题占的比例相当高,排查后先别急着调模型,先解决数据入库问题。3.3 第三步:围绕切分策略做对照实验切分是检索质量的基础,值得专门花一轮时间做对比实验。我的做法是搭一个小型实验环境,对同一批数据分别用几种切分策略跑一遍,然后在查询镜像集上对比召回率。比如对技术文档,我会对比“固定 512 token 不重叠”“512 token 加 64 重叠”“按 Markdown 标题切”“按语义边界工具切”这几种方案。结果往往差异明显,尤其在文档结构清晰的情况下,按结构切分的效果要远好于固定长度硬切。原因也好理解,标题本身就是天然的语义边界,RAG 切分顺着它走,才能保住主题的完整性。重叠的意义在于把边界信息多保留一份,避免关键信息恰好卡在切分缝上。但重叠不是越多越好,太多重叠会导致内容冗余,降低检索精度。常规区间在 50 到 100 token。3.4 第四步:引入混合召回再加粗排如果单纯向量检索的命中率偏低,下一步就是接混合召回。比较通用的实现是向量检索和 BM25 各跑一路,对结果做加权融合。权重如何设置要用查询集调,先从 50/50 起步,然后分别观察偏好精确词还是偏好语义的查询类型的表现,再微调,不过大多数情况下最终结果都在 40/60 到 60/40 之间。然后是提醒了一百遍的加粗排。粗排的输入就是混合召回的 Top 50,输出是整理后的 Top 8。粗排模型一般以排序阶段微调的多任务模型为基座,部署时先用 CPU 推理也够用,如果延迟敏感再考虑压缩或上 GPU。重排层不建议省。我唯一见过重排意义不大的情况,是语料只有一两百条、用户提问都非常模板化。只要语料规模上千条,查询模式分散,重排对效果的影响基本都是决定性的。3.5 第五步:查询改写与多路召回查询改写的价值经常被低估,因为它让人觉得“不就是在提示词里加两句话”,但实测效果常常出人意料。最简单的方式是构造一个改写提示词,把用户问题、历史对话、期望的检索式格式都喂给模型,让模型输出一到三个候选检索式。这里有个细节很多人忽略:改写后的查询不要直接替换原查询,而是和原查询一起并行检索,最后合并结果。因为大模型改写存在过度概括的风险,可能把“iPhone 14 电池更换价格”写成了“苹果手机维修费用”,反而丢失了精确信息。多路并行检索再加去重,才能既扩大覆盖又不丢失精确词。3.6 第六步:元数据过滤与精细化路由到这一步,检索端的基本优化已经到位,但还有一个锦上添花的动作:元数据过滤。如果你的文档带有来源、时间、分类、部门等字段,可以在检索时强制过滤,把搜索范围缩小到相关子集,质量和速度都会提升。比如企业知识库里既有技术文档又有行政制度,用户问“请假流程”时,如果系统能先按文档类型过滤掉技术文档,检索精度会明显上升。这类过滤规则有的写在索引阶段,有的写在查询阶段,实现成本都不高。还可以做查询路由:先判断 query 属于哪个领域,再路由到对应的专业索引。比起一套通用索引打天下,这在多业务线的知识库场景下效果更可控。4. 评估与回归:怎么验证“检索端修好了”4.1 检索侧指标怎么设做了这么多优化,得有量化手段确认真的有效。我常用的指标有三类,每个都有明确含义:召回率@K:正确答案是否出现在前 K 个结果里。这是最核心的指标,因为 RAG 的底线是信息能不能被找到。命中位置:正确答案平均排在什么位置。方案从“找到”到“排前面”还有距离。排序相关性:用粗排后的得分均值或人工标注的相关性分数来评估粗排质量。这些都建议画成曲线看。只看单一数值容易忽略部分查询变差、部分查询变好的抵消效应。按查询类型分组统计是更细的做法,比如分为“专有名词型”“描写描述型”“多跳复合型”,分别看指标变化,能更精准判断优化方向。4.2 端到端效果对比:必须用同一批真实问题最后一步是回到端到端效果对比。不要用几条测试样例口头判断“好像好多了”,要用一组固定问题、固定参考答案反复测同一版本。我习惯将查询集分成两个部分:一部分优化调参时看效果,一部分留作盲测,避免过度拟合到测试集上。一般迭代三轮以后,前测集指标会上升而盲测集指标可能不动,这时就要考虑是不是调参过拟合了。此时回归到数据层面,重新检查是否有更合理的路线。4.3 生成侧什么时候才需要介入判断完检索侧之后,还有少部分问题确实在生成侧。典型表现为:检索结果里已经给出了完整答案,但模型回答时仍然漏了要点、或者自作主张补充了文档里没有的额外信息。这种情况才需要动生成逻辑。常见介入方式包括:在提示词里明确要求“只根据提供文档回答,不要凭记忆补充”;把整体答案拆成“先简述再分条”的输出结构;或者对输出段落做忠实度校验,检测是否有与文档事实不符的表述。我接触的项目里,真到了需要针对生成侧动手的比例大概只有两成。其余八成,优化检索端之后就基本能解决问题。5. 实战问题与避坑清单5.1 高频问题速查表我在多个项目里反复遇到的几类问题,整理成了一个表,给读者们留个备份。遇到类似症状可以直接按图索骥。症状表现可能根因优先排查方向答案凭空捏造,看不出出处检索零召回或上下文无相关内容检查索引是否缺失、切分是否切断回答只覆盖问题一半召回不全或排序靠后的关键片段丢失提升 召回深度、加粗排答非所问但片段“相关”向量召回相似语义跑偏混合召回、查询改写型号/编号类查询总是找不到向量模型对强标识符不敏感加入 BM25 精确词匹配修一次好一次,换问题又崩测试查询集覆盖太窄扩充查询镜像集加了粗排反而变差粗排模型与领域不匹配微调粗排数据或换推理策略这张表不能解决所有问题,但它能帮你把优化精力集中在正确的方向,避免无头苍蝇式调试。5.2 几个容易忽略的细节第一个细节:索引更新频率。文档更新后,索引要重新构建或增量更新,很多测试环境的“效果差”其实是索引没跟上新文档,旧数据一直占着查询结果席位。第二个细节:检索日志一定要留全。当初没留日志,后面想复盘某个 query 为什么坏了,只能重新复现,效率极低。现在所有关键 RAG 请求里都保留 query、检索到的片段 ID、排序得分、最终输出这几个字段,出了任何效果问题都能快速回溯。第三个细节:粗排时别追求全准确率。粗排应该比“哪个绝对更相关”,而是“哪个明显更不相关”,把噪声压下去即可,因为用模型解决两可情况会放大它的幻觉。容忍模糊排序,把可靠排序做对,往往比追求满分更稳。第四个细节:别把嵌入模型和粗排模型混为一谈。它们的训练目标不同、交互模式不同、改变其中一个,整个召回链路的特性就会变。升级嵌入模型之后一定要重跑全链路评估,不能只看单点改进。5.3 迭代秩序:先窄后宽,先冷后热最后一条经验是优化节奏。我的建议是先用固定测试集把线上影响大、现象明显的 query 一条条优化过去,再做全量回归。这跟练拳一样,先把动作一招一式纠正,再打整套,才不容易把坏习惯固化。冷门但重要的知识段落和管理逻辑也不能忽略,哪怕用户提问频率不高,一旦被问错,后果很严重。先优化这部分,再来处理热门问题的性能优化,整体的稳定性和满意度都会更高。6. 一点个人体会:把检索端当产品来做技术在调参里越陷越深之前,我建议先退一步整体看一遍 RAG 架构。检索端不是一个“写条检索逻辑就完事”的功能,它直接决定了整个系统能力的上限。换模型、调提示词、做微调,全都是在有限召回结果上做后处理,回天乏力。所以我每一版 RAG 设计,检索端永远先做“数据检查”“查询集镜像”“指标基线”这三件事。数据检查让脏数据不过夜,查询集镜像让每一次改动都能量化,指标基线让优化方向有据可循。做好了这三件事,后面的调参自然就变得清醒。如果你现在正被某个 RAG 效果差的问题折磨,我的建议是:从今天起,不要再反复折腾大模型那一侧了。去查你的索引切分是否合理,去把那个“看一遍检索结果”的日志功能加上,去问自己“这一段检索回来的内容,到底有没有覆盖用户真正的问题”。把答案找出来,你离解决这个问题的距离,就不会远了。