很多刚接触Agent的朋友都会问同一个问题我的模型已经在海量数据上训练过了为什么做一个问答Agent还是漏洞百出我在用LangChain搭一个内部知识库Agent时也踩过这个坑——模型把网上某个过时的报销标准当成我们公司的制度一本正经地回复了错误金额。问题不在模型智力而在于模型根本没有一条“知识获取管道”去拿你仓库里的权威资料。这个系列讲到第四篇正好卡在最关键的位置知识获取管道。这个管道在今天的Agent架构里有一个标准答案就是RAGRetrieval-Augmented Generation检索增强生成。RAG并不是什么新东西但它从“一个让模型引用外部资料的技巧”变成“Agent的标准组件”这中间经历了很多实战检验。今天这篇我会从Agent为什么需要独立的知识获取管道讲起拆解RAG的工作链路再给出一套能从0到1落地的搭建方案最后聊一聊Agent和RAG结合时真正容易翻车的细节。内容包括混合检索、命中率、切块策略这些老生常谈但不一定真做对的东西也会聊到Agentic RAG这种更进阶的形态。想搭一个能回答私域问题的Agent或者想把现有Agent从“瞎猜”变成“翻资料”这篇应该对你有用。1. Agent的知识从哪来模型里装的不是一个企业的知识库1.1 模型参数里的知识是“死”的回答瞬息万变的业务问题会露怯预训练模型的本质是把海量文本压缩进一组参数里这组参数在训练完成之后就固定了。你可以把它想象成一个只读过指定教科书的人教科书印好那天他脑子里的知识就定格了。你问他今年的年报数据他只能根据旧数据瞎编你问他刚改的考勤制度他只能按照训练数据里的通用模板发挥。知识截止时间、领域偏差、私有数据缺失这三座大山让裸模型在真实业务场景里很难直接当Agent用。很多团队刚开始做Agent时天真地以为给模型加一个系统提示词“请严格按照公司制度回答”就能解决。结果模型依然自信地输出不存在的条款。原因很简单提示词只是约束模型的表达方式并没有给它新的知识来源。知识如果不进入上下文模型就只能在自己的参数里挖挖不出来就编。1.2 知识割裂才是Agent落地的最大阻碍我见过不少企业制度在OA里技术文档在Confluence里产品介绍在飞书文档里历史问题答疑在微信群聊天记录里。这些数据分散在不同系统格式不统一权限也不一样没有一个模型能直接把这些内容“记住”。这就是热搜词里反复出现的“知识割裂”。Agent要解决知识割裂就不能只靠一次检索。它需要一条管道把不同来源的数据统一收集、切片、向量化、存索引然后按需取用。这条管道就是知识获取管道。它存在的价值不是简单地把文档塞进数据库而是让Agent能够在合适的时间、以可验证的方式拿到准确的信息。1.3 知识获取管道的三个目标新鲜、精准、可溯源判断一条知识获取管道是否合格我通常会盯三个指标新鲜数据源更新后管道能否在可接受的时间内让Agent感知到比如制度改了旧版本不应该再被检索出来。精准检索出来的内容是否和当前问题强相关相关性差的片段不仅没用还会干扰模型生成。可溯源模型回答中的每条关键信息能否对应到原始文档的某一段可溯源是建立信任的基础也让后续纠错变得简单。这三个目标听起来简单但做起来每一步都有坑。接下来的内容会反复围绕这三点展开。2. RAG的基本盘从“先检索后生成”到“带着参考资料作答”2.1 用一个图书馆类比看懂RAG你刚入职一家新公司有人问你“年假怎么休”你不会翻随身带的常识手册而是去翻公司的员工手册。RAG干的就是这件事先根据你的问题去知识库里找出最相关的几段内容再把这些内容连同问题一起交给模型让模型基于这些内容作答。这个流程的关键在于“找出最相关的几段内容”。传统的关键词搜索只能匹配字面遇到“请假”和“休假”就失灵了。RAG用的是向量检索把文本转换成一组数字也就是Embedding向量然后根据向量之间的余弦距离或点积来判断语义相似度。用户问题转成向量后去向量库里找距离最近的几个片段这就是最基础也最常见的召回方式。2.2 一条典型RAG链路拆解一条最简单的RAG链路通常包含离线索引和在线查询两个阶段。离线索引阶段做的事包括文档加载从PDF、Word、Markdown、数据库等不同源读取内容。文本清洗去掉页眉页脚、多余换行、乱码字符。切块Chunking把长文档切成若干个小片段控制每个片段的信息密度。向量化用Embedding模型把每个片段变成向量。写入向量数据库同时存储原文文本、向量、元数据文件名、页码、章节等方便后续过滤和溯源。在线查询阶段做的事包括查询理解对用户问题做必要改写比如纠正错别字、补充上下文。召回把问题向量化从向量库里找出Top-K个最相似的片段。重排可选用重排序模型对召回结果精排提升相关性。生成把用户问题和检索到的片段拼接成Prompt交给大模型生成回答。这五个环节每个都能展开成一篇踩坑日记。尤其是切块和召回直接决定了后续生成质量的上限。如果你的检索结果本身就跑偏了大模型再聪明也是巧妇难为无米之炊。2.3 为什么不建议把整篇文档直接塞进上下文有人可能会想既然大模型的上下文窗口越来越大那我干脆把整个知识库文档塞进去不就完了这个思路在文档很少、总字数很小时可以凑合但一旦文档超过几十万字就会出现三个问题成本失控按Token计费的大模型API会把大部分Token浪费在无信息量的背景介绍上。注意力稀释窗口里塞太多无关内容模型反而抓不住关键信息专业术语叫“Lost in the Middle”中间部分的知识容易被忽略。延迟变高长上下文处理时间长Agent交互体验会变得很糟糕。所以RAG的核心不是“给模型更多文档”而是“只给模型最需要的那几段”。知识获取管道的核心能力在于高效地找到那几段。3. 从0到1搭一个能用的RAG管道切块、向量化和混合检索3.1 解析和切块第一步就决定成败我见过太多人花大量时间调Embedding模型和提示词却对上游的切块策略毫不在意。实际上切块粒度直接影响召回命中率。切得太粗一块包含多个知识点检索进来后有效信息被稀释切得太细上下文可能丢失依赖前文才能理解的句子变成孤儿。具体选择要根据你的文档类型和查询模式来定。在我的实践里一个比较稳妥的起点是对于规则制度、技术规范这类语义块清晰的内容可以按段落或章节边界切。没有明确结构的长文本用固定长度切分比如chunk_size500字符中文overlap50左右。注意按Token切和按字符切不一样。如果用OpenAI的EmbeddingToken是基本单位中文1个汉字大约等于1到2个Token。按字符切简单直观按Token切更符合模型实际处理逻辑。代码上非常典型的一版切块是这样的from langchain_text_splitters import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , ] ) chunks splitter.split_text(document_text)RecursiveCharacterTextSplitter会优先按段落分段落太长再按句子分保证切出来的块尽量保持语义完整。如果你用的是类似LangChain的框架它已经封装好了如果自己用Python写原理也不复杂。另一个值得一试的方案是父子切块把文档先用较小的粒度切成若干子块让检索更精准同时保留包含这些子块的父亲段落让生成更完整。检索时先命中子块然后把子块所属的父块送给模型。这样既保证了召回精度又避免了上下文被打断。3.2 向量化Embedding模型选型没有标准答案Embedding模型的作用是把文本变成一串浮点数这一段与那一段“像不像”就由向量间的距离决定。选型时我一般看三个维度语言适配度如果知识库主要是中文尽量选在中文上训练和评测过效果较好的模型。早年我用过一个英文为主的Embedding模型中文语义相减完全不对味换模型之后命中率直接提升十个百分点。维度与索引压力向量维度越高表达力越强但占用空间和查询延迟也越高。常见的开源模型输出维度在768到1024商业化API也有384维的。如果文档量不大几万块以内维度的影响很小。是否本地部署数据敏感的企业不适合用外部API直接向量化。本地部署开源模型如bge-m3、Qwen-based Embedding等能兼顾隐私和效果。向量化之后下一步是把向量写进向量数据库。可选的产品很多开源的Milvus、Qdrant、Chroma以及直接基于PostgreSQL的pgvector。初期数据量不大用Chroma、pgvector这类轻量方案就够等规模上来了再迁移到专业向量库。3.3 检索升级关键词和向量一起上混合检索才稳只用向量检索常见的毛病是模型对专有名词不敏感比如一个只有“C-302号耗材”这种特殊编码才会出现的问答向量检索可能召回一堆包含“耗材”但没有具体编码的片段而真正的答案因为编码在文本里低频出现被漏掉了。这时候需要传统的关键词检索来补位。混合检索的做法一般是同时跑两路召回BM25关键词检索适合记住精确词、编号、拼写变体。向量语义检索适合找到语义相同但表述不同的内容。然后把两路结果合并。最简单的合并方式叫RRFReciprocal Rank Fusion给每个结果按排名赋权第一名的分数是1第二名是1/2第三名是1/3以此类推然后把同一文档在两路中的分数相加取Top-N。这样做不需要调权重稳定且实现简单。一段关键的RRF代码思路def rrf(ranked_lists, k60): scores {} for ranked in ranked_lists: for rank, doc_id in enumerate(ranked, start1): scores[doc_id] scores.get(doc_id, 0) 1 / (k rank) sorted_docs sorted(scores.items(), keylambda x: x[1], reverseTrue) return [doc_id for doc_id, _ in sorted_docs]混合检索之后通常还需要做一次精排。也就是用重排序模型把召回到的几十个候选重新打分挑出相关性最高的5到10个送给模型。开源社区常用bge-reranker系列效果明显。我的经验是加了重排之后生成质量通常会有肉眼可见的提升代价是多了一次模型推理带来几十到几百毫秒的延迟属于可以接受的成本。3.4 上下文注入给模型材料的顺序和结构也有讲究检索出来的片段不能随便拼在一块就丢给模型。通常的做法是在每段前添加来源说明告诉模型这是“某种文档”的一部分并且禁止模型编造文档里没写的内容。举个例子参考信息按重要性排序 [1] 《员工手册》第3章第2节年休假说明 片段内容... [2] 《HR问答-2025》第42条请休假常见问题 片段内容... 请仅根据参考信息回答用户问题如果参考信息中没有提及请明确回答“未在参考中找到相关内容”。这样做有几个好处模型能根据来源判断语气和格式溯源方便回答中可以带出引用编号同时在提示词里限定边界能适当减少幻觉。4. Agent与RAG的融合从“每次先检索”到Agent自己决定什么时候查4.1 固定RAG是直通车Agent时代需要的是智能调度普通RAG的调用路径是死的用户一问就检索一遍然后生成。但在真实Agent场景里问题往往是动态的。比如用户说“帮我整理一下最近的报销数据顺便看看新制度下哪些单据需要重新走流程”。这个问题至少要拆成两步先查找报销数据再查找新制度并对齐。如果只用一次性检索很难拿到跨多个来源的完整信息。Agentic RAG的思路是把“是否检索、检索什么、检索几次”交给Agent通过推理决策。Agent根据自己的任务拆解动态决定调用RAG工具的次数和查询词。这相当于把RAG从一个管道变成了一个可编排的工具。4.2 给Agent加一个“查资料”的技能在实践里最简单的做法是把RAG封装成一个工具让Agent在ReAct循环中自主调用。在LangChain或LangGraph里这个工具就是一个普通的Tooldef search_knowledge_base(query: str, top_k: int 5) - list[str]: # 内部实现混合检索 - 重排 - 返回片段列表 return docs tools [Tool(name知识库检索, funcsearch_knowledge_base, description当用户问题涉及内部制度时使用)] agent create_react_agent(llm, tools)你可以给工具加上一个描述告诉模型“这个工具适合查找内部文档例如制度、流程、FAQ”。模型会在需要时调用它而不是每次用户说什么都先去检索。这样也能让Agent在处理开放性话题时不浪费检索资源减少无关上下文干扰。4.3 多跳检索、查询重写和结果验证Agent与RAG结合后玩法就多了查询重写Agent在检索前根据对话历史改写用户问题。用户说的是“那项目金怎么报”“那”指的是上文中的“2025年项目奖金制度”不改写的话检索不到。多路检索一个问题同时查几个不同库比如“报销QA库”和“财务政策库”然后把结果汇总交给模型合并生成。多跳检索第一轮检索结果里提到“参见《差旅管理办法》”Agent判断需要再去检索《差旅管理办法》然后结合两份文档回答。结果验证Agent生成回答后再让模型对回答中的关键段落和检索来源做一致性比对发现冲突就重新检索或修正。这些能力让RAG不再是一条被动的管道而真正成为Agent的“手和脚”。这也是“技能Skill怎么和RAG结合”这种问题经常被问到的原因。实质上就是让Agent能主动检索、多次检索并把检索结果和已有信息编排成新的答案。4.4 记忆、对话历史和RAG的组合顺序Agent和RAG组合最常见的问题之一是对话历史污染。用户上一句问“春节放假那你觉得机票价格会涨吗”Agent在第二句检索“机票价格”时如果把整段历史都拼进查询里检索接口反而混乱。所以设计上要区分长期记忆放进RAG的上下文中短期对话历史只用于查询改写而不是一股脑传给检索。我的经验是RAG工具内部单独维护一个“干净的查询词”。Agent在调用工具前会先对用户最新问题和对话历史做摘要提取一个和当前意图最匹配的检索Query这个Query才是真正发去PRAG检索。这样能兼顾上下文连贯和检索精准。5. 命中率低先检查数据侧这几个地方5.1 先搞清楚“命中率”是怎么算的深度学习圈子里喜欢说Hit Rate也就是“检索结果中包含正确答案的比例”。假设有100个测试问题每个问题从知识库里应召回对应的信息片段如果其中85个问题在Top-5检索结果里找到了准确内容那么Top-5命中率就是85%。这个指标能直观反映检索管道的质量。要注意命中率不等于最终回答准确率。因为即使检索到了正确内容模型也可能生成错误总结反过来检索到了相关内容但没完全对应模型也可能依靠常识答对。所以在评估RAG时我会同时看“检索命中率”和“最终回答质量”两个维度。尤其是要单独拆出检索环节做评测别把模型的错误都归咎于检索不到位。5.2 数据侧问题比模型侧更隐蔽很多团队算法调了半天发现难受点全在数据上文档内容没解析干净扫描版PDF没走OCR表格变成了图片内容检索不到。切块太机械把一句完整的话拦腰截断前面半句在后一个块后面半句在前一个块怎么都能错开。元数据丢失检索时想按部门、时间过滤但因为索引时没有写入元数据只能裸查全文。数据更新不及时旧版本库还在线上新制度已经发布。Agent检索到老内容回答自然错误。有一个真实案例让我印象很深某企业做制度问答Agent问到“加班补贴标准”系统怎么都检索不到正确片段。排查后发现问题出在PDF里这个表格被转成了图片模型只看到了图片标题没有提取到表格内容。换用带表格识别能力的文档解析方案后问题瞬间消失。5.3 缓存、评估和持续迭代的平衡不要一上来就追求全自动化评估。先把RAG管道跑起来手工测试30到50个典型问题把检索结果打印出来看就能发现大多数问题。再到正式环境里收集用户反馈慢慢搭建一个评估集包含问题、期望答案、期望来源。每次改动切块或检索策略后在评估集上跑一遍确认命中率没有回退再上线。缓存也要谨慎。检索缓存可以缓存query - 检索结果节省重复请求的开销。但缓存必须设置过期时间而且数据更新时要主动失效相关缓存。否则用户以为系统坏了问到的永远是前几天被删掉的老信息。另外如果知识库里有一部分内容适合用知识图谱来承载比如复杂的实体关系“某项目的负责人是谁”“某供应商参与过哪些项目”可以考虑在图谱上做检索再把结果并回RAG链路中。这也就是目前经常提到的GraphRAG、本体增强RAG的方向。它不适合所有场景但如果你遇到大量多跳关系型提问值得试一试。5.4 我给新手的一条必看清单最后列一张落地清单照着做基本不会跑偏把知识库文档统一命名明确版本号和更新时间。解析时优先保住表格和代码块不要只输出纯文本。切块参数先从chunk_size500, overlap50开始再根据命中率调。用中文适配的Embedding模型至少在100个真问题上验证效果。第一版就上混合检索BM25向量两个结果用RRF融合。在送入模型前做一次重排Top-K选5到8个片段。给每个片段保留来源元数据回答时带出处。用评估集持续监控命中率任何改动都在上线前跑回归。我个人做RAG项目的最大体会是这个技术看起来简单真正堆到生产环境里四处漏水的地方一定都在数据准备和检索细节上。模型的能力早就够了能让你翻车的永远是你没洗干净的那份PDF或者选歪了的那把小刀。把RAG这条知识获取管道做扎实了你的Agent才算真正“接上了地气”。下一步再往上做工具调用、任务规划、多智能体协作才有稳定的地基。如果你正在从0到1搭自己的Agent我建议先把这篇讲到的管道跑通再想那些花活。数据入口稳了后面每一步都会顺很多。