☰
RAG基础:Agent知识获取管道全解析与避坑指南
2026/11/4 4:42:40 网站建设 项目流程

前阵子做一个企业内部文档问答Agent,模型一本正经地告诉我某款产品的保修期是三年。我翻了一下原始合同,里面写得明明白白:整机一年、主要部件两年、特定耗材不保。问题在于,模型根本没有检索到那份合同——它只是在凭自己训练时的记忆在编答案。

这就是典型的Agent“知识获取管道”缺失。你可以把推理规划做得再漂亮,工具调用设计得再精巧,只要模型没有可靠的途径获取外部知识,它就只能在参数记忆的池子里瞎猜。这篇是这个系列里专门讲知识获取管道的一篇,核心内容是RAG(Retrieval-Augmented Generation,检索增强生成)的基础。读完你能搞清楚RAG在Agent里解决什么问题、完整流水线有哪些环节、检索质量受哪些因素控制,以及实际落地时我踩过的那些坑。

1. 为什么Agent必须有一条知识获取管道

1.1 参数化记忆的天花板

大模型的所谓“知识”,本质上是训练时被压缩进权重里的参数化记忆。它有天然的三个天花板:一是时效性,模型的知识截止日期固定在那里,今天新发布的政策、上个月调整的价格体系,它连听都没听过;二是稀缺性,某些长尾领域内容在语料里出现的次数太少,模型根本记不住;三是私有性,企业内部合同、设备检修记录、产品设计文档永远不会进入公开语料,更不可能被模型背下来。

你当然可以靠微调把一部分知识塞进权重,但对于持续变化的私有知识库,微调的成本和维护负担都不现实。

1.2 幻觉的根源与RAG的解法

模型一本正经地编造保修期的根源,就是它在生成时缺少可引用的依据。早期很多人把幻觉归咎于模型本身,后来大家逐步意识到:幻觉在很多时候不是模型的问题,而是你没有提供给它正确的参考材料。

RAG的思路很直接:不逼模型背诵知识,而是在它生成之前,先从外部知识库里检索出相关片段,把片段作为上下文塞进Prompt,让模型基于这些材料作答。这样模型就不用从参数记忆里硬抠答案,而是像开卷考试一样,对着资料答题。有了明确出处,答案的准确性、可解释性和可追溯性都会明显提升。

1.3 RAG与微调的边界

很多人一上来就问:我应该用RAG还是微调?我的判断标准很简单——

  • 知识需要频繁更新、来源是大量私有文档:选RAG
  • 需要改变模型的回答风格、输出格式、特定任务能力:选微调
  • 两者结合的场景其实最常见:RAG负责“喂”最新知识,微调负责“教”输出习惯

RAG和微调不是二选一的关系,只是它们在知识获取这个问题上各自承担的角色完全不同。本篇聚焦RAG这条知识管道本身。

2. RAG流水线拆解:五个环节一个都不能省

RAG不是一个模型,也不只是一个算法,它是一条数据管道。我把这条管道拆成五个环节:加载、切分、向量化、检索、生成。每个环节都有独立的坑,哪个偷懒都会在最终效果上暴露出来。

2.1 加载:格式解析才是第一道暗坑

加载环节的任务是把各种格式的原始文档变成纯文本。PDF、Word、Markdown、HTML、扫描件,每种格式都有自己的脾气。

PDF是最麻烦的。很多PDF看起来是文字,实际导出时没有文本层,或者文本层顺序错乱,直接解析出来是一段乱序字符。这时候需要OCR兜底,而且表格型PDF解析出来经常丢行列关系——两列数据变成一列,检索时关键词倒是能命中,但上下文语义已经不对了。

实操建议:

  • 文本型PDF用pypdf、pdfplumber这类库优先跑一遍
  • 扫描版PDF直接上OCR管线,不要浪费时间去调文本提取
  • 表格密集的文档优先转成Markdown或HTML,保留表格结构,比纯文本更适合后续切分
  • 从Word导出的PDF,如果源文件还在,直接用python-docx读源文件比解析PDF可靠得多

加载完的文本一定要做清理:去页眉页脚、去重复换行、去无关水印。这一步看着不起眼,但对后续切分和Embedding的影响非常大。

2.2 切分:分块策略决定了检索的下限

切分(Chunking)是把长文本切成小块的过程。为什么必须切?因为Embedding模型有最大输入长度限制,而且被检索的单元越小,命中语义的精度越高。但切得太小,单块语义不完整;切得太大,向量被稀释,检索精度反而下降。

我在第3章会专门展开切分的参数取舍,这里先记住一个原则:切分必须以语义完整性为首要目标,而不是以字符数均匀为首要目标。

2.3 向量化:Embedding模型把文本变成坐标

切好的文本块要转成向量,才能被向量检索。Embedding模型做的事,就是把一段文本映射到一个高维向量空间里,语义相近的文本在空间里距离更近。

理想情况里,向量维度在数百到数千不等,常见的是1024或1536维。选Embedding模型时,有三个关键考量:

  • 中英文还是纯中文场景:中文场景优先考虑在中文语料上训练或优化过的模型,效果差距在专业领域会非常明显
  • 领域适配:通用模型处理法律、医疗、代码这些垂直领域文本时,效果普遍弱于领域微调后的模型
  • 向量维度与存储成本:维度越高精度潜力越大,但存储开销和检索延迟都会上升

业界常用的选择包括OpenAI的text-embedding-3系列、BGE系列(如bge-large-zh、bge-m3)、m3e等,具体选型看预算和部署条件。开源的BGE-m3在中文场景尤其是专业文档上的表现很能打,而且支持本地部署,没有数据外泄风险。

2.4 入库与检索:向量数据库不只是存向量

向量数据库负责存储向量和元数据,并提供相似度检索。Chroma适合本地快速验证,Qdrant和Milvus适合生产环境,Weaviate功能全面但部署偏重,PGVector适合想复用已有PostgreSQL的场景,Elasticsearch则适合既有ES基础设施、需要文本检索与向量检索一体化的团队。

选型的核心逻辑不是哪个最新,而是你的团队已经熟悉什么、数据规模有多大、是否需要分布式扩展。小项目用Chroma/PGVector足够,别一上来就上Milvus集群,运维成本会吃掉你的开发时间。

入库时除了向量,还要把原文、来源路径、文档ID、章节信息、更新日期等元数据一起存进去。很多项目前期图省事只存向量和文本,后期做多轮对话、做权限过滤、做知识溯源时才发现元数据不够,回头补数据是极其痛苦的过程。

检索环节的本质是“在向量空间里找最近的Top-K个文本块”。常用的相似度度量有余弦相似度、内积、欧氏距离,对归一化向量来说,余弦相似度最常用,因为它的值与向量模长无关,只关注方向上的相似性。

2.5 生成阶段:Prompt里塞多少上下文才合适

检索得到的Top-K个文本块最终要拼接进Prompt,让模型基于这些材料生成答案。这一段最常被忽略的几个问题:

  • 上下文超长:一次塞入8个1000字的文本块,加上用户问题,长度压力很大
  • 上下文无关内容干扰:检索回来的块可能只有一两个与问题真相关,其他都是陪跑的,反而是干扰
  • 没有引用来源要求:模型生成时如果不被要求“严格基于给定材料”,它还是倾向于动用参数记忆

我的习惯是:Prompt里明确告诉模型“你是企业内部知识库的问答助手,只能依据上下文中提供的信息回答。如果上下文中没有相关信息,直接回答‘根据现有资料无法确认’,不要自行编造”。同时要求模型在回答末尾标注引用来源编号。这一条Prompt规则,能挡住一大半幻觉问题。

3. 检索质量是RAG的命门:从召回率到重排序

很多RAG项目跑起来之后效果差,不是模型不行,而是检索环节拉胯:该召回的内容没召回,召回来的内容排在前面的又不是最相关的。下面几个影响因素我逐个说。

3.1 chunk_size实战取值与语义边界的权衡

先说最常被问的:切分长度到底取多少合适?

纯粹的字符数切分(Fixed-size Chunking)最简单,但也是最容易破坏语义的方式。我见过一个合同文本,其中一个条款正好被从中间切成了两半,前半块是“甲方应于XX日前支付”,后半块是“乙方方可启动交付”,检索时无论命中哪一半,模型得到的都是残缺信息。

按结构切分(以文档结构、段落为边界)是目前个人实践中最稳的方案。Markdown或HTML文档天然有标题层级,按标题把内容切成有语义边界的块;PDF里的段落,也尽量以自然段为基本单元,而不是机械数字符。

关于chunk_size的具体取值,我用过256、512、1024这几个档位,总结下来:

  • 256:适合FAQ条目、短条款、字典式内容。每块信息密度高但独立性强,问答场景召回精准
  • 512:适合产品说明、流程文档,语义完整性普遍够用,是大多数场景的折中选择
  • 1024:适合长上下文推理、需要全局视角的技术方案文档,但召回精度会下降,对Rerank的需求更高

再结合重叠窗口(overlap):相邻切块之间保留50-100字符的重叠,确保被切在边界附近的语义不彻底断裂。这个参数在长文档里很关键,新手最容易漏掉。

3.2 混合检索:向量召回兜不住关键词命中

纯向量检索有一个漏斗:它擅长语义相似,但精确字符串匹配反而不行。比如用户搜索设备型号“PLC-200”,Embedding会把“可编程控制器”语义相近的文档召回来,但精确包含“PLC-200”的那份参数表反而排在后面。

解决思路是混合检索(Hybrid Search):同时对同一批文档跑向量检索和BM25等传统关键词检索,然后把两路结果融合。

融合办法常用RRF(Reciprocal Rank Fusion),核心逻辑是同时出现在两路结果里的文档排名被强化。用RRF之后,实际体验是“语义相近”和“精确命中”都不漏。我个人把混合检索视为生产级RAG的标配,而不是进阶选项。

3.3 重排序:召回3条不如精排1条

向量检索和BM25各自的排序都只是“初筛”,它们的排序依据是相关性分数,但相关性分数高不等于“对当前问题最有用”。重排序(Rerank)解决的就是这个问题:先粗召回20条候选,再用更强的排序模型精排,最后取前3-5条。

Rerank的价值我是在一个客服场景里体会到的。不加Rerank时,Top-1经常是错误文档;加上Rerank之后,Top-1的准确率提升了近20个百分点。Rerank模型的典型代表有Cohere的Rerank系列、BGE的bge-reranker、以及各种开源Cross-Encoder模型。需要注意Rerank是会引入额外延迟的,需要权衡是否值得。

粗召回数量与精排数量的比例,我一般按“20召回、5精排”来做初始配置,再根据评测结果调整。

3.4 评测指标:Hit Rate和MRR怎么算

调参没有任何意义,除非你有评测。RAG检索效果最基础的两个指标:

  • Hit Rate(命中率):针对一组标准问题,每个问题有一个(或多个)标准答案所在的知识块。系统检索返回的Top-K中是否包含该知识块?包含就算命中。Hit Rate = 命中问题数 / 总问题数。
  • MRR(平均倒数排名):比Hit Rate更进一步,它考虑正确答案排在第几。每个问题计算1 / 排名位置,取所有问题的平均值。MRR越高,说明正确答案整体排位越靠前,Rerank和排序策略的优化空间主要看这个指标。

我强烈建议任何RAG项目在一开始就顺手建一个50-100条标准问题集,从真实用户问题里挑,把标准答案所在的知识块标注好。没有这个评测集,你改chunk_size还是换Embedding模型都是拍脑袋;有了这个评测集,每一次改动都有了可量化的反馈。

4. 从标准RAG到Agentic RAG:知识管道进化为Agent的推理工具

4.1 标准RAG的“一问一答”局限

标准RAG流程是:用户提问 → 检索一次 → 拼接上下文 → 生成答案。在简单FAQ场景下够用,但它的局限很明显——只做一轮检索,且检索策略完全固定。

两个典型场景它能把问题搞砸:

  • 复杂查询需要多步检索。用户问“我们上季度销售额最高的产品,在第三季度的退货率是多少”,需要先检索“上季度销售额最高的产品”得到产品名,再用产品名去检索“第三季度 退货率”。一次检索拿不到最终答案。
  • 用户表达模糊。用户问“那个新合同什么时候生效”,文档里写的可能是“本协议自双方签署之日起生效”。第一次检索的关键词“新合同”“生效”很可能匹配不到“协议”“签署之日”。标准RAG不会去改写查询词再检索一次。

4.2 把检索变成Agent的一个决策动作

Agentic RAG的核心思想,是把“检索”从一段固定代码变成Agent可自主决定的动作。Agent根据当前问题判断:是否需要检索?用什么关键词检索?检索一次够不够?是不是还需要再检索一次?甚至可以把多个检索工具并行组合使用。

实际落地时,这会呈现为工具化的形态。Agent的tools列表里加上search_knowledge_base这个工具,Agent在推理规划阶段决定调用与否、调用参数,然后拿到检索结果继续推演。这和第三篇里讲的工具调用机制是通的。

再进一步,查询改写也是一个关键动作。Agent在检索前可以把“那个新合同”改写为“合同 生效 签署 日期”,再带着这些词去检索。这比固定RAG管道里硬编码的查询预处理灵活得多。

4.3 GraphRAG与Ontology RAG的进阶思路

向量检索处理的是“语义相似”,但处理不了“多跳关系”。比如“张三负责的项目里,用了哪个供应商的数据库?”这类问题,需要沿着“张三→项目→供应商→数据库”这条关系链走,向量检索做不到,因为它只是找到语义相近的片段。

GraphRAG的思路是:先用大模型从文档里抽取实体和关系,构建知识图谱,然后在图谱上执行多跳查询。像微软开源的GraphRAG,就是在索引阶段把文档转化为实体关系图,回答问题时先在图上游走再生成。代价是构建成本高、耗时久,适合关系密集、查询多跳频繁的高价值场景。

Ontology RAG则更进一步,在知识图谱上引入本体层(Ontology),显式定义实体类型、属性、关系约束,相当于给检索加了一层领域规则。比如“项目”必须关联“客户”,“供应商”必须有“所属行业”属性。有了这层约束,检索结果会更可控,也更符合业务语言。缺点是需要领域专家参与建模,维护成本不低。

我的建议是:如果你的业务关系简单,别为了赶时髦上GraphRAG——向量检索加混合检索已经能覆盖绝大多数场景。等真遇到多跳关系查询的硬需求,再上图谱也不迟。

4.4 多轮对话中的知识管道设计

多轮对话里RAG有另一个容易被忽视的问题:用户的新问题经常依赖上一轮的信息。比如用户先问“A设备的功率是多少”,得到答案后又问“它适合用在哪些场景”,这个“它”指的是A设备。如果每一轮都独立检索,第二轮的“它适合用在哪些场景”根本检索不到有效信息。

常见解法是:在入口处做对话状态压缩——把多轮对话的历史摘要和当前问题合并成一个自包含的查询,再进入RAG管道。这在Agent架构里通常是Memory模块和Query Rewriting模块的职责,知识库检索本身只需要拿到改写后的完整问题即可。

5. 落地避坑实录:我踩过的五个坑

5.1 PDF表格被“读碎”了

最早一次做RAG,数据源是一批设备参数PDF。当时直接按段落提取文本,结果表格行列全乱:参数名和数值错位,检索“功率 2.5kW”时匹配到的文本块里功率后面跟着的是别家的型号。后来痛定思痛,把所有表格类PDF全部转为Markdown格式再走切分,表格结构保住了,检索准确率立刻上一个台阶。

5.2 长文档切分切断了因果链路

有一次做合规文档问答,用户问“哪些情况下合同可以解除”。源文档里有整整一节标题叫“合同解除的条件”,但因为按固定字符数切块,这一节被切成了3块,Top-3检索结果只把其中两块召回来,模型回答漏掉了最重要的一条解除条件。

后来长文档全部改成“按标题层级优先、字符数兜底”的切分规则,并且把overlap从50提高到150。漏召回的问题基本消失。

5.3 Top-K拍脑袋,召回忽高忽低

早期我把Top-K设成5,有些问题上下文够用,有些问题召回了5个块但真正关键的只有第6个,就差那么一点。后来在评测集上把Top-K从3调到10分别跑了Hit Rate,发现这个项目在Top-K=8时命中率最高,K继续增加Hit Rate不再上升,但MRR反而下降——因为无关块多了,正确答案排名被稀释。别迷信默认值,用评测结果说话。

5.4 忘记存元数据,后续多轮对话难以为继

吃过最实的亏是:第一版入库时只存了向量和正文文本,没存文档来源和章节号。后来要做引用溯源,要求答案后面注明“参考某某合同第几条”,结果所有文本块都没有来源信息,整个库要重灌。这真的是最贵的教训。现在我的每条切块元数据固定包含:文档ID、文档名称、原始路径、章节路径、页码、入库时间。别偷懒。

5.5 没有评测集,调参全靠玄学

有一段时间我同时调chunk_size、Embedding模型、Top-K三个参数,每次改完都靠肉眼抽几条问题看效果,根本说不清是哪个改动起了作用。后来花了两个晚上把50条标准问答和对应的知识块ID标注好,写了脚本自动跑Hit Rate和MRR,效率立刻不一样。再后来我把这个评测集纳入到一个简单的CI流程里,每次改动自动跑一遍,低于基线就回滚。RAG项目能走多远,基本取决于你对评测这件事重视多早。

最后分享一点个人体会:多数RAG项目效果最终不是被模型环节卡死的,而是被数据清洗、切分策略、元数据设计和评测闭环卡死的。数据侧的功夫花得越足,模型侧的那一点点差异就越不关键。如果你正要搭建Agent的知识获取管道,先把上面这些基础打扎实,再考虑花哨的进阶架构,你会少走很多弯路。

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

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

立即咨询