三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

大模型系列——解读RAG(检索增强生成)2万字详解

大模型系列——解读RAG(检索增强生成)2万字详解

引言:大模型时代的“外挂大脑”

2022年底ChatGPT的横空出世,将大语言模型(Large Language Model, LLM)推向了前所未有的高度。无论是撰写文案、编写代码,还是逻辑推理、语言翻译,LLM都展现出了令人惊叹的能力。然而,随着应用的深入,LLM的三大“原罪”逐渐暴露在开发者面前:

  • 知识截止与幻觉:模型的知识固化在训练截止日期,无法感知实时信息。当被问到不知道的内容时,模型往往会一本正经地“胡说八道”,这种现象被称为“幻觉”(Hallucination)。
  • 私有数据脱节:企业内部的海量私有文档、数据库、API接口,LLM无法直接触达。想让模型回答“公司今年的年假政策是什么?”,如果不做任何处理,它只能泛泛而谈。
  • 长文本记忆瓶颈:虽然上下文窗口(Context Window)已扩展至百万Token级别,但直接将整本百科全书塞进Prompt,不仅成本高昂,且模型往往无法有效利用长文本中间部分的信息,导致“迷失在中间”的问题。

在这样的背景下,检索增强生成(Retrieval-Augmented Generation, RAG)应运而生。它并非一种全新的模型架构,而是一种精妙的“应用范式”。简单来说,RAG 充当了 LLM 的“外挂大脑”或“联网搜索引擎”。在回答用户问题之前,RAG 先从外部知识库中检索最相关的信息,将这些信息作为“参考资料”连同问题一起交给 LLM,让 LLM 基于“参考资料”作答。

本文将深入解读 RAG 的核心原理、技术架构、关键模块、优化策略及未来演进方向,力求用 2 万字的篇幅,带你彻底吃透 RAG。

一、RAG 核心概念与基本流程

1.1 什么是 RAG?

RAG 全称是 Retrieval-Augmented Generation,即检索增强生成。它由 Facebook AI 研究院(Meta AI)于 2020 年在论文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》中首次正式提出。RAG 将信息检索系统与 LLM 的生成能力相结合,旨在解决 LLM 在知识密集型任务中知识不足和生成幻觉的问题。

直观理解:如果把 LLM 比作一位记忆力超强但知识面有限的闭卷考生,那么 RAG 就是给这位考生配了一台联网的电脑。考试时,考生(LLM)遇到不确定的题目,随时可以查阅资料(检索),然后结合资料和自己的理解作答(生成)。

1.2 RAG 的三步核心流程

一个标准的 RAG 流程可以分为三个核心步骤:

  • 索引(Indexing):将私有数据(PDF、Word、数据库、网页等)进行清洗、切分,然后通过 Embedding 模型转换为向量,存入向量数据库。这一过程通常在离线阶段完成。
  • 检索(Retrieval):当用户提问时,将问题同样转换为向量,在向量数据库中搜索相似度最高的 Top-K 个文本块(Chunks)。
  • 生成(Generation):将检索到的相关文本块与用户原始问题组合成一个增强的 Prompt,交给 LLM 生成最终答案。

1.3 RAG vs. 微调(Fine-tuning)

在企业级应用中,RAG 和微调是两种最主流的 LLM 定制化方案。两者并非互斥,实际场景中常结合使用,但它们的侧重点截然不同:

  • RAG:侧重于“记忆力”。适合需要实时更新知识、查询特定文档库、要求事实准确且可溯源的场景。优点是成本低、更新快,缺点是无法改变模型的写作风格和深层逻辑。
  • 微调:侧重于“学习新技能”。适合让模型学习特定领域的术语、风格或格式(如医学报告、法律文书、代码补全)。缺点是成本高,无法实时更新知识,且容易发生灾难性遗忘。

一个形象的比喻:RAG 是给模型一本“参考书”开卷考试,微调是让模型回炉重造“修学分”。

二、RAG 技术架构深度解析

2.1 索引构建:从数据到向量

索引构建是 RAG 系统的基石,其质量直接决定了检索效果的上限。这一阶段主要包括以下几个关键环节:

2.1.1 数据清洗与提取

实际业务中的数据来源五花八门,可能是扫描版 PDF(图片)、Word 文档、HTML 网页、Markdown 文件,甚至是 PPT。数据清洗的目的是将非结构化数据转化为干净、连贯的文本流。

  • PDF 解析:工具如 PyMuPDF、Unstructured、PDFPlumber 等。对于扫描版 PDF,需要引入 OCR(光学字符识别)技术,如 PaddleOCR、Tesseract。
  • 格式清洗:去除页眉页脚、乱码字符、多余空格和换行符。对于 HTML 表,需要保留表格结构,避免语义丢失。
  • 元数据提取:保留文档标题、页码、章节、作者等元数据,这些信息在后续检索召回时可用于精细化过滤。
2.1.2 文本分块策略

LLM 的上下文窗口有限,且 Embedding 模型对长文本的语义表征能力会衰减。因此,我们需要将长文档切分成更小的“块(Chunks)”。分块策略是 RAG 中最具艺术性的环节之一,以下是几种常见策略:

  • 固定大小分块:最简单的策略,设定固定长度(如 512 Token),按字符或 Token 切分。缺点明显,容易在句子中间切断,导致语义割裂。
  • 递归字符分割:LangChain 默认的分割器。按优先级(如换行符、句号、空格)顺序递归尝试切分,尽可能保持语义完整性。
  • 语义分块:利用 Embedding 模型计算相邻句子的余弦相似度,当相似度出现显著下降时,说明语义发生了转折,此时进行切分。这种方法效果好,但计算成本较高。
  • 文档结构感知分块:对于 Markdown,按标题层级切分;对于 Docx,按段落样式切分。这种策略能最大程度保留文档的结构化信息。

无论采用哪种策略,重叠窗口都是一个重要的技巧。即在相邻 Chunk 之间保留一段重叠文本(如 10%~20%),防止关键信息正好落在切分边界上而被截断。

2.1.3 向量化与向量数据库

文本切分完成后,需要将每个 Chunk 通过 Embedding 模型映射为高维向量(如 768 维或 1536 维)。选择合适的 Embedding 模型至关重要:

  • 通用模型:OpenAI 的 text-embedding-3-large、text-embedding-ada-002;Google 的 text-embedding-004;智谱的 Embedding-3 等。
  • 中文优化模型:BGE(BAAI General Embedding)、M3E、Stella 等,在中文语义理解上表现更优。
  • 精调模型:针对特定领域(如医疗、法律)使用对应语料进行微调,能显著提升召回率。

向量数据库则是存储和检索这些向量的基础设施。主流选择包括:

  • 专用向量数据库:Chroma(轻量开源)、Milvus(分布式高性能)、Pinecone(全托管云服务)、Weaviate、Qdrant。
  • 全文与向量混合数据库:Elasticsearch(通过向量插件)、PostgreSQL(pgvector 扩展)、Redis(Redis Stack)。

2.2 检索增强:从查询到召回

当用户输入问题后,系统进入在线检索阶段。这一阶段的目标是尽可能快、准、全地找到与问题相关的 Chunk。

2.2.1 查询预处理

用户直接输入的问题往往不够精确,需要经过预处理:

  • 查询改写:利用 LLM 将口语化、模糊的查询改写为更精准的检索查询。例如,用户问“那个能看视频的卡怎么办?”,改写为“显卡驱动安装视频教程”。
  • 多轮对话查询拆分:在多轮对话中,用户可能使用代词或省略主语。例如,“他有什么代表作?”需要结合上文理解的“他”是谁,将问题补全为“周杰伦有什么代表作?”。
  • HyDE(Hypothetical Document Embeddings):先让 LLM 根据问题生成一个假设性的答案,然后用这个假设答案去检索,而不是直接用问题检索。这种方法能弥合“问题”与“答案”之间的语义鸿沟。
2.2.2 混合检索策略

单纯依赖向量相似度检索(语义搜索)并非万能。例如,搜索“苹果公司最新财报”,向量检索可能召回大量关于“苹果水果”的营养信息。混合检索将向量检索与关键词检索(BM25)结合,取长补短:

  • 向量检索:擅长捕捉语义相似性,对同义词、近义词友好。
  • 关键词检索(BM25/TF-IDF):擅长精确匹配,如特定术语、人名、产品型号、合同编号等。

通过 RRF(Reciprocal Rank Fusion,倒数排名融合)或加权求和算法,将两种检索结果融合排序,能显著提升召回质量。

2.2.3 重排序

初步检索召回了 Top-K(如 50 个)候选 Chunk,但这些 Chunk 的排序可能不够精细。重排序模型(Re-ranker)采用更复杂的交叉编码器架构,对查询和候选 Chunk 进行成对相关性打分,精选出 Top-N(如 5 个)最相关的 Chunk 送入 LLM。

  • 开源 Re-ranker:BGE-Reranker、bge-reranker-v2-m3、Cohere Rerank(商业)。
  • LLM 重排序:直接利用 LLM 本身进行排序,如 RankGPT 的思路,将候选列表交给 LLM 用特定的 Prompt 指令排序。

2.3 生成增强:从 Prompt 到答案

检索到相关 Chunk 后,最后一步是构建 Prompt 并生成答案。这一阶段的核心是“如何让 LLM 高效利用参考资料”。

2.3.1 Prompt 工程模板

一个典型的 RAG Prompt 模板如下:

你是一个专业的知识问答助手。请严格根据以下提供的参考资料回答用户问题。 如果参考资料中没有相关信息,请明确告知用户“未找到相关信息”,不要编造。 请以 Markdown 格式输出,并注明引用来源。 参考资料: {context} 用户问题: {question} 回答:
2.3.2 上下文压缩与整合

当检索到的文档过多时,往往会超出 LLM 的上下文窗口限制。此时需要采取策略:

  • Summarization:对每个 Chunk 进行摘要,只将摘要送入 Prompt。
  • LLMLingua:微软提出的提示压缩技术,在保留关键信息的前提下,将 Prompt 压缩至原长度的 1/3 甚至更少。
  • LongContext Reorder:研究发现,LLM 对 Prompt 开头和结尾的信息利用最好,对中间部分利用较差。将重要 Chunk 放在开头和结尾,次要的放在中间,可提升生成质量。
2.3.3 引用溯源

为了增强可信度,RAG 系统通常在答案中附带引用来源。通过 Prompt 要求 LLM 在引用参考资料时标注编号(如 [1]、[2]),用户可以点击链接跳转到原始文档片段,验证答案的真实性。这是 RAG 相比纯 LLM 生成的一大核心优势。

三、RAG 的进阶范式与优化

3.1 朴素 RAG 的局限性

上述流程被称为“朴素 RAG(Naive RAG)”。在实际落地中,它往往面临以下问题:

  • 检索质量低:向量检索召回率低,关键信息漏检。
  • 相关性不足:召回的内容与问题相关度不高,包含大量噪声。
  • 上下文整合失败:LLM 未能有效利用参考材料,或忽略材料自行编造。
  • 多模态无力:无法处理文档中的图片、表格等富文本信息。

针对这些局限,业界先后提出了 Advanced RAG 和 Modular RAG 等进阶范式。

3.2 Advanced RAG:精细化流程优化

Advanced RAG 在朴素 RAG 的基础上,针对检索前、检索中、检索后三个阶段进行了精细化优化。

3.2.1 检索前优化
  • 滑动窗口检索:检索时不仅返回匹配的 Chunk,还附带其前后相邻的 Chunk,为 LLM 提供更完整的上下文。
  • 句子窗口检索:索引时以小粒度(如句子)存储,检索时返回包含该句子的整个段落或大 Chunk,兼顾检索精度和上下文完整性。
  • 多级索引(Hierarchical Index):建立两层索引。第一层是文档摘要索引,第二层是 Chunk 索引。检索时先快速定位相关文档,再在该文档内精确检索 Chunk,大幅提升效率。
3.2.2 检索中优化
  • 子问题分解:对于复杂问题,先用 LLM 将其拆解为多个子问题,分别检索,最后汇总答案。
  • 迭代检索:根据 LLM 的初步回答,判断是否需要进一步检索补充信息,形成“检索-生成-再检索”的循环。
  • 多路召回:同时从向量数据库、传统搜索引擎(Google/Bing)、内部知识图谱等多路召回,综合排序。
3.2.3 检索后优化
  • 信息压缩:使用 LLM 对召回的 Chunk 进行摘要,剔除无关信息。
  • 重排序:同 2.2.3 所述。
  • Self-Reflection:让 LLM 评估自己的回答,判断是否忠实于参考材料,是否需要修正或补充。

3.3 Modular RAG:可插拔的功能模块

Modular RAG 将 RAG 系统抽象为多个可插拔的功能模块,支持按需组合,灵活应对复杂场景。

  • 搜索模块:集成搜索引擎 API,获取实时信息。
  • 记忆模块:利用 LLM 自身的记忆能力,对历史对话中的重要信息进行总结和存储,避免重复检索。
  • 路由模块:根据用户查询意图,智能路由到不同的数据源或处理流程。例如,查询“天气”路由到搜索引擎,查询“公司政策”路由到向量数据库。
  • 任务适配模块:根据下游任务(如摘要、翻译、代码生成)动态调整 Prompt 模板和检索策略。
  • 融合模块:对多路召回或多模态信息进行对齐和融合,生成统一答案。

3.4 Graph RAG:从文本到知识图谱

微软在 2024 年提出的 Graph RAG(基于图的检索增强生成)是 Modular RAG 的一个重要分支。传统 RAG 基于向量相似度,擅长回答“事实类”问题(如“某事件的时间地点”),但在回答“全局性总结类”问题(如“整个数据集的主要主题是什么?”)时捉襟见肘。

Graph RAG 的核心思路是:

  • 图构建:从原始文本中提取实体(人物、地点、组织、概念)和关系,构建知识图谱。
  • 社区发现:使用 Leiden 等算法对图进行社区划分,识别主题聚类。
  • 社区摘要:对每个社区内的实体和关系,用 LLM 生成摘要,形成层次化的知识结构。
  • 检索生成:对于全局性问题,检索相关社区摘要;对于细节性问题,检索具体实体。两者结合,兼顾宏观与微观。

Graph RAG 极大地提升了 RAG 系统对数据集的整体理解能力,但构建和更新图谱的工程成本也更高。

四、RAG 实战:从零搭建一个 RAG 系统

4.1 技术栈选型

构建一个生产级 RAG 系统,推荐以下技术栈组合:

  • 编排框架:LangChain / LlamaIndex(高抽象,快速原型);Dify / FastGPT(低代码平台)。
  • 解析与加载:Unstructured(多格式解析)、BeautifulSoup(HTML 解析)。
  • Embedding 模型:BAAI/bge-large-zh-v1.5(中文开源)、OpenAI text-embedding-3-small(商业)。
  • 向量数据库:Milvus(分布式)、Chroma(轻量)、Elasticsearch(混合检索)。
  • LLM:GPT-4o / Claude 3.5 Sonnet(商业)、Qwen2.5-72B / DeepSeek-V3(开源)。
  • 后端服务:Python(FastAPI / Flask)。
  • 前端展示:Streamlit / Gradio(快速原型),或自研 Web 应用。

4.2 核心代码实现

以下以 LangChain 和 Chroma 为例,展示一个基于 Python 的朴素 RAG 实现。

4.2.1 环境准备
pip install langchain langchain-community langchain-openai chromadb unstructured pypdf
4.2.2 文档加载与切分
from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter 加载 PDF loader = PyPDFLoader("knowledge_base.pdf") documents = loader.load() 文本切分 text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] ) chunks = text_splitter.split_documents(documents) print(f"共切分为 {len(chunks)} 个文本块")
4.2.3 向量化与存储
from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma 初始化 Embedding 模型 embeddings = OpenAIEmbeddings( model="text-embedding-3-small", # base_url="https://api.openai-proxy.com/v1" # 如需代理 ) 向量化并存入 Chroma vectorstore = Chroma.from_documents( documents=chunks, embedding=embeddings, persist_directory="./chroma_db" ) vectorstore.persist() print("向量数据库构建完成!")
4.2.4 检索与生成
from langchain_openai import ChatOpenAI from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate 自定义 Prompt 模板 prompt_template = """你是一个专业的知识问答助手。请严格根据以下参考资料回答用户问题。 如果参考资料中没有相关信息,请明确告知用户“未找到相关信息”,不要编造。 参考资料: {context} 用户问题: {question} 回答:""" PROMPT = PromptTemplate( template=prompt_template, input_variables=["context", "question"] ) 初始化 LLM llm = ChatOpenAI( model="gpt-4o", temperature=0.1, # RAG 场景建议低温度,减少幻觉 # base_url="https://api.openai-proxy.com/v1" ) 构建 RAG 链 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=vectorstore.as_retriever(search_kwargs={"k": 4}), chain_type_kwargs={"prompt": PROMPT}, return_source_documents=True ) 提问 question = "请介绍一下 RAG 的核心原理" result = qa_chain.invoke({"query": question}) print("答案:", result["result"]) print("\n引用来源:") for doc in result["source_documents"]: print(f"- {doc.metadata['source']} (第{doc.metadata['page']}页)")

4.3 评估与优化

RAG 系统的效果评估通常分为两个层面:

  • 检索评估:使用 Hit Rate、MRR(Mean Reciprocal Rank)、NDCG 等指标评估检索阶段的召回效果。
  • 生成评估:使用 RAGAS(RAG Assessment)框架,从以下维度评估:
    • 忠实度(Faithfulness):答案是否完全基于参考材料,有无编造。
    • 答案相关性(Answer Relevancy):答案是否切题。
    • 上下文相关性(Context Relevancy):召回的材料是否与问题相关。
    • 上下文召回率(Context Recall):参考材料是否覆盖了答案所需的所有信息。
from ragas.metrics import faithfulness, answer_relevancy, context_relevancy, context_recall from ragas import evaluate 构建评估数据集 eval_dataset = Dataset.from_dict({ "question": ["你的问题列表"], "answer": ["LLM 生成的答案"], "contexts": [["召回的 Chunk 列表"]], "ground_truth": ["标准答案"] }) 评估 result = evaluate( eval_dataset, metrics=[faithfulness, answer_relevancy, context_relevancy, context_recall] ) print(result)

五、RAG 的落地挑战与最佳实践

5.1 多模态 RAG:突破纯文本限制

现实世界的文档远不止纯文本。PDF 中包含大量图表、表格、公式,PPT 中包含图片和架构图。如果不对这些信息进行解析,RAG 将丢失大量关键知识。

  • 表格解析:使用 Unstructured 等工具将表格转换为 HTML 或 Markdown 格式,保留结构信息,让 LLM 能够理解行与列的对应关系。
  • 图片理解:引入多模态大模型(如 GPT-4o、Qwen-VL)对图片进行描述(Captioning),将图片描述存入索引。检索时,文本描述和图片可同时召回。
  • 公式处理:对于 LaTeX 公式,保留原格式;对于图片公式,使用 OCR 加 LaTeX 转换工具。

5.2 安全与权限控制

在企业级 RAG 应用中,权限控制是硬性需求。不同角色、不同部门的员工,能访问的文档范围不同。

  • 元数据过滤:在索引时为每个 Chunk 添加权限标签(如 department: "sales")。检索时,在查询过滤条件中加入用户所属部门,确保只返回有权限访问的文档。
  • 数据脱敏:对于文档中的敏感信息(身份证号、手机号、银行卡号),在索引前进行脱敏处理,或在 LLM 生成后进行脱敏后处理。

5.3 实时性与增量更新

知识库不是一成不变的。新文档不断产生,旧文档可能被修改或删除。

  • 增量索引:监听文件系统或数据库变更,当新增或修改文档时,自动触发索引更新流程。
  • 定时全量重建:对于更新频繁的知识库,设定定时任务,在业务低峰期进行全量索引重建。
  • 脏数据清理:建立过期文档的清理机制,确保检索结果不会包含已作废的信息。

5.4 缓存与成本优化

RAG 系统中,LLM 调用的 Token 消耗是主要成本来源。

  • 语义缓存:对相似用户问题,直接返回缓存的答案,避免重复的检索和 LLM 调用。如使用 GPTCache、Redis 等。
  • 精确匹配缓存:对完全相同的问题,直接返回缓存答案。
  • Prompt 精简:不要将所有检索结果都塞进 Prompt。使用重排序模型精选最相关的 Top-3,减少 Prompt Token 消耗。

5.5 幻觉治理的最后防线

尽管 RAG 极大降低了幻觉,但 LLM 仍然可能忽略参考材料,或断章取义。以下措施可进一步加固:

  • Self-Check:让 LLM 生成答案后,再生成一个自我检查,逐条验证答案中的事实是否能在参考材料中找到依据。
  • NLI 校验:使用自然语言推理(NLI)模型,判断答案与参考材料之间是否存在蕴含关系、矛盾关系或无关关系。
  • 后处理过滤:对 LLM 输出进行关键词过滤,禁止输出特定敏感词,或强制要求答案格式。

六、RAG 的未来演进趋势

6.1 Agentic RAG:智能体驱动的 RAG

2025 年以来,AI Agent 成为行业热点。Agentic RAG 将 RAG 系统与 Agent 框架结合,赋予 RAG 系统规划、推理、调用工具的能力。

  • 自主规划:Agent 接收复杂任务后,自主规划检索步骤,决定先检索什么、后检索什么。
  • 工具调用:Agent 可以调用计算器、数据库查询、API 接口等工具,获取更精确的信息。例如,用户问“今年的销售额比去年增长了多少?”,Agent 会先调用数据库查询 API 获取精确数据,而不是从文档中检索一个可能过时的数字。
  • 多步推理:Agent 可以执行“检索-推理-再检索”的循环,直至收集到足够的信息回答用户问题。

6.2 Self-RAG:自我反思的 RAG

Self-RAG 是一种让 LLM 在生成过程中自我决定何时检索、检索什么、以及如何评估检索结果的新范式。它引入了一组特殊的“反思 Token”:

  • Retrieve Token:模型决定是否需要检索。
  • IsRel Token:判断检索到的文段是否相关。
  • IsSup Token:判断生成内容是否得到检索文段的支持。
  • IsUse Token:判断生成内容是否有用。

通过训练 LLM 在生成时输出这些反思 Token,Self-RAG 实现了更精细的检索控制,在多个基准测试上超越了传统 RAG。

6.3 端到端 RAG 模型

当前的 RAG 系统大多是“拼接式”的:检索器、重排序器、生成器各司其职,通过 API 调用或内存传递数据。未来的趋势是训练端到端的 RAG 大模型,将检索和生成能力内化到同一个模型参数中,降低系统复杂度和延迟。

6.4 知识图谱与 RAG 的深度融合

Graph RAG 已经展示了知识图谱的巨大潜力。未来,知识图谱将与 RAG 系统更深度地融合,不仅仅是作为静态的检索源,而是作为动态更新的知识基础设施。例如,每次对话后自动更新知识图谱,实现知识的持续积累和进化。

七、总结与展望

RAG 是当前大模型应用落地的最核心范式之一。它巧妙地将信息检索与文本生成两大技术结合,在保持 LLM 强大语言能力的同时,有效解决了知识时效性、事实准确性和私有数据接入三大痛点。

回顾全文,我们从 RAG 的基本概念出发,深入剖析了索引构建、检索增强、生成增强三大核心模块的技术细节,探讨了从朴素 RAG 到 Advanced RAG、Modular RAG、Graph RAG 的演进路径,并给出了实战代码和落地最佳实践。

展望未来,Agentic RAG、Self-RAG、端到端 RAG 以及多模态 RAG 将成为技术演进的主旋律。RAG 不会取代 LLM,而是会成为 LLM 不可或缺的“记忆系统”和“感知器官”。

对于开发者和企业而言,现在正是深入学习和实践 RAG 的最佳时机。从简单的文档问答入手,逐步引入混合检索、重排序、多模态解析和 Agent 能力,你会发现,大模型的真正价值,在“外挂大脑”的加持下,才刚刚开始释放。

正如 Sam Altman 所言:“AI 的真正力量不在于它知道什么,而在于它知道如何去找到答案。”——而这,正是 RAG 赋予 AI 的核心能力。

← 返回列表