写AI Agent系列到这个第四篇,我明显感觉骨架已经搭得差不多了:前面的规划策略、工具调用、状态管理都有了,但真正让Agent"有脑子"而不是"有嘴"的那一步,恰恰是它怎么获取知识。今天要聊的这条"知识获取管道"——也就是RAG(检索增强生成)——几乎是现在所有AI Agent落地的必选项。你让模型去处理私有文档、实时业务数据或产品手册,靠它自己背诵的一切根本不现实,闭卷考试永远考不过开卷考试。这篇文章适合正在从零搭建AI Agent的开发者,也适合那些已经跑通Agent基础、但发现回答总是"一本正经地胡说八道"的人。
我一直坚持一个判断:Agent的聪明程度,一半在模型,另一半在它能不能按需问到"对的人"。RAG就是把千千万万的资料变成Agent的"养料",它解决的不只是知识割裂的问题,更是让Agent从"记得多少"变成"能找到多少"。这一篇我就把RAG的底层原理、关键步骤、参数细节和落地坑,一次讲透。
1. 让LLM开卷考试:为什么Agent必须有一条知识获取管道
1.1 从"记忆力差劲"到"知识饥饿":Agent真正的痛点
先说个挺反直觉的现象:大模型不是"知道"很多吗?为什么还要外挂知识库?
问题恰恰出在"知道"这两个字上。LLM的参数里确实压缩了大量公开语料的知识,但它的知识是"静态"的。训练完成后,它的世界就停在了那一天:新上线的产品、你公司的内部流程、某个项目的机密文档、某个垂直行业的专有术语,它一概不知。就算喂给它再多的对话上下文,它也受限于窗口长度,不可能把几十万字的手册全部塞进去推理。
这就在做Agent时产生了一个很尴尬的局面:你可以让Agent调用工具、执行流程、写代码,这些"行为能力"都很好解决;但一旦涉及到特定领域的事实性知识,它就会开始"自信地瞎编"。我见过太多开发者的第一版Agent,表面能力齐全,一问到具体业务细节就开始编一个看起来合理、实际上完全不对的答案。这不是模型不够强,而是你的Agent缺少一条"按需取用知识"的管道。
那条管道,就是RAG。它的核心思路可以用一句话概括:让LLM开卷考试。模型本身作为"答题人",但它身边始终摆着参考书,每次回答问题前,先到参考书里查一段相关的内容,再基于这段内容作答。
1.2 RAG是个什么"管道"?生命周期其实从存储就开始了
很多新手理解RAG的时候,把它当成一个"检索-生成"的简单流程:问一句、搜一段、拼起来。这个理解不算错,但太粗了。
完整的RAG管道至少包含三个环节:把知识预处理成可检索的索引层、把用户问题转成检索指令、把检索结果交给LLM做可信生成。三个环节任何一个掉链子,最终答案都是残的。
我更喜欢用"图书馆"做类比。想象你要在图书馆里查资料,RAG做的事情不是把整座图书馆背下来,而是:先把一本本书编成目录,放到书架上;接到问题时去查目录,挑出最相关的两三本书;最后把书翻到关键页,让答题人对照着页码写明答案。这里的每一个动作都对应RAG技术栈里的具体模块。
很多人有个误区,上来就去调大模型的prompt,想让模型"记住"领域知识。也就是所谓的"长上下文硬灌"。说实话,在小规模场景下,比如几十页文档,这招确实能用,它也简单;但一旦知识规模扩大、或者知识需要频繁更新,硬灌就会出现两个问题:一是成本爆炸,每次请求都拖着几十万token的上下文,费用和延迟都很感人;二是知识冲突,旧资料和新资料堆在同一个窗口里,模型根本不知道该听谁的。RAG的另一个关键优势,就是把"更新知识"从"换模型"降维成"换索引"——今天改了业务规则,重传一份文档就能生效。
1.3 什么时候该上RAG,什么时候不该硬上RAG
我也得泼一点冷水:RAG不是万能药,有些场景你确实不该上。
该上RAG的典型场景,通常具备两个特征:第一,知识是相对静态或半静态的,比如产品文档、规章制度、历史工单、论文库、FAQ;第二,知识不能靠公开语料覆盖,或者更新频率远超模型重新训练的周期。你做一个客服机器人、内部知识助手、文档问答系统、行业咨询Agent,基本都命中这个范畴。
不该硬上RAG的场景也有不少。比如你的知识可以完整塞进prompt且完全不需要实时更新,那就没必要平白引入检索层;再比如你的问题并不是"信息查找型",而是"创造型或推理型",例如让Agent写广告语、做头脑风暴,RAG对它的帮助就很有限,它缺的不是资料,是发散能力。判断标准,我觉得就一条:Agent的失败,到底是因为"找不到信息"还是"处理不了信息"?前者用RAG,后者大概率要换模型或改策略。
2. RAG管道的三段式拆解:摄取、检索与生成
2.1 摄取阶段:文档变成可搜索的"知识卡片"
先看最容易被忽略、却又最决定上限的摄取阶段。摄取的本质是把原始文档从"人可读"变成"机可查"。
第一步是解析。PDF、Word、Markdown、HTML,每种格式的解析难度完全不同。PDF里如果有扫描件,你可能还得先做OCR;表格识别、多栏排版、页眉页脚,这一层处理不好,后面的检索全在垃圾里捞金子。我常用的顺序是:先做格式归一化,统一成Markdown或纯文本,再做清洗,去掉无意义的空格、页码、重复水印,最后再考虑切块。
第二步是结构识别。这一步很多人都跳过了,但恰恰决定检索质量。文档的标题层级、表格结构、段落语义,这些都是宝贵的上下文锚点。你把它切丢了,检索回来的永远是半句话,没有出处、没有章节归属,LLM看着也一头雾水。现在不少RAG框架提供了基于文档结构的切分器,比如markdown header splitter,它会优先按标题切,尽量保留完整的小节作为知识单元,而不是机械地按字数砍。
第三步是分块和向量化,把切好的知识单元变成固定维度的向量,存入向量库。关于切块和向量的细节,我放到第3节单独讲,因为它值得单独讲。
2.2 检索阶段:把用户问题翻译成"找资料的指令"
检索阶段,很多人以为是"直接把用户问题拿去搜就完了",实际上这一步的深度也很有讲究。
一个朴素问题是:用户问题和我存在知识库里的表述,往往不是同一个说法。用户问"上次那台服务器怎么老是磁盘满",知识库里写的是"磁盘空间不足问题排查流程"。纯粹的语义向量可以缓解一部分词汇差异,但更稳的做法是走query改写。也就是让一个轻量模型,先把用户问题改写成若干条适合进知识库检索的关键句,再拿这些改写后的句子去分别检索。这一步很像是给Agent配了一个"翻译官",把口语打成检索词。
检索阶段还有两个容易被忽视的点:元数据过滤和权限过滤。一个知识库里可能装了几千份文档,有的属于技术部、有的属于销售部;有的文档是2023年的、有的是2024年的。如果不做元数据过滤,你搜出来的知识可能来自过期甚至越权的文档。现在成熟的检索服务都会要求在写入知识时一并维护好元数据,比如文档ID、作者、部门、时间、标签。检索时先按元数据缩小候选集,再走语义相似度,效果会干净很多。
2.3 生成阶段:让LLM只基于给它的材料说话
最后一个生成环节,看起来最简单,其实最需要设计。因为一旦上下文里混入了检索回来的不相关内容,LLM就有可能被带偏。生成阶段的Prompt有一个基本原则:明确告诉模型,只有我给你的参考资料才是事实依据,超出资料范围的事情,要么直说不知道,要么标记为推测。
我会在system prompt里写清楚三件事:第一,参考资料按编号给出,引用时标注来源;第二,如果资料之间存在矛盾,要主动指出来,而不是揉成一个和稀泥的答案;第三,能回答的回答,不能回答的明确拒绝。这三条看着简单,实际能挡住一大堆"幻觉落地"问题。
生成阶段还有一个几乎人人都遇到的坑:检索回来的top-5片段,可能只有两段和问题相关,剩下三段是强凑的。你硬把五段都塞给LLM,它就会被不相关内容干扰。比较好的做法是给每段打一个与问题的相关分,然后设定一个阈值,低于阈值的段落直接丢弃,宁可少给资料,也不要给污染资料。
3. "切不对就白搭":文本切块与向量化的实操细节
3.1 切块的粒度为什么决定检索质量上限
先抛一个结论:切块粒度一旦定错,后面做多少优化都只是打补丁。
切块太粗的问题很好理解——一个块里包含了A、B、C三个主题,用户问A的时候,系统把这个大块检索回来了,里面一半内容跟问题无关,这既浪费上下文空间,又干扰LLM判断。切块太细的问题则隐蔽得多:一个块只有几十个token,语义信息不完整,可能把一段完整的解决方案拦腰截断,检索结果的"相关信息密度"也很低,模型拿到了零碎的句子,拼不出完整答案。
从我自己的经验看,起始参数可以参考这样一个区间:普通文档切块,每个块大概256到512个token,相邻块之间有20到50个token的overlap(重叠)。这个overlap不是什么仪式感,它的作用是防止关键信息恰好在切刀处被劈成两半,让同一个信息至少在一个块内保持完整。如果你处理的是代码仓库,按函数或方法切;处理的是对话记录,按"一个完整问答对"切;处理的是合同条款,按"一个条款号"切。总之,切块边界应该跟着"语义天然边界"走,而不是跟着固定字数走。
3.2 向量化:embedding模型的选择与注意点
切完之后就是向量化。embedding模型的作用,是把一段文字从自然语言映射成一个扁平的向量,让语义相近的文字在向量空间里距离更近。这一步的选型直接影响检索的"手感"。
市面上的embedding方案很多,包括商业API和开源模型。我的建议是:如果你做的是中文场景,优先评估中文效果好的模型;如果涉及中英混合,最好有一个能同时处理双语的。不要迷信"单维越高越好",实际上768维、1024维都够用,越高的维度往往意味着存储开销越大。另一个非常重要的点是:查询侧和文档侧的处理方式要匹配。有些模型会用"[CLS]"之类的方式压缩整句语义,有些模型则强调"指令前缀"。你要把自己的query和doc按模型要求统一格式,否则效果会莫名其妙地变差。
向量化的工程细节我也会特别留意:批量embedding的速度和单条embedding完全不是一个量级,写摄取管道时一定要按批次处理;向量库的索引参数,比如HNSW的M和efConstruction,对内存占用和召回率都有影响;而正常的数据量下,用cosine相似度就足够了,不需要过度调参。
3.3 元数据:让知识管道拥有"档案管理员"
这一小节必须单独拿出来说,因为太多项目死在"裸奔的向量库"上。光有向量,你的知识库就是一个没有档案柜的仓库:所有篮子长得一模一样,找东西全凭缘分。元数据就是给每一个知识块贴上档案标签。
我给自己定的标准是,每个知识块至少要带上这些元数据:文档ID、文档标题、文档类型、所属领域/部门、创建时间、更新时间、以及可能用到的权限级别。有了这些信息,你在检索时可以做两件非常有价值的事情:一是范围过滤,比如只想搜销售部门的文档,直接按department=销售过滤;二是时效过滤,指定只看最近一年的资料。这两件事不做的话,你的RAG碰到"旧文档和新闻档内容冲突"的场景就会完全失控。
还有一个容易被忽略的元数据价值:引用的可追溯性。当Agent回答用户问题时,如果能附上一句"这个结论来自《XX规范》第3章",用户的信任感会完全不一样。而要做到这一点,就依赖你在每个知识块写入时就把标题和章节信息存进元数据。从基础阶段养成维护元数据的习惯,比后期补建省太多力气。
4. 检索质量不靠玄学:混合检索、重排与相关性验证
4.1 关键词与向量搭配:混合检索的互补逻辑
跑过一段时间RAG的人都会遇到一个典型场景:纯向量检索对"看起来不像但意思相近"的句子很灵,但一碰到精确词匹配就翻车。比如搜"Bug-12345"这个编号,语义上该匹配哪段?谁都说不清楚,但关键词一搜就能直接命中。这就是为什么我现在强烈建议,检索阶段不要只用向量,要走混合检索。
混合检索的常规搭配是BM25关键词检索加上向量语义检索。BM25是传统的信息检索算法,它擅长精确词、专有名词、编号的匹配;向量检索擅长同义改写、语义近义。两者跑出来之后,再用一个分数融合机制(比如RRF)把两边的排名合并。我项目里的默认配置是:向量检索和关键词检索各取前20个候选,融合后取前5个。这样既保留了语义扩展能力,又不会漏掉精确匹配项。下表是我在真实场景里对三种检索方式的对比感受:
| 检索方式 | 优势 | 劣势 | 典型适用场景 |
|---|---|---|---|
| 纯关键词(BM25) | 精确词命中强、可解释性强 | 无法处理同义改写、表达差异 | 工单编号、产品型号、法律条文 |
| 纯向量检索 | 语义理解强、能泛化 | 专有名词容易"语义漂移" | 概念咨询、口语化提问、长句问答 |
| 混合检索 | 兼顾语义与精确、召回更全面 | 实现复杂度稍高、需调融合权重 | 大多生产级知识问答场景 |
4.2 重排(Rerank):把候选结果重新"人肉按需排序"
混合检索把候选带回来了,但距离"高质量答案"还差一脚。这一脚就是重排。
首轮检索(不管是向量还是BM25)追求的是"召回率":我要确保真正相关的内容在候选池里,哪怕混进来一堆不相关的。但最终给LLM的信息窗口是有限的,所以我们必须从候选池里挑出最精华的几段。这就要用到重排模型。
重排和首轮检索最大的区别在于:首轮检索为了效率,通常用双塔(bi-encoder)结构,也就是把query和文档分别编码,再算相似度,速度很快但精度有限。重排阶段用的是交互式编码(cross-encoder),把query和文档拼在一起送进模型,精细地判断两者之间的语义关系。你可以理解为首轮检索用的是"速配",重排才是"认真相亲"。实操上,我会把top-20的候选交给重排模型,取top-3到top-5进入最终上下文。代价是重排比首轮检索慢,但由于只对少量候选执行,延迟完全可接受。
4.3 用命中率和人工抽检管住检索质量
讲完上面的手段,最后聊聊"度量"。很多项目上线后,只用"用户感觉回答得准不准"来验证RAG质量,这完全不够。我至少会用两类指标来管住检索质量。
第一类是离线指标,最常用的是命中率(Hit Rate)和MRR(倒数排名均值)。思路很简单:准备一批"问题-答案所在文档片段"的评测集,跑一遍检索流程,看看真正相关的片段有没有出现在top-k里。命中率衡量的是"有没有找到",MRR衡量的是"排得靠不靠前"。第二类指标是人工抽检。机器指标只能回答"相关或不相关",但它感受不到"这段资料虽然相关但过时了""这段资料和问题逻辑上不够搭"。我的习惯是,每次调整完切块参数或embedding模型,抽20到50条case做人工审核,从真实用户的视角给检索质量打分。
质量问题是会传导的:检索阶段撤回一段含混不清的内容,生成阶段再怎么努力也编不出精确答案。反过来说,只要检索阶段质量盯住了,生成阶段的事情就简单多了。
5. 从基础RAG到Agentic RAG:管道如何长进Agent里
5.1 从"一次检索"到"多轮检索":Agent需要自主判断
基础RAG的逻辑是"问一次,查一次,答一次"。这在单跳问题场景下够用,但真实业务里大量问题是多跳的。比如用户问:"我们的新客户成功经理在最近一个项目里遇到的部署问题,对应的产品缺陷文档有哪些?"你得先定位客户成功经理相关的项目,再找部署问题,再关联到产品缺陷库——这不是一次检索能完成的。
这就是Agentic RAG的用武之地。Agentic RAG不是一种新技术框架,而是一种把RAG嵌入Agent决策循环的思维。它让Agent自己判断:这个问题需不需要检索?应该检索哪个知识库?检索一次够不够?返回的结果是不是已经能回答问题?如果不够,下一步该再检索还是换个查询词?
我之前做过一个内部运维Agent,最初是基础RAG,用户问"虚拟机一直重启是什么原因",它能基于知识库给出一份回答,但等用户追问"按这个排查了还是不行,你看这块磁盘也不对"时,它就傻了。改成Agentic RAG之后,Agent会先把问题拆成"重启原因排查"和"磁盘异常诊断"两个子问题,依次检索,再合并出结论。这个过程不是某一次prompt工程能搞定的,而是靠规划能力加多轮检索能力组合实现的。
5.2 "知识管道"和"Agent"之间,该谁指挥谁?
这里有个设计站位问题想提醒一下:不要让RAG变成一个被动的"知识接口",也不要让Agent变成每次都无脑调RAG的"检索机器人"。知识管道和Agent的关系,应该是管道提供弹药,Agent决定什么时候、用什么方式开火。
在我自己的工程实践里,我更倾向把检索模块设计成Agent的一个"工具"。Agent在规划阶段会判断"当前意图是信息查询型,需要调用知识检索工具",然后决定检索query、过滤条件,以及是否要递归检索。具体实现时,不管用LangChain、LlamaIndex,还是Spring AI这类框架,核心思想都一样:检索工具必须带清晰的入参和出参定义,Agent才能正确调用它。比框架更重要的是给这个"工具"写清楚能力和边界。比如描述里写明"本工具用于查询产品文档和FAQ,返回参考文献列表,若检索结果为空请尝试改写关键词",这会让Agent的调用准确率高很多。
5.3 下一步在工程上可以做的三类增强
在理解了Agentic RAG的基本逻辑之后,我建议再往三个方向做工程增强,它们都是Agent落地时会被频繁用到的能力。
第一是查询改写与扩展。Agent拿到用户原话后,先自己产出2到3个检索变体,比如把口语改成书面语、拆分长问句、补上必要的上下文。第二是知识库路由。企业内部通常不会只有一个知识库,技术文档、销售材料、财务制度各有归属。与其让一个库大杂烩,不如按域拆分多个索引,由Agent基于意图去选择"去哪个库查"。第三是答案验证。在生成完最终答案后,增加一步"自检":答案中的关键陈述是否都能在检索到的资料里找到依据?找不到依据的部分必须删掉或标记为推测。这三个增强的成本都不高,但对提升最终答案的可信度立竿见影。
值得一提的还有方向性的尝试,比如把知识图谱和RAG结合(GraphRAG)或者用本体(Ontology)来约束检索关系。这类方案更适合强关系型知识,比如组织架构、系统依赖、业务流程,基础RAG确实难以表达A依赖B、B触发C这类链路,但这是整个RAG演进里的进阶话题了,这一篇先把基础管道打扎实,将来再拆开细讲。
6. 落地时绕不开的坑,以及我踩出来的解药
6.1 知识更新与旧文档的"尸体"问题
做RAG几个月后,你会发现最头疼的往往不是检索精度,而是"知识过期"。公司在迭代、文档在翻修,今天还正确的流程,下周就不算了。如果你只用增量更新的方式往知识库里添加新文档,旧文档永远躺在索引里,检索结果里新旧信息互相打架,Agent一会按旧规则回答,一会按新规则回答,用户直接懵。
我的解药是给知识库引入生命周期管理。第一层是版本化:文档更新时不是覆盖式写入,而是给每个文档或知识块带上版本号和时间戳。第二层是下线机制:如果一份文档被标记为废弃,要能从索引里真正删除或至少通过元数据过滤掉,而不是单纯"不再新增"。第三层是定期巡检:我习惯设置一个周期任务,把那些长期没有被检索命中的旧知识块抽样看一遍,确认它们是否已经过时。知识管道不是建设完就一劳永逸的,它需要像产品一样持续维护。
6.2 短期记忆、长期记忆和RAG的重叠边界
这是我在多个Agent项目里遇到过的经典混淆:短期对话记忆、长期用户记忆、RAG知识库,三者到底怎么分工?
我会这样区分:短期记忆管"这次会话聊到哪了";长期记忆管"这个用户/这个项目的偏好和画像";RAG管"客观的、领域性的、可检索的资料"。你如果什么都往RAG里塞,比如把用户的个性化偏好也存进知识库,那么所有用户都会搜到这个用户的偏好,完全串味。反过来,如果你把产品知识硬塞进长期记忆,Agent会被无关信息占满,而且长期记忆的更新机制根本不适用于文档型知识。
所以我的建议是:数据写入时先做分类。只是某一次会话里的临时信息,交给会话上下文;需要长期记住的用户事实,交给记忆组件;正式的文档资料、FAQ、业务规则,才进RAG管道。三类存储的更新频率、查询方式、生命周期都不同,强行统一只会让系统变得笨重。
6.3 成本与延迟:别让Agent每步都去翻资料
最后聊一个容易被忽视的工程问题。Agentic RAG的代价在于:一次用户提问,Agent可能要规划、要多次检索、要重排、再调用LLM生成,甚至还要再验证一遍。这一套流程下来,延迟不再是基础的"一次查询几百毫秒",而可能上升到秒级甚至十几秒,token费用也会明显增长。
我控制成本和延迟的几个方法:一是引入路由判断,也就是前面说过的,先判断这个问题到底需不需要走RAG,不需要就直接生成,别硬绕一圈。二是做好缓存,对常见的重复问题,把检索结果缓存一段时间,命中缓存就直接跳过检索流程。三是控制多跳深度,给Agent的规划设定最大检索次数,比如最多3轮,超过之后强制生成,防止它在检索里钻牛角尖。四是尽量选择高性价比的embedding和重排模型组合,追求收益和成本的平衡,而不是一味地堆最重的模型。
在实际业务里,检索并不是越"重"越好。我曾经把一个客服Agent从"每问必检索5段资料"优化成"先路由、再按置信度动态决定检索段落数",结果平均延迟降低了一半,用户满意度反而没有下降。这个优化给我的启发是:RAG管道是给Agent服务的,要让Agent学会按需取用,而不是每个问题都像在做学术综述。
按我个人的经验,刚开始搭建RAG知识获取管道时,最容易犯的错就是"文档一多就想上复杂架构"。其实九成以上的场景,把摄取、检索、重排这几个基本功做扎实,效果就已经远超坏掉的复杂架构了。如果你也正在从零搭AI Agent,我的建议是:先拿几百份文档,把切块参数、混合检索和评测集跑通,再谈Agentic RAG的炫技能力。管道稳了,Agent才能真正站在知识的肩膀上。