1 RAG 概述
大型语言模型(LLM)如 GPT-4、Llama 3 等,凭借其强大的参数化知识(Parametric Knowledge)和推理能力,在自然语言处理领域取得了革命性的突破。然而,它们并非完美无缺。其内在知识受限于训练数据的截止日期,无法获取最新信息;同时,它们在处理高度专业化或私有领域的知识时,容易产生 " 幻觉 “(Hallucination),即编造不实信息。
为了解决这些核心痛点,检索增强生成(Retrieval-Augmented Generation, RAG) 范式应运而生。RAG 的核心思想非常直观:与其强迫模型 " 记住 " 全世界的知识,不如让它在需要时去 " 查阅 " 相关的资料。这就像从 " 闭卷考试 " 转向 " 开卷考试 “,通过为 LLM 提供一个外部知识库(非参数化知识),极大地提升了其回答的准确性、时效性和可信度。
本文将深入剖析 RAG 的完整工作流,从原始文档到最终生成答案,详细拆解分片(Chunking)、索引(Indexing)、召回(Retrieval)、重排(Reranking)和生成(Generation) 这五个关键步骤,并探讨每个环节所涉及的核心技术。
从宏观上看,RAG 是一个将信息检索(Information Retrieval, IR)系统与生成式语言模型(Generative Model)相结合的框架。其工作流程可以概括为:当接收到用户查询时,系统首先从一个大规模的文档集合(知识库)中检索出与查询最相关的若干信息片段,然后将这些片段与原始查询一同注入到提示(Prompt)中,最后交由 LLM 基于这些 " 上下文 " 来生成最终的、有理有据的答案。
2 RAG 技术全流程详解
2.1 分片 (Chunking / Segmentation)
Chunking(分片) 是在 RAG 流程的数据预处理阶段,将原始文档(如 PDF、长文本、网页等)切分成更小、更易于管理的、并且在语义上相对完整的文本块(Chunks)的过程。
为什么需要分片?
- 适配模型上下文窗口(Context Window):这是最直接的原因。LLM 无法一次性处理无限长的文本。分片确保了我们送入模型的上下文信息不会超过其处理上限(如 4K, 8K, 128K tokens)。
- 提升检索精度(Retrieval Accuracy):这是更深层次的原因。向量嵌入(Embedding)是将文本的 " 语义 " 压缩到一个向量中。如果一个 Chunk 过大,包含了太多不相关的主题,它的语义向量就会变得 " 模糊 " 和 " 平均化 “,就像一张包含了太多景物而没有焦点的照片。这会导致在进行相似度搜索时,无法精确匹配到用户的具体查询意图,即 " 信噪比 " 过低。
- 平衡上下文完整性与信息密度:一个理想的 Chunk 应该像一个高质量的 " 知识卡片 “。它既要包含足够完整的上下文,让 LLM 能够理解其内容,又要足够聚焦,确保其向量表示能够精准地指向一个核心语义。这是一个关键的权衡(Trade-off)。
主流的 Chunking 策略
- 固定大小分片 (Fixed-size Chunking)
- 工作原理:按固定的字符数或 Token 数进行切分,例如每 1000 个字符一个 Chunk。通常会设置一个
chunk_overlap
(重叠区),比如 100 个字符,以防止语义信息在切分边界被硬生生截断。 - 优点:实现极其简单,计算速度快,结果可预测。是项目初期快速搭建 PoC (Proof of Concept) 的首选。
- 缺点:语义破坏性强。它完全不关心文本的内在逻辑,很可能将一个完整的句子、段落或代码块从中间切开,严重影响 Chunk 的语义完整性。
- 工作原理:按固定的字符数或 Token 数进行切分,例如每 1000 个字符一个 Chunk。通常会设置一个
- 递归字符分片 (Recursive Character Text Splitting)
- 工作原理:这是 LangChain 等框架中默认且最常用的方法。它提供一个分隔符列表,按优先级进行递归切分。例如,它会首先尝试用
\n\n
(段落)来切分,如果切分后的块仍然大于设定的chunk_size
,它会接着在那个块内部尝试用\n
(换行)切分,然后是.
(句号),最后是空格。 - 优点:兼顾了简单性和语义保持。它尽可能地尊重了文档的自然结构(段落、句子),是目前效果和效率之间平衡得最好的 " 瑞士军刀 " 式策略。
- 缺点:对于没有明显分隔符的 " 长篇大论 " 式文本,其效果会退化成固定大小分片。
- 工作原理:这是 LangChain 等框架中默认且最常用的方法。它提供一个分隔符列表,按优先级进行递归切分。例如,它会首先尝试用
- 结构化/语义分片 (Content-aware Splitting)
- 工作原理:利用文档的内在结构或语言学特征进行切分。
- 按结构 (Structural):对于 Markdown,可以按标题(
#
,##
)分片;对于 HTML,可以按标签(<p>
,<div>
)分片;对于代码,可以按函数或类定义分片。 - 按句子 (Sentence):使用 NLTK、spaCy 等 NLP 库,将文本精确地切分成句子。每个句子或多个相邻的句子可以组成一个 Chunk。
- 按结构 (Structural):对于 Markdown,可以按标题(
- 优点:语义完整性最高。能确保每个 Chunk 都是一个语法和逻辑上的独立单元。
- 缺点:
- Chunk 大小不均:句子的长度差异可能很大,导致 Chunk 大小极不稳定,给后续处理带来挑战。
- 上下文丢失:单个句子可能缺乏必要的上下文信息。为了解决这个问题,通常会将多个句子组合在一起,或者在检索后,将被命中的句子所在的整个段落都提供给 LLM。
- 工作原理:利用文档的内在结构或语言学特征进行切分。
- Agentic Chunking
- 工作原理:这是一种非常前沿的思路。它不再依赖固定的规则,而是利用一个 LLM(作为 Agent)来决定如何分片。大致流程是:LLM 逐段阅读文档,根据其对内容的理解,判断哪里是语义的自然断点,然后输出切分好的 Chunks。
- 优点:理论上能达到最高的语义切分质量,因为它模拟了人类阅读和总结的过程。
- 缺点:成本高、速度慢。每次分片都需要调用 LLM API,对于大规模文档处理来说开销巨大。目前更多处于研究和探索阶段。
- 结构化文档 (Markdown, Confluence):优先考虑结构化分片,因为它能最好地保留文档的层次结构。
- 非结构化文档 (纯文本, PDF 扫描件):递归字符分片是最佳的起点。
- 事实问答 (Q&A):倾向于更小、更精确的 Chunk(如句子分片或命题分片),以提高信噪比。
- 文档摘要 (Summarization):倾向于更大的 Chunk,以保留更完整的上下文,帮助模型理解段落间的关系。
2.2 索引 (Indexing)
Indexing(索引) 在 RAG 流程中,是承接 " 分片(Chunking)” 之后,为 " 召回(Retrieval)” 阶段做准备的核心步骤。它的本质目标是:将非结构化的文本块(Chunks)转换成机器可以高效理解和查询的结构化数据格式。
如果说分片是把一本书拆分成一页页的知识卡片,那么索引就是为这些卡片建立一个高性能的、语义感知的目录系统。这个过程主要包含两个不可分割的核心环节:1. 内容的向量化表示(Vector Embeddings) 和 2. 向量的高效存储与查询结构(Vector Database)。
向量嵌入 (Vector Embeddings)
工作原理:我们使用一个预训练的深度学习模型,即嵌入模型(Embedding Model),将每一个文本 Chunk 映射(map)到一个高维的、稠密的浮点数向量(Vector)。这个向量可以被看作是该 Chunk 在一个复杂 " 语义空间 " 中的坐标。在这个空间里,意思相近的文本,其向量在空间中的距离也更近。
[!NOTE] 模型选择维度 模型性能,从多个维度(分类、聚类、检索等)全面评估模型; 领域适应性(通用领域或者医疗、法律专业的特定微调模型); 成本与延迟; 向量维度与存储(维度(如 768, 1024, 1536),维度越高,信息越丰富,开销越大)。
向量数据库 (Vector Database)
有了向量,我们就需要一个专门的系统来存储它们,并提供毫秒级的相似度搜索能力。这就是向量数据库。
近似最近邻 (ANN) 由于在海量数据中进行精确的最近邻搜索(Brute-force KNN)计算量过大,所有主流向量数据库都采用了近似最近邻(Approximate Nearest Neighbor, ANN) 算法。其核心思想是牺牲一点点绝对的精确性,来换取查询速度几个数量级的提升。在 RAG 场景下,找到 99% 相似的文档和 98.9% 相似的文档,对最终结果影响微乎其微,因此 ANN 是完全可以接受且必要的。
- HNSW (Hierarchical Navigable Small World):
- 工作原理:可以把它想象成一个多层级的 " 高速公路网 “。它构建了一个图结构,节点是数据向量,边表示邻近关系。底层是密集的 " 国道 “,连接着所有邻近的点;上层是稀疏的 " 高速公路 “,只连接距离很远的点。查询时,从顶层最稀疏的图开始,快速定位到目标区域,然后逐层下降,直到在最底层找到最近的邻居。
- 优缺点:查询速度极快,召回率高,支持动态增删数据。但构建索引时内存消耗大,构建过程也较慢。是目前实时、高频查询场景下的首选。
- IVF (Inverted File Index):
- 工作原理:类似传统信息检索中的倒排索引。它首先通过聚类算法(如 K-Means)将整个向量空间划分为
n
个区域(Cells)。每个向量被分配到其最近的聚类中心所在的区域。查询时,只需计算查询向量与所有聚类中心的距离,找到最近的k
个区域(nprobe
参数),然后只在这k
个区域内进行精确搜索。 - 优缺点:索引构建速度快,内存占用相对较小。但查询性能和精度高度依赖
nprobe
这个参数的调优,且对于动态增删数据的支持不如 HNSW 灵活。更适合数据相对静态、写入不频繁的场景。
- 工作原理:类似传统信息检索中的倒排索引。它首先通过聚类算法(如 K-Means)将整个向量空间划分为
索引是 RAG 系统中连接 " 语义理解 " 与 " 高效检索 " 的桥梁。一个成功的索引策略,是优秀 Embedding 模型和合适 Vector DB 的有机结合。
2.3 召回 (Retrieval)
Retrieval(召回) 是 RAG 流程中动态、实时的核心环节。当用户提出一个查询(Query)时,召回阶段的任务就是根据这个查询,快速、准确地从已经建立好的索引(Index)中,找出与查询意图最相关的 Top-K 个信息片段(Chunks)。
基础召回技术:语义向量搜索
- 工作原理:
- 查询向量化:使用与索引阶段完全相同的 Embedding 模型,将用户的实时查询也转换成一个查询向量(Query Vector)。
- 相似度计算:在向量数据库中,计算这个查询向量与所有已存储的文档块向量之间的相似度。
- Top-K 提取:根据相似度得分从高到低排序,返回得分最高的 K 个文档块。
- 关键细节:
- 相似度度量 (Similarity Metric):最常用的是余弦相似度 (Cosine Similarity),因为它只关注向量的方向(语义)而不受其长度影响。在向量都经过归一化(Normalization)处理后,它等价于计算更快的点积 (Dot Product)。
- K 值的选择:
K
是一个重要的超参数。K
值太小,可能遗漏重要信息(低召回率);K
值太大,可能引入过多噪声(低精确率),并增加后续 LLM 处理的成本和延迟。K
值的选择需要通过实验和评估来确定,通常在 3 到 10 之间是一个比较合理的起始范围。 高级召回策略:突破单一向量搜索的瓶颈
- 混合搜索 (Hybrid Search)
- 动机:结合语义相关性和词法相关性的优点。
- 工作原理:将两种或多种搜索算法的结果进行融合。最经典的组合是:
- 向量搜索 (Vector Search):捕捉 " 意思 " 上的相似,如查询 " 苹果公司最新财报 " 能匹配到包含 " 库比蒂诺巨头季度营收 " 的文档。
- 关键词搜索 (Keyword Search):如 BM25 算法,捕捉字面上的匹配。它对于包含特定术语、产品 ID、错误码等 " 必须精确匹配 " 的查询至关重要。
- 融合策略:通常使用一种称为 Reciprocal Rank Fusion (RRF) 的算法来合并两路搜索结果的排序。RRF 不关心不同算法返回的原始分数,只关心每个文档在各自排序列表中的位置(rank),这使得它对不同分数的尺度不敏感,融合效果非常鲁棒。
- 应用场景:几乎是所有生产级 RAG 系统的标配。
- 多路召回/查询扩展 (Multi-Query Retrieval / Query Expansion)
- 动机:用户的原始查询可能过于简洁或存在歧义。
- 工作原理:利用 LLM 的强大语言能力,对原始查询进行 " 头脑风暴 “。
- 生成多个变体:将用户的查询(如 “RAG 性能优化 “)输入给 LLM,让它生成几个不同角度但意图相同的子查询(如 " 如何提升 RAG 检索速度 “、“RAG 系统中的 reranking 技术 “、” 优化 RAG embedding 模型的策略 “)。
- 并行召回:对每个子查询都独立执行一次召回。
- 结果合并去重:将所有召回结果汇集起来,去除重复的文档块,得到一个更全面、更多样的候选集。
- 优点:极大地提升了召回率,能从多个角度捕捉用户的潜在意图。
- 缺点:增加了 LLM 调用成本和召回阶段的延迟。
2.4 重排 (Reranking)
Reranking(重排) 是在 RAG 流程中,位于召回(Retrieval) 之后、生成(Generation) 之前的一个可选但通常至关重要的优化步骤。它的核心任务是:对召回阶段返回的 Top-K 个候选文档块进行一次更精细、更昂贵的二次排序,以将最相关的文档块排在最前面。
为什么需要重排?
- 提升精度 (Improve Precision):召回阶段使用的双编码器(Bi-Encoder)模型为了速度,是独立计算查询和文档向量的,缺乏深度的交互。这会导致一些语义上相近但实际不相关的 " 假阳性 " 结果。Reranking 使用更强大的模型来修正这些排序错误。
- 应对 " 中间丢失 " 问题 (Mitigate “Lost in the Middle”):研究表明,LLM 在处理长上下文时,对开头和结尾部分的信息关注度最高,而中间部分的信息容易被 " 忽略 “。如果不进行重排,最关键的文档块可能恰好被排在中间,导致 LLM 无法有效利用。将最相关的 1-2 个文档块通过重排置于最前面,能极大地提升生成质量。
- 降低成本与延迟 (Reduce Cost & Latency):召回阶段可能会返回较多的文档(例如 K=20 或 50)。如果将这么多文档全部塞给 LLM,不仅会消耗大量的 Token(增加成本),还会因为上下文过长而增加 LLM 的推理延迟。通过 Reranking 筛选出最精华的 Top-N(例如 N=3 或 5)个文档,可以显著优化整个系统的性价比和响应速度。
核心技术:
Reranking 的技术核心是交叉编码器(Cross-Encoder) 模型。理解它与召回阶段的双编码器(Bi-Encoder) 的区别,是理解 Reranking 本质的关键。
- 双编码器 (Bi-Encoder) - 用于召回
- 工作原理:它有两个独立的编码塔,一个用于编码查询(Query),另一个用于编码文档(Document)。它们分别将输入文本转换成向量,整个过程查询和文档是互相不见面的。最后通过计算这两个独立向量的余弦相似度来判断相关性。
- 优点:速度极快。因为所有文档的向量可以被提前计算并索引。实时查询时,只需计算一次查询向量,然后进行高效的向量搜索即可。
- 缺点:精度有限。由于缺乏交互,模型无法捕捉查询词和文档词之间细微的、复杂的关联。
- 交叉编码器 (Cross-Encoder) - 用于重排
- 工作原理:它只有一个编码器。它将查询和文档块作为一个整体拼接起来(例如用
[SEP]
分隔),然后一起输入到模型中(如 BERT)。在模型内部,通过自注意力机制(Self-Attention),查询的每个 Token 都可以和文档的每个 Token 进行充分的交互。最终,模型输出一个单一的分数(通常在 0 到 1 之间),直接代表这对(query, document)
的相关性。 - 优点:精度极高。深度的交互使其能够捕捉到非常精细的语义匹配关系,远胜于双编码器。
- 缺点:速度极慢。因为它无法预先计算任何东西。每次查询,都必须将查询与召回的 K 个文档逐一配对,并完整地进行 K 次模型前向传播。这使得它完全不适用于大规模的全量检索。
- 工作原理:它只有一个编码器。它将查询和文档块作为一个整体拼接起来(例如用
总结一下这个关键的权衡 (Trade-off): RAG 系统巧妙地利用了这个架构差异,形成了一个两阶段的漏斗模型:
- 召回阶段:用快而粗的 Bi-Encoder 从海量文档中快速筛选出几十个候选者。
- 重排阶段:用慢而精的 Cross-Encoder 对这几十个候选者进行精细打分和排序。
Reranking 是 RAG 系统从 " 可用 " 迈向 " 卓越 " 的精度放大器。它体现了一种重要的工程思想:用计算成本换取质量,并将最昂贵的计算只用在最需要的地方。
2.5 生成 (Generation)
Generation(生成) 是 RAG 流程的最后一公里,也是直接面向用户的价值出口。它的核心任务是:将原始的用户查询(Query)和经过召回、重排后筛选出的高质量上下文(Context)整合在一起,交由一个大型语言模型(LLM),以生成一个流畅、准确、忠于原文且满足用户意图的最终答案。
核心挑战
- 忠实性 vs. 创造性 (Faithfulness vs. Creativity):如何确保 LLM 的回答严格基于提供的上下文,而不是自由发挥、编造信息(即 " 幻觉 “)?这是 RAG 的根本目标。
- 上下文整合能力 (Context Integration):当提供的上下文包含多个、甚至相互矛盾的信息片段时,LLM 如何进行有效的综合、提炼和判断?
- 指令遵循能力 (Instruction Following):如何让 LLM 准确理解并执行我们的指令,比如 " 如果信息不足,请明确告知 " 或 " 请用表格形式回答 “?
- 安全性与偏见 (Safety & Bias):如何防止 LLM 生成有害、不当或带有偏见的回答,即使提供的上下文中可能包含此类内容?
提示工程 (Prompt Engineering):
- 技术描述:这是将所有信息 " 喂 " 给 LLM 的关键一步。需要构建一个结构化的 Prompt,清晰地指导 LLM 如何行动。一个典型的 RAG Prompt 模板如下:
【角色】 你是一个严谨的 AI 研究助手。 【指令】 1. 根据下方提供的多个 " 上下文信息 ",用简洁、专业的语言回答用户的 " 问题 "。 2. 你的回答必须严格依据上下文,禁止使用任何外部知识。 3. 在回答中,使用 [来源 N] 的格式注明每个信息点来自哪个上下文。 4. 如果所有上下文都无法支持回答,请直接回复:" 根据现有资料,无法回答该问题。" 【上下文信息】 --- [来源 1: RAG 白皮书.pdf] {context_chunk_1} --- [来源 2: 优化技术博客.md] {context_chunk_2} --- 【问题】 {user_query} 【回答】 (请遵循以上指令进行回答)
答案的后处理与验证 (Post-processing & Validation)
- 事实一致性检查:在生成答案后,可以再调用一次 LLM(或使用 NLI 模型),让它判断**” 生成的答案 " 与 " 原始上下文 " 之间是否存在事实冲突**。这是一个 " 自我修正 " 的环节,可以捕获一部分幻觉。
- 格式化与清洗:对 LLM 的输出进行编程方式的清洗,例如移除不必要的解释、修正格式、确保引用的正确性等。
- 敏感信息过滤:在输出给用户之前,通过敏感词库或安全模型,对答案进行一次扫描,确保不包含不当内容。
3 总结
RAG 并非单一的技术,而是一个精密的、可高度定制化的系统工程。它的五个核心步骤——分片、索引、召回、重排、生成——环环相扣,共同决定了最终输出的质量。
- 分片是数据预处理的基石,决定了知识库的粒度和质量。
- 索引通过向量化技术,为海量非结构化数据搭建了通往语义理解的桥梁。
- 召回是效率的保证,利用 ANN 搜索从亿万信息中快速定位相关线索。
- 重排是精度的升华,通过更强大的模型对候选信息进行二次筛选,确保 " 好钢用在刀刃上 “。
- 生成是价值的兑现,借助 LLM 的能力将检索到的原始信息转化为人类易于理解的智慧。
构建一个高质量的 RAG 系统,需要在每个环节进行细致的评估和优化。从选择合适的分片策略,到调优嵌入模型,再到设计高级召回与重排流程,每一步的改进都能显著提升系统的整体性能。随着技术的不断演进,如自适应 RAG(Self-Corrective RAG)、图 RAG(Graph RAG)等更先进的范式也在不断涌现,预示着 RAG 在未来智能应用中的核心地位将愈发稳固。