二、RAG核心流程:索引、检索、生成三大阶段详解

好,咱们直接进入正题。RAG 系统说白了就干三件事:把文档存好、把相关段落找出来、让大模型基于这些内容回答。这三步分别对应索引、检索、生成。我当年刚接触 RAG 时,总觉得这玩意儿不就是「搜索+LLM」吗?后来踩了不少坑才明白——每一步都有门道。

2.1 索引阶段:让知识变得可搜索

索引阶段的目标很明确:把原始文档变成计算机能快速检索的格式。我个人习惯把这一步拆成四个子任务:

  1. 文档解析:PDF、Word、HTML……不同格式有不同的解析器。我记得有次项目里遇到扫描版 PDF,OCR 识别率低得离谱,后来换了专门的文档解析服务才搞定。
  2. 文本分块:把长文档切成小块。为什么?因为大模型的上下文窗口有限,而且检索时粒度太粗容易混入噪声。
  3. 向量化:用 Embedding 模型把文本块转成向量。这一步决定了检索的「语义理解」能力。
  4. 存储:把向量和原始文本存到向量数据库里,比如 FAISS、Milvus、Chroma。

分块策略:我建议 chunk_size 设为 256-512 tokens,overlap 设为 10%-20%。太小了语义不完整,太大了检索精度下降。你想想看,一个 2000 tokens 的块,里面可能包含三个不同的话题,检索时很容易答非所问。

2.2 检索阶段:找到最相关的知识

检索阶段的核心是「召回」。用户问一个问题,系统得从海量文档里捞出最相关的几段。这里有两种主流方式:

检索方式 原理 适用场景
稀疏检索(BM25) 基于关键词匹配,计算 TF-IDF 加权得分 精确匹配、专业术语查询
稠密检索(向量检索) 基于语义相似度,计算向量余弦距离 语义理解、同义词替换、模糊查询
混合检索 两者结合,用 RRF 或加权融合排序 大多数生产环境

嗯,这里要注意:纯向量检索不一定比 BM25 好。我曾经在一个法律文档项目中,用户问「合同违约赔偿标准」,BM25 因为匹配了「违约」「赔偿」关键词,召回效果反而比向量检索好。后来我采用了混合检索,召回率提升了 15%。

我的经验:检索阶段别只盯着 top-k。我建议同时返回 top-5 和 top-10 的结果,然后让重排序模型(Cross-Encoder)重新打分。这样能过滤掉那些「语义相似但实际无关」的噪声。

2.3 生成阶段:让大模型「带着答案说话」

生成阶段就是把检索到的文档块和用户问题一起喂给大模型。这里有个关键设计——Prompt 模板。我见过太多人直接把检索结果拼到问题后面,结果模型要么忽略上下文,要么被噪声带偏。

一个合格的 Prompt 模板应该包含:

  • 系统指令:告诉模型「你是一个问答助手,只能基于给定文档回答」
  • 上下文:检索到的文档块,按相关性排序
  • 用户问题:原始问题
  • 输出约束:如果文档中没有相关信息,直接说「不知道」
# 一个典型的 RAG Prompt 模板
你是一个专业的问答助手。请基于以下文档内容回答问题。
如果文档中没有相关信息,请直接说「我不知道」,不要编造答案。

文档内容:
{context}

用户问题:{question}

请给出简洁、准确的回答:

避坑指南:我曾经在生成阶段犯过一个低级错误——把检索到的所有文档块都塞进 Prompt,结果上下文太长,模型开始「幻觉」了。后来我严格限制最多输入 3-5 个文档块,每个块不超过 512 tokens。记住:质量永远比数量重要

2.4 RAG 系统架构图与组件职责

下面这张图是我在项目中常用的 RAG 架构。别被「架构图」三个字吓到,说白了就是数据怎么流、每个环节谁负责什么。

┌─────────────────────────────────────────────────────────┐
│                    用户输入(问题)                       │
└────────────────────────┬────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│                   检索阶段(Retriever)                   │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐              │
│  │ 查询编码  │  │ 向量检索  │  │ 重排序    │              │
│  │ (Query    │→│ (ANN搜索) │→│ (Cross-   │              │
│  │  Encoder) │  │          │  │  Encoder) │              │
│  └──────────┘  └──────────┘  └──────────┘              │
└────────────────────────┬────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│                   生成阶段(Generator)                   │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐              │
│  │ Prompt   │  │ 大语言模型│  │ 输出后处理│              │
│  │ 组装     │→│ (LLM)    │→│ (格式检查)│              │
│  └──────────┘  └──────────┘  └──────────┘              │
└────────────────────────┬────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│                    最终回答                              │
└─────────────────────────────────────────────────────────┘

各组件职责说明:

组件 职责 常见选型
文档解析器 将 PDF、Word 等格式转为纯文本 PyMuPDF、Unstructured、LlamaParse
文本分块器 按语义或长度切分文档 RecursiveCharacterTextSplitter、Semantic Splitter
Embedding 模型 将文本转为向量 text-embedding-3-small、BGE、E5
向量数据库 存储向量并支持 ANN 检索 FAISS、Milvus、Chroma、Pinecone
检索器 执行查询并返回 top-k 结果 BM25、向量检索、混合检索
重排序器 对检索结果重新打分排序 Cross-Encoder、Cohere Rerank
大语言模型 基于上下文生成回答 GPT-4、Claude、Llama、Qwen

核心要点:RAG 不是简单的「检索+生成」拼凑。索引阶段决定了你能召回什么,检索阶段决定了你能召回多准,生成阶段决定了你能回答多好。三个环节环环相扣,任何一个短板都会拖垮整个系统。

好了,这一章的内容就到这里。下一章我会详细讲文档解析与分块策略——这块坑特别多,尤其是 PDF 表格和混合排版文档的处理,到时候我会把踩过的坑一一列出来。