RAG检索优化实战:从文档解析到重排序的完整链路
做RAG项目十个有九个半最后卡在检索这一环。前面文档拆分、向量化做得再漂亮检索召回一堆不相关的内容生成端再怎么调prompt都白搭。我自己从第一版RAG系统跑通到真正能上线用中间大概有一半时间都耗在文档检索的调优上。这篇就把我在这条路上踩过的坑、验证过的方案、以及最后沉淀下来的标准流程完整梳理一遍。这篇文章主要面向三类人刚接触RAG、准备搭知识库但不知道从哪入手的同学已经在跑RAG流程、但检索效果差强人意、想系统调优的开发者以及准备面试RAG相关岗位、需要把检索链路讲清楚的人。我会从文档解析开始一路讲到分块、向量化、召回、重排序和评测把完整链条拆开揉碎。1. 为什么文档检索决定RAG成败把“查得准”拆成四个关键节点很多人一开始做RAG注意力全放在大模型怎么生成上觉得检索不过是“查一下向量库”。这个认知害了不少人。实际上生成端能发挥多少实力完全取决于检索端把哪些内容送到了模型面前。检索结果如果是一堆噪音生成端就算有GPT-4级别的能力也只能一本正经地编。1.1 检索环节在RAG里的真实占比从工程投入上看一个相对完整的RAG项目检索相关的组件——文档加载、清洗、分块、向量化、索引构建、召回、重排序——大概会占掉整个项目七成以上的代码量和调试时间。生成部分反而简单无非是选模型、写prompt、做流式输出。很多团队低估了这一点结果就是索引建得粗糙上线后用户问几个稍微复杂的问题就露馅。更具体一点说检索链路里每一个环节都可能在某个特定查询下变成短板。比如文档解析丢了一个表格那所有关于这个表格内容的提问都会失效分块没处理好一条完整逻辑被切断检索能召回关键词但召不回语义embedding模型选得跟文档领域不匹配专业术语的相似度计算直接跑偏。这些都不是生成端能补救的。1.2 判断检索质量的核心标准召回率、命中率与排序评判检索质量不能靠“感觉还行”。我习惯用三个维度来衡量召回率Recall关注的是“该召回的有没有被召回”。比如知识库里有十篇文档都提到某个政策条款一次查询只召回了三篇那召回率就是0.3。这个指标决定了答案的上限——没被召回的内容生成端再聪明也看不到。命中率Hit Rate更严格一些要求答案真正“藏”在召回内容的某一段里。很多时候召回率看着不错但真正承载答案的那一段没进结果命中也就不成立。排序质量则决定了生成端能不能第一时间读到关键信息。大模型的上下文窗口有限如果正确答案排到了第10位而前9位都是干扰项模型很容易被带偏。MRR平均倒数排名就是专门衡量这个的指标。1.3 先定一个可衡量的基线我的建议是任何检索优化工作开始前先建立一套最小可用的评测集和基线数据。哪怕评测集只有几十条查询也比没有强。否则你根本不知道改了一个参数到底是变好了还是变差了所有的优化都会变成碰运气。这个基线的建立方法我会在第7章详细展开。先把完整的检索标准流程讲清楚从文档进入系统的第一站开始。2. 文档加载与解析脏数据进库后面全白干文档检索的第一步不是向量化而是把源文档里的内容“无损”地拿出来。这里的“无损”不只是文字不丢还包括结构不丢、语义边界不丢。很多人在这步省事直接PDF转文本就灌进向量库后面检索效果差还找不到原因。2.1 不同文件类型的加载方案实际项目里最常见的三种文件类型PDF、Word、PPT/扫描件。每种类型的处理方案差别很大。PDF分两类处理文本型PDF和扫描型PDF。文本型PDF理论上可以直接抽取文字但很多PDF的文本层顺序是乱的——尤其是多栏排版的论文或报告抽出来之后段落在左栏和右栏之间跳来跳去。遇到这种情况不能简单地“按顺序读”必须做版面分析。扫描型PDF则必须走OCR开源的PaddleOCR和Tesseract都是常见选择前者对中文的支持明显更好识别表格结构时的效果也更稳。Word文档用python-docx读取即可但要注意处理嵌入的表格、文本框、页眉页脚。页眉页脚里的重复内容比如公司名称、页码默认应该丢弃否则它们会在向量库里形成大量噪音每次检索都可能被无关的页眉内容干扰。PPT更麻烦一些信息分散在标题、正文、备注里。很多知识库项目会丢掉演讲者备注但备注里往往藏着最完整的解释内容。我一般会把PPT每页的标题、正文、备注拼接成一条记录并保留页码作为元数据。2.2 版面分析与表格抽取最容易翻车的环节版面分析是个容易被忽略但极其关键的步骤。同一页PDF上可能同时有正文、图表、脚注、水印如果一股脑全抽出来当成连续文本检索时就会产生大量错位。我之前做过一个财报知识库项目一开始直接用PDF文本抽取结果所有财务问题的检索结果都不理想。排查后发现PDF文本层里表格数据被按行拆散并穿插进了正文段落一条完整的“营业收入X亿元”被截成了两半embedding自然算不出有效的语义表示。后来换了版面分析方案把每个区块单独提取表格整体作为独立文本块处理检索命中率立刻有了质的提升。对于复杂表格纯文本抽取基本都会破坏行列对应关系。一个更稳健的思路是把表格转成有结构的描述性文本比如把“2023年营收 | 2024年营收 | 增长率”这样的表头行和每一行数据拼接成“2023年营收为xxx2024年营收为xxx增长率为xx%”这种自然语言句子。这样既保留了语义完整性也方便embedding模型理解。2.3 清洗规则与元数据保留文本清洗不是简单去掉空格。常见的清洗操作至少要覆盖以下几类去除页眉页脚、页码、水印字符串规范化空白字符统一全角半角去除无意义的换行符PDF抽取时每行末尾经常有硬换行压缩连续空行处理乱码字符和特殊符号特别是从老式PDF里抽出的控制字符元数据的保留同样重要。每篇文档进入系统时应该记录来源文件名、章节标题、页码、文档类型、上传时间这些信息。有元数据的好处是双重的一个是检索过滤——用户限定只看某个章节时可以直接过滤另一个是引用溯源——生成端在回答时能准确标注“参考自XX文档第X页”这个能力在企业知识库场景几乎是刚需。3. 分块策略语义完整性与块大小的平衡文档切分成块是RAG流程里直接决定“检索到的东西能不能用”的关键环节。块切得太大向量化后语义会被稀释块切得太小语义不完整检索到了也看不懂。这中间的平衡纯靠经验但有一些基本规律可以遵循。3.1 按固定字符切 vs 按结构切很多RAG框架默认提供固定字符切分比如每256个字符或512个字符切一块重叠20到50个字符。这种切法实现简单、性能可控但问题在于它会无情地切断语义边界。举个例子一段话是“该政策自2024年1月1日起施行适用于所有注册在本市的企业”如果固定字符切分刚好把“自2024年1月1日起施行”切在上一块、“适用于所有注册在本市的企业”切在下一块那么单独检索任何一块都拿不到完整政策信息。按结构切分则更接近人类理解文档的方式按标题分段按段落切块把列表项合并成有意义的整体。Markdown标题、Word的标题样式、PDF的标题字体这些都可以作为切分边界。实践中我的默认策略是先按文档结构切出“父块”如果父块过长比如超过模型token上限再从段落边界二次切分而不是一开始就无脑按字符数切。3.2 Embedding模型的max tokens与重叠窗口切分块的长度上限必须跟embedding模型的上下文长度对齐。很多开源embedding模型的最大输入长度是512个token或者8192个token超过上限的部分会在向量化时被直接截断相当于静默丢信息。比单纯设定上限更重要的一点块的实际长度应该显著小于模型上限。因为一个块的语义密度才是关键而不是把上限撑满。我的经验是对于通用知识库256到512个token之间的块比较合适。超过512个token单个块的语义就开始发散低于128个token块与块之间的上下文断裂会变得严重。重叠窗口overlap的作用是缓解边界切断问题。切分时让前后两块有一小段重叠文本比如50个token这样即使关键信息落在边界上也大概率会完整出现在某一块里。重叠设置有一个副作用文件总的存储量和索引体积会变大但这点成本换来的召回稳定性是值得的。3.3 代码、表格、问答对等特殊块的处理不同内容类型有不同的最佳块形态这一点标准框架很少替你考虑。代码片段应该按函数、类、方法级别切块一个函数整体作为一个块。按行数切或者按字符切会让函数体四分五裂检索出来既没法看也没法用。表格内容我在第2章说过应该转成结构化的自然语言描述再切块。如果表格太大还要按行组分块不能整张表灌成一个块——一张几十行的宽表转成文本后有上千token向量化后语义严重模糊。问答对FAQ应该每条问答作为一个完整块。这类内容的特征是问题短、答案长检索时用户往往是拿问题去匹配所以块的头部最好就是问题原文答案紧随其后。有些框架会把问题和答案分开embedding检索时用问题部分做匹配效果也不错但工程上多了一套管理成本。还有一种常见场景是产品规格说明书里面大量出现短条目对应编号和属性描述。这种应该把编号名称属性值整体拼接成一条文本块否则用户问“XX型号的重量是多少”只检索到“重量2.3kg”这种片段也能用但丢了型号上下文的匹配精度就差很多。3.4 切分参数的影响用实测数据说话参数怎么定不能光靠理论要做对比实验。我在一个包含500篇技术文档的知识库上做过一次切分实验结果非常有参考价值切分策略块平均token数Recall5Hit Rate5固定256字符无重叠约1800.620.51固定256字符重叠30字符约1900.650.55按标题切分超限再按段落切约3600.780.66按标题切分段落边界表格结构化约3400.840.73同一个embedding模型、同一套检索逻辑仅仅是切分策略从固定字符换成结构切分命中率就从0.51涨到0.66再加上表格结构化处理来到0.73。这个提升幅度比我后来换任何模型都大。所以每次有人问我RAG效果不好先调什么我都说先别急着换模型把分块策略和文档解析质量搞扎实再说。4. 向量化与索引Embedding选型、相似度计算与索引结构分块完成后下一步是把每个块转成向量并建索引。这个环节表面上只是调API但选型不当会造成很多隐蔽问题。这里展开说几个关键决策点。4.1 Embedding模型选型与维度选择Embedding模型的选型核心考量是领域匹配度和语言支持。中文场景下直接用开源的通用英文模型效果通常很差必须选中文语料训练充分的模型。目前中文场景用的比较多的是BGE系列、M3E系列和text2vec系列OpenAI的text-embedding-3-small在中文上也能用但国内业务涉及数据合规时通常还是建议部署开源模型或走私有化方案。模型输出维度会影响存储和检索性能。常见的有384维、768维、1024维、1536维和3072维。维度越高理论上表示能力越强但存储开销和检索延迟也越大。对百万级以下的知识库768维是一个比较均衡的选择。这里有一个很多人忽略的点同一套系统里全程只能用一个embedding模型。分块时用A模型向量化上线后又换了B模型但旧的向量数据没重新生成这会导致新老向量在语义空间里不一致检索效果大打折扣。凡是涉及模型切换必须重建全量索引。4.2 相似度算法内积、余弦与欧氏的取舍向量化之后怎么判断两个向量的相似度也有讲究。主流的选择是余弦相似度和内积部分场景用欧氏距离。余弦相似度关注方向差异对向量模长不敏感。绝大多数语义检索场景选它最稳因为它更关注语义方向是否一致而不是绝对数值大小。内积则综合考虑方向和模长。如果embedding模型训练时用的是内积形式的损失函数检索时也用内积往往效果更好。需要特别注意的是有些模型默认对向量做归一化归一化之后余弦相似度和内积在数值上等价这时候用哪个都行。欧氏距离在低维稠密向量上也能用但对模长敏感容易受个别维度数值放大的影响我在实际项目中用得比较少。具体选哪个最终的答案应该来自你自己的评测集——同一批向量分别用不同相似度算法跑检索看哪个MRR高就选哪个。4.3 索引类型Flat、IVF、HNSW与磁盘索引向量索引决定了检索的效率和精度需要根据数据量来选。数据量在十万级以下时暴力检索Flat完全够用。原理就是把查询向量和库里每个向量都算一遍相似度虽然计算量大但这个量级下延迟依然在几十毫秒级别精度还最高。数据量到百万级以上就需要近似最近邻索引ANN。HNSW分层可导航小世界图是当前工程上最常用的选择检索速度快召回精度也比较高代价是建索引时内存开销较大。IVF倒排文件系列则先把向量聚类成多个桶检索时只搜最近的几个桶速度更快但精度会有一定损失。实际项目中我给知识库做索引时的判断标准很简单十万元素以下直接Flat超过百万再切到HNSW并且用评测集跟踪召回率变化。Mivus、Weaviate、qdrant、Elasticsearch的向量插件都内置了这些索引类型配置成本并不高。另外还有一点元数据过滤应该建在索引层面。比如用户限定“只看2024年的文档”如果过滤发生在检索之后那检索结果可能已经被非2024年的内容挤掉了正确的做法是把时间范围作为索引过滤条件让检索在过滤后的子集上进行。5. 检索召回从BM25、稠密向量到混合多路召回到了召回阶段核心任务是“从索引库里找出跟用户问题最相关的候选块”。成熟方案不会只依赖一种召回方式而是让不同的召回通道互相补位。5.1 稀疏检索BM25不可替代的原因BM25是经典的关键词匹配算法很多做RAG的人一上来就奔着向量检索去把BM25丢在一边这是不对的。向量检索擅长的是语义相似度匹配比如用户问“怎么申请退款”它能匹配到“客户发起退费流程”这种表述不同、语义相近的文本。但它有一个明显的弱点对专有名词、精确术语、编号、公式这类需要精确匹配的内容效果不稳定。用户搜索产品型号“A-100-X”embedding可能检索出各种语义相关的“高性能设备”却偏偏漏掉包含精确型号的文档。BM25恰好能补这个位。它对精确词项匹配非常敏感只要文档块里出现了查询词就能打出高相关分。而且BM25没有embedding模型引入的“语义偏差”问题对冷门术语和生僻编号的匹配效果非常可靠。更重要的是关键词匹配和语义匹配在结果上往往是互补的——关键词能拿到精确匹配向量能拿到同义改写。两条路同时跑再合并结果能显著提升整体召回率。5.2 稠密检索的API调用与实现稠密检索指的是用embedding模型把查询文本向量化然后在向量索引中检索相似向量的过程。在实现上有一个关键的差异点需要留意query向量化的文本不一定和chunk向量化的文本完全一致。比如有些方案会把query做一遍改写把口语化的问题改写成适合检索的短语或者提取出query里的核心实体再拿去向量化。我自己实践下来最简单的做法就是直接用原始query向量化配合下面的混合检索策略已经能拿到相当好的效果。但基线的结果差强人意时query改写是值得尝试的优化方向。用代码表示稠密检索的核心逻辑大概是这样的from sentence_transformers import SentenceTransformer import numpy as np # 加载与索引阶段相同的embedding模型 model SentenceTransformer(BAAI/bge-large-zh-v1.5) # 查询向量化 query_vector model.encode(user_query, normalize_embeddingsTrue) # 向量库检索以numpy暴力检索为例生产环境用Milvus等 scores np.dot(vector_corpus, query_vector) top_indices np.argsort(scores)[::-1][:top_k]代码虽然简单但有两个细节值得提。一个是用normalize_embeddingsTrue把向量归一化这样内积和余弦相似度等价检索结果更稳定。另一个是top_k的设置不要一上来就给很激进的值取20到50之间的候选数量留给后面的重排序去精挑这样比直接输出top 3效果好得多。5.3 多路召回与分数归一化多路召回的核心逻辑是BM25跑一路关键词召回向量检索跑一路语义召回然后再把两路结果合并去重。但这里有个常见问题BM25的分数和向量相似度分数不是同一个量纲不能直接放一起排序。BM25分数范围可能是0到30向量相似度范围可能是0到1直接相加或直接排序都会让一路召回被另一路彻底压制。我用过的最简单的合并方案是标准化排序法。具体做法是先分别从两路取top N比如各取30条合并成一个候选池并去重然后分别对两路的结果做min-max归一化让分数都落到0到1区间最后把同一文档的两路分数做加权求和权重根据实验调节常用的起点是BM25权重0.3、向量检索权重0.7。加权合并虽然简单但实际效果提升非常明显。在我做的项目里纯向量检索的MRR10是0.61加上BM25混合之后涨到0.73。原因就是两类召回互补一个是“懂意思”一个是“认字儿”用户的真实查询往往两种特征都有。5.4 检索超参数top_k、候选集与阈值召回阶段需要调的超参数主要有三个每路召回数量、候选池大小、相似度阈值。每路召回数量决定了召回的上限一般取20到50。太少了容易漏太多了后续重排序的计算开销变大。候选池大小是多路召回合并之后的池子大小通常比最终返回给生成端的结果多3到10倍。假设最终要给生成端提供top 5的块候选池建议至少保留20到30条给重排序留出充足的挑选空间。相似度阈值的作用是过滤明显不相关的内容。比如设置余弦相似度低于0.35的块一律丢弃。这个阈值不能拍脑袋需要通过评测集来标定。太严会误伤正确结果太松等于没设。一个实用技巧是统计评测集里“正确答案”的最小相似度分数把阈值设为这个值的80%左右留出安全余量。6. 重排序精排模型怎么让检索结果脱胎换骨多路召回拿到的是“候选集”里面内容庞杂排序逻辑也还是粗粒度的。如果直接把候选集塞给生成端大模型的注意力会被大量低质量内容分散。所以在这个节点上重排序环节非常关键。6.1 Rerank的价值召回精度从0.6到0.9我印象最深的一次改进是在一个企业内部知识库上做的对比。当时多路召回已经跑通MRR10是0.73Hit Rate10是0.82。看起来好像能用了但用户反馈经常是“看了半天没有我要的答案”。原因很简单——虽然正确答案在10条候选里但它往往排在第6、第7位生成端的注意力被前面几条低质量内容占满了。后来在候选集上接了一个rerank模型终排结果只看top 3Hit Rate3从0.58涨到了0.87用户反馈立刻好了非常多。这说明召回阶段保证了“答案在不在池子里”而重排序决定了“答案会不会被看见”。这两个环节的质量缺一不可。6.2 Cross Encoder与Bi Encoder的区别重排序主流方案用的是Cross Encoder架构和召回阶段常用的Bi Encoder有本质区别。Bi Encoder的思路是把query和doc分别编码成向量再用向量相似度计算相关性。优点是快可以预先算好所有doc的向量检索时只需算query向量。缺点是query和doc在编码阶段彼此独立交互信息完全丢失一些需要精细理解的关系比如“A不是B的原因”它判断不了。Cross Encoder的思路则是把query和doc拼接成一段完整的文本一起送进模型让模型在编码过程中充分捕捉两者的交互信息。这就像让一个人同时看问题和答案来判断匹配度而不是分别看。效果显著更好但代价是速度慢——每一个候选文档都要跑一次模型前向计算没法预计算。实际应用中我观察到Cross Encoder在精排这种“候选集不大、必须精确”的场景下效果和成本是最优平衡的。候选集一般是20到30条每条拼上query跑一次几十毫秒到几百毫秒的延迟完全可接受。6.3 Rerank的工程落地方案重排序的工程实现主流思路是用Sbert库加载一个Cross Encoder模型比如BGE-reranker系列或bge-reranker-v2-m3然后对候选集逐条计算相关性分数并排序from sentence_transformers import CrossEncoder # 加载rerank模型 reranker CrossEncoder(BAAI/bge-reranker-v2-m3) # 构造query和候选块的配对 pairs [(query, chunk_text) for chunk_text in candidate_chunks] # 计算相关性分数 scores reranker.predict(pairs) # 按分数降序排序 ranked sorted(zip(candidate_chunks, scores), keylambda x: x[1], reverseTrue)工程上有几个容易出错的地方需要提醒。一个是rerank的候选块文本不要太长超过模型最大长度会被截断所以候选块在进入rerank前最好截取关键段落比如每块取前512个token。另一个是对分数做归一化因为不同rerank模型的分数范围不一样后续如果要在多个文档之间做比较归一化会方便得多。如果文档数量非常庞大几十条候选集也可以分段并行rerank然后再合并。还有一点重排序模型的更新频率一般低于embedding模型选型时建议优先选多语言支持好、泛化能力强的版本避免频繁跟着上游模型升级而重建全链路。7. 检索效果测评没有评测集的RAG工程都是拍脑袋任何检索优化工作如果没有一套可靠的评测方法和指标就等于闭着眼睛开车。RAG检索效果不好时先别说换模型、调参数先建评测集。7.1 评价指标Recallk、MRR、Hit Rate、NDCG常用指标里Recallk前k条结果中包含相关文档的比例、Hit Ratek前k条结果中是否命中过正确答案、MRR第一个正确答案排名的倒数以及NDCG排序质量指标同时考虑相关性和位置各有侧重。我真实项目的做法是同时看两个核心指标Hit Rate3和MRR10。Hit Rate3衡量“生成端能不能看到答案”因为它决定大模型最终的输出质量MRR10衡量“检索排序整体合不合理”用于观察调优方向是否偏离。还有一个实际经验指标提升不等于用户可感知提升。比如MRR从0.7提到0.75数学上好看了普通用户可能感觉不到差别。但Hit Rate3从0.6提到0.8用户会明显觉得“回答靠谱多了”。所以对外报告优化效果时优先讲跟用户体验直接相关的指标。7.2 构建自己的评测集从文档中挖问题构建评测集不需要从零写问题最佳切入点是从文档内容里“挖”问题。我常用的方法有三步。一是从标题和章节标题生成查询。文档的每个二级标题、三级标题往往是内容的浓缩把标题作为查询词对应的章节内容就是标准答案。这类查询天然有结构适合验证检索的基本能力。二是从关键段落反推查询。挑出那些信息密度高的段落从中提取出可能被用户问到的实体和关系构造出“这个条款对谁适用”“那个指标的阈值是多少”这类具体问题。这类查询是真实用户最常输入的类型。三是从真实日志收集。如果系统已经上线用户的真实query就是最好的评测集。挑出高频但检索结果差的query人工标注应该命中的文档片段把这些样本加入评测集持续用真实反馈反向驱动优化。评测集的数量起步30到50条足够逐步扩展到100到200条就具备参考价值了。关键是保证多样性简单查询、复杂查询、术语查询、口语化查询各占一定比例。7.3 检索链路优化实验流程有了评测集和基线调优就变成一组可重复的实验循环。我的标准流程是这样跑一次全链路记录当前指标的基线数据每次只改一个变量其他因素全部固定。比如这次只改分块策略embedding、召回路数、rerank都不动在评测集上重新跑一遍对比指标变化如果提升有效保留该变更进入下一个变量的优化所有关键变更做完后做一次综合回归确认各项改动叠加后整体效果确实变好这套流程看起来繁复但实际收益非常大。我见过太多团队“感觉”换了个embedding模型就提升了但也说不清提升在哪里结果过了两个星期又发现某类查询效果退化。有了评测集和实验流程所有结论都可追溯。有一句话我很认同没有评测的RAG优化本质上是把随机改进当成经验。8. 检索优化的进阶方向Graph RAG、Agentic RAG与混合策略标准检索流程稳定跑通之后如果还想继续提升效果有几个进阶方向值得探索。它们不是替代标准流程而是在标准流程之上的增强。8.1 什么时候要考虑Graph RAGGraph RAG最近讨论热度很高它的思路是在文档检索之前先抽取实体和关系构建知识图谱然后通过图搜索找到与查询相关的事实路径。这和多路召回是两种不同的信息组织范式向量检索擅长“语义相似”图检索擅长“多跳关系”。什么场景适合引入Graph RAG我总结下来有三个特征文档里的知识以实体关系为主用户问题涉及多个实体之间的关联且答案不能只凭单一文档块得出。比如“A产品在2023年之后是否兼容B协议”这个问题需要跨越多个文档片段把A产品、B协议、2023年三个实体之间的关系串起来纯向量检索很可能找不到一条完整答案。图检索则可以通过“A产品—兼容—B协议”“B协议—发布时间—2023年”这样的路径直接给出答案片段。但Graph RAG有很高的工程成本实体抽取准确率、关系图谱质量、图存储与查询的运维都不是简单配置就能搞定的。对一个知识库做完整实体和关系抽取本身大概率还需要跑LLM每条文档的抽取成本都不低。我自己的建议是常规场景先把标准RAG链路调到最好只有当问题确实需要跨实体推理、或者文档本身就是强关系型数据如产品架构、组织架构、法规体系时再引入图检索。8.2 Agentic RAG中的多轮检索与工具调用Agentic RAG把检索从“单轮查一次”变成“根据主模型决策多次查”。典型场景是用户先问了一个问题主模型判断需要先查文档A确定某个概念再根据这个概念查文档B找更具体的答案中间还可以改写查询词、切换检索工具。我做过一个简单的Agentic RAG原型核心是给主模型提供几个检索工具向量检索、BM25检索、文档列表查询、元数据过滤查询。主模型根据用户问题决定调用哪个工具、各调几次、是否组合结果、最终怎么组织回答。这个方法让系统能处理那种需要分步骤检索的复杂问题。工程上的门槛在于可靠性和成本。多轮检索意味着多次模型调用延迟和token费用都会明显上升。同时主模型的决策扰动比单步检索大得多一旦推理方向跑偏结果可能比标准流程还差。所以在做Agentic RAG之前必须确保单轮检索本身已经足够好否则Agent只会把错误放大。8.3 检索缓存的工程价值最后分享一个看似不起眼、但实际收益巨大的一点检索缓存。生产环境里用户的高频问题大多集中在少数主题上。与其每次都走一遍完整的检索-重排序流程不如对最近一段时间的热门query做结果缓存。当同一个query再次出现时直接返回缓存结果延迟可以从几百毫秒降到几毫秒成本几乎为零。缓存策略需要注意两个问题一是缓存失效问题知识库更新后相关缓存必须同步失效二是相似问题处理问题缓存通常以query文本精确匹配为主如果两个用户问的是同一件事但措辞不同缓存就命中不了。更进阶的做法是把query先embedding化用向量近似匹配来命中语义相似的缓存但这个方案对工程要求更高暂时不是必须。我的建议是优先做精确匹配缓存配合“新文档入库后自动清理涉及该文档的缓存”这个机制已经能在真实业务里省下不少成本。从文档解析到分块、向量化、多路召回、重排序再到评测优化这是我在多个RAG项目里反复打磨后沉淀下来的完整检索链路。每一步踩过的坑都在上面写清楚了。如果你正准备做RAG或者正在调一个效果不理想的知识库建议先按这套流程把检索链路跑通跑稳再考虑那些花哨的进阶玩法。检索稳了RAG的整个地基才算真正打牢。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →