2024 年以“Retrieval Augmented Generation”为关键词的论文超过了一千篇,相比2023年增长了近10倍。这种指数级增长背后,是 RAG 从学术概念快速演进为企业级 AI 落地的核心技术范式。
去前,RAG 还只是解决大模型幻觉问题的辅助手段;今天,它已经成长为连接 LLM 能力与行业知识需求的桥梁。
每当将大模型应用于实际业务场景时发现,通用的基础大模型基本无法满足实际业务需求,主要有以下几方面原因:
- 知识的局限性:大模型自身的知识完全源于训练数据,而现有的主流大模型(deepseek、文心一言、通义千问…)的训练集基本都是构建于网络公开的数据,对于一些实时性的、非公开的或私域的数据是没有。
- 幻觉问题:所有的深度学习模型的底层原理都是基于数学概率,模型输出实质上是一系列数值运算,大模型也不例外,所以它经常会一本正经地胡说八道,尤其是在大模型自身不具备某一方面的知识或不擅长的任务场景。
- 数据安全性:对于企业来说,数据安全至关重要,没有企业愿意承担数据泄露的风险,尤其是大公司,没有人将私域数据上传第三方平台进行训练会推理。这也导致完全依赖通用大模型自身能力的应用方案不得不在数据安全和效果方面进行取舍。
而RAG就是解决上述问题的有效方案。
一句话总结:
RAG(中文为检索增强生成) = 检索技术 + LLM 生成技术。
RAG技术简介
当用户向 LLM 提问一个问题(qustion),RAG 从各种数据源检索相关的信息,并将检索到的信息和问题(answer)注入到 提示词模板中,LLM 最后给出答案。
难道我们不能只给 LLM 整个知识库吗?
- 模型长下文长度有限(尽管模型的长下文越来越长)
- 发送大量文本会变得相当昂贵。
- 研究表明发送少量相关信息比发送大量无关信息会得到更好的答案。
完整的RAG应用流程主要包含两个阶段:
- 数据准备阶段:数据提取——>文本分割——>向量化(embedding)——>数据入库
- 应用阶段:用户提问——>数据检索(召回)——>注入Prompt——>LLM生成答案

RAG本质上是模块化的 - 文档解析、分块、检索、重排、生成,每个模块都可以独立优化。
1 数据提取和处理
RAG系统中负责数据提取和处理的模块为文档解析与分块。即从各种各样的数据类型转换成知识库、向量库可以处理与保存的格式。
生产环境中,面向的数据类型一般是PDF、doc文档、txt文档、PPT、代码等。
网络上存在不少开源库,可以读取和解析这些类型的文档。基本上所有的开源RAG框架,例如langchain等都会有这些常用类型文档的解析能力。而在实际上这些开源库和开源框架,确实已经可以完成绝大部分数据提取的任务。
而针对长尾类型例如双栏、多栏PDF,难度高、样本少,除非是部门在这些领域有足够技术积累、或者是这些特殊文档占据所有文档足够大的比重,否则并不建议在这里花费大量人力。
RAG系统的重点和难点之一就在于文本分割,一个naive的RAG系统通常会按照固定长度切分,这种方式的弊端不限于以下几点:
- 文本块没有完整的全局上下文,这严重限制了问答过程。
- 需要研究调整 top-k / 相似度分数阈值,太小的值可能会导致相关上下文被忽略,而太大的值则可能会增加与无关上下文的成本和系统延迟。
- 向量召回结果可能并不总是最合适上下文,因为这个过程本质上是分别确定文本和上下文。
不管用哪种方式读取文本,哪种方式切分文本之后,都可以将非结构化的文档分解成一个一个的文本块,因为文本块之间可能有一些关联关系,所以这里定义文本块为Node(节点)。节点可以是文本块、图标或者别的内容,每个节点还回保存各种元信息、关键信息。
对于这些Node,有以下常见构建索引的方式:
- 列表索引
- 关键词索引
- 树索引
- 组合索引
- pandas/sql 索引
- 文档摘要索引
- 知识图谱索引
列表索引 :对一个文档按照纯文本读取,然后按照固定长度切分,我们可以得到最简单的索引结构,一般称为list index。在搜索过程中,只需要根据一定的检索规则,例如keyword过滤或者embedding召回,得到过滤后的节点合并到生成模块。
树索引 :当有大量的文档,或者可以明确提取到文档的大纲、标题信息的时候,可以采取树索引,树索引是一种树形结构的索引,其中每个父节点都是子节点的总结。在索引构建过程中,树是自下而上地构建的,直到我们最终得到一组根节点。对于树索引的检索,涉及从根节点向下遍历到叶节点。
关键词表索引:这对于将用户query路由到不同的数据源非常有用。有点类似es的倒排索引的概念,对每个节点提取关键词,共享相同的关键词的节点会联系到一起。在搜索时,从用户query中提取相关关键词,并将其与预先提取的节点关键词进行匹配,以获取相应的节点。提取的节点将传递到生成模块。
组合索引:可以为每个文档内的文本创建树形索引;然后生成一个列表索引,涵盖整个文档集合的所有树形索引。具体涉及如下步骤
- 从多个文档创建树索引
- 从树形索引生成摘要(树形索引对于总结文档集合非常有用)
- 在树形索引之上创建一个列表索引的图(列表索引适用于综合多个数据源的信息来合成答案)
- 每个文档树或者树的Node构建关键词索引
pandas/sql 索引:用于结构化数据,例如表格或者数据库,通过生成pandas命令和SQL语句来查找结构化的数据。
文档摘要索引 :通过提取每个文档的非结构化文本摘要,从而提高检索性能。该索引包含的信息比单个文本块更多,比关键词标签具有更多的语义含义。它还允许灵活的检索,包括LLM和基于向量的方法。本质上它是利用LLM对文档进行压缩。
在构建时,文档摘要索引使用LLM从每个文档中提取摘要。在问答时,它根据以下方法使用摘要检索相关文档:
- 基于LLM的检索:获取文档摘要集合,并请求LLM识别与用户query相关文档+相关性评分
- 基于向量的检索:利用摘要向量的相似性来检索相关文档,取top k的结果
知识图谱索引 :通过从文档中提取知识三元组(主语,谓语,宾语)来构建索引,例如GraphRAG。在查询时,常见的为2种,一种是类似于pandas、sql index生成查询语句。或者利用节点的文本信息利用其他的检索方式搜索相关的信息。
以下是工程实践过程中,针对不同类型文档的具体处理方式:
技术文档和代码
技术文档最大的特点是有清晰的层级结构。章节、小节、代码块、配置项,这些都是天然的切分边界。根本不用傻乎乎地每512个token切一刀,那会把一个完整的配置说明劈成两半。
正确做法是按标题分层切分。每个h2或h3标题带出来的内容作为一个chunk,同时在元数据里记录这个chunk在文档里的位置——比如”第3章 > 配置管理 > 3.2 配置文件”。这样检索的时候,模型能知道这段内容的上下文在哪。
代码块要特殊处理。一段完整的代码示例不能被切断,要么整个保留,要么不要。可以把代码块单独提取出来,标记语言类型,再把前后的文字说明作为context一起存。
代码仓库的结构性更强。函数、类、模块,这些都是天然的切分单位。用AST解析把代码拆成语法树,然后按函数或类切块。每个函数作为一个chunk,但要带上足够的上下文信息:这个函数属于哪个类、import了什么依赖、在哪个文件的第几行。如果有注释就更好了,直接作为这个chunk的描述。
Doc文档
大部分Doc文档会自带结构,例如存在标题信息和段落上下级关系等。固定长度的分割方式同样不适合这样的文档。
正确做法是1. 仿照人类阅读此类文档的方式,以完整段落为间隔进行分割。2. 解析标题序列信息,保持上下级关系和子级关系,并且子段落需要融合父级段落信息,从而构建出一颗文档树。
2 向量化存储与检索
RAG的狭义用法,指的是向量匹配相关度的方法——embedding:将一段文本、图片向量化为高维空间的向量表征,以用户的query来匹配向量表征,从而检索出对应的内容,并将检索到的内容放到上下文中从而增强fact grounding。
下图表示文档的向量化存储与检索过程:

这一部分主要有三大步骤:向量化存储-检索-重排序。
向量化存储:向量化是一个将文本数据转化为向量矩阵的过程,该过程会直接影响到后续检索的效果。常见向量化模型都可以在 huggingface模型排行榜 找到。然后将向量存储到向量数据库如Faiss、Milvus等。
检索:将用户query向量化之后与向量数据库中的数据计算相似度,取一定数量的候选向量。在多轮对话中用户query会缺少上下文元素,需要现结合历史对话和预存知识对用户的query进行改写,或者分解成子查询,然后进行检索。
重排序Reranking:向量检索(ANN / FAISS / Milvus 等)本质是:“语义相似度匹配”,但语义相似 ≠ 问题真正相关,所以向量检索只能作为初筛从百万级文档中捞出 Top-50 或 Top-100 的候选片段。重排序是将用户的 Query 和初筛出的 Candidates 成对输入到 Cross-Encoder(交叉编码器) 模型甚至是LLM中。Reranker 会对每一对进行深度的交互式计算,输出一个相关性评分。
RAG不足之处与改进
但是RAG绝非灵丹妙药,如今RAG的不少问题已经暴露:
- 用户的请求以自然语言发出,混杂了无关元素,直接进行向量搜索的话反而干扰搜索结果。这时候又需要专门的模型来改写用户query后进行检索,去除无关元素。
- RAG本身对于搜索结果进行了切片,模型最终读到的是只言片语,如果模型在当前RAG切片当中没有获得足够的信息,缺乏多轮搜索的能力。
- 除去多模态和模糊匹配的场景下,向量匹配法未必优于传统关键词搜索。
上述很多问题是由文档分块向量化存储和检索过程导致的,RAG的狭义用法,指的是向量匹配相关度。而实际上RAG(Retrieval Augmented Generation)的思想是检索增强生成,本质上是通过检索的方式为LLM动态注入知识。
因此我们不应该只局限于向量检索,而是回归问题本质:如何将最相关、最有效的信息,以最高性价比的方式纳入模型的上下文处理体系。
针对现有RAG系统的改进tricks层出不穷,如:Query改写、HyDE、混合检索、GraphRAG、重排序、迭代检索。
Query改写:通过重写或修改用户Query,来提升检索和RAG的效果。在RAG问答系统中,用户的问题可能不够好,例如问题过于简单、过于抽象、表达模糊等等,利用这种用户Query去从知识库里检索知识,可能检索不出有用的知识出来。因此,Query改写就是通过重写用户Query来缓解这个问题的。
Query改写技术处理方法:
重写:包括Multi-Query、RAG-Fusion。
Multi-Query就是对一个用户Query,利用大模型将其重写为N个不同角度的Query,来更全面地检索知识库。最后,将这些知识库+原始Query送入LLM,得到回答。
RAG-Fusion和Multi-Query重写类似,区别就是在于去重的部分(漏斗)。在Multi-Query中,所有的知识片段都是一视同仁地重要的,而在RAG-Fusion中,会对这些知识片段按重要性排序。排序的方法,根据知识片段出现的次数、每一个问题里的次序来排序。例如,如果某个知识片段在Q1-Q3的retrieval结果里都出现,且排序都靠前,则该知识片段更重要。最后,输入给LLM的知识片段也是按排序结果输入,并告诉LLM,越前面的知识越重要。
更具体:划分子问题进行回答。
将复杂问题解构为多个独立的递进的子问题,依次回答各个子问题,得到最终的答案。独立回答是分别对每一个子问题进行检索和回答,最后将所有问题+回答放在一起,输入LLM得到输出。递归回答将问题解构为三个子问题,检索相关知识,回答是递进的,即Q1的Query-Answer对,会输入到Q2的回答中,Q3的回答会利用的Q1和Q2的回答。
更抽象:Step-back。Step Back将用户问题化为更加抽象、通用的问题。这样,retrieve时可以检索出更通用、全面的知识。甚至于,在检索之后,LLM根据检索结果,判断是否检索结果是否完备、是否足够回答问题,然后追问用户,让用户补全信息。例如:用户问天气怎么样?模型在检索到获取天气的接口后发现还需要位置信息,并且模型没有根据可以获取用户位置,那么模型并不会直接回答,而是继续追问用户。
Prompt路由:假设我们有多个Prompt模板,如何选择最合适的Prompt去应对不同的问题。我们可以采用Semantic routing语义路由,做法:将问题、各个Prompt都通过embedding machine变成embedding,然后计算问题与各个Prompt的距离(如余弦相似度距离),选择距离最近的Prompt。
混合检索:向量索引,比如 faiss、nmslib 以及 annoy。这些工具基于近似最近邻居算法,如聚类、树结构或HNSW算法。此外,还有一些托管解决方案,如 OpenSearch、ElasticSearch 以及向量数据库。
但是向量检索并不是万能的,例如,一个函数的声明可能在20行,函数的具体定义可能在400行,而这个函数用到的其他依赖函数则散落在整个代码当中。单纯依赖向量切片的RAG,提供不了代码的思路和全貌。并且chunk切分的方式也很容易导致检索结果被切断,例如检索到段落标题之后,子段落被切断导致回答不完整。
混合检索,实现的是文本检索 + 向量检索。很多时候利用文本检索的方式结果反而更好,比如采用倒排索引技术,通过关键词快速定位到文档,同时结合诸如TF-IDF等算法优化搜索结果的相关性。结合传统的基于关键字的搜索(稀疏检索算法,如 tf-idf 或搜索行业标准 BM25)和现代语义或向量搜索,并将其结果组合在一个检索结果中。
这里唯一的关键是如何组合不同相似度分数的检索结果。这个问题通常通过 Reciprocal Rank Fusion 算法来解决,该算法能有效地对检索结果进行重新排序,以得到最终的输出结果。
GraphRAG:今年最热的概念之一就是GraphRAG。不可否认GraphRAG在全局问题上的效果显著,但用下来发现,ROI真的不高:
- Token消耗巨大 - 实体抽取、关系建立、社区摘要,Token成本是普通RAG的5-10倍
- 图谱质量堪忧 - 自动抽取的实体关系充满噪声,远不如人工构建的知识图谱
- 维护成本高 - 文档一更新,图谱就要重建,这个成本在生产环境难以接受
RAG系统如何评估
我们现在做RAG都是做的pipeline,涉及到切块、相关性召回、拒答等多个环节,每个环节都可以单独做评测。目前主要是从两个层面:检索-生成,两个过程中的情况来进行RAG质量的评估:
检索层
这个层面决定输入质量,要能确保喂给LLM的上下文是精准且完整的。
在这个层面评价RAG能力有两个维度指标:
上下文精度:衡量检索到的相关内容是否排在 Context 的前列。
上下文召回:衡量回答问题所需的所有关键事实,是否都被检索出来了。
生成层
这个层面决定决定加工质量,要能确保 LLM 的输出是忠实有用的,防止出现幻觉。
在这个层面评价RAG有以下维度指标:
- 答案正确性:通过计算生成答案与标准答案在语义和事实上的相似度(0~1分)进行评估,衡量生成的回答是否真正解决了用户的问题,而非答非所问。
- 忠实度:通过将回答拆解为多个陈述(Claims),逐一验证这些陈述是否能在检索到的 Context 中找到证据支持,是否参考了检索结果。
- 拒绝回答:1。遇到无权限或者非法问题的时候是否拒绝回答。2。遇到检索结果不支持回答问题的时候是否拒绝回答而不是随意回答。
RAG未来发展
2023年刚开始发展时,RAG面临的一大问题是上下文窗口太小了,只有8K或者16K的上下文窗口导致无法放入太多的检索结果,这对于检索方式有很高的要求。
而随着如今模型上下文窗口的扩展,已经有模型支持长达128K的上下文了,很多时候可以不太依赖RAG,而是依靠长上下文,让模型自己从上下文中选取关联的数据。从这个角度看,似乎RAG的用武之地没那么大了。
但是从实践来看,我们还离不开检索增强的方法。随着Agent的发展,RAG可能会成为Agent的一个模块或者工具,即Agentic RAG 系统。随着AI Agent的兴起,RAG的功能逐渐从检索增强生成”变成了上下文工程,Agent需要组装三类上下文:
1. 领域知识(Knowledge)
- 企业内部文档、产品手册、历史案例
- 这就是传统RAG的强项
2. 工具描述(Tools)
- API文档、函数说明、调用示例
- 当工具数量>100个,如何选择成为大问题
3. 交互历史(Memory)
- 对话历史、用户偏好、任务状态
- 本质也是一种检索问题
这三类数据的管理,本质上都是检索问题。RAG的技术栈(向量索引、混合检索、重排序)可以完美复用。