☰
RAG 检索增强生成全链路拆解:从文档切块到 Agentic RAG 实战
2026/11/3 16:27:40 网站建设 项目流程

1. RAG 到底是什么,为什么 Agent 开发绕不开它

先把结论摆在前面:RAG(Retrieval-Augmented Generation,检索增强生成)不是某个具体框架的名字,也不是某个产品的功能,而是一套“先查资料、再让模型开口”的工程范式。它的核心动作只有三步——把知识切块存起来、根据问题把相关块捞出来、把捞出来的内容塞进大模型的上下文里让它基于这些内容作答。听起来简单到有点朴素,但正是这套朴素机制,撑起了现在绝大多数企业级 Agent 的知识底座。

我最早接触 RAG 是在做一个内部文档问答机器人。当时天真地以为把 PDF 丢给模型就行,结果模型张口就来、编得比真话还顺。后来才明白,大模型的参数里存的是“世界的一般印象”,不是“你公司上周刚改的报销制度”。RAG 解决的就是这个错位:让模型在回答前先看一眼你给它的资料,把“凭记忆答”变成“开卷考”。对于 Agent 开发来说,这一点尤其致命——Agent 要调用工具、要做多步决策,如果第一步的知识就是错的,后面整条链路全崩。

所以这篇文章我打算把 RAG 从里到外拆一遍。适合谁看?如果你正在做 Agent 项目、准备面试被问到 RAG、或者单纯想给自己的知识库接个大模型,这篇都能用。我会讲清楚每个环节为什么这么设计、参数怎么算、坑在哪里,而不是只丢几个 API 调用示例。全文基于我自己的实操经验和常见工程实践展开,涉及具体数值的地方我会说明推导过程,方便你按自己的场景调整。

1.1 一个生活化类比:RAG 就是给模型配了个图书管理员

你可以把大模型想象成一个博学但记性有点飘的教授。他读过很多书,但你问他“我们实验室上周那台仪器的校准参数是多少”,他只能瞎猜。RAG 做的事情,就是给这位教授配一个图书管理员:你提问,管理员先去书架上找到最相关的几页,递给教授,教授照着这几页回答。管理员找得准不准,直接决定教授答得对不对。

这个类比里藏着 RAG 的三个关键角色:知识库(书架)、检索器(管理员)、生成器(教授)。很多人做 RAG 失败,不是教授不行,而是管理员找错了书,或者书架本身就没整理好。后面我会反复回到这个类比,因为大部分优化点都能对应到“书架怎么摆”“管理员怎么找”上。

1.2 RAG 和微调、长上下文到底怎么选

经常有人问:既然现在模型上下文能塞几十万 token,我直接把所有文档塞进去不就行了,还要 RAG 干嘛?这个问题问得好,我实测过。假设你有 500 份文档、每份 2 万字,总共 1000 万字,就算上下文够大,每次提问都塞进去,成本和延迟会让你怀疑人生。而且模型在超长上下文里会“注意力涣散”,中间部分的内容经常被忽略,这就是所谓的“lost in the middle”现象。

微调是另一条路:把知识直接训进模型参数。但微调有个硬伤——知识更新要重新训练,而且模型容易“记住”却不会“引用”,你没法追溯它到底从哪句话得出的结论。RAG 的优势恰恰在于知识可热更新、答案可溯源、成本可控。我的经验是:事实性、频繁变动的知识用 RAG;风格、格式、语气这类“行为模式”用微调;两者不冲突,可以叠加。

方案知识更新可溯源成本适合场景
RAG实时,改库即可强,能给出出处中,主要是检索和推理企业知识库、客服、Agent 工具知识
微调需重训弱高,训练+部署固定风格、特定任务格式
长上下文直塞实时中极高,token 爆炸少量文档、一次性分析

2. RAG 的核心链路拆解:从文档到答案的每一步

一条完整的 RAG 链路,粗略分是“索引”和“查询”两大阶段。索引阶段离线跑,把原始文档变成可检索的向量;查询阶段在线跑,把用户问题变成向量、检索、重排、拼上下文、生成。每个环节都有讲究,我逐个拆。

2.1 文档加载与清洗:垃圾进,垃圾出

这一步最容易被忽视,但它是 RAG 质量的地基。我见过太多项目,检索效果差,最后发现是 PDF 解析出来一堆乱码和页眉页脚。文档加载的核心任务是把各种格式(PDF、Word、HTML、Markdown、数据库记录)统一转成纯文本,同时保留结构信息。

PDF 解析是重灾区。扫描版 PDF 需要 OCR,文字版 PDF 要注意分栏、表格、公式。我常用的策略是:优先用能保留布局的解析器,表格单独抽出来转成 Markdown 或结构化文本,页眉页脚用规则或重复检测去掉。清洗阶段要处理的问题包括:多余空白、乱码字符、重复段落、超长无意义内容(比如版权声明)。

注意:不要在这一步做过度清洗。有些项目为了“干净”把标点、换行全删了,结果句子边界丢失,后面切块时把一句话切成两半,检索出来语义残缺。清洗的目标是去噪,不是重写。

2.2 文本切块:切得好,检索就成功了一半

切块(Chunking)是 RAG 里最考验经验的一环。为什么不能整篇文档当一个块?因为向量模型对长文本的表示会“平均化”,一篇讲十个主题的长文,它的向量和任何一个具体主题都不太像。为什么不能切太碎?因为一句话的块缺乏上下文,检索出来模型看不懂。

常见的切块策略有这么几种:

  • 固定长度切块:按 token 数或字符数切,简单粗暴,但容易切断句子。适合结构松散的文本。
  • 递归字符切块:按段落、句子、词的优先级递归切,尽量在自然边界断开。这是最常用的默认策略。
  • 语义切块:用 embedding 计算相邻句子的相似度,在语义转折处切。效果好但慢。
  • 结构化切块:按 Markdown 标题、HTML 标签、代码函数切。对有结构的文档最友好。

块大小怎么定?我的经验值是256 到 512 个 token,配合10% 到 20% 的重叠(overlap)。重叠是为了防止边界信息丢失——一个概念刚好跨在两个块之间,没有重叠就会两边都检索不到。这个数值不是拍脑袋:太小(比如 128)会导致上下文不足,模型答不完整;太大(比如 1024)会引入噪声,检索精度下降。你可以把它理解成切西瓜,块太大一口咬不下还沾一脸,块太小全是皮没肉。

2.3 Embedding 模型选型:向量质量的决定因素

Embedding 模型负责把文本变成向量,它的好坏直接决定检索准不准。选型时我看三个维度:语言支持、维度、检索性能。中文场景一定要选对中文优化过的模型,很多英文模型在中文上表现断崖式下跌。

维度不是越高越好。高维度理论上能表达更多信息,但存储和计算成本上升,而且边际收益递减。常见的有 384、768、1024、1536 维。我的建议是:先用主流的中等维度模型跑通,效果不够再换大的。

还有一个关键点:查询和文档必须用同一个 embedding 模型。我踩过这个坑——索引时用 A 模型,查询时手滑用了 B 模型,结果检索出来的东西驴唇不对马嘴,排查了半天才发现是模型不一致。这个错误很隐蔽,因为代码不会报错,只是效果差。

2.4 向量数据库:存哪里、怎么查

向量数据库负责存储向量并做相似度检索。选型时考虑:数据量、是否需要持久化、是否要混合检索、部署复杂度。小项目用内存向量库就够了,数据量上来了再换专业的。

向量库特点适合场景
内存型(如 FAISS)轻量、快、无需服务原型验证、小数据量
Chroma易用、支持持久化、API 友好中小项目、快速开发
专业向量库高并发、分布式、混合检索生产环境、大数据量

检索方式上,最基础的是余弦相似度或内积的近似最近邻搜索(ANN)。但纯向量检索有个问题:它对关键词不敏感。比如你搜“错误码 E1024”,向量检索可能给你返回一堆讲“错误处理”的文档,就是找不到那个具体编码。这时候就需要混合检索——向量检索 + 关键词检索(如 BM25),两路结果融合。这是提升 RAG 命中率最有效的手段之一。

2.5 重排:把最相关的顶到最前面

检索出来 Top-K 个块后,直接塞给模型往往不够好,因为向量相似度高不等于真的相关。重排(Rerank)用一个更精细的模型(通常是交叉编码器)对“问题-文档”对逐一打分,重新排序。它的计算比向量检索慢,但精度高,所以只对检索出来的少量候选做。

我的标准流程是:向量检索召回 Top 20 到 50,重排后取 Top 3 到 5 塞进上下文。为什么是 3 到 5?因为上下文窗口有限,塞太多反而稀释重点,还可能引入矛盾信息。重排模型的选择上,中文场景同样要选中文优化的,否则效果打折。

2.6 上下文组装与生成:最后一步别翻车

把检索到的块拼成 prompt 时,有几个细节:给每个块标注来源(方便溯源和引用)、控制总长度(别超模型上下文)、明确指令(告诉模型“只根据以下资料回答,资料没有就说不知道”)。最后这条特别重要,不加的话模型又会开始自由发挥。

生成阶段还有个技巧:让模型引用来源编号。比如资料标了 [1][2],要求模型回答时带上引用。这样用户能验证,你也能快速定位是检索错了还是生成错了。

3. 动手搭一个最小可用的 RAG:完整实操流程

光讲原理不够,我带你走一遍完整流程。这里用 Python 生态里最常见的组合,代码可以直接抄。环境准备、依赖安装、索引构建、查询生成,一步步来。

3.1 环境准备与依赖安装

先建虚拟环境,装核心依赖。我习惯用 pip,你也可以用 conda。

python -m venv rag_env source rag_env/bin/activate # Windows 用 rag_env\Scripts\activate pip install langchain langchain-community chromadb sentence-transformers pypdf

这里解释下每个包的作用:langchain提供链路编排,chromadb是向量库,sentence-transformers提供 embedding 模型,pypdf负责解析 PDF。如果你要用在线 embedding 服务,把sentence-transformers换成对应的 SDK 即可。

3.2 文档加载与切块代码

假设你有一份 PDF,先加载再切块。

from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 加载 loader = PyPDFLoader("knowledge.pdf") docs = loader.load() # 切块:块大小 500 字符,重叠 100 splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=100, separators=["\n\n", "\n", "。", "!", "?", " ", ""] ) chunks = splitter.split_documents(docs) print(f"切出 {len(chunks)} 个块")

注意separators里我加了中文标点。默认的分隔符是英文的,中文文档如果不加,切块会在奇怪的地方断开。这个细节很多人不知道,导致中文 RAG 效果莫名差一截。

3.3 构建向量索引并持久化

from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma # 选一个中文友好的 embedding 模型 embedding = HuggingFaceEmbeddings( model_name="BAAI/bge-small-zh-v1.5", model_kwargs={"device": "cpu"} ) # 建库并持久化 vectordb = Chroma.from_documents( documents=chunks, embedding=embedding, persist_directory="./chroma_db" ) vectordb.persist()

bge-small-zh-v1.5是个中文效果不错、体积又小的模型,适合本地跑。如果你追求更好效果,可以换bge-large-zh,代价是慢一些、占内存多一些。持久化目录建好后,下次直接加载,不用重新索引。

3.4 检索与生成:把链路串起来

from langchain_community.llms import Ollama # 加载已有索引 vectordb = Chroma( persist_directory="./chroma_db", embedding_function=embedding ) # 检索 query = "报销流程是什么?" retrieved = vectordb.similarity_search(query, k=4) # 组装上下文 context = "\n\n".join([f"[{i+1}] {d.page_content}" for i, d in enumerate(retrieved)]) # 生成 llm = Ollama(model="qwen2.5") prompt = f"""只根据以下资料回答问题,资料没有的内容就说不知道,并标注引用编号。 资料: {context} 问题:{query} """ answer = llm.invoke(prompt) print(answer)

这段代码就是一个最小可用的 RAG。检索 Top 4,拼上下文,让本地模型基于资料回答。跑通之后,你会发现它已经能处理不少文档问答场景了。

3.5 参数计算:Top-K 和块大小怎么定

很多人问 Top-K 到底取多少。我的推导逻辑是这样的:假设模型上下文能放 8000 token,每个块 500 token,那么理论上最多能放 16 个块。但实际不能塞满,因为要给问题和回答留空间,还要考虑噪声。所以取 3 到 5 个块比较稳妥,对应 Top-K 设 4 到 6,再配合重排。

块大小同理:太小检索不准,太大噪声多。500 字符(约 300 到 400 中文 token)是个平衡点。如果你的文档句子特别长,可以适当放大到 800;如果是 FAQ 这种短问答,可以缩到 200。

4. 常见问题与排查技巧实录

RAG 跑起来容易,跑好难。下面这些坑我都踩过,整理成速查表,你遇到问题时可以对照排查。

4.1 检索不准:问题出在哪一环

检索不准是最常见的问题,表现是“答非所问”或“找不到相关内容”。排查顺序应该是:先看切块,再看 embedding,最后看检索策略。

现象可能原因排查方法解决
检索结果完全不相关embedding 模型不匹配语言手动测几条 query 的相似度换中文优化模型
检索结果沾边但不精准块太大,主题混杂打印检索到的块内容减小块大小,加重叠
关键词搜不到纯向量检索对关键词不敏感用具体术语测试加 BM25 混合检索
明明有答案却检索不到切块切断了关键句检查原文和块的对应调整分隔符,用语义切块

我印象最深的一次排查:用户问“如何重置密码”,检索出来的全是“密码安全规范”。后来发现是切块时把“重置密码”的操作步骤和“密码规范”切到了同一个块里,向量被平均了。把块改小、按标题切之后,问题解决。

4.2 生成胡编:模型不听话怎么办

检索对了,模型还是编,通常是 prompt 没约束好。我的做法是:明确指令 + 引用要求 + 兜底话术。指令里写死“只根据资料回答”,要求标注引用编号,并给出“资料未提及”的标准回复。另外,把 temperature 调低(0 到 0.3),减少随机性。

还有一种情况是检索到的资料本身互相矛盾。这时候模型会“和稀泥”。解决办法是在重排阶段做去重和冲突检测,或者让模型明确指出矛盾点,而不是强行给一个答案。

4.3 性能瓶颈:慢在哪里

RAG 的延迟主要来自三块:embedding 计算、向量检索、大模型生成。embedding 和检索通常很快(毫秒级),大头在生成。如果整体慢,先看是不是模型太大或上下文太长。优化手段包括:用更小的生成模型、减少 Top-K、开启流式输出让用户先看到部分结果。

向量检索在数据量大时会变慢,这时候要考虑索引优化(如 HNSW 参数调整)或换专业向量库。我实测过,百万级向量用内存库检索会明显卡顿,换专业库后恢复到毫秒级。

4.4 独家避坑清单

  • 别在索引和查询用不同 embedding 模型,这个错误不报错但致命。
  • 中文文档一定要加中文分隔符,否则切块质量差。
  • 保留元数据(来源、页码、标题),排查和溯源时救命。
  • 定期评估检索命中率,建一个测试集,每次改动后跑一遍,别凭感觉。
  • 上下文别塞满,留出空间给模型推理,塞太满反而答不好。
  • 注意 token 计费,在线模型按 token 收费,Top-K 开太大成本飙升。

5. 从基础 RAG 到 Agentic RAG:进阶方向

基础 RAG 是“一问一查一答”,但 Agent 场景下,检索本身可能是个需要决策的动作。这就是 Agentic RAG 的思路:让 Agent 自己决定要不要检索、检索什么、检索几次、结果够不够。比如用户问一个多跳问题,Agent 可能先检索 A,根据 A 的结果再检索 B,最后综合回答。

实现上,这通常借助 Agent 框架,把检索封装成一个工具(tool),让模型通过 function calling 自主调用。好处是灵活,能处理复杂查询;代价是链路变长、延迟增加、调试变难。我的建议是:简单问答用基础 RAG,复杂多跳、需要推理的用 Agentic RAG,别为了炫技把简单问题复杂化。

另一个进阶方向是 GraphRAG,把知识建成图结构,检索时沿图遍历。它适合实体关系密集的场景,比如人物关系、组织架构。但构建和维护成本高,不是所有场景都值得。

5.1 Agentic RAG 的检索决策逻辑

Agentic RAG 的核心是让模型判断“我现在的信息够不够回答”。实现时通常给 Agent 一个检索工具和一个“回答”工具,模型自己选。如果检索结果不相关,它可以改写查询再检一次。这个循环要有次数上限,否则模型可能陷入无限检索。我一般设 3 次上限,超过就强制回答或承认不知道。

5.2 评估:怎么知道你的 RAG 好不好

没有评估的 RAG 就是盲人摸象。我常用的指标有两个:检索命中率(正确答案是否在检索结果里)和答案正确率(最终回答对不对)。建一个几十条的测试集,覆盖常见问题和边界情况,每次改动后跑一遍。别小看这个习惯,它能帮你避免“改了一个参数,修好一个 case,弄坏十个 case”的悲剧。

评估工具上,可以用现成的 RAG 评估框架,也可以自己写脚本对比。关键是要有 ground truth,也就是每个问题对应的标准答案和应检索到的文档。这个测试集前期投入大,但长期回报极高。

5.3 知识库维护:RAG 不是一劳永逸

很多人以为建好索引就完事了,其实知识库需要持续维护。文档更新了要重新索引,过期内容要清理,新增内容要补充。我建议做一个增量索引流程:监听文档变化,只对变化的文档重新切块和 embedding,而不是全量重建。全量重建在数据量大时非常耗时。

另外,定期 review 检索日志,看看用户都在问什么、哪些问题答不好。这些真实数据是优化 RAG 最宝贵的输入,比拍脑袋调参有效得多。

最后分享一个我自己的体会:RAG 的效果,七分靠数据整理,两分靠检索策略,一分靠模型。很多人把精力全花在换模型、调参数上,却忽略了最基础的文档清洗和切块。把地基打牢,用中等模型也能跑出好效果;地基不牢,用再强的模型也是白搭。这个道理,我在好几个项目里反复验证过。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询