
做AI Agent的朋友大概率都有过这种经历模型本身能力很强但一聊到具体业务就像个刚入职的新人啥都不知道。我早期做企业内部知识问答时试过把文档全文塞进上下文结果token直接爆掉回复还满嘴跑火车。后来才意识到问题出在缺少一条正经的知识获取管道——而这正是RAGRetrieval-Augmented Generation检索增强生成真正要解决的事。这是走进AI Agent系列第四篇我把RAG基础拆开讲清楚它是什么、管道里每个环节怎么选、实际搭建会踩哪些坑以及怎么从RAG走向Agentic RAG。这篇文章适合两类人一类是刚接触Agent开发只听过RAG这个词想知道它到底怎么运转的另一类是已经用LangChain之类框架跑通过demo但觉得效果不稳、想深入理解原理的人。我会从实际项目经验出发把索引端、查询端、模型选型、检索策略这些环节一一拆开尽量不用论文式的弯弯绕保证你读完就能照着落地。1. AI Agent为什么离不开RAG这条知识管道1.1 先理解瓶颈参数式知识的天花板现在的LLM确实很强但你得承认它的知识是凝固的——所有东西都塞在模型参数里训练完成那一刻就定了。哪怕GPT-4级别的大模型回答最新的财报数据公司内部的审批流程某个产品线的实时库存这类问题时它要么老实说不知道要么就开始编。这就是所谓的幻觉。我经常打一个比方模型像是一个读过一万本书的聪明人但它没有任何工作经验也没看过你们公司的邮件和会议纪要。你问它行业通识它能聊得头头是道你问它咱们公司报销单要填几个字段它只能猜。这种问题的本质是参数式知识的天花板知识有截止日期、有领域边界、有私密性。想让Agent真正落地到业务里就必须给它一条从外部世界获取实时、精准、且私有知识的管道。1.2 RAG在Agent架构里的定位查询时的外挂大脑RAG的思路其实很朴素既然模型脑袋里没有这些知识那就在它回答之前先把相关的资料从外部知识库捞出来塞进上下文里让它带着答案作答。这个先捞再答的过程就是Agent架构里的知识获取管道。Agent的决策循环可以拆成感知-思考-行动而感知环节最核心的信息来源就是这个管道。业务Agent问客户报修了应该怎么处理它先去RAG管道里检索故障处理手册拿到SOP片段再结合手册内容生成回复。RAG的价值不只是补充知识它还给Agent带来了两个关键能力一是可溯源——回答的结论可以关联到具体文档片段这对企业内部场景极其重要二是可更新——文档变了重新索引就行不用重新训练模型。1.3 为什么是管道而不是一次性拼接很多第一次接触RAG的人会觉得这不就是拼提示词吗把检索结果塞进prompt让模型回答有什么复杂的如果只做过一两次demo确实如此。但一旦进入生产环境你会发现这条链路里每一个环节都可能让最终答案变味文档格式乱七八糟、切分方式不对、向量检索召回了一堆噪声、用户提问的表达方式和文档不一致……这些问题不是靠改一句prompt能解决的。所以我才把它叫知识获取管道。它是一整套索引、存储、检索、排序、生成的流水线每一环都有独立的优化空间。这也是为什么很多RAG框架LangChain、LlamaIndex、Spring AI甚至AgentScope 2.0提出的RAG as a Service都在卷这块——因为这是Agent落地最硬的地基。2. RAG管道的五段式拆解每一环都可能让结果崩掉2.1 第一环文档加载与清洗管道的第一站是把原始资料变成可处理的文本。这里最大的坑就是以为加载完就完了。PDF翻页提取出来发现段落是碎的、表格乱码、图片里的字全丢了这是常态。Word文档可能混着批注和修订痕迹HTML里全是导航噪音。我处理过一份企业内部制度汇编PDF解析出来每句话后面都跟着一个换行符如果直接拿去切分语义会被切得稀碎。所以正规做法是加载完必须做清洗——去掉页眉页脚、合并断行、识别表格结构、必要时用OCR处理扫描件。这一步虽然没有太多技术含量但决定了后面所有环节的上限。资料都不干净后面检索得再准也白搭。提示清洗时建议保留文档的来源信息文件名、页码、章节号作为元数据。后期做引用溯源全靠这个。2.2 第二环切分策略决定检索粒度切分chunking是整个RAG里最容易被低估的一环。切多大、怎么切直接决定检索召回的内容是刚刚好还是差一点。最常见的做法是固定长度切分比如每500个token一段各段之间重叠100个token。重叠的作用是防止某句话刚好被拦腰截断导致信息缺失。但固定切分的缺点也很明显它不理解语义边界可能把一段完整的故事切成两半也可能把两个毫不相关的话题凑在一起。更聪明的做法是按结构切分。Markdown标题、HTML的h1/h2、PDF里的章节小标题都是天然的切分边界。比如一个产品文档按## 功能说明这种二级标题切出来的块几乎就是一个完整的知识单元。还有按语义切分的方案原理是先让模型识别哪些句子属于同一个主题再决定切分点——效果好但成本高、速度慢大部分场景用不上。我给一个经验值通用问答场景chunk_size建议在300-500个token之间overlap设置为50-150个token。如果你做的是需要强上下文的场景比如长合同条款分析chunk要适当调大如果是FAQ这种短平快的问题chunk可以再小一点。2.3 第三环Embedding模型怎么选Embedding是整个管道里把文本转成向量的关键。选错模型后面检索效果直接打折。选型时要考虑几个维度模型的语言能力、输出向量维度、领域贴合度、以及部署方式。中文场景下我实测过的开源模型里BGE系列比如bge-large-zh和M3E在中文语义检索上表现稳如果是全球化内容OpenAI的text-embedding-3-small和Cohere的Embed v3也很成熟。这里没有绝对最优关键是要在你的领域数据上做验证。有一个容易被忽略的点Embedding模型和底座的LLM不一定要绑定同一家。你现在用GPT-4做生成检索向量完全可以本地部署一个开源的BGE模型两者互不干扰。向量维度也不一定越高越好高维度带来更高精度但存储和检索成本也上去了——很多生产系统会做降维比如把1024维压到256维效果损失很小但性能提升明显。最后强调的是如果预算和隐私允许尽量在垂直领域数据上对Embedding做微调。通用Embedding在专业术语上经常表现一般微调之后命中率能提高不少具体数据我在第5章问题排查里会说。2.4 第四环向量数据库选型向量数据库负责把Embedding结果存起来并在查询时快速找回最近邻。市面上的选择很多但场景不同答案完全不同。先说本地方案。Chroma和FAISS适合原型验证和小规模个人项目部署简单装个包就能玩。我之前做过一个内部Demo只用Chroma存了几千条文本片段检索速度毫秒级完全够用。生产级场景推荐Milvus或Qdrant。它们支持分布式、数据量大、有完善的权限控制和监控。Qdrant的过滤能力很强可以方便地按元数据比如时间范围、部门标签做筛选Milvus在超大规模上亿向量下性能优势明显。Pinecone和Weaviate也是好选择主要看你团队更熟悉哪套运维体系。这里有一组通用指标供参考单条向量存储的物理开销、检索P99延迟、以及是否支持混合检索向量全文。很多向量库正在把BM25全文检索也做进去这直接关系到下一环节的检索策略值得认真考虑。2.5 第五环检索策略与重排检索是RAG管道里最能体现功力的环节。最简单的是纯向量检索query转成向量在库里找余弦相似度最高的几个片段。问题在于向量检索擅长语义相似但不擅长精确匹配。比如你搜CRM系统报错代码E2001向量检索可能召回一堆系统报错解决方案却偏偏漏了精确提到E2001的那一段。所以生产环境基本都会采用混合检索向量检索 BM25关键词检索再用RRFReciprocal Rank Fusion这样的算法把两路结果融合排序。检索出来的结果还不是终点——Top 1的不一定是最相关的需要再加一个Rerank重排模型把候选片段按相关性重新排序截取Top K送入生成。我在实践里发现加了重排之后RAG答案的准确率能提升10%-20%代价只是多了一次模型推理非常划算。但也要小心检索Top K不能贪多。塞太多片段进上下文不仅浪费token还会引入噪声模型反而不知道以谁为准。我一般控制在3-5个片段具体看场景复杂度。3. 实操从0到1搭一条可用的RAG管道3.1 技术栈选型与边界条件动手之前先明确技术栈。我这里用一个最常见的组合作为示例LangChain做流程编排、Chroma做向量存储、BGE或OpenAI Embedding做向量化、OpenAI或本地LLM做生成。这套组合的好处是组件都是Modular的每一步都可以替换适合学习也适合迁移到生产。如果你在Java生态Spring AI和LangChain4j的RAG模块也很成熟核心概念一致照着下面的流程改一下API调用方式就行。不用纠结选什么语言RAG管道的思想是通用的。3.2 索引端加载、切分、向量入库先看索引端的核心代码Python示例以伪接口形式展示方便你迁移到任意框架# 1. 加载文档 from langchain_community.document_loaders import PyPDFLoader loader PyPDFLoader(公司制度手册.pdf) documents loader.load() # 2. 清洗与元数据保留此处省略PDF清洗细节 for doc in documents: doc.metadata[source] 公司制度手册.pdf doc.metadata[page] doc.metadata.get(page, 0) # 3. 切分 from langchain.text_splitter import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个片段约500字符 chunk_overlap100, # 重叠100字符 separators[\n\n, \n, 。, , , , , ] ) chunks splitter.split_documents(documents) # 4. 向量化 from sentence_transformers import SentenceTransformer embed_model SentenceTransformer(BAAI/bge-large-zh-v1.5) texts [chunk.page_content for chunk in chunks] embeddings embed_model.encode(texts, normalize_embeddingsTrue) # 5. 存储到向量库 import chromadb client chromadb.PersistentClient(path./chroma_db) collection client.get_or_create_collection(company_policy) collection.add( ids[fchunk_{i} for i in range(len(chunks))], embeddingsembeddings.tolist(), documentstexts, metadatas[chunk.metadata for chunk in chunks] )这段代码里两个细节值得多说一句。第一切分器的separators顺序很重要。优先按段落\n\n切再按句子标点。切最后按空格——这个顺序保证切出来的块尽量是语义完整的段落。第二Embedding时做了normalize_embeddingsTrue这样后续用余弦相似度检索时可以直接用向量点积代替余弦计算性能更好。3.3 查询端检索、重排、拼装提示词索引建好之后查询端其实更考验策略def retrieve_and_answer(query, top_k5): # 1. query向量化 query_vec embed_model.encode([query], normalize_embeddingsTrue)[0] # 2. 向量检索 results collection.query( query_embeddings[query_vec.tolist()], n_resultstop_k, include[documents, metadatas, distances] ) # 3. 按距离过滤可选余弦距离阈值 filtered_docs [] for doc, dist in zip(results[documents][0], results[distances][0]): if dist 0.35: # 阈值需要根据实际数据调参 filtered_docs.append(doc) # 4. 拼装上下文生产环境建议在此之前加Rerank context \n\n.join( f[来源{meta.get(source)} 第{meta.get(page, ?)}页]\n{doc} for doc, meta in zip(filtered_docs, results[metadatas][0]) ) # 5. 生成 prompt f你是企业内部知识助手。请基于以下资料回答问题。 如果资料中没有相关信息请直接说“资料中没有找到相关内容”不要编造。 资料 {context} 问题{query} # 调用LLM生成以OpenAI为例可替换为本地模型 response openai_client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: prompt}], temperature0.3 ) return response.choices[0].message.content, filtered_docs这里最重要的不是代码本身而是两个设计决策。一个是距离阈值过滤。如果query向量和所有候选片段都不太近说明知识库里可能根本没有相关内容这时候与其让模型硬答不如直接告诉用户没找到。这就涉及RAG管道的拒答机制能有效减少幻觉。另一个是prompt里带引用来源。把片段的文件名和页码拼进上下文模型在回答时会更倾向于引用这些来源生成的答案具备可追溯性这在企业内部场景几乎是刚需。3.4 别忘了评估光跑通不算完RAG管道跑通只能说明有输出不能说明答得对。我见过太多人demo阶段兴致勃勃一到评估环节就抓瞎。评估维度至少有四个层级检索质量召回率、命中率、MRR、生成质量忠实度、答案相关性、端到端体验回答是否有引用、是否拒绝未知问题、性能成本延迟、token消耗。现在RAGAS这类评估框架很流行但我的建议是先准备一份50-100条的黄金测试集人工标注好标准答案和它对应的文档片段再跑自动评估。没有这份测试集谈RAG优化都是盲人摸象。我还习惯做攻击性测试问一些明显不在知识库里的问题以及一些与知识库相似但完全不同的问题看系统会不会乱答。很多RAG的幻觉不是出现在答不出的时候而是出现在答非所问却很自信的时候。4. 从RAG到Agentic RAG检索不再是一次性买卖4.1 传统RAG最大的坑一次命中就收工前面讲的基础RAG本质上是一个一次检索、一次生成的流程用户提问转向量检索Top K拼prompt生成回复。整个过程很线性没有反馈回路。这个模式在大多数文档问答场景下够用但一旦遇到复杂问题就会露馅。举个例子用户问上季度华东区销量最好的三个产品是什么——这个问题首先需要知道华东区在文档里到底对应哪些关键词其次可能需要同时查产品文档和销售数据表最后还要做聚合。一次从向量库里捞出几个片段根本拼不出完整答案。更麻烦的是检索质量本身不可控。有时候第一次检索出来的结果就是不对的但传统RAG没有反悔机制模型只能基于错误上下文硬答。这类问题靠调优不是不能缓解但治标不治本。4.2 Agentic RAG到底是什么Agentic RAG的核心变化是把检索这件事从一次函数调用变成智能体的一次行动循环。Agent不再是被动接收检索结果而是主动决定怎么检、检几轮、结果不满意怎么办。具体来说Agentic RAG通常具备这么几种能力查询改写与分解把复杂问题拆成多个子问题逐个检索再聚合。比如刚说的华东区销量最好的三个产品Agent会先检索华东区 定义再检索2025 Q3 产品销量数据组装答案。路由与工具选择不只是检向量库还可以选择查SQL数据库查产品API查搜索引续前端页面。Agent根据问题类型把请求路由到不同知识源。自我修正Corrective RAG第一轮检索结果不够好Agent会评估结果质量、改写查询词、重新检索甚至主动向用户追问澄清。多轮多步检索回答一个复合问题可能需要的不是一轮检索而是先得到A再用A去检索B的多步过程。这里面用到的技术模型包括Self-RAG让模型给检索内容打质量分决定用还是不用和CRAG引入检索评估器发现结果不可靠时触发修正流程等思路都是把检索策略本身变成了Agent可调用的工具。4.3 什么时候上Agentic RAG我不建议一上来就做Agentic RAG原因很简单会带来额外的延迟、token消耗和稳定性风险。如果你需要回答的问题大部分是从文档里找出某个信息这类简单问答基础RAG 一个Rerank重排已经能达到很好的效果。这时候硬上Agentic反而会拖慢响应速度、引入更多不确定因素。当你的典型问题满足以下任意几条时再考虑升级问题需要跨多个知识源、检索结果经常不理想但通过换关键词能搜到、用户提问非常口语化和模糊、需要支持多轮追问和上下文澄清。特别是知识库内容还在快速增长、结构五花八门的阶段Agentic RAG的自适应能力就显得很有价值。我目前在搭建多智能体系统时常用的做法是底层知识获取管道仍然是RAG但通过Agent的规划层来决定要不要检索、检索几次、检索结果是否足够。也就是说RAG负责稳定地提供知识Agent负责聪明地使用知识。这两者的边界正是Agentic RAG的设计精髓。5. 常见问题与排查技巧实录5.1 检索命中差先查这四件事排障时我通常按下列顺序排查命中率极高第一检查切分粒度。这是最常见的坑。chunk太大会引入大量无关句子检索的向量被噪声稀释chunk太小则可能让关键信息被截断。建议先从500字符左右开始再根据测试集调大调小。第二检查Embedding模型与领域匹配度。通用模型在不少垂直领域上效果不够好如果知识库术语密集比如医疗、法律、编程预算允许就做领域微调BGE和M3E都有对应教程。第三检查query和文档的措辞鸿沟。文档里写甲方应于30日内支付用户问多久要付款两句话在字面上完全没有重合纯粹靠语义向量可能拉不近。解决方案是加关键词/同义词表比如构建付款-支付-打款映射或者在索引端把别名也写入可检索字段。第四Top K太小。很多案例把Top K设成1-2结果第一个候选就不对根本没有重排空间。先设到5-8观察候选质量再逐步收紧。5.2 切分让人头疼几种特殊情况怎么处理常见场景里真正需要认真对待切分的是表格、代码块和长篇幅结构文档。表格直接把表格转成纯文本会丢失列结构和行列对应关系。我常用的办法是把表格转成带表头的Markdown语法让模型能读懂每一行的含义更复杂的情况可以按行切分每一行保留表头信息作为前缀。代码块代码是强结构文本必须保留缩进和换行建议使用专门的语言感知切分器。长文档比如合同、规章制度按标题层级切比按固定长度切有效得多。LangChain的MarkdownHeaderTextSplitter就是干这个的先用标题把文档切成大段再在大段内做精细切分既保留章节上下文又保证片段粒度可控。5.3 混合检索与重排实战数据说话我在一个客户项目的真实数据上做过实验用纯向量检索时Hit5约为72%加入BM25混合检索RRF融合后提升到81%再加上一个重排模型后Hit3直接到了88%。这说明单靠一种检索方式很难覆盖所有query类型——有的问题靠语义能搜到有的问题必须靠精确关键词匹配。这里给你一个实操模板候选阶段可以用宽松条件Top K取20左右向量BM25混合重排阶段再严格过滤最终只留3-5个送给LLM。这样既保证召回率又保证上下文干净。重排模型的选型上bge-reranker和Cohere Rerank都用过效果上互有胜负但bge在中文开源场景下更灵活、无调用成本。5.4 别忘了权限与安全知识管道的红线RAG的知识获取管道最容易忽略的是权限粒度。企业知识库有大量部门级、项目级甚至个人级的敏感资料如果检索时不去过滤文档可见范围等于把机密信息输出给了不该看到的人。我建议在索引端就把文档打上权限标签比如部门、机密级别查询时带上用户角色信息检索阶段就通过元数据过滤而不是在生成之后再做检查。简单说把权限控制前置到检索环节是效率和安全的最佳平衡点。另外不要在知识库里放任何不适宜公开的内容RAG管道会自动把检索到的东西拼进提示词任何资料都有可能被回答带出来这个红线必须守住。聊到这里RAG基础这条链路就完整了从文档清洗、切分、向量化、存储到检索、重排、生成再到Agentic RAG的演进路线每一步都有自己的门道。我个人在实际操作中最大的体会是RAG不是一个装好即用的组件而是一条需要持续调优的管道。跑通demo很简单但想让它稳定地服务业务你必须建立起自己的评估集和排障流程。最后再分享一个小技巧如果你的知识库是少量高质量文档与其纠结各种花哨的切分和重排不如先把文档质量提上去——格式规整、标题清晰、术语统一。很多时候知识管道的上限取决于你喂给它的原料有多干净。