☰
RAG管道全解析:从文档切分到Agent知识获取的实践指南
2026/9/29 18:51:01 网站建设 项目流程

1. 为什么说RAG是Agent的知识获取管道

如果只看模型本身,你会发现一个挺拧巴的现象:大模型肚子里装了海量的常识,但你一聊到具体业务它就露馅。比如模型能给你背出《红楼梦》的判词,你问它"我们公司售后政策里写着超过十五天能不能退"它就哑了——不是它偷懒,是这类私有知识它压根没见过。

我在做Agent项目时有句话常挂嘴边:模型负责"聪明",知识库负责"知道"。一个Agent没有外部知识获取机制,就像高材生被关在没有资料室的房间里考试,脑力再强也只能瞎猜。这也是第四篇我想把RAG单独拎出来讲的直接原因——它是Agent"考试"时补充资料的那个通道,也就是知识获取管道。

需要先说明一点,这套内容适合有基本Python经验,想从零理解RAG原理并在自己Agent里落地知识查询能力的开发者。如果你已经用过LangChain但始终说不清每个环节在干什么,这篇文章也能帮你把概念和实操之间的裂缝填上。

1.1 Agent的知识饥饿:模型自带的只是"常识"

聊训练数据这件事,得先放下一个错觉:模型不是数据库,它是"学会如何预测下一个词"的统计机器。它的记忆是某种压缩过的、模式化的东西,不是逐字记下原文等你查询。这带来两个致命限制:一是训练语料有截止时间,之后的新消息它不知道;二是任何私有数据只要没有公开到训练语料里,对它来说就等于不存在。

Agent想在真实业务里跑起来,面对的恰恰是这两个边界。拿客服场景举例:你给Agent的工单系统、产品手册、退货政策都是私有文档,模型连看都没看过;你让它自动处理一条昨天用户提交的工单,这些内容比训练数据还新。靠推理硬编是不可能的,必须先有一个"喂知识"的通道。

这里要区分一个概念,知识获取和上下文不一样。往上下文窗口里塞几段检索出来的相关资料,是一种"临时借用知识"的方式;而RAG做的是"为每次提问现找现用"——它不试图让模型记住知识,而是让模型在回答问题的那一刻手里恰好有正确的资料。这个区别看着小,实际决定了RAG的系统设计方向:存储、索引和检索才是主角,模型只是最后一步的阅读者。

1.2 三种知识注入路线对比:为什么RAG是主流

想让模型"知道"某个新领域的知识,市面上就三条路线:微调、长上下文、RAG。我见过很多团队上来就想微调,结果折腾一个月效果还不如直接prompt示例给得好。

微调的本质是改变模型的权重,让它把某些知识"内化"。它适合风格迁移、输出格式固定、特定领域术语习惯等场景,但它有三个硬伤:训练成本高一截、每次知识更新都要重训、以及改完权重你很难追溯模型到底学没学到、学到哪一步了。如果你只是想让模型知道一份动态变化的政策文档,微调是最不划算的方案。

长上下文则是把希望寄托在更大的窗口上。这两年窗口确实越做越大,但"能装下"和"用得好"是两回事。窗口变大后,模型在超长上下文里的注意力会出现稀释,位于中部的信息更容易被忽略,业内管这个叫"lost in the middle"。而且每轮都塞全量文档,成本和延迟直线上升,这跟Agent多轮交互的场景基本是冲突的——你不会想让Agent每次回答前都读一遍整个产品目录。

RAG站在中间的位置:它把知识从模型内部挪到了模型外部。知识存在知识库里,每次有提问,检索出最相关的几个片段,拼进Prompt。好处立刻就能看见:知识可以随时换、随时更新,成本可控,而且回答可以带来源链接,用户能验证,模型的幻觉空间也被压缩了。这也是现在几乎所有生产级AI应用默认使用它的原因。

1.3 "管道"到底管什么:四个环节的职责切分

我这些年带项目,觉得用一个比喻理解RAG最好使:它是一条流水线,原料是你的原始文档,产出是模型的回答,中间四个环节各有分工。

第一个环节是解析与清洗。PDF、Word、Markdown、HTML各有各的结构,表格、代码块、扫描件各有各的坑。这一步的目标只有一个:把一份文档变成机器能读、且保留了足够语义信息的纯文本。

第二个环节是分块与向量化。把长文档拆成合适大小的块,然后交给嵌入模型,把每个块变成一个高维向量。这一步最关键,因为后面检索什么,完全取决于这里块切得对不对、向量算得准不准。

第三个环节是检索。用户提问时,把问题也向量化,然后在向量空间里找"距离最近"的那几个知识块。这里有个容易忽略的事:检索到的内容质量,决定了下游生成的上限。分类模型做得再烂,只要检索没检索对,回答就不可能对。

第四个环节是生成。把用户问题加检索到的文档片段按一定模板拼进Prompt,交给大模型让它基于这些材料回答。生成环节听起来最简单,实际讲究更多:怎么排布、怎么避免模型忽略中间块、要不要带引用、指令该怎么写,都有经验在里面。

这四个环节环环相扣,任何一个瘸腿都会拖垮整条管道。下面我按管道顺序,从数据预处理一路写到生成环节,把每一段的原理和实操都拆开来讲。

2. 管道第一站:知识从文档到索引

这一站经常被低估。很多教程demo里三步就完成了加载,让人觉得文档处理没什么可讲的。但真正在生产里跑过的人都有同感:RAG系统的最终效果,有相当一部分在源头就注定了——垃圾进,垃圾出。

2.1 文档解析:别小看PDF和网页的处理差异

先说最常见的坑。把一份PDF直接丢给解析工具,你会得到各种残次品:扫描件会变成一张张图片,文字根本抽不出来;文字版PDF里的表格会被横七竖八地切成碎片;多栏排版的技术文档,解析后逻辑顺序是乱的,本属于同一段的内容可能被拦腰断开。

处理PDF,我通常先判断它是文字型还是扫描型。文字型用常规解析器能拿到可编辑文本,但表格和排版还是要额外处理——比如某些工具可以按行或按块提取,你能保留下标题的层级关系,这对后面分块大有帮助。扫描型必须先做OCR,这一步会有识别错误,必须配合后续清洗。如果你想偷懒,现在很多文档解析服务号称"PDF转Markdown一步到位",实测下来对简单文档还行,遇到复杂排版仍然会出错,别把宝全押在它身上。

网页抓取是另一个常见来源。HTML里到处都是导航栏、广告位、版权通告,直接拿正文会惨不忍睹。我在做数据抓取时会先做两步:用选择器定位正文容器,把整个页面裁出来;再把多余DIV剥掉,只留标题、段落、列表、表格这类语义元素。处理完的数据干净了,嵌入模型算出来的向量才不会跑偏。

还有一类容易被忽略的是多页文档的连续性。一本操作手册如果按页码被硬切成单页,上下文就碎了:第3页说"按上一步操作…",第2页的内容在另一个块里,检索的时候就对不上。所以解析完还要做"拼页"处理,把属于同一章节的内容重新粘起来。这个细节看着小,实际决定了多轮检索的稳定性。

2.2 切分策略:chunk size为什么是玄学

切分是整个RAG里最没有完美答案的环节。块太大,嵌入时信息被稀释,检索回来的块里可能只有一小段是用户关心的;块太小,单个块缺乏上下文,检索结果是零碎句子,没法直接用来生成答案。这事没有银弹,但有几个方向可以把握。

固定长度切分是最朴素的做法,按字符数或token数硬切,常见配一个overlap来保证相邻块之间不丢上下文。我自己的起步配置一般是512个token左右的窗口配80个token的重叠,然后根据实测效果慢慢调。纯固定切分的毛病是容易打断句子甚至打断句号,内容语义完整性没保障。

进阶一点的做法是按文档结构切分。既然Markdown有标题层级、PDF有章节标记,切分器可以先识别结构,以标题为边界做递归切分:遇到大标题开新块,子标题下内容足够长再继续切。这样切出来的块,几乎不会出现语义断裂,检索命中率会明显提高。我强烈建议文档从源头就保留好结构信息,这对后面所有环节都是福报。

语义切分是更激进的路线:先切一小段送进模型,让它判断和下一段是不是同一主题,靠语义连续性来决定边界。效果最好,但成本高、速度慢,适合文档总量不大但对效果有极致要求的场景。多数业务场景,按结构切分已经是性价比很高的选择。

切分完之后还有一步容易漏掉的——清洗。空行、重复的页眉页脚、乱码字符要在向量化之前清理掉。我见过有团队把每一页的"产品操作手册"页眉一并嵌了进去,结果检索时用户问任何问题,都能匹配到一堆这个页眉,一次检索8个结果有5个是垃圾。这种问题查起来很隐蔽,但源头其实只需要过滤一下行内容就能避免。

2.3 嵌入模型选型与向量库选择

分好块之后,要做的就是把每个块变成高维向量。这里涉及嵌入模型的选型。中文场景下,我常用的思路是:优先考虑在中文语料上表现好的模型,比如现成的bge系列或同类开源模型。嵌入模型决定了"语义距离"的质量,选得好,检索才有基础。

嵌入模型有几个参数要心里有数:向量维度决定了存储和检索的规模,维度越高越占资源但表达力不一定线性提升;最大输入长度限制决定了你喂进去的文本不能太长,超出就要截断或调整。选模型时可以做一个小样本测试:准备一批问题,让系统和答案片段计算相似度,看看相关结果的得分和非相关结果的得分分得开不开了。分不开,说明嵌入模型选得有问题。

向量库的选择,要看你的数据规模和使用场景。几百条文档做成demo,用轻量级库或嵌入式向量库就够了,Redis、Chroma这类都能跑,部署省事。数据量到了百万级,生产服务化部署,就需要Milvus或Elasticsearch这类专门的向量搜索引擎了。不必一开始就上重型武器,等量来了再迁移,迁移成本没有想象中那么大——前提是你从第一天就把"文档ID、切块内容、向量、元数据"这套schema设计好。

这里还要多说一句:向量库本质是个数据库,除了存向量,还要存原始文本和元数据。因为检索出来后,最后给模型看的是原文,不是你算出来的那个向量。如果你只存向量不存文本,检索再多结果都白搭。

3. 管道第二站:检索召回,质量的分水岭

检索是RAG里最能体现工程师水平的地方。原因也简单:生成环节有太多现成的模型可以兜底,但检索错了,模型再聪明也只能在错误材料上编答案。这一站的成色,直接决定系统可用性。

3.1 从"关键词匹配"到"语义匹配"

早期的信息检索靠词面匹配:用户搜"退货",文档里没有"退货"这个词但有"退款",那就算没匹配上。关键词匹配的问题就在这——同义词、近义词、换种说法就查不到了。

向量检索的思路完全不同。嵌入模型把文本和问题都映射进一个高维语义空间,语义相近的文本在空间里天然距离就近。你问"退货流程",块里写"申请退款的操作步骤",虽然词面不重叠,语义上也该被搜出来——向量检索能解决这种场景。

但这不意味着向量万无一失。在实际测试里,向量检索对专有名词、缩写、型号这类精确信息经常翻车:"PLC-3000"这种序列号,语义匹配很难比得上"正则匹配"和"关键词语义一致"。"整件包含所有现象"更好更通用的做法是混合检索:用BM25做关键词召回,同时做向量语义召回,然后把两路结果合并去重,再统一排序。这样既保住语义泛化能力,也保住精确匹配能力,是我在所有生产项目里的默认配置。

3.2 召回质量的三把尺:recall、precision、hit rate

聊检索就离不开评估指标。我见过太多人调了半天向量阈值,但说不清楚目标是什么。RAG里的检索评估,至少要看这三把尺子。

第一把是recall(召回率):针对一个测试问题,检索出的结果里,真正相关的有多少。在RAG场景里召回率的意义是"有没有把该找的找回来"。第二把是precision(精确率):检索出的结果里,有多少是真正相关的。它衡量的是"有没有把不该找的也召回来了"。第三把是hit rate,用我自己的话说就是"答案材料是否在前K个结果里"——给一个测试题,相关文档片段是否出现在检索结果Top-N中,命中率越高说明检索链路越可靠。

实际做法上,我会准备一个50条左右的人工标注集:问题、相关文档片段、是否命中。拿它跑一轮,看看hit rate是多少,再逐条看没命中的问题为什么没检索到。这一步对调优的帮助远超玄学式加维度。

3.3 检索白合与重排序:把命中率再往上顶

即使混合检索已经做了,Top-K结果里也常有"相关但不对位"的情况:系统检回了正确文档,但正确的那一段在不该出现的位置。这时候**重排序(Re-ranking)**就派上用场了。

重排序的原理很好理解:第一轮用轻量向量检索快速找100个候选块,然后交给一个精度更高的排序模型,对候选块按"与用户问题的相关性"重新打分,取前3~5个作为最终结果。重排序模型往往本身就是一个精排模型,它比向量距离更能捕捉细粒度相关性,代价是速度慢,所以只能用在第一轮的少量候选项上,不能全库跑。这一招通常能让命中率涨十来个点,是我项目里的常备组件。

还有一个细节是关于Top-K和阈值的配合。初学者常犯的错是到处调相似度阈值,想把低相关度结果全过滤掉。但阈值设得越高,漏召回的风险越大,而重排序已经能处理前面的一批低质量候选。我的习惯是:第一轮宽松一点,Top-K开大(比如50~100),阈值基本不设;重排序后只保留得分靠谱的前3~5个。这样召回率不掉,精度又不差。

4. 管道第三站:生成,让模型把资料"用起来"

检索做得再漂亮,最后一步生成没接住,用户感受到的还是"智障回答"。生成环节的任务不是"生成",而是在正确材料上生成,并且要看起来有理有据。

4.1 检索结果如何塞进Prompt

把检索到的文档块直接糊进Prompt,是最粗糙的用法。模型看一堆没有结构的文本,很容易找不到重点,或者开始在无关信息上自由发挥。我在实践中会把检索结果做两件事。

第一是排版。给每个文档块编号,用分隔线和说明文字隔开,告诉模型:"以下是参考资料,回答时优先参考它们的内容。"模型对清晰结构的信息利用效率远远高于乱糟糟的一段文字,这个观察在多轮长文本里尤其明显。

第二是控制数量和信息量。通常我给最终生成阶段3到5个块,每个块在200到500 token之间,加在一起控制在模型能一口气读完的范围。塞得太多,模型注意力分散,哪个都读不仔细,最后生成的答案反而更空。

Prompt模板上也有一点小讲究。指令部分和材料部分要分开:开头说清楚角色和任务,中间给资料,结尾再重复一遍"请只基于上述资料回答,并标注引用来源"。这样三层结构,模型更不容易跑偏。>

有一个坑我踩过:检索回来的块未必都是相关的,偶尔会有错配的噪声块。如果你不告诉模型"资料可能包含无关内容,别瞎用",它会把噪声块也当依据编进去。正确的写法是加一句"如果资料中没有答案,直接说明不知道",能显著降低幻觉。

4.2 Agent场景的检索:多轮交互下的动态需求

RAG在单独问答里是"一问问一答",但在Agent场景里就不是这么简单了,因为它要服务于多轮对话和任务分解。

多轮对话里的第一个问题是query改写。用户说"它怎么退?",这个"它"如果不结合上文,检索系统根本不知道搜什么。解决方法是把历史对话和当前问题一起交给模型,让模型把当前问题改写成一个能独立检索的完整查询语句,再去检索。这一步看着多花钱和时间,但对多轮命中率帮助巨大。

第二个问题是意图与实体信息的使用。用户问"上次那个订单怎么操作?",如果只是改写成"那个订单怎么操作",检索还是抓瞎。要让Agent在改写时把对话里提到的具体实体(订单号、产品名、日期)提取出来,拼进查询语句里,检索才有意义。这本质上已经很接近Agentic RAG的思路了——检索不再是被动执行一次,而是Agent主动决策,可能检索多轮、多来源,再动态决定下一步。

4.3 引用溯源与幻觉控制

RAG一个很大的优势就是可溯源:检索到的知识块自带来源,模型回答时如果能带上引用,用户就能自己核实,错误回答也能被快速抓住。我在系统设计里强制要求流式输出时附带上引用的块ID,然后在前端展示成链接。这看起来是个体验细节,实际上是一个质量校验机制——一个回答如果引用的内容和它说的话对不上,问题当场暴露,比用户事后吐槽强得多。

幻觉是RAG避不开的话题。就算检索对了,模型也可能在生成时自由发挥几句,怎么管?我的经验是三层防护:第一层在指令层面就跟它说清"只基于资料回答";第二层在检索结果结构上做干净,去掉无用字段,只留"可能有用"的信息;第三层在最终生成后加一个简单的验证环节——让模型自己评估一下:"你刚才的回答里,哪句话在资料里找不到依据?"这招叫自洽性校验,不用额外模型,实测能拦住不少幻觉。

5. 实操:从本地文件到RAG管道的搭建记录

说了这么多原理,不落地等于白说。下面我按一套最小可用的方案,大概写下从本地文件到能问出答案的完整搭建过程。这里我会以一个技术选型示例为主,重点讲解每一步在做的事,而不是追求某个框架的API熟练度。

5.1 环境与数据准备

我一贯的路线是:Python + LangChain作为编排层,嵌入模型用开源的BGE系列,向量库用轻量的Chroma起步,生成模型用OpenAI兼容接口的任意大模型。这套组合的好处是全开源可替换,重点是让你理解管道逻辑,而不是被某个商用工具绑架。

准备数据时,我建议先找你最熟悉的业务文档,别一上来拿几百份PDF练手。拿一份操作手册或者政策文档,转成Markdown,人工确认内容没乱、结构完整——这保证了后续问题都出在管道本身而不全在数据质量上。做第一轮调试,最怕变量太多。

5.2 端到端跑通的最小代码示例

起步代码大概长这样,我用伪代码加注释的方式写,方便你看逻辑,不纠结具体API:

# 1. 加载文档 document = load_markdown_file("handbook.md") # 解析后得到纯文本块列表,保留章节元数据 # 2. 切分:按标题结构递归切分 chunks = recursive_splitter.split(document) # 每块约512 token,块与块之间重叠80 token # 3. 向量化 embeddings = BGEEmbedding(model_name="bge-base-zh-v1.5") vectors = embeddings.encode(chunks) # 4. 存进向量库 vector_store = Chroma(collection_name="handbook") for chunk, vector in zip(chunks, vectors): vector_store.add(vector, metadata={"source": chunk.page_id}) # 5. 检索 query = "退货需要哪些手续" q_vector = embeddings.encode(query) candidates = vector_store.search(q_vector, top_k=50) # 6. 重排序 reranked = re_rank(query, candidates) final_blocks = reranked[:4] # 7. 组装 Prompt 并调用 LLM prompt = assemble_prompt(query, final_blocks) answer = llm.chat(prompt)

这套流程跑通以后,你就有一个可以问问题的RAG雏形了。但我要泼一盆冷水:demo跑通只是万里长征第一步,接下来才是考验。别急着加复杂功能,先做一件事——准备20个你真实业务里会遇到的问题,挨个问一遍,看答案错在哪。

5.3 实测效果与调参记录

我自己测试时遇到过一个很典型的案例。第一版系统把政策文件按固定长度500字符切块,问"十五天内退货怎么操作",系统的前三个检索结果里有两个来自产品介绍页,答案自然一派胡言。当时怀疑嵌入模型选得不对,换了好几个模型还是老样子。

后来逐条查,才明白问题出在源头:政策原文里有很长一段总则内容,跟"退货操作"相关的句子夹在总则和细则中间,被切碎了。改成按标题结构切分后,同一问题一下子就能命中细则那一整段,答案瞬间就正常了。这个故事我想强调的只有一点:很多检索问题,根源在切分,而不在模型。

调参过程我也记录了一组数据供你参考:切分粒度从500字符调到800字符后,hit rate反而掉了五个点——因为窗口太大,针对性信息被稀释了。反过来,当重叠从0调到80,整体命中率又回升了一些。这说明每个参数都要用你的真实数据测,别照搬任何人的配置。

6. 从RAG到Agentic RAG:管道会往哪里走

把基础RAG跑通之后,你大概率会开始琢磨一个事:这个管道现在只会"查一次答一次",能不能让Agent自己去决定怎么查、查几轮、要不要结合多个知识库?这条路就是现在热门的Agentic RAG。

6.1 静态管道与动态编排的差异

基础RAG的流程是固定死的:检索、生成,结束。Agent化之后,模型开始有主导权:它可以把检索当成一个工具来调用,甚至可以决定"这个问题先查政策,再根据政策内容去查对应产品的库存",一次任务里调两次检索,检索之间还有依赖关系。

编排能力来自哪里?来自我们把检索封装成"工具",并且给大模型一个清晰的工具使用协议。模型收到用户问题后,不是直接去命中某个固定流程,而是自己规划:需要什么知识,就调什么工具,拿回结果再做下一轮推理。这就是从"管道"到"Agent"的关键转变:知识获取从预定的流程,变成了模型主动决策的行动。

这种转变的价值在于,复杂问题能拆解着查了。比如"我们仓库还有多少能退货的库存",单次检索抓不到完整答案,但Agent可以先查退货政策,再查库存记录,再把两轮结果合并起来回答。这已经不是传统RAG能做好的事。

6.2 Agent如何"主动"使用知识管道

把RAG升级成Agentic RAG,有几件具体的事可以做。第一个是让Agent自己生成检索计划。第二个是给Agent配上多路知识工具——比如一个工具查内部政策,一个工具查FAQ,一个工具查产品参数,Agent根据问题选择调用哪个。第三个是让Agent判断检索结果够不够,不够就继续查,够了才给出最终回答。

这个方向我也还在持续摸索中,目前比较实用的经验是:别一上来就把全部流程交给Agent自由发挥。可以先显式定义两三种检索模式,让Agent在这几套模式下做选择,稳定后再逐步放权。完全自由的编排,在真实业务里经常因为一次错误决策导致整个任务失控。

关于技能编排、系统提示词和自定义工具的细节,我打算放到下一篇文章展开。这一篇先把知识获取管道的地基打好——毕竟,无论Agent规划得多聪明,它最终要做出高质量回答,看的还是知识管道能不能把对的资料送到它手上。就我个人经验而言,这恰恰是决定AI应用成败的基石。

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

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

立即咨询