做 RAG 项目最怕什么不是模型不够强也不是向量库选得不对而是辛辛苦苦搭好的检索问答系统一问就答非所问引用的资料明明就在知识库里模型却像没看见一样。我这两年一直在折腾大语言模型LLM的应用落地RAG检索增强生成是绕不开的核心架构今天就把我优化 RAG 性能的经验系统地整理一遍从数据准备到检索策略再到生成控制每个环节都有可以直接抄作业的参数和配置。这篇内容适合正在做 RAG 落地的开发者、准备用私有知识库做问答的团队以及那些已经把 RAG 跑起来但效果不理想、想系统性提升召回率和答案质量的朋友。我会把优化思路拆解开讲清楚每一步为什么这么做、怎么做、踩过哪些坑。1. 先搞清楚 RAG 性能瓶颈到底在哪很多团队一上来就调向量检索的参数或者换更强的生成模型但效果往往不明显。原因很简单RAG 是一个链路链路里任何一个环节出问题最终答案都会受影响。我自己的经验是优化之前先做瓶颈定位比盲目调参重要十倍。1.1 RAG 链路的四个关键环节一个完整的 RAG 流程可以拆成四个阶段数据预处理、向量索引构建、检索召回、生成答案。每个环节都有各自的性能影响因素而且是层层递进的关系。数据预处理阶段决定知识库的“底子”。文档格式乱七八糟、内容冗余、切分不合理后面无论怎么调都救不回来。向量索引构建阶段的核心是 Embedding 模型和向量存储方案这决定了语义相似度计算的准确性。检索召回阶段负责从知识库里找出最相关的片段召回率不够就会漏掉关键信息。生成阶段则受 Prompt 设计、上下文窗口管理和模型能力的影响决定了模型能不能用好检索到的内容。我用过一个很直观的排查方法把问题直接丢给模型不带任何检索上下文看它怎么答再带上检索上下文看它怎么答。如果两份答案差异巨大说明检索环节是有效的问题可能出在生成端如果带了上下文还是答错而且检索结果明显不相关那问题就更可能出在检索或者数据切分上。1.2 性能问题优先级排序按照我踩过的坑RAG 性能问题的优先级应该是数据质量 检索召回 上下文组织 模型选择。很多团队反着来先砸钱换更大的模型效果依然拉胯。比如知识库里的文档用 PDF 直接解析表格内容全丢这时候模型再强也答不对数据。再比如文档切分尺寸设置为 500 个字符固定步长不重叠一段逻辑完整的内容被切成两半检索的时候永远只能召回一半的信息。有个经验值可以参考如果检索结果的 Top5 相关度都不高先检查数据切分再看 Embedding 模型是否匹配领域语言最后才怀疑向量库。如果检索结果相关但模型答案仍然错误再检查 Prompt 结构、上下文是否超长被截断、是否有指令冲突。这个排查顺序帮我解决过好几个项目里“看起来没问题但效果很差”的疑难杂症。2. 数据准备阶段把知识库的底子打好数据准备是 RAG 优化里投入产出比最高的环节却最容易被忽视。一批高质量的知识库数据配合合理的切分策略能让检索效果直接上一个台阶。2.1 文档清洗是第一步原始文档格式千奇百怪PDF 里的页眉页脚、扫描件的 OCR 噪声、网页导出的重复导航栏这些内容如果不清理会被切进 chunk 里成为检索噪声。我之前处理一批行业报告每页都有大段公司介绍页眉检索“某产品参数”的时候召回的全是页眉文本。清洗阶段要处理的典型问题包括统一编码格式UTF-8 必须统一否则乱码直接污染向量去除页眉页脚、页码、水印文字处理表格和图片表格转文本或 Markdown 格式图片用 OCR 转文字否则信息直接丢失去重文档内重复段落、跨文档重复内容都要去重。我建议用内容解析工具将文档转成结构化 Markdown 再做清洗而不是直接拿纯文本处理这样能保留标题层级和表格结构对后续切分非常有帮助。2.2 Chunk 切分策略尺寸、重叠与分隔符切分策略直接影响检索的精准度。切大了一个 chunk 里混入多个主题向量表示会被“平均化”检索相关度下降切小了语义不完整单独一个片段信息量不足模型生成答案时缺少上下文。我的经验值如下通用文本 300 到 500 个 token 的块大小比较合适配合 10% 到 20% 的重叠代码或结构化数据用按函数、类、模块边界切分表格数据建议整表作为一个 chunk保留 Markdown 表格结构法律合同这种长段落文档用 800 到 1000 token 配合段落边界切分。关键技巧是按语义边界切分而不是死板地按字符数切。我通常的做法是先用文档结构标题、段落做一级切分再对超长段落做二级切分并在切分点保留前后各一段文字作为重叠。这样每个 chunk 的语义完整性远高于固定长度硬切。Markdown 的标题结构可以天然作为切分锚点按 H1/H2 切出章节级 chunk再对过长的章节递归切分。补充一个很容易忽略的点切分后的 chunk 最好生成一个 ID 关联到原始文档位置方便溯源和调试。我调试检索效果时经常要定位“这个 chunk 在原始文档的哪一段”没有这个关联关系会很痛苦。3. 检索策略优化召回准不准全靠这里检索阶段决定了模型能看到什么。召回不相关的内容模型再聪明也会被误导相关的内容没被召回模型只能瞎编。这个环节优化空间最大也是能立竿见影看到效果的部分。3.1 Embedding 模型怎么选Embedding 模型负责把文本变成向量它的能力上限决定了语义检索的天花板。通用领域的中文文本目前有不少开源模型效果不错但需要注意几个关键点上下文长度老模型只有 512 tokenchunk 超过这个长度会直接截断信息丢失向量维度维度越高精度潜力越大但存储和计算成本也越高领域适配度法律、医疗、代码等领域建议用领域微调过的模型通用模型对这些领域的专业术语表征能力较弱。我踩过最大的坑是忽略了归一化问题。有些模型输出的向量不是归一化的直接计算内积相似度会导致结果偏向长度更长的向量。正确做法是统一对向量做 L2 归一化再用点积相似度或者直接用余弦相似度。这个坑尤其容易出现在刚切换 Embedding 模型时新旧模型的向量分布特性不同相似度计算方式也要跟着调整。对比过几款主流 Embedding 方案后我的体会是如果预算充足、数据量在千万级以下直接选择商业 Embedding API 能省不少事质量和稳定性都有保障如果数据量大且对延迟敏感或者需要定制领域语义自托管开源模型是更好的选择。用开源模型的话建议先在一个小规模业务数据集上做抽象检索测试对比召回 Top10 的相关性不要只看开源榜单的分数。3.2 混合检索向量检索和关键词检索互补纯向量检索有一个明显短板对实体名词、编号、产品型号这类精确匹配不敏感。比如用户问“BK-2024-03 型号的故障码”向量检索可能召回一堆关于该型号的泛泛描述而漏掉包含精确故障码的那段话。解决思路是混合检索同时跑向量检索和关键词检索BM25再把结果合并去重。关键词检索用 BM25 算法就够不必搞复杂的倒排优化。把两路召回结果合并后做分数归一化向量相似度通常在 0 到 1 之间BM25 分数则可能是个位数甚至更高直接相加会让 BM25 主导结果。我的经验做法是分别计算各自排名的百分位分数再加权权重系数看业务侧重点调我常用的基线是召回后让向量和 BM25 各贡献一半权重再根据结果调整。召回数量建议取 Top20 到 Top50而不是经典的 Top5。因为重排阶段还有一轮筛选召回多一些给重排更多选择空间。但也不能无脑多取上下文窗口有限取太多会稀释有效信息。3.3 查询改写与多轮对话处理用户提问的原始形式往往不适合直接检索。口语化问题、指代不明的代词、缺少关键实体的问题在检索前做改写能显著提升召回率。两个常用方法一是基于 LLM 的查询改写让模型把用户问题重写为更适合检索的关键词组合二是 HyDE假设性文档嵌入让模型先生成一个假设答案用这个答案去检索再把检索结果拿回来给模型做最终回答。HyDE 的思路是假设答案比问题更接近目标文档的语义空间这样检索出来的内容更相关。但代价是多次调用模型延迟和成本都会增加。实测下来查询改写对多轮对话的收益最大。用户连续追问时模型需要结合历史会话生成独立完整的检索查询。我的做法是把历史对话和当前问题一起交给模型要求它生成一个不依赖上下文的独立问题再用于检索。这一步做好了整个对话系统的体验会明显提升。4. 重排序与上下文优化让模型只看有用的信息检索召回的结果是“候选池”里面既有金子也有沙子。直接把 Top20 全部塞给模型不仅浪费上下文窗口还可能因为噪声太多把模型带偏。这个阶段的优化目标是精炼上下文让模型专注于高价值信息。4.1 Rerank 重排序比想象中更重要重排序的作用是对召回结果做精细相关性打分把最相关的内容排到最前面。跟向量检索的粗排相比Rerank 通常是交叉编码器结构把查询和文档拼在一起过模型计算量更大但精度更高。我观察过很多项目召回阶段做得中规中矩加上 Rerank 之后答案质量提升非常明显。原因在于向量检索是文本语义相似度的近似匹配而 Rerank 是真正的相关性判断两者解决的不是一个问题。Rerank 模型的选择上开源的中文重排模型对中文场景足够用速度快、效果可观。重排后的 Top5 作为最终上下文送给生成模型。如果重排分数整体都很低说明召回质量不行此时不要盲目相信前几个结果可以返回“未找到相关资料”的兜底答案或者触发另一个召回策略。这一点对降低幻觉率很重要。4.2 上下文压缩与去噪知识库里的 chunk 常常包含大量不直接回答问题的背景信息。把整个 chunk 全部塞进上下文既占空间又增加模型注意力分散的风险。解决思路是压缩抽取 chunk 中最可能与答案相关的一两句话保留出处信息拼接成精简上下文。我自己常用的做法是让模型按“支持性文本引用来源”的格式输出候选片段再做拼接。效果上上下文体积至少能压缩 30% 到 50%长文档场景更明显。还有一个折中方案上下文较长时压缩 prompt 和生成 prompt 共用主模型保证压缩时不做朴素截断而是语义改述。谨慎之处是压缩过程可能引入信息损失所以我只对超长 chunk 做压缩短 chunk 直接原样使用。另外上下文顺序也有讲究。我测试过按检索分数降序排列、按原文出现顺序排列以及把最相关的放第一段这三种方案实测把最相关的上下文放在 prompt 开头模型回答的引用准确率更高。这可能跟模型对开头位置的注意力更强有关所以即便排序不变也要手动确保高置信度上下文位置靠前。4.3 组装上下文的结构化技巧上下文不仅要有内容还要有结构。直接把字符列表拼成长文本没有层次模型对哪段内容对应哪个来源会很糊涂。我推荐用 XML/标签式结构组织上下文让每个片段带有明确的来源标记和序号提示模型引用时使用标记。结构化上下文的两种常见方式带来源的分段格式适用于“请根据以下资料回答”的问答场景每段末尾标注来源编号方便追溯。JSON 格式适用于程序化生成场景上下文不仅有正文还有元信息需要模型做数据抽取。这样处理后答案不仅更准确还天然带了可追溯性对需要审计的行业场景尤其必要。5. 生成阶段优化模型能力与 Prompt 设计的最后一道关把前面几个环节都做好了检索质量已经不错但生成阶段仍然可能让最终效果打折扣。Prompt 设计不是写一段漂亮的提示词就完事而是要让模型理解你的 RAG 体系。5.1 Prompt 里必须排斥幻觉的结构在系统提示中明确告诉模型仅基于提供的上下文回答如果上下文不包含答案明确说也不许用内部知识补全需要引用来源时用上下文的标记编号。这些约束写清楚能明显降低幻觉率。我见过不少人写 Prompt 时会怕说太重了模型不回答实际上要敢于写强约束。有一段时间被“很抱歉我没有足够信息”的拒答频率困扰后来把引用要求改成了“如果上下文充分必须引用原文出处而不是泛泛说明”并将上下文的来源标记直接呈现在 prompt 里效果明显好转。有一个细节很关键Prompt 里尽量少问“请根据上下文分析”这种开放式措辞多给具体动作指令比如“从参考资料中提取相关内容如果参考中没有答案直接回答‘未找到相关信息’”。模型的合规性和可控性会好很多。5.2 模型参数调节生成模型的热度Temperature有必要调低0.1 到 0.2 比较合适让模型更贴近上下文。如果做的是知识库问答不是创意写作高 Temperate 只会增加幻觉。Top-p 保持在 0.9 左右即可不必跟 Temperature 同时都调得特别极端。最大生成长度未必越长越好回答长度控制在 500 到 800 token 通常已能覆盖大多数业务问题避免模型为了凑长度而编造内容。不要忽略 stop sequences对于结构化输出场景终止的标记要定义清楚否则模型很容易输出多余内容。5.3 自定义脚本与结构化约束的取舍开源模型对复杂指令遵循能力比较有限特别是对中文结构的输出遵循常不稳定。如果希望稳定输出 JSON 结构要么用强大的商业模型并配兼容格式要么用逻辑自带的工具调用能力实现。预算充足时输出结构靠模型能力解决成本更低、泛化最稳预算紧张时可以用简易的文本模板限制格式但不要期望模型严格遵守太嵌套的 JSON 约束。我自己经常用的兜底方案是先让模型只输出纯文本答案程序再对答案做关键词切分、抽取结构化字段比死磕模型输出格式要稳得多。关键是弄清楚主模型到底擅长什么别把工程期望强加给模型幻觉能力上。6. 评估体系与常见问题排查RAG 系统没有评估就没有优化方向。很多团队凭感觉调参今天觉得效果好了明天换个问题又不行其实是没有建立评估标准体系。6.1 评估三维度召回率、忠实度、答案相关性召回率评估的是“正确的信息有没有被检索出来”。做法是把答案中涉及的关键信息与检索返回的上下文做匹配评测判断信息是否有上下文支撑。忠实度评估的是“答案是否严格基于上下文”答案里的每一条核心陈述是否都能在上文里找到依据。答案相关性评估的是“最终答案是否真正回答了用户问题”不偏题、不答非所问。我实际维护了一套模拟评测集约 50 到 100 个典型业务问题覆盖高频场景与疑难场景每次改动之后跑统一评测对比三个维度分数变化。分数下降超过 5 个点就要回滚。注意评测集的覆盖面要定期更换防止模型开关过拟合到固定问题上。6.2 典型的性能瓶颈快速定位表调试 RAG 性能时一张快速定位表能帮你少走弯路现象可能原因排查顺序检索结果明显不相关文档切分不合理、Embedding模型领域不匹配先看召回内容再换切分策略最后考虑更换Embedding检索相关但答案错误Prompt约束不足、模型依赖内部知识增强Prompt约束、调低Temperature、强引用要求答案引用了不存在的来源上下文拼接错乱或字符截断检查上下文组装逻辑、保证引用标记与内容对应网络搜索无相关内容但业务知识库有召回数量不足或者知识库未覆盖调大召回量、检索前改写查询、增加数据检索慢向量索引类型不当、资源不足检查索引类型和硬件资源、考虑量化索引6.3 我遇到过的三个高频坑切分后丢失语义边界导致召回错误。这是最常见的问题表现为检索出来的 chunk 总是截在句子中间。解决方案就是引入段落/标题边界的递归切分。固定相似度阈值已经过时导致的延迟敏感或阈值失效。不同领域的相似度分数分布差异很大统一设 0.7 的阈值对法律文本可能过严、对新闻类又过松。建议不要用绝对阈值使用“TopK 相对分数差”动态截断能保留必要召回又过滤低质量结果。Rerank 没有做版本管理导致效果难以复现。Rerank 模型的版本变化会影响排序结果不锁版本的话隔一段时间同一查询效果旧变了。建议把 Embedding/Rerank 都固定版本并记录在部署配置中。另外一个容易忽略的坑是向量库的索引参数过于激进比如非时效性数据的暴力检索。对千万级以下数据量HNSW 索引足够精度和性能均衡过度压缩的量化索引会让向量精度明显下降影响召回质量而不自知。7. 进阶优化知识增强与多路召回的组合拳如果常规优化做完了效果还是不够可以考虑更有针对性的进阶方案。这块成本更高但往往能把 RAG 效果推到新的高度。7.1 知识库结构化和图增强纯文本向量库适合通用问答但对结构化查询支持有限。比如“上季度华东区的销售额是多少”如果知识库里是分散的报表文本向量检索很难准确聚合。做法是将结构化数据表格、数据库记录先抽取为 JSON/图谱结构存入单独的结构化存储问题涉及结构化查询时走结构化检索再和向量检索结果合并。图增强 RAG 尤其适合强关联关系的领域比如产品体系、组织架构、项目依赖关系。把实体间的关联存入图数据库查询时从实体出发沿关联扩展检索到的上下文往往比纯文本向量检索更完整。7.2 细粒度缓存与快速拒绝策略线上 RAG 系统的性能和效果要同时考虑。高频问题或重复问题建立精确语义缓存命中缓存直接返回节省检索和生成成本。缓存可以用查询向量或查询文本摘要做主键。同时对检索置信度极低的 query 直接拒绝回答而不是用弱上下文硬答。这能防止在线上产生大量低质量回复长远看对用户体验的伤害比拒答更大。7.3 数据回流与迭代闭环RAG 的效果依赖知识库质量而知识库发现问题的最好来源是线上用户反馈。每次用户对答案点踩、反馈都对应一条数据回流。我建议的闭环机制是当用户对答案“不满意”时记录问题、上下文、答案、用户反馈原因定期批量分析失败原因。属于检索失败的就优化切分或召回属于生成失败的就改进 Prompt 或调整参数。线下评测集也要把线上收集的高频难题补充进去形成循环迭代。这个机制坚持两三个月RAG 效果提升会超过一开始“大力出奇迹”式的模型替换。8. 实操复盘一次典型的 RAG 性能优化路径最后分享一次我在模拟项目 X 中的优化经历。初始系统检索质量的 Top5 正确率不到 40%答案大部分答非所问。沿着上文框架一步步排查最终把正确率提到了 82% 左右。第一步先替换了切分策略把原来的固定 512 字符切分改为按标题层级加段落边界重叠设置为 20%。这一步 Top5 正确率提升到 50% 左右检索结果开始能看到正确片段了。第二步把 Embedding 模型从通用的开源模型换成了领域适配模型Top5 正确率提升到 65%。这一步主要是让模型更理解领域术语后语义召回的准确度提升明显。第三步引入 BM25 混合检索加 Rerank 重排召回池从 Top10 扩大到 Top30重排后取 Top5。这一步 Top5 正确率提升到 75%。混合检索解决精确匹配问题Rerank 解决相关性排序问题两者缺一不可。第四步调整 Prompt 结构和生成参数强化引用约束Temperature 从 0.7 降到 0.1答案的忠实度明显提升用户可感知的正确率到了 82% 左右。第五步建立了评测集和数据回流闭环后续优化不再是“凭感觉调参”而是针对失败案例精准迭代。两个月后评测正确率稳定在 86% 到 88%这个结果对于业务落地已经比较能打了。回看这次优化最大的体会是RAG 的效果不是某一个单一模型的功劳而是数据、检索、生成三个环节环环相扣的结果。很多人执着于换更强的大模型或者更贵的 Embedding API反而忽略了数据切分和召回策略这些基础优化。从数据侧做起先把检索质量拉起来再调整生成端这条路径是我验证过最稳妥、性价比最高的。
阅读完成 · 觉得有帮助?