
RAGRetrieval-Augmented Generation检索增强生成这个词在 AI Agent 的圈子里火了两三年但大多数人的理解停留在“给大模型接一个知识库”这个层面上。真正动手搭过 RAG 管道的人都知道知识获取管道远没有想象中那么简单——文档怎么切、向量怎么存、召回怎么调、生成怎么约束每一步都是坑。这一篇作为 AI Agent 系列第四篇我把 RAG 讲透它到底解决什么、最小可用管道怎么搭、我在实战里踩过哪些坑、以及怎么评估一套 RAG 系统好不好用。适合所有打算在 Agent 里接知识库的开发者也适合那些听过 RAG 概念但没真正跑通过流程的人。1. 为什么需要 RAG知识割裂问题与问题拆解1.1 大模型的知识盲区到底在哪里先想清楚一个问题ChatGPT 再聪明它也不知道你公司内部那份 2026 年版《产品报价审批流程》写了什么。原因很简单预训练模型的知识来自公开语料的快照训练截止日期之后的信息它一概不知即便训练过它记下来的也是概率分布而非原文。这就是所谓“知识割裂”——大模型内部的知识与你实际检索时需要的知识根本不在一个空间里。知识割裂体现为三种具体场景。第一实时性知识比如今天的股价、最新的安全通告、刚发布的产品文档。第二私有化知识比如企业内部的制度文件、项目复盘、客服对话记录这些内容根本不会出现在公开语料里。第三高精度的专有术语比如医疗影像报告里的描述、法律合同里的条款表述模型就算“知道”这些词也无法保证引用的准确性和出处。我在实际项目里遇到过很典型的例子给一个制造业客户做设备故障排查助手模型对“伺服驱动器报警代码 12A”的理解完全基于泛化知识它根本不知道客户设备手册里的具体处置建议。这不是模型不够聪明而是它的知识来源里就没有客户的设备文档。RAG 就是来解决这个问题的——在模型生成答案之前先从外部知识源里检索出相关的片段再把片段作为上下文交给模型重新生成。换句话说让模型“先翻书再回答”而不是让它凭记忆瞎编。1.2 RAG、微调、长上下文三种方案怎么选给 Agent 注入知识市面上主流有三条路RAG、微调Fine-tuning、长上下文Long Context。很多人一开始就纠结选哪条其实它们解决的是不同层面的问题可以结合使用而不是彼此替代。微调的本质是改变模型的权重。它适合的场景是你希望模型固定学习某种“风格”或“表达格式”比如把输出统一成 JSON、模仿客服的话术体系。但微调不适合承载事实性知识——模型在训练时会把知识“压扁”成参数你很难控制它最终记住什么更别提知识频繁更新时还得反复重训。长上下文则是把整本文档直接塞进 prompt做法简单粗暴但 token 成本随输入长度线性暴涨而且有实测数据表明模型对超长上下文中部位置的注意力会明显衰减也就是俗称“lost in the middle”。RAG 的定位刚好是两者的中间态。它把知识存储在外部需要时检索若干片段作为上下文成本可控、更新灵活——要加新知识往库里丢一份文档重新向量化即可不需要动模型权重。对 AI Agent 来说RAG 还有一个微调不具备的优势可溯源。你可以在回答后面附上引用的文档片段和来源用户能验证答案这在 B 端场景几乎是刚需。下面这张表可以帮你快速做选型方案适用场景优势劣势RAG私有知识、频繁更新的资料库可溯源、更新快、成本可控检索质量决定回答上限微调固定格式、输出风格、领域语言行为稳定、响应快知识固化、更新麻烦、成本高长上下文单篇长文档理解、一次性分析实现简单、信息完整token 贵、长文注意力衰减2. 一个最小可用 RAG 管道的完整搭建2.1 完整链路从文档到回答的四步搭建 RAG 最怕一上来就选框架、配向量数据库结果跑了个 demo 却说不清每一环节在做什么。我习惯先把链路抽象成四个步骤加载与清洗、切块与向量化、存储与索引、检索与生成。所有 RAG 系统无论复杂到什么程度底层都是这四步。第一步把目标文档读取进来做格式解析和文本清洗。第二步把长文本切成语义相对完整的块并调用 embedding 模型把每一块转成高维向量。第三步向量写入向量数据库同时构建索引便于相似度检索。第四步用户提问时把问题也向量化去向量库里召回最相似的块然后拼进 prompt 交给大模型生成。整个链路里决定效果上限的其实不是大模型而是召回阶段能不能把真正相关的片段捞出来——检索不到生成再强也白搭。下面我把每一环的关键细节拆开讲。我自己搭过 LangChain、LlamaIndex 以及完全手写的管道结论是框架只是工具理解了每一环的数学直觉和参数含义你才能在不同框架之间无缝切换而不是被框架 API 绑架。2.2 文档加载与清洗别小看排版问题知识库的数据源往往五花八门PDF、Word、Markdown、HTML、甚至是扫描件。文档加载这一步看似简单但恰恰是后续切块质量的源头。PDF 看起来最正式实际解析时最痛苦——多栏排版会被读成左右穿插的乱序文本表格会丢行列结构页眉页脚混进正文。Word 相对好一些但图片里的字模型读不到文本框顺序也经常乱。Markdown 是最友好的因为我可以在解析时保留标题层级后面直接按结构切块效果远好于纯文本。清洗这个过程我踩过的坑足够写一篇单独的复盘。核心经验是切块之前必须先做规则清洗。比如去掉页眉页脚、页码、目录页把“第 3 页 / 共 10 页”这类噪声删掉对于明显是表格的内容优先转成 Markdown 表格格式或者把表格行拼接成一句通顺的描述文本否则向量化之后语义信息会大幅损失。如果你是做长文档问答还要注意把图表标题和正文文案从解析结果里剥离出来它们往往会被嵌进奇怪的位置。我的预处理顺序通常是源文件转成纯文本或 Markdown → 按页合并 → 正则去噪声 → 规则识别标题层级 → 导出为带元数据的块。这里说的“带元数据”是指每个块要记录来源文件名、页码、章节标题这些信息在后续生成引用和溯源时必不可少。很多人做 RAG 会把元数据信息丢掉等要回答里加出处时就傻眼了。2.3 切块与 embedding参数不是瞎拍的切块chunking是 RAG 管道里最容易被低估的环节。切大了一个块里包含太多主题检索时噪声大切小了语义被切断模型拿到的信息不完整。核心目标是保持“语义完整”让每一块在独立语境下也能被理解。我见过很多新手直接按固定 512 个字符盲切结果一个完整的合同条款被拦腰截断检索出来的内容上下文不连贯回答自然漏洞百出。常用的切块策略有三种层次。最基础的是固定长度加重叠窗口按 token 数不是字符数设定 chunk_size同时设置 chunk_overlap 让相邻块有交叉避免边界信息丢失。经验值方面我一般从 chunk_size500、overlap50 起步再根据文档类型调整。技术文档可以稍微放大客服对话记录则建议调到 300 以下。进阶做法是结构感知切块利用 Markdown 的标题层级把同一小节的内容聚成一个完整块这个方案对结构清晰的文档效果最好。再进阶是父子切块父块覆盖大段落上下文子块负责精确检索召回后取父块作为上下文兼顾精准度和完整性。embedding 模型的选择同样关键。目前主流做法是用 bge、m3e 这类中文表现不错的开源模型或者直接调 OpenAI 的 text-embedding-3-small。国内商用环境里我更倾向于部署本地 embedding 模型既省钱又免去数据出域的风险。向量维度不是越高越好高维度意味着更大的存储和更慢的检索但检索精度未必线性提升。相似度度量常用余弦相似度向量标准化之后余弦相似度其实就等于点积选择数据库索引类型时可以用这个性质。2.4 检索与生成召回后如何“说话”检索阶段有两个参数需要调召回数量 top_k以及相似度阈值 threshold。top_k 决定拿多少片段进 prompt太小可能漏掉关键信息太大则上下文太长容易引入噪声。threshold 决定最低相似度线低于这个分数的片段直接丢弃答案宁缺毋滥。我通常会先设 top_k4、threshold0.3然后根据评估结果反复调。注意embedding 模型输出的相似度分数不是“绝对概率”不同模型的分值分布差异很大阈值要根据自己的模型实测标定不能直接抄别人博客里的数值。生成阶段的本质是“让模型看着材料说话而不是发挥想象力”。所以 prompt 里必须明确约束第一只依据提供的上下文回答不臆造第二如果上下文中没有答案直接说“知识库中没有找到相关信息”不要强行作答第三给出结论时标注引用来源。我的生成 prompt 主干写着“你是企业知识库助手基于以下资料片段回答用户问题。资料中没有的内容请明确说明。回答时在句末标注参考资料编号”。后面拼接时资料片段前加上编号前缀回答里就能用 [1] 这样的标记关联出处。检索方式上纯向量检索并不是万能的。关键词精确匹配在某些场景下仍然更可靠比如型号“PLC-X7”、代码“ERR_203”这类专有名词embedding 的语义相似无法保证命中而 BM25 一查一个准。所以我的标准方案是混合检索BM25 加向量检索把两路结果合并去重后再给一个 rerank 模型重排让高相关片段顶到最前面。rerank 会额外花一点时间但效果提升显著特别是在 top_k 不高的场景下这一个重排动作往往能把回答质量从“能用”拉到“好用”。3. 踩坑记录与实战调优从能用走向好用3.1 切块翻车实录同一个问题答不对了先分享一个真实经历。我给客户做法律合同问答助手合同文档是 PDF 转出来的纯文本我图省事直接用了固定长度切块。上线测试时发现凡是涉及“违约责任”的提问回答质量时好时坏。查了召回内容才发现合同的“违约责任”条款长达三页被切成了六七个块其中几块的边界刚好落在关键金额数字和日期中间。模型拿到的片段里要么只有“违约金为人民币”没有后面的具体数额要么只有“2026 年 3 月前”不知道前面说的是什么义务。这类问题在固定长度切块下几乎无法避免。我的解决办法是换成结构感知切块加父子分块的组合先识别合同固有的“第 X 条”结构以条款为单位切出父块再对每个父块按 500 token 切出子块用于检索检索命中的是子块但 prompt 里放的是整个父块。这样既保证了精确匹配条款内容又不会丢失条款上下文。这个改动看起来小实际把问题的精确回答率提升了接近三成。这里给一段简化版的切块逻辑方便你理解父子分块的核心思路def hierarchical_chunking(text, structure_pattern第[一二三四五六七八九十百千0-9]条, chunk_size500, overlap50): parts split_by_structure(text, structure_pattern) chunks [] for part in parts: # 父块保留完整结构单元 chunks.append({parent: part, children: split_by_token(part, chunk_size, overlap)}) return chunks3.2 检索命中但回答还是错的答案在召回质量更隐蔽的问题出现在“明明检索到了相关片段但模型回答还是不对”。这种情况排查起来最花费时间。我遇到过一个典型case用户问“设备报错怎么办”召回结果里有一份非常匹配的售后维修手册片段但模型回答引用的却是另一个不相关的故障说明。定位后发现问题出在 top_k 的合并策略上——我当时的代码直接把相似度最高的片段按顺序拼接结果第一段虽然是强力匹配第二段却是低相关的噪声模型在生成时被第二段带偏了。这类问题有三板斧第一检查召回分数分布看看 top_k 里从第几名开始分数断崖式下跌如果前 3 名都高、第 4 名骤降把 top_k 从 5 改到 3 就能消除噪声。第二引入 rerank 模型让语义相关度高的片段重新排到前面而不是傻傻地按检索分数排序。第三检查 embedding 模型是否适合领域文本通用模型在专业术语上的表现往往不佳必要时得拿领域语料做微调或换成领域版模型。还有一类召回失败的情况容易忽略问题里的关键信息是缩写比如“说下 ERP 的 MRP 运算怎么配”而知识库文档里写的是“物料需求计划MRP计算逻辑”。向量检索对这类缩写和全称的匹配能力有限混合检索里加上 BM25 也不一定能命中因为全称和缩写字面完全不一样。我的方案是维护一个同义词典在检索前对 query 做一次改写扩展把“MRP”扩成“MRP 物料需求计划”把“ERP”扩成“ERP 企业资源计划”。主动改写 query 比反复调参数更有效。3.3 生成阶段的三个低级错误生成阶段有三个坑属于“不遇到不觉得遇到真头大”。第一个坑是不要求模型引用来源。很多教程里的 prompt 只说“根据资料回答”模型给出一个看似合理的回答用户没法判断对错。加上“句末标注[编号]”的约束后回答质量会显著提升——模型会更谨慎因为每个结论都得有出处。第二个坑是没有兜底输出设计。知识库里没有答案时模型还会硬凑一段相关话题的内容。我在 prompt 里加了一句话“如果资料中没有相关信息请明确回答‘知识库中暂未找到相关内容’不要尝试推测。”这一个改动就直接干掉了八成幻觉。第三个坑是上下文过长导致 prompt 截断。top_k5、每块 800 token拼接后动辄 4000 token如果模型上下文窗口不够后面的片段被截断模型只能基于前几个片段作答。解决方案是先估算 prompt 长度超限时按 rerank 分数截断而不是简单按顺序截断。此外生成阶段还要和召回阶段联动调试。输出引用编号和实际上下文不对应往往是生成 prompt 里片段编号拼接错误——这个低级错误我犯过一次排查整整两小时。强烈建议在生成响应之外单独输出一个引用列表的结构化日志包含命中的片段编号、文件名、页码、相似度分数排查问题会快很多。3.4 从 LangChain 到自研踩坑框架不是银弹我第一版 RAG 管道用的是 LangChain直接套它的链式调用demo 跑得飞快。但随着需求复杂化问题开始出现框架封装太深检索分数、切块中间结果、prompt 模板的实际渲染结果被层层包裹出了质量问题很难定位。后来我拆到用 LlamaIndex 做数据接入和索引自己写检索和生成逻辑再后来干脆把整个管道改为自研服务只保留框架做数据解析。每拆一层调优的灵活度就高一层。不是说框架不能用而是你要清楚框架帮你做了什么、隐藏了什么。如果只是验证 RAG 流程是否能跑通LangChain、LlamaIndex 完全够用但进入调优阶段我强烈建议你能直接看到每一环节的中间产物——切出来的块长什么样、检索回来的片段排第几、分数是多少。这些中间态的可观测性决定了你能不能从“碰运气调参”走向“系统化调优”。4. 评估与进阶RAG 的上限由什么决定4.1 先定标尺再调优RAG 评估的四个指标不做评估就去调参等于闭着眼睛调色。我见过太多团队花费几个星期“优化” RAG却始终说不清“优化”了什么。科学的做法是先把评估标尺立起来。RAG 系统至少要跟踪四类指标召回质量、生成质量、性能、成本。召回质量用命中率Hit Rate、召回率Recall和平均倒数排名MRR衡量——通俗讲就是“正确答案是否出现在召回的片段里”“出现在第几名”。生成质量用忠实度Faithfulness和相关性Relevance衡量——忠实度看回答是否严格基于上下文相关性看回答是否切题。这两个维度都可以用 LLM 自动打分的办法评估嫌贵就用规则加少量人工抽检。性能和成本就不用解释了首 token 延迟、吞吐量、单次问答 token 消耗这些是上线后必须盯住的。我维护评估数据集的方法是从真实用户问句里挑 50 到 100 条覆盖不同难度的题目每道题标注标准答案和应命中的文档 ID。之后每次改动切块参数、embedding 模型或 prompt都跑一遍同样的数据集横向对比指标变化。这套闭环说起来似乎不太复杂但它把 RAG 调优从“我感觉变好了”变成“数值从 0.72 涨到 0.79”也让团队内部有了一致的沟通语言。4.2 从基础 RAG 走向 Agentic RAG给 Agent 的启示RAG 做扎实之后下一步就是把它嵌进 Agent 的行为链路里。这就是热词里反复出现的 Agentic RAG。基础 RAG 是单轮“检索—生成”问题复杂一点就失灵比如用户问“对比一下这三款服务器的接口规范和价格”直接把整个问题拿去向量检索很难找到同时覆盖三款产品的片段。Agentic RAG 的处理方式是Agent 先把问题拆成三个子问题分别去知识库检索再汇总答案。这背后是 Agent 的规划能力——把检索从一次调用变成多次决策中间可以循环先检索一轮发现信息不足改写 query 再检索或者先调一个工具拿到用户属性再带着属性去检索对应知识。我在生产项目里实践过的模式是把 RAG 封装成 Agent 的一个标准工具Agent 根据用户意图决定是否调用、调用几次、检索结果够不够用。这一层抽象让 RAG 不再是孤立的管道而成为 Agent 知识获取能力的一部分。另外知识库的向量化不是一次性工作。文档会更新、会淘汰向量库里的旧版本如果不清理检索会被历史版本污染。我在生产环境里会为每个知识库维护一份文档版本表更新文档时先按文档 ID 删除旧向量再写入新向量并记录每次更新的时间戳。Agent 在检索时还能增加一个时间维度过滤优先取最新版本的内容这对政策类、制度类知识尤其关键。从 Ontology RAG、GraphRAG再到基于知识图谱的本体增强检索RAG 的进阶方向本质都是在解决同一个问题如何让检索系统拥有结构化的世界知识而非停留在“文本相似度匹配”。GraphRAG 用知识图谱把文档实体和关系抽出来回答“实体之间的关联”类问题时明显更强本体 RAG 则把领域概念体系注入检索过程让系统理解“诊断”和“检测报告”的业务关系而不是纯粹字面相似。这些方向学起来成本不低但理解了基础 RAG 的管道逻辑进阶其实就是对某一环的替换和增强。RAG 管道做到最后你会发现性能上限不是模型决定的而是数据基建决定的——切块干不干净、文档元数据全不全、混合检索配没配、评估集覆盖广不广每一项都比换一个大模型更影响最终效果。我个人在实操里最深的体会是先用最小管道跑通再建立评估闭环最后才谈优化这个顺序千万别反。另外再分享一个小技巧给每个 prompt 模板和参数组合加一个标识日志里带上版本号上线之后排查问题你会感激当初这个习惯。从基础 RAG 到 Agentic RAG知识获取管道远不是“检索加生成”五分钟就能收工的事情每一步打磨都值得这条路长但越往后价值越大。