二、RAG核心流程:索引、检索、生成三大阶段详解
好,咱们直接进入正题。RAG 系统说白了就干三件事:把文档存好、把相关段落找出来、让大模型基于这些内容回答。这三步分别对应索引、检索、生成。我当年刚接触 RAG 时,总觉得这玩意儿不就是「搜索+LLM」吗?后来踩了不少坑才明白——每一步都有门道。
2.1 索引阶段:让知识变得可搜索
索引阶段的目标很明确:把原始文档变成计算机能快速检索的格式。我个人习惯把这一步拆成四个子任务:
- 文档解析:PDF、Word、HTML……不同格式有不同的解析器。我记得有次项目里遇到扫描版 PDF,OCR 识别率低得离谱,后来换了专门的文档解析服务才搞定。
- 文本分块:把长文档切成小块。为什么?因为大模型的上下文窗口有限,而且检索时粒度太粗容易混入噪声。
- 向量化:用 Embedding 模型把文本块转成向量。这一步决定了检索的「语义理解」能力。
- 存储:把向量和原始文本存到向量数据库里,比如 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 表格和混合排版文档的处理,到时候我会把踩过的坑一一列出来。