
1. 为什么 RAG 落地总在“最后一公里”翻车做过 RAG 项目的人大概都有同一种体感Demo 阶段惊艳上线之后拉胯。你拿一份 PDF 丢进去问什么答什么感觉通用人工智能不过如此可一旦换成真实业务里的几百上千份文档问题就全冒出来了——该召回的内容没召回不该召回的一大堆模型拿着半截上下文开始一本正经地胡说。很多人第一反应是“换个更强的 embedding 模型”或者“上个更大的 LLM”折腾一圈发现提升有限钱倒是花了不少。我前后经手过几个 RAG 项目从早期的 LangChain 快速原型到后来用 Spring AI、LangChain4j 做企业级知识库踩过的坑基本能凑成一本小册子。这篇就把分块、召回、重排这三个最核心环节里我认为最有价值的 6 个实战结论摊开讲清楚。它们不是论文里的理论而是我在真实数据上反复调参、对比、翻车之后沉淀下来的判断。先说清楚这篇适合谁看如果你正在做 RAG 知识库、企业文档问答、产品检索这类项目已经跑通了基础流程但效果卡在瓶颈上那这篇基本就是给你写的。如果你还没入门也能看懂因为我会把每个结论背后的“为什么”讲透而不是甩一堆参数让你抄。核心关键词就几个RAG、分块、召回、重排、embedding全文围绕它们展开不跑题。我先把结论的骨架亮出来后面逐个展开分块不是越小越好也不是越大越好关键看“语义完整性”和“检索粒度”的平衡召回阶段别迷信单一向量检索混合检索才是稳定方案重排不是可选项是决定最终命中率的关键一环embedding 模型选型要看语言、领域和成本不是排行榜第一就适合你分块、召回、重排三者是联动的单独优化任何一个都容易白费力气评估体系必须提前建否则你根本不知道改动是变好还是变坏。下面进入正题。2. 分块策略别再用固定长度切一切了2.1 固定长度分块为什么在真实文档上必然翻车刚接触 RAG 的时候几乎所有人都会用最朴素的分块方式按字符数或 token 数切比如每 500 字一块重叠 50 字。这个方法在结构规整的文本上勉强能用但真实业务文档是什么样是带标题层级的产品手册、是表格和正文混排的合同、是问答对形式的客服记录、是代码和说明交织的技术文档。你拿固定长度一刀切下去最典型的后果就是一个完整的操作步骤被切成两半前半段在块 A后半段在块 B用户问“这个功能怎么用”检索到块 A模型只看到半截步骤回答自然缺胳膊少腿。我做过一个对比实验用同一份 200 页的产品文档分别用固定长度分块和语义分块问 50 个真实用户问题。固定长度分块的召回命中率大概在 62% 左右语义分块能到 81%。差距主要就来自那些被切断的语义单元。这个数字不是绝对的但方向很明确分块的边界应该尽量落在语义的自然断点上而不是数字的整数位上。那什么是语义自然断点段落、章节标题、列表项、表格行、问答对这些都是。你要做的是先解析文档结构再按结构分块而不是拿到纯文本就开始切。2.2 语义分块与结构分块的实操做法具体怎么做分两步走。第一步是文档解析把原始文件PDF、Word、HTML、Markdown转成带结构标记的中间格式。这一步很多人偷懒直接用 PyPDF2 抽纯文本结果标题、正文、表格全糊在一起后面怎么分块都救不回来。我的建议是尽量保留结构信息比如用 Markdown 作为中间格式标题用#标记表格用管道符列表用-。这样后面分块时就能识别出“这是一个二级标题下的三个段落”。第二步是按结构分块规则可以这样定一级标题作为大块边界二级标题作为中块边界每个中块内部如果段落总长度超过阈值比如 800 token再按段落切表格单独成块不要把表格和正文混在一起列表项如果语义独立可以单独成块也可以整组保留看检索需求。这里有个关键参数块的最大长度和最小长度。最大长度受 embedding 模型的输入限制和 LLM 上下文窗口影响一般控制在 512 到 1024 token 之间比较稳妥。最小长度别低于 100 token太短的块信息量不足检索出来也没用。重叠部分我建议保留 10% 到 15%主要是为了防止边界处的语义丢失但重叠太多会引入冗余增加检索噪声。提示分块完成后一定要抽样人工检查。随机抽 20 个块看看有没有明显的语义断裂、有没有把不相关的内容硬塞在一起。这个动作花不了半小时但能帮你发现 80% 的分块问题。2.3 分块粒度与检索粒度的匹配问题还有一个容易被忽略的点分块粒度要和检索粒度匹配。什么意思如果你分块分得很细每个块只有一两句话那检索时确实容易命中但命中之后给 LLM 的上下文太碎模型拼不出完整答案。反过来如果块很大一个块里塞了五六个主题检索时向量表示会被平均掉命中率反而下降。我的经验是分块时按“一个块回答一个问题”的原则来切。也就是说你想象用户会问什么问题每个块应该能独立回答某一类问题。产品手册里“如何安装”是一个块“如何配置”是另一个块“常见报错”再一个块。这样检索时用户问安装命中的就是安装块上下文干净模型回答也准。如果文档本身没有这么清晰的结构那就退一步按“主题段落”切每个块围绕一个主题长度控制在 300 到 600 token。这个范围是我试下来比较平衡的区间既不会太碎也不会太泛。3. 召回环节单一向量检索为什么不够用3.1 向量检索的天然短板向量检索也就是常说的语义检索的原理是把 query 和文档块都映射到同一个向量空间然后算余弦相似度取最相近的 top-k。它的优势是能理解语义用户问“怎么退款”文档里写“如何申请退货”字面不重合但语义相近向量检索能命中。这是它比关键词检索强的地方。但它的短板也很明显。第一对专有名词、型号、代码、编号不敏感。用户问“CADENCE 位号重排怎么操作”如果文档里写的是“位号重排Reference Designator Reordering”向量检索可能因为训练语料里这些术语出现频率低导致向量表示不准召回失败。第二对精确匹配需求无能为力。用户问“错误码 E1024 是什么意思”向量检索可能召回一堆语义相近但错误码不同的内容。第三对长尾 query 效果差。冷门问题在向量空间里可能落在稀疏区域相似度计算不稳定。我实测过一个企业 ERP 知识库纯向量检索的 hit rate 大概在 70% 上下剩下 30% 的失败案例里超过一半是专有名词和精确匹配类问题。这个比例在真实业务里是致命的因为用户往往就是带着具体型号、具体错误码来问的。3.2 混合检索的落地配置解决方案是混合检索向量检索 关键词检索BM25 或类似算法两路结果融合。关键词检索负责精确匹配向量检索负责语义匹配两者互补。融合方式有两种一种是加权求和给两路分数各乘一个权重再加起来另一种是 Reciprocal Rank FusionRRF按排名融合不依赖分数绝对值更鲁棒。我一般用 RRF因为它不需要调权重省事且稳定。具体做法是向量检索取 top-20关键词检索取 top-20然后用 RRF 公式合并取合并后的 top-10 进入下一阶段。RRF 的公式很简单每个文档的得分是sum(1 / (k rank))k 通常取 60。这个方法的妙处在于它只看排名不看分数避免了不同检索器分数尺度不一致的问题。配置上关键词检索我推荐用 BM25成熟稳定Elasticsearch、OpenSearch 都内置支持。如果不想引入额外组件也可以用简单的 TF-IDF 或者 BM25 的轻量实现。向量检索这边Milvus、Qdrant、pgvector 都是常见选择看你的技术栈。Spring AI 和 LangChain4j 都提供了混合检索的抽象但底层还是得自己配。注意混合检索的两路结果要去重。同一个文档块可能被两路都召回融合前先按块 ID 去重否则会重复占位挤掉其他有用结果。3.3 召回数量怎么定才合理top-k 取多少这个问题我被问过无数次。我的答案是召回阶段宁多勿少重排阶段再收窄。因为召回是漏斗的第一层漏掉的内容后面再也找不回来。我一般向量检索取 top-20 到 top-30关键词检索取 top-20融合后取 top-15 到 top-20 进入重排。重排之后最终给 LLM 的上下文控制在 top-3 到 top-5。为什么不直接召回 top-5因为向量检索的排序质量有限真正相关的内容可能排在第七第八位你取 top-5 就漏了。多召回一些让重排模型去精挑细选整体效果更好。代价是重排阶段的计算量增加但重排模型通常比 LLM 小得多这点开销值得。有个数据可以参考我在一个法律文档问答项目里召回 top-5 的 hit rate 是 68%召回 top-20 再重排取 top-5hit rate 提升到 89%。这 21 个百分点的提升几乎全部来自“多召回 重排”这个组合。4. 重排被低估的命中率放大器4.1 重排到底在做什么重排Rerank的本质是一个精排模型它接收 query 和候选文档块输出一个相关性分数然后按分数重新排序。和向量检索的区别在于向量检索是双塔结构query 和文档分别编码最后算相似度速度快但精度有限重排是交叉编码器Cross-Encoderquery 和文档拼在一起输入模型能捕捉更细粒度的交互信息精度高但速度慢。所以典型架构是向量检索快粗筛→ 重排慢精排→ LLM生成。重排模型的选择上开源的有 BGE-Reranker、Cohere Rerank有免费额度、Jina Reranker 等。我常用的是 BGE-Reranker 系列中文效果不错部署也简单。如果追求极致效果且预算充足Cohere Rerank 的 API 调用很方便延迟也低。重排的输入是 query 候选块列表输出是每个块的相关性分数。你按分数降序取 top-n 就行。这里有个细节重排模型的输入长度有限制通常是 512 token。如果你的块超过这个长度会被截断影响精度。所以分块时控制长度不仅是为了 embedding也是为了重排。4.2 重排模型的选型与部署选型上我列几个我实际用过的模型语言支持部署方式相对效果备注BGE-Reranker-v2-m3中英本地部署强推荐平衡好Cohere Rerank 3多语言API很强有免费额度延迟低Jina Reranker v2多语言API/本地强长文本支持好bge-reranker-base中英本地中轻量适合资源受限本地部署 BGE-Reranker 的话用 HuggingFace Transformers 或者 Text Embeddings InferenceTEI都行。TEI 部署简单性能也好适合生产环境。显存占用方面base 版本大概 1-2GBlarge 版本 3-4GB看你的 GPU 情况。如果不想自己部署Cohere Rerank 的 API 是最省事的调用一次大概几十毫秒成本按调用量算。对于中小规模知识库这个方案性价比很高。LangChain4j 和 Spring AI 都集成了 Cohere Rerank配置几行代码就能用。4.3 重排前后的效果对比与参数调优重排的效果提升有多大我拿一个客服知识库做过对比不加重排top-5 的 hit rate 是 72%加了 BGE-Reranker 之后top-5 的 hit rate 到 91%。这个提升幅度在 RAG 项目里算是非常显著的而且成本增加有限。所以我一直说重排是 RAG 落地里性价比最高的一个环节没有之一。调优方面主要关注两个参数重排的候选数量和最终返回数量。候选数量我一般设 15 到 20太少重排没得选太多重排延迟增加。最终返回数量看 LLM 的上下文窗口和任务需求一般 3 到 5 个块足够。如果 LLM 上下文很大可以放宽到 8 到 10 个但要注意噪声也会增加。还有一个技巧重排分数可以设阈值。如果所有候选块的重排分数都低于某个阈值比如 0.3说明这次检索可能没有真正相关的内容这时候可以触发兜底策略比如返回“未找到相关信息”或者转人工。这个机制能有效减少幻觉因为模型不会拿着不相关的上下文硬编答案。5. Embedding 模型选型排行榜第一不一定适合你5.1 中文场景下的 embedding 模型对比Embedding 模型是 RAG 的地基地基不稳上面怎么调都白搭。选型时不能只看 MTEB 排行榜因为排行榜的评测数据集和你的业务数据分布可能差很远。我选 embedding 模型主要看四点语言支持、领域适配、向量维度、推理成本。中文场景下我实际用过的几个模型BGE-M3目前中文开源里综合最强的之一支持多语言、长文本8192 token向量维度 1024。缺点是模型较大推理稍慢。BGE-large-zh-v1.5中文专用效果稳定维度 1024社区使用广泛。text-embedding-3-largeOpenAI多语言效果好维度可调但 API 调用有成本数据出境需考虑合规。Conan-embedding中文榜单表现很好适合纯中文场景。GTE-Qwen2阿里系中文效果不错长文本支持好。如果预算允许且数据可以走 APIOpenAI 的 text-embedding-3-large 是很省心的选择。如果要求本地部署BGE-M3 或 BGE-large-zh 是稳妥方案。选型时建议拿你自己的业务数据做个小评测构造 50 到 100 个 query-文档对看哪个模型的召回命中率最高。这个评测花半天时间但能避免选错模型后的大量返工。5.2 向量维度与检索性能的权衡向量维度直接影响检索速度和存储成本。维度越高表达能力越强但检索越慢、存储越大。1024 维是当前主流768 维在效果和成本之间也比较平衡。有些模型支持 Matryoshka 表示学习可以截断维度比如 1024 维截到 512 维效果损失不大但速度提升明显。BGE-M3 和 text-embedding-3 都支持这种特性。如果你的知识库规模在百万级以下维度的影响没那么大1024 维完全没问题。如果到了千万级甚至亿级就要认真考虑降维或者量化。量化方面可以把 float32 转成 int8存储直接省 75%检索速度也快效果损失通常在 1% 到 2% 之间可以接受。Milvus、Qdrant 都支持量化索引配置一下就行。提示换 embedding 模型意味着所有文档块都要重新编码这是一笔不小的开销。所以选型时尽量一次选对别频繁换。如果非要换做好全量重编码的准备并且要重新评估检索效果。5.3 领域微调 embedding 的时机什么时候需要微调 embedding我的判断标准是通用模型在你的业务数据上 hit rate 低于 75%且失败案例集中在领域术语上。比如医疗、法律、金融这些专业领域通用模型对术语的理解可能不够精准微调能带来明显提升。微调 embedding 需要构造正负样本对通常是 query-正文档-负文档的三元组。数据来源可以是用户点击日志、人工标注、或者用 LLM 合成。微调框架用 sentence-transformers 就行几张 GPU 卡跑几个小时。但微调有风险数据质量差会导致效果不升反降所以一定要留出验证集微调前后对比。如果数据量不够或者没精力搞微调退而求其次的做法是在 query 侧做扩展。比如用户问“位号重排”你可以用 LLM 把 query 扩展成“位号重排 Reference Designator Reordering 操作方法”再拿去检索这样能弥补一部分术语鸿沟。这个技巧成本低见效快值得一试。6. 分块、召回、重排的联动调优与评估体系6.1 三者联动的调优顺序分块、召回、重排不是独立的它们互相影响。调优时如果东一榔头西一棒子很容易白费力气。我总结的顺序是先定分块再调召回最后上重排。为什么这个顺序因为分块决定了检索的基本单元分块不合理召回和重排怎么调都上限有限。召回是在分块基础上做粗筛召回数量和质量直接影响重排的输入。重排是最后一道精筛前面漏掉的内容它救不回来。所以必须按这个顺序来每一步稳了再走下一步。具体操作上分块阶段用人工抽检 小规模评测确认块质量召回阶段对比纯向量、纯关键词、混合检索的 hit rate确定最优组合重排阶段对比不同重排模型和参数看最终 hit rate 和 LLM 回答质量。每一步都记录数据形成基线后面改动才有参照。6.2 构建 RAG 评估集的实操方法没有评估集调优就是盲人摸象。评估集怎么建最靠谱的是从真实用户问题里采样。如果项目刚起步没有用户日志就找业务方访谈让他们提 50 到 100 个典型问题。每个问题标注出应该命中的文档块ground truth然后计算 hit rate、MRR、NDCG 这些指标。Hit rate 最直观top-k 结果里有没有包含 ground truth有就是 1没有就是 0平均一下就是命中率。MRR 看的是第一个正确结果排在第几位越靠前越好。NDCG 考虑排序质量更精细但计算复杂。我一般用 hit rate 和 MRR 就够了简单有效。评估集要覆盖不同类型的问题事实型“X 是什么”、操作型“怎么做 X”、对比型“X 和 Y 的区别”、精确匹配型“错误码 E1024”。每类问题至少 10 个这样评估结果才有代表性。评估集建好后每次改动都跑一遍看指标变化。指标下降就回滚上升就保留。这个流程听起来笨但比拍脑袋靠谱得多。6.3 常见瓶颈的定位与突破RAG 效果上不去瓶颈到底在哪我整理了一个排查表症状可能瓶颈排查方法解决方向召回内容不相关分块太碎或 embedding 不准人工看召回块内容调整分块粒度换 embedding召回内容相关但排序靠后重排缺失或重排模型弱看 ground truth 排名加重排换更强重排模型召回内容相关但 LLM 答非所问上下文噪声大或 prompt 问题看 LLM 输入上下文减少召回数量优化 prompt专有名词召回失败向量检索短板看失败 query 类型上混合检索query 扩展长文档召回不全分块切断语义检查分块边界语义分块增加重叠整体 hit rate 低多环节问题分环节评估按分块→召回→重排顺序调这个表我贴在工位上出问题就对着查效率很高。大部分 RAG 瓶颈不是单一环节的问题而是多个环节叠加。比如分块太碎导致召回噪声大噪声大导致重排也救不回来最后 LLM 回答质量差。所以排查时要一层层剥别指望一个改动解决所有问题。7. 我在实际项目里踩过的坑和几条硬经验说几个具体的翻车案例。第一个是分块重叠设太大。早期我为了“保险”把重叠设成 50%结果检索时同一个内容被召回好几次占了 top-k 的名额真正有用的内容反而被挤掉。后来把重叠降到 10% 到 15%hit rate 反而提升了。这个教训是重叠是为了防边界丢失不是为了增加召回量别本末倒置。第二个是重排模型和 embedding 模型不匹配。我用 BGE-M3 做 embedding却用了另一个体系的 reranker结果重排分数和向量分数尺度差异大融合时排序混乱。后来统一用 BGE 系列问题消失。所以选型时尽量用同一体系或经过验证的组合别随便混搭。第三个是忽略 query 预处理。用户输入往往很口语化比如“那个退款咋弄啊”直接拿去检索效果很差。加一层 query 改写用 LLM 把口语 query 转成规范 query“如何申请退款”再检索hit rate 能提升 10 个点以上。这个预处理成本很低但收益很大强烈建议加上。最后一个经验是关于评估的别只看 hit rate要看端到端回答质量。有时候 hit rate 提升了但 LLM 回答反而变差因为召回了更多噪声。所以评估要分两层检索层看 hit rate生成层看回答准确率和幻觉率。两层都达标才算真的好。这个内容后续还可以这样扩展把 Agentic RAG 的思路引进来让模型自己决定检索几次、检索什么、要不要重排而不是固定流程。这块我还在试等有稳定结论再单独写一篇。如果你也在做 RAG欢迎交流你踩过的坑尤其是分块和重排这块我觉得还有很多细节值得挖。