首页 > 教程攻略 > ai资讯 >RAG检索增强生成最佳实践

RAG检索增强生成最佳实践

来源:互联网 时间:2026-08-26 14:07:30

检索增强生成(RAG)的完整工作流,远看似乎只是“检索+生成”的简单组合,但真正深入其中就会发现,这里面涉及到的环节和决策点相当多。面对这么多可选的模块和技术,一个很实际的问题就摆在了面前:怎么才能把它们组合起来,搭出一套真正好用的RAG系统?

接下来,我们把这个问题拆解开来看。先从典型的RAG流程讲起,然后逐一梳理每个模块都有哪些被验证过的“最佳实践”,最后再看看如何对这套系统进行端到端的评估。


RAG的工作流程

先看一张典型的RAG流程图,这样对整个链条有个直观的印象。

图 1:检索-增强生成工作流程

从用户提问到最终生成回复,中间包含了几个关键的中间环节:

  • 查询分类

    :先判断一下,用户的这个问题到底需不需要去检索外部知识。毕竟,不是所有问题都要联网查,很多简单问题模型自己就能搞定。

  • 检索

    :如果需要,就从知识库里把最相关的文档捞出来。

  • 重新排序

    :捞出来的文档未必都那么精准,需要根据相关性重新排个序,把最靠谱的放在最前面。

  • 重新打包

    :把筛选排序后的文档整理成一个结构化的形式,方便后续处理。

  • 总结

    :最后一步,从这些文档里提炼关键信息,去芜存菁,生成最终的回答。

除此之外,这张图还揭示了一连串需要决策的问题:文档怎么切分?用什么模型来做语义嵌入?向量数据库选哪个?模型怎么微调?每一步都有讲究。


查询分类

为什么要先做“查询分类”?道理很简单:不是所有的用户提问都需要劳师动众地去检索一遍。模型本身已经具备了一定的知识储备,强行检索不仅会增加响应时间,有时候反而会引入不必要的噪音。

所以,一个合理的思路是:只有当问题超出了模型参数里存储的知识范围时,才需要启动检索。实践中,我们可以把用户的任务按照是否提供了足够信息,分成15种类型。那些完全依赖于用户提供的信息就能回答的任务,标记为“sufficient”,没必要检索;而那些需要模型动用外部知识才能回答的任务,则标记为“insufficient”,需要尽快启动检索。

图 2:不同任务的检索要求分类

这个分类过程,通过训练一个分类器就能自动完成。

图 3:查询分类器的结果


分块

文档切分(Chunking)是整个RAG流程的基础。把长长的文档切成小块,既能提高检索的准确性,又能避免把过长的内容一股脑塞给模型。

分块通常有三个层级可选:

  • 标记级分块

    :最简单粗暴,但容易把一个完整的句子切成两半,破坏语义,影响检索质量。

  • 语义级分块

    :直接用LLM来判断句子在哪断开最合理,保留了完整的语义上下文,但代价是计算时间会长不少。

  • 句子级分块

    :一种折中的方案,在保留语义和简洁高效之间取得了不错的平衡。

在实际应用中,句子级分块往往是更务实的选择。不过,即便确定了用句子级,还有几个参数需要仔细斟酌。

  • Chunk Size 分块尺寸:

    块的大小直接影响性能。块越大,提供的语境越丰富,有助于模型理解,但处理速度会变慢;块越小,检索效率高,但可能因为缺乏上下文而答非所问。

衡量分块效果,主要看两个指标:

忠实度

相关性

。忠实度看的是生成的回复有没有脱离检索到的文本,相关性看的是检索到的文本和最终回复是不是真的跟用户问题有关。

  • Chunk 组织形式:

    最终选型时,较小的块可以设为175个字节,较大的块设为512个字节,块与块之间可以有20个字节的重叠。

  • 嵌入模型的选择:

    这块也有讲究。实验数据显示,LLM-Embedder这个模型能取得跟BAAI/bge-large-en差不多的效果,但模型体积只有人家的三分之一。所以,在性能和大小之间权衡,LLM-Embedder是个很划算的选择。


向量数据库

存储和检索这些高维向量,当然离不开向量数据库。我们对五个主流的开源向量数据库做了个详细的横向对比:Wea viate、Faiss、Chroma、Qdrant 和 Milvus。

从对比结果来看,

Milvus

在各项基本标准上表现都很全面,综合性能在开源的几个选项里是最突出的。


检索

检索模块的核心任务,就是根据用户查询,从建好的库里找出最相关的那top-k个文档。几种主流的技术和它们的组合方式,值得拿出来说道说道。

  • 查询重写

    :用户输入的查询可能不够精确,那就先用LLM把查询“洗”一遍,让它能更好地匹配文档。

  • 查询分解

    :用户的问题可能是个复杂问题,那就把它拆成几个更简单的子问题,分别去检索。

  • 伪文档生成

    :比如众所周知的HyDE方法,它会根据你的查询先生成一个“假设的答案”,然后用这个假设答案的嵌入向量去库里找相似的文档。

不同检索方法的结果

上图的结果很能说明问题:有监督的方法,其表现要明显好于无监督的方法。最终的得分冠军,是结合了HyDE和混合搜索的LLM-Embedder。因此,把HyDE + 混合检索作为默认的检索方案,是一个稳妥的选择。所谓混合检索,就是把稀疏检索(比如BM25)和密集检索(基于向量)结合起来,既能保证效果,又能把延迟控制在较低的水平。


重新排序

第一轮检索出来的文档,排序可能并不完美。这时候就需要“重新排序”模块上场,把最相关的信息精准地提到最前面。通常有两种主流方法:

  • DLM 重新排序

    :用深度语言模型(DLM)对文档和查询的相关性进行“真”或“假”的二分类判断。推理时,就按照模型预测为“真”的概率来排序。

  • TILDE 重新排序

    :这种方法更巧妙,它通过预测模型词表中每个词的概率,来独立计算每个查询词出现的可能性。它能把文档得分预计算好,推理时非常快。TILDEv2版本做了进一步优化,只对文档里实际存在的词建索引,进一步提升了效率。

综合来看,

monoT5

在性能和效率之间取得了最佳平衡,是首选的通用方案。如果对效果有极致追求,那

RankLLaMA

值得一试。而如果只是想在固定数据集上快速做实验,

TILDEv2

则是最合适的选择。


重新打包

文档的顺序,其实也会影响LLM的最终表现。为了解决“中间位置的信息容易被忽略”这类问题(也就是著名的“迷失在中间”现象),可以在重新排序之后,再加一个“重新打包”模块。这里也有三种不同的策略:

  • 前向方法

    :按照重新排序后的相关性得分,从高到低排列。

  • 反向方法

    :反过来,从低到高排列。

  • 侧向方法

    :这个思路来自“迷失在中间”这篇论文的发现——模型对输入内容的开头和结尾部分的注意力最强。因此,把最相关的信息放在这些位置,效果会更好。

这些打包方法的具体表现,会由后续的LLM模块来体现,我们会在下一节的综合评估中看到它们的表现。


总结

检索回来的文档里,总有不少冗余信息。这些杂质不仅会干扰LLM生成准确的回复,还会让输入的提示词变长,拖慢推理速度。因此,对检索到的文档进行有效的“总结”或“压缩”,就成了RAG流程中至关重要的一环。

实现总结的方式,可以分成两类:

  • 提取式压缩器

    :把文本拆成句子,然后给每个句子打分排序,选出最重要的那个。
  • 生成式压缩器

    :这个更高级,它会综合多篇文档的信息,重新组织语言,生成一个连贯的摘要。

两种方式都可以选择基于查询或不基于查询。我们重点评估了三种方法:

  • Recomp

    :同时集成了提取式和生成式压缩器,功能很全面。
  • LongLLMLingua

    :在LLMLingua基础上做了改进,能够更聚焦于与查询相关的关键信息。
  • Selective Context

    :通过识别并删除输入上下文中的冗余信息,来提高LLM的效率。

三种方法的对比如下:

从图中可以看出,

Recomp

的表现最为出色,是首选的推荐方案。LongLLMLingua虽然在榜单上表现不佳,但它有一个很可贵的优点:它没有在这些测试数据集上训练过,展现出了更好的泛化能力。因此,如果遇到一个新的、没有见过的领域,把LongLLMLingua作为一个替代方案,是很有价值的。


结论

梳理完这一切,有几个关键点值得再强调一下:

  • 系统组件的重要性

    :RAG系统的每一个环节,从查询分类到最终的生成,都不是可有可无的。任何一个环节的短板,都可能成为整个系统的瓶颈。这提醒我们,在设计复杂系统时,对每一个组件性能的优化都至关重要。

  • 模块化设计的重要性

    :独立优化和测试每个组件,是模块化设计带来的最大红利。它可以让你在不影响其他模块的情况下,方便地对某个环节进行技术升级,或者在不同的应用中复用这个模块。

  • 系统的实验方法

    :最后,整个研究建立在公认的数据集和详尽的测试之上,这使得结论具有很强的说服力和可推广性。这种系统的实验设计思路,本身就是值得借鉴的。