RAG 核心流程拆解:索引、检索、生成

RAG 系统说白了就三步:先存好、再找到、最后生成。听起来简单,但每一步都有不少坑。我刚开始搭 RAG 时,以为把文档扔进向量库就完事了,结果检索出来的东西驴唇不对马嘴。后来才明白,这三步每一步都得精心设计。

咱们把这三个模块拆开看看,每个模块到底在干什么。

1. 索引阶段:把知识变成机器能懂的结构

索引阶段的目标很明确——把原始文档变成可检索的结构化数据。我个人习惯把这个阶段分成四个子步骤:

  1. 文档解析:把 PDF、Word、HTML 等格式转成纯文本
  2. 文本分块:把长文本切成合适大小的片段
  3. 向量化:用 Embedding 模型把文本块转成向量
  4. 存储:把向量和元数据存入向量数据库

核心要点:索引质量直接决定检索效果。你想想看,如果分块策略不对,后面再怎么优化也白搭。

这里有个常见的误区。很多人觉得分块就是简单按字符数切,比如每 512 个字符一刀切。我在项目中遇到过这种做法的后果——切出来的块语义不完整,检索时经常返回半句话。后来我改用语义分块,按段落、句子边界来切,效果好了很多。

分块策略 优点 缺点 适用场景
固定长度分块 实现简单,速度快 语义不完整,边界生硬 日志、短文本
语义分块 保留完整语义 块大小不统一 技术文档、论文
递归分块 兼顾大小和语义 实现复杂 长文档、书籍
基于模型分块 最精准 速度慢,成本高 高精度场景

我的经验:对于大多数技术文档,我建议用 256-512 个 token 的块大小,配合 20% 的重叠。这样既能保证语义完整,又不会让检索结果太冗余。

2. 检索阶段:从海量知识中找到最相关的

检索阶段是 RAG 的核心。用户问一个问题,系统要从索引里找到最相关的几个片段。嗯,这里要注意,检索不是简单的「找相似」。

我常用的检索方式有三种:

  • 向量检索:用余弦相似度或欧氏距离找最近邻
  • 关键词检索:用 BM25 等算法做精确匹配
  • 混合检索:把向量检索和关键词检索的结果融合

为什么会需要混合检索?我举个例子。用户问「苹果公司的创始人是谁」,向量检索可能找到「乔布斯创立了苹果」这个片段,但关键词检索能确保「创始人」这个词被精确匹配。两者结合,召回率更高。

避坑指南:我曾经只用了向量检索,结果用户问「2024 年的财报」时,系统返回了「2023 年的财报」,因为向量太相似了。后来加了关键词权重,才解决了这个问题。

检索阶段还有一个关键参数——Top-K。K 值太小,可能漏掉重要信息;K 值太大,又会引入噪声。我一般从 K=5 开始调,根据实际效果上下浮动。

3. 生成阶段:把检索结果变成流畅的回答

生成阶段就是把检索到的片段喂给大语言模型,让它生成最终答案。这一步看似简单,但有个大坑——上下文窗口限制。

LLM 的上下文窗口是有限的。比如 GPT-4 的 8K 上下文,你不可能把所有检索结果都塞进去。所以需要做重排序和压缩。

# 一个简单的重排序示例
def rerank_and_generate(query, retrieved_chunks, llm, top_n=3):
    # 1. 用交叉编码器重排序
    scores = cross_encoder.predict([(query, chunk) for chunk in retrieved_chunks])
    
    # 2. 取 Top-N
    top_chunks = [chunk for _, chunk in sorted(zip(scores, retrieved_chunks), reverse=True)][:top_n]
    
    # 3. 构建 prompt
    context = "\n\n".join(top_chunks)
    prompt = f"基于以下信息回答问题:\n\n{context}\n\n问题:{query}"
    
    # 4. 生成
    return llm.generate(prompt)

生成阶段还有个容易被忽略的点——引用来源。我建议在生成时让 LLM 标注每个答案片段来自哪个文档块。这样用户能追溯来源,也方便调试。

整体流程:一张图看懂

下面这张图展示了 RAG 系统的完整流程。从原始文档到最终答案,三个模块环环相扣。

RAG 核心流程架构图 原始文档 文档解析 文本分块 向量化 向量数据库 用户查询 查询向量化 向量检索 重排序 LLM 生成 最终答案 索引阶段 检索阶段 生成阶段

三个模块的职责对比

最后用一张表总结一下三个模块的核心职责:

模块 核心职责 关键组件 常见问题
索引 把原始文档转成可检索的结构 解析器、分块器、Embedding 模型、向量库 分块不合理、向量质量差
检索 从索引中找到最相关的片段 检索器、重排序器、混合检索策略 召回率低、噪声多
生成 基于检索结果生成最终答案 LLM、Prompt 模板、上下文压缩 上下文超限、幻觉

这三个模块不是孤立的。索引质量影响检索效果,检索质量又直接影响生成质量。我见过不少团队只优化其中一个模块,结果整体效果上不去。嗯,记住一句话:RAG 系统的瓶颈往往在最短的那块板。