这就是 RAG
写在前面
最近在学习鱼皮的 LangChain4j 教程中接触到 RAG 相关内容,期间在 B 站看到下面这个视频后,对 RAG 的整体思路有了一次比较清晰的梳理。结合自己的理解过程,整理了这篇关于 RAG 理论基础的学习笔记,希望能对初学 RAG 的同学有所帮助。
如果你是第一次系统接触 RAG,建议先观看原视频,再阅读本笔记,会更容易理解其中的核心概念和整体流程。
视频链接:这就是 RAG:一看就懂的个人知识库架构
RAG 面向的问题
LLM 在面对其不确定的问题时容易产生幻觉(一本正经地胡说八道)。一个最直接的缓解方式是:将相关文档作为上下文一起发送给 AI,让其基于已有的资料回答问题。
但是在实际场景中,文档往往很长,而与用户问题真正相关的信息只集中在少量片段中。当把整份文档都提供给 AI 时,信息过载反而会影响 AI 回答的质量,模型容易抓不住重点。
能不能不发整份文档,而是只发和用户问题真正相关的部分?
这便是 RAG 这个技术要解决的核心问题!
RAG 的核心思想与基本流程
RAG(Retrieval-Augmented Generation)是一种 AI 应用架构,其核心思想是在生成回答之前,通过检索机制为大语言模型提供与用户问题相关的外部上下文,从而提升回答的准确性和可靠性。
在 RAG 架构下,当系统接收到用户问题后,会先进入检索阶段。
在检索阶段,系统根据用户问题,从已有的文档库中筛选出一小部分与用户问题高度相关的内容片段。
检索完成后,系统会将用户问题与检索得到的内容片段一并作为上下文输入给 LLM,用于生成最终回答。
以上过程构成了 RAG 架构下一次问答的基本流程。
其中,检索阶段是 RAG 架构中的关键环节。通过在生成之前对上下文进行筛选,可以有效控制输入给 LLM 的信息范围,使模型更多地依赖与用户问题相关的内容,从而提升回答的准确性并降低幻觉出现的概率。
检索阶段的核心问题
在 RAG 架构中,检索阶段的主要职责是从文档库中的海量文本中筛选出与用户问题相关的内容片段。
一个直观的做法是基于关键词进行匹配,但这种方式对表达形式高度敏感,难以准确反映文本与问题之间的语义相关性。
因此,检索阶段真正需要解决的问题是如何判断文档片段与用户问题在语义层面上的相关性。
语义如何表示?
如何以计算机可处理的方式表示文本的语义?
若让初学者从零开始解决这一问题,在实践中往往并不现实。在工程实践中,通常会采用已有的通用方案来完成语义表示。其中最常见的一类方案,是使用 Embedding 模型。
Embedding 模型
Embedding 模型用于将一段文本转换为向量表示,以刻画文本在语义层面的特征。通过这种方式,原本难以直接处理的文本语义,被映射为计算机可以处理和比较的数值形式。
具体来说,这种向量通常表现为一个固定长度的数值数组,例如 [0.12, -0.34, 0.89, …],可以被视为文本在高维语义空间中的一个点。
向量中的每一个元素对应的是 Embedding 模型在训练过程中自动学习到的抽象语义特征,这些维度本身通常不具备可直接解释的含义。**向量维度的数量决定了语义表示的表达空间规模,维度越高,Embedding 模型具备的潜在语义表达能力通常也越强。**因此,在实际使用中,更关注的是向量整体的空间分布及其与其他向量之间的相对位置,而非单个维度的具体数值。
Embedding 模型会将语义相近的文本映射为在向量空间中位置更接近的点,而语义差异较大的文本,其对应向量的位置则相对更远。
在实际应用中,Embedding 模型生成的向量通常具有较高的维度,往往达到数百甚至上千维。为了便于直观理解,这里仅以二维向量空间作为示意:

图中每一个点表示一段文本经过 Embedding 模型映射后在向量空间中的位置。语义相近的文本,其对应点在向量空间中的位置更接近;语义差异较大的文本,其对应点之间的距离则更远。
在这种表示方式下,文本之间的语义相关性可以通过向量在空间中的相对位置来刻画,用户问题也不例外。
当用户提出问题时,系统同样会使用 Embedding 模型将用户问题转换为向量表示。
例如,当用户提出“老王喜欢吃什么?”这样的问题时,该问题对应的向量会靠近“老王喜欢吃瓜”“老王爱吃瓜”等语义相关文本对应的向量位置,如图所示:

于是,程序就可以计算每一个已有点到问题点之间的距离,并选取其中距离最近的几个作为上下文,如图所示:

文档库搭建
在 RAG 架构中,文档通常需要在进入检索阶段之前进行预处理。整体流程可以概括为三个步骤:文本切片、向量化和存储。通过这一过程,原始文档被构建为一个可供后续检索和生成使用的文档库。
1. 文本切片(Chunking)
在实际应用中,原始文档通常篇幅较长,既不适合直接作为整体进行向量化,也不利于后续的相关性检索。因此,在进入向量化阶段之前,通常需要将其拆分为多个较小的文本片段(Chunk),这一过程称为文本切片(Chunking)。
文本切片的核心目标是在控制文本长度的同时,尽量保留语义的完整性。如果切片过大,单个片段中会包含过多无关信息,影响检索精度;如果切片过小,又可能导致语义被割裂,使单个片段缺乏足够的上下文信息。
在工程实践中,文本切片通常基于一定的规则进行,例如按照固定长度、段落边界或句子边界进行拆分,并在必要时引入重叠区域,以减少语义被截断的情况。具体采用哪种切片策略,往往需要在语义完整性、检索精度以及系统性能之间进行权衡。
通过文本切片,原始的长文档被转换为一组长度可控、语义相对独立的 Chunk,为后续的向量化处理和相似度检索奠定基础。
2. 文本向量化(Embedding)
在完成 Chunking 之后,文档已经被拆分为一组长度可控、语义相对独立的 Chunk。接下来,需要对这些 Chunk 进行统一处理,使其能够参与后续的相关性检索。
具体做法是:对每一个 Chunk 使用 Embedding 模型进行处理,将其转换为对应的向量表示。该过程通常以批量方式离线执行,即在文档进入系统时提前完成,而不是在用户每次提问时重复计算。
通过这一向量化步骤,原始的 Chunk 被转换为一组结构统一、可直接比较的向量形式,为后续基于相似度的检索提供基础。
3. 向量与文本的存储
在完成 Chunking 和 Embedding 之后,系统已经得到了一组与文档内容一一对应的向量表示。接下来,需要将这些向量及其对应的原始 Chunk 进行存储,以支持后续的检索过程。
仅存储向量本身并不足以完成实际应用场景下的问答需求。向量主要用于相似度计算,而最终提供给 LLM 的上下文仍然是原始的文本内容。因此,在存储阶段,通常需要将向量与其对应的 Chunk 建立关联关系,以便在检索到相关向量后,能够快速定位并取回对应文本。
在工程实践中,这类数据通常会被统一存放在专门用于向量检索的存储系统中,即向量数据库。该系统需要支持基于向量相似度的高效查询,并能够返回与向量关联的原始文本片段,为后续回答生成提供输入。
通过以上步骤,原始文档被构建为一个可检索的文档库,形成了从文本处理到存储的完整闭环,为后续基于用户问题的检索和生成奠定基础。
RAG 的完整流程
综合以上内容,可以将一次基于 RAG 架构的问答过程概括为如下完整流程。
首先,系统在离线阶段对原始文档进行处理,依次完成文本切片、向量化以及向量与文本的存储,构建可供检索使用的文档库。
当用户提出问题时,系统会使用同一 Embedding 模型将用户问题转换为向量表示,并在文档库中基于向量相似度进行检索,筛选出与用户问题语义最为相关的一小部分文本片段(通常取相似度最高的前 K 个结果)。
随后,系统将检索得到的文本片段与用户问题一并组织为上下文输入,提交给大语言模型。在上下文约束下,模型基于所提供的内容生成回答,并将结果返回给用户。
至此,从文档准备、问题检索到回答生成,一次完整的 RAG 问答流程便得以完成。
