AI Agent的知识获取管道:RAG基础原理与工程实践
发布时间:2026/9/30 18:35:00 锦皓数字建站

聊到 AI Agent很多人第一反应是规划、工具调用、记忆维护这些模块。但真正在业务里跑过几个 Agent 之后你会发现一个很扎心的现实Agent 的推理能力再花哨知识跟不上照样给不出靠谱答案。这一篇是我“走进 AI Agent”系列的第四篇核心就一个主题——知识获取管道RAG 基础。RAG 全称 Retrieval-Augmented Generation检索增强生成本质上就是给大模型外挂一个可查的资料库让模型在回答前先去检索相关内容再基于这些内容组织答案。它能解决的是大模型知识截止、私有资料缺失、以及回答时一本正经胡说八道这三类典型问题。这篇文章适合两类人一是准备给自己或团队搭建 Agent 但不知道知识部分从哪下手的人二是已经在用 LangChain 之类的框架、想系统把 RAG 捋清楚的开发者。我会按原理 → 最小实现 → 进阶形态 → 踩坑复盘的节奏来讲尽量让你看完就能上手复现。1. 先把 RAG 讲明白为什么 Agent 离不开知识获取管道1.1 从“模型什么都知道”到“模型需要查资料”大模型刚火起来的时候很多人的认知是一个模型就是万能的你问什么它都能答。这个认知在闲聊场景下问题不大真正做业务就露馅了。你让 Agent 去回答我们公司最新的报销流程是什么它不可能知道——模型训练数据里根本没有你们公司的内部文档。你让它去查某某型号设备的质保政策它可能给你编一个听上去很有道理、但实际完全不存在的规定。这就是知识截止和幻觉问题本质是模型的知识来源太单一了。要解决这个问题思路其实和带新人很像。一个刚毕业的实习生进公司你直接把他丢到客服岗位他能答出来的全都是大学教材里那点东西一问到公司内部流程就懵。这时候正确的做法是什么给他一套公司内部的文档系统告诉他客户问什么先翻这些资料翻到了再回答翻不到就承认不知道。RAG 就是给大模型配上了这样一套内部文档系统只不过这个过程被工程化了把文档切块、向量化、存进索引然后在每次回答前做一次检索把命中的内容拼进提示词里让模型基于这些材料作答。这也是为什么我把 RAG 叫做知识获取管道。在 Agent 的整体架构里规划模块决定怎么拆解任务工具调用模块决定用什么外部能力而知识获取管道回答的则是模型回答问题时从哪儿拿知识、怎么拿、拿到多细。这个管道决定了一个 Agent 回答的准确性和可信度比很多花哨的调度逻辑都重要。1.2 RAG 的三段式流程索引、检索、生成把 RAG 拆到最细其实就是三个环节索引、检索、生成。索引阶段是离线完成的你把一批文档准备好清理掉无关信息切成一个个小块然后把每一块文本用 embedding 模型转成向量连同原文和元数据一起存进向量数据库。检索阶段是在线发生的用户提问后先把问题也转成向量然后去向量数据库里做相似度搜索找出最相关的几个文档块。生成阶段就更好理解了把检索到的文档块拼成一个限定性的上下文连同用户的原始问题一起交给大模型让它只基于这些内容来回答。这里有个很关键的认知误区很多人以为 RAG 就是把文档塞给大模型让它读。这种做法不是 RAG是超长上下文硬塞。一来不是你文档都能塞进上下文窗口二来大模型在超长上下文里对中间信息的注意力衰减很严重塞得越多越容易答偏。RAG 的价值在于通过检索把海量文档压缩成每次只需要看三五块、总共几千字的核心片段。换句话说RAG 不是让模型读完全部资料而是让模型每次只读当前最该读的那部分。我常打一个比方RAG 像是图书馆里的检索员你问一个问题检索员先去书架上把相关的三五本书翻出来翻到对应页再把这几页递给翻译官翻译官基于这几页内容给你一个准确答复而不是让翻译官把整个图书馆背下来再回答。这个比喻也解释了为什么 embedding 选择和检索策略如此重要——检索员找得准不准直接决定了后面的一切。1.3 它跟 Agent 是什么关系很多人把 RAG 和 Agent 分开谈好像它们是两个互相竞争的技术实际在真实项目里RAG 往往是 Agent 的一个子模块或者说是 Agent 能调用的一个知识工具。你在设计 Agent 时通常会给它挂上几个能力查天气的 API、查数据库的工具、执行代码的脚本。RAG 在这个体系里就是一个查文档的工具——输入一个问题输出一堆相关文档片段。Agent 决定什么时候调用这个工具、调完之后怎么利用检索结果这就是后面要讲的 Agentic RAG。所以在看完这一篇基础原理后你再回头看 Agent 项目里的知识部分思路会跟看黑盒完全不同你能知道为什么这个 Agent 答不上某个问题、该去调哪个环节而不是一味地怀疑模型不够强。2. 搭建一个最小可用的 RAG从零到能跑的完整过程2.1 技术选型框架、向量库、模型怎么配新手第一个问题通常是我该用什么框架。我的建议很直白练手阶段不要纠结直接在 LangChain 或 LlamaIndex 里选一个先用最快路径跑通再去研究内部实现。LangChain 生态最成熟、教程最多遇到问题随便一搜就有答案LlamaIndex 对文档索引的处理更精细如果你重点是做知识库而不是 Agent 编排它可能更顺手。国内团队如果考虑中文生态和企业集成可以看 Spring AI 或者 AgentScope 这类项目——它们对国产模型和本地部署支持得更好。向量库的选择相对简单。纯本地练手用 Chroma 或 FAISS 就够了代码量少、不需要额外起服务正式项目里常见的是把向量存进已有的存储系统比如 PostgreSQL 的 pgvector、Redis 的向量搜索或者单独的 Milvus。选型逻辑不是哪个最新用哪个而是看你的数据量、并发量和已有的技术栈。数据量在百万级以下、并发不高pgvector 完全够千万级以上、并发要求高再上 Milvus。模型这边有两类一个是 embedding 模型负责把文本转成向量一个是生成模型负责最后组织答案。中文场景我非常推荐 BGE 系列如 bge-m3或者国产的 text2vec它们在中文语义上的表现比很多英文原版模型好不少。生成模型可以用 OpenAI、Claude国内则很成熟地接 DeepSeek、通义千问、智谱 GLM 这些。有一点要注意embedding 模型和生成模型没有绑定关系你完全可以用 bge-m3 做向量化再用 DeepSeek 做生成这在实际项目里很常见。2.2 数据准备的三个关键点清洗、切分、元数据数据准备是 RAG 里最不性感但最决定成败的环节。我做过好几个知识库最后发现 70% 的答案质量问题都出在数据没处理好而不是模型不行。第一清洗。文档里经常混着页眉页脚、导航文字、表格错位、重复段落这些噪声不剔除向量化后会把检索结果带偏。表格尤其麻烦直接转成纯文本经常读不通建议把表格转成 Markdown 格式或者字段值的键值对描述再进知识库。图片里的文字信息更要小心如果文档里大量是产品说明书截图你得考虑接 OCR否则那些内容模型根本看不见。第二切分。这是新手最喜欢问、也最爱出错的地方。切分策略直接影响检索命中率。块太大一块塞进好几页内容向量变成一个四不像检索出来相关性不高块太小语义被拆碎检索可能漏掉关键句。常规经验是块大小chunk size在 300800 字之间块与块之间重叠overlap控制在 10%20%。这个范围不是拍脑袋定的它跟 embedding 模型的能力和上下文窗口有关——太小丢语义太大了提示词里放不下几块。我强烈建议用递归字符切分器RecursiveCharacterTextSplitter让它按段落、句号、逗号这样的层级来拆而不是固定按字数硬切。如果文档本身有清晰的 Markdown 结构也可以按标题层级来切把同一个二级标题下的内容作为一个块。另外务必要给每个块加上元数据来源文件名、页码或章节标题、更新时间。这些信息一是能帮你做碎片的追溯和引用溯源二是在检索后可以按元数据过滤比如只搜近一年的文档、只搜某类产品的说明。第三别忘了增量更新。知识库不是建一次就完事了文档会改、产品会迭代、政策会调整。如果你每次都是全量重建索引数据量大之后会非常痛苦。所以设计数据管道时我会建议从第一天就给每个文档块加一个内容哈希和版本号检测到文档变更时只删掉旧块、写入新块而不是整个集合重建。这个习惯能让你少踩很多坑。2.3 索引与检索embedding 的差异和召回的核心数据准备完之后进入索引。这里要留意不是所有文本都适合用纯向量检索。例如设备型号 A100 的保修期是几年这类含精确编号的问题语义检索往往不如关键词检索。这时候有多种选择一种是上混合检索Hybrid Search把向量检索和 BM25 关键词检索结果做个融合比如 RRFReciprocal Rank Fusion 算法另一种是给元数据里加上编号、型号等精确字段在检索时先用过滤器圈定范围再做语义搜索。我在真实项目里流程通常是先元数据过滤再混合检索最后按相关性分数倒序取TopK。embedding 模型的选择也要讲究。不同模型映射出的向量空间不同维度从 768 到 1024、2048 不等直接影响相似度计算的粒度。中文场景我踩过的坑是早期直接用某个英文 embedding 模型处理中文文档检索时经常出现意思相关但文本完全不搭的结果换到 bge-m3 之后命中率明显提升。所以选 embedding 模型时一定要拿你自己领域的文档做个小样本测试不能光看榜单分数。检索时还有一个容易被忽略的参数TopK 取多少条。取太少可能漏掉关键信息取太多噪声增大、生成模型反而不聚焦。我一般先取 35 条然后看答案质量再往上加。对于多步推理任务topK 可以放宽到 68 条让上下文更丰富一些。另外检索的相似度分数不要直接当置信度看因为不同 embedding 模型的分数分布差异很大0.7 在这个模型里很高在另一个模型里可能只是中等水平。2.4 最小实现代码一版能跑通的主流程下面给一段最小可运行的核心流程代码基于 LangChain 加 Chroma。代码本身不复杂但你把这段跑通了RAG 的主链路就算完整落地了。注意这里省略了 API Key 配置你需要根据自己选的模型补上。from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceBgeEmbeddings from langchain_community.vectorstores import Chroma # 1. 加载文档以本地 txt/md 为例 with open(knowledge_base.md, encodingutf-8) as f: text f.read() # 2. 切分按段落和句子层级递归切分块间保留 10% 重叠 splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap80, separators[\n\n, \n, 。, , , , , ], ) chunks splitter.split_text(text) # 3. 向量化本地运行无需外部 API embedding_model HuggingFaceBgeEmbeddings( model_nameBAAI/bge-m3, model_kwargs{device: cpu}, encode_kwargs{normalize_embeddings: True}, ) # 4. 存入向量库直接指定持久化目录 vector_store Chroma.from_texts( textschunks, embeddingembedding_model, persist_directory./chroma_db, ) # 5. 检索query 先向量化再余弦相似度搜索 TopK query 我们的报销流程是什么 retrieved vector_store.similarity_search_with_score(query, k4) for doc, score in retrieved: print(fscore{score:.4f} | 内容片段: {doc.page_content[:50]}...)检索出来的片段再拼成提示词交给生成模型通常长这样from openai import OpenAI client OpenAI(api_keyyour-api-key, base_urlhttps://your-endpoint) context \n\n---\n\n.join([doc.page_content for doc, _ in retrieved]) prompt f请仅根据以下参考材料回答问题。如果材料中没有相关信息请直接说明“资料库中未找到相关内容”。不要编造。 参考材料 {context} 问题{query} response client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], ) print(response.choices[0].message.content)这段代码有几个细节值得展开说说。separators的排序是有讲究的它代表切分的优先级先尝试按双换行切切完还超过 500 字再往下按单换行、句号、逗号逐级拆这样能最大程度保住语义完整。normalize_embeddingsTrue这个参数会在向量化后做归一化这样点积等价于余弦相似度分数更稳定。Chroma 的persist_directory会把索引落到本地磁盘重启程序后不用重建——这个在调试阶段特别实用。跑通这段代码之后建议你做个小小的验证实验准备 20 条测试问题一半是文档里能找到明确答案的一半是完全没有答案的然后用你搭好的管道跑一遍人工记录每个问题回答是否准确。这就引出了下一节要讲的评估指标。3. 别把 RAG 当死管道Agentic RAG 与知识管道进阶3.1 基础 RAG 的四个不痛快基础 RAG 这套流程跑通后很快会遇到四个让人挠头的情况。第一个是多跳问题。用户问上季度华东区销量最高的产品它的售后政策有什么变化这需要先查出哪个产品销量最高再拿产品名去搜售后政策。基础 RAG 只做一次检索通常会漏掉第二跳的信息。第二个是问题重写缺失。用户说那它的价格呢代词它在检索时被向量化向量库里如果没有上下文的话检索效果就会很差。第三个是路由缺失。知识库里有产品手册、有财务制度、有客服话术用户问财务问题你却跑去产品手册里做检索浪费时间还答不准。第四个是检索次数固定。基础 RAG 不管问题多简单多复杂都只检索一次、只取固定数量的文档块遇到简单问题过度检索引入噪声遇到复杂问题又检索不够。这些不痛快本质上是同一个问题RAG 被设计成了固定管道而不是动态决策过程。它不知道用户想干嘛也不知道自己检索的结果够不够用。3.2 升级思路检索即工具Agent 自己做决策Agentic RAG 的解决思路简单说就是不要写死每次检索的时机和次数而是把检索知识库封装成一个 Agent 可以反复调用的工具由 Agent 根据当前对话状态决定要不要检索、检索几次、检索完之后还缺不缺信息。这个看起来只是架构上的小调整实际效果差别很大。举几个我在项目中验证过的模式Query Rewriting查询重写Agent 在检索之前先根据对话历史把那它呢改写成完整的问题华东区上季度销量最高的产品的售后政策有什么变化然后再做检索。这一招对多轮对话效果提升非常明显可以配合一个小模型来做重写。Query Routing查询路由Agent 先判断这个问题的意图决定走哪个知识库或哪种检索方式。比如判断是财务类问题就走财务索引是产品问题就走产品手册甚至可以决定要不要走混合检索而不是单纯向量检索。路由判断用轻量的分类模型或者干脆再调一次大模型都可以。Multi-step Retrieval多步检索Agent 把查产品销量和查售后政策拆成两步每一步都走检索 → 判断是否足够 → 不足则继续检索的循环最后再把两步结果汇总给生成模型。这对应到实际场景就是前面说的多跳问题。Self-RAG 与 Corrective RAG 这类思路也值得了解。Self-RAG 让模型在回答时给自己生成检索标记决定哪些地方需要检索、哪些地方可以直接回答回答完再对自己生成的答案做评分。Corrective RAG 则是在检索之后加一个质量评估器如果觉得检索结果跟问题不相关就触发重新检索或者改用别的搜索方式。这些做法本质上都是把决策权从开发者硬编码的逻辑手里部分交给了 Agent 运行时。3.3 RAG as Service 与知识中台当 RAG 不再是某一个 Agent 的附庸而是被多个 Agent 共享时它的形态会继续演变。2026 年再看这个方向一个明显的趋势是RAG as Service——把知识获取管道单独抽出来做成一个服务层对外提供统一的索引、检索、更新接口内部管理多个知识库、多套 embedding 模型和多种检索策略。比如 AgentScope 2.0 里对 RAG 能力的构建就是把整个知识管道服务化不同的下游应用只需对接一套 API不用自己重复搭建索引和检索逻辑。这个思路背后是工程上的复用需求。当一个企业里同时跑着客服 Agent、运维助手 Agent、内部问答 Agent 时如果每个 Agent 都自己搭一套 RAG数据和计算成本都是浪费。抽成中台之后知识库统一维护、检索能力统一升级、权限统一管控各 Agent 只负责决定什么时候调、怎么用检索结果整个体系会清爽非常多。我在企业内部落地时对这种中台化收益感受很深业务方只关心文档有没有更新到位算法团队只关心检索准确率有没有变化上层 Agent 团队只关心接口契约稳不稳定各干各的不再互相拖累。3.4 衡量管道好坏的指标不只是 hit rate聊 RAG 评估时大家最常挂在嘴边的是 hit rate命中率。这个概念本身不复杂检索返回的结果里有多大比例包含回答问题的正确答案。计算方式可以这样定义对一组测试问题每个问题标注出答案来自哪个文档块然后看系统检索返回的 TopK 里是否包含该块。如果 100 个问题中有 72 个问题的正确块出现在检索结果里那么 hit rate 就是 0.72。但我要提醒一句hit rate 只是检索阶段的指标评估的是资料有没有找到不评估答案说得好不好。后者要看忠实度faithfulness和回答正确率。忠实度指的是模型生成的答案是否严格基于检索到的资料有没有添油加醋回答正确率则是从用户视角看的最终答案质量。一个完整的 RAG 评估体系至少应该包含这三个层面检索层看 hit rate 和 MRR平均倒数排名生成层看忠实度和相关度端到端可以再做用户满意度的人工评估。如果你需要量化 hit rate一个简单的做法是构造一份带黄金块的测试集# 测试集格式假设问题 - 正确答案所在块的 ID检索结果 - 命中的块 ID hit_count 0 total len(test_set) for q, gold_chunk_id in test_set.items(): retrieved_ids retrieve(q, top_k4) if gold_chunk_id in retrieved_ids: hit_count 1 hit_rate hit_count / total这个值如果低于 0.6通常说明检索环节存在较大问题优先排查 embedding 模型、切分策略和检索模式是不是该上混合检索0.7 以上算是勉强可用但要继续优化到 0.8 以上才敢放到生产环境。实际项目的目标线不能一刀切文档数量越多、问题类型越杂hit rate 的下限会越低所以关键在于你的测试集要贴近真实用户的问题分布而不是自己随手编几个 QA。4. RAG 实战中的常见坑与排查实录4.1 高频故障速查表先给一张速查表你遇到问题可以直接对号入座。症状可能原因优先排查方向检索结果明显不相关embedding 模型与文档语言/领域不匹配换中文/领域专用 embedding做小样本对比测试答案能找到但总是答偏切分块过大或跨主题调小 chunk_size按标题层级切分观察具体切分点文档里明明有答案回答却说没有检索 topK 太小或检索模式单一增大 TopK开启混合检索检查元数据过滤是否误伤答案编造事实生成时限制了上下文但模型自行发挥提示词里强调仅基于资料可加约束模板检查忠实度多轮对话中答非所问检索时没有带入对话历史在检索前加入查询重写/多轮改写步骤不同用户问相似问题结果差异大向量库中混入了未清洗噪声或重复内容清洗数据、去重、加内容哈希校验知识更新后回答还是老版本索引没有增量更新检查更新管道按文档版本号重建受影响的块这张表列出来的问题有一半是模型本身能力不够更多时候其实是数据管道和信息架构没做好不要一上来就怀疑模型。我见过不少团队把预算砸在换更强的大模型上但最后发现换回小模型、修好切分和检索后效果反而更好。4.2 排查流程与具体操作遇到线上回答质量不行我的排查顺序通常是固定的先看检索再看生成最后才看模型。第一步把检索结果全部打印出来人工看一眼。如果检索到的 3 块内容跟问题毫不相关那问题在检索层继续排查 embedding、索引内容和切分逻辑如果检索到的内容看起来对但最终回答还是不对那问题在生成层。第二步单独测检索。把问题和库里已知正确的那块文档做相似度比对看分数是否正常。如果分数异常低说明 embedding 对这块领域文本理解得不好。这时可以做一个小实验把同一段文档用不同的 embedding 模型各向量化一次与问题向量算相似度横向对比哪个模型分更高。别迷信排行榜亲手跑一遍最清楚。第三步用固定检索结果来测生成。手动把正确的文档块拼进提示词让模型生成答案。如果模型用完全正确的资料还是答错提示词约束或者模型能力的问题如果模型正常作答说明检索层输出的上下文噪声太大影响了生成。这个步骤看起来很笨但能帮你快速把故障范围缩小一半。第四步观察日志里的真实查询。很多线上问题不是技术问题而是用户问法跟测试集差太远。把近一周线上日志里的低满意度 query 抽出来扩充进测试集再迭代优化比闷头调参数有效得多。4.3 我的几条实操经验最后分享几条自己踩出来的经验不一定写在文档里但我觉得比很多官方教程实用。第一条不要把用户原始问题直接拿去检索除非对话只有一轮。多轮场景下先处理指代和上下文哪怕只是简单把最近几轮提问拼到一起效果都会好很多。我早期做的知识库上线后发现 30% 的问题都带这个它那这类指代词全是靠重写解决的。第二条混合检索的收益比大多数人想象得大。纯向量检索在中文语义理解上已经不错但遇到精确型号、人名、政策编号时经常抓瞎。加上 BM25 关键词召回再做融合击中率能提高 510 个百分点。实现上也不复杂LangChain 里可以直接配EnsembleRetriever把向量检索器和关键词检索器组合起来。第三条切分不能只看字数要看语义边界。固定 500 字切出来中间可能把一个完整的表格从中间劈开或者把以上条款自发布之日起生效这种总结句拆到下一个块里。我的做法是先看切分结果的可读性再定参数而不是只盯着数字调。如果文档格式稳定我更推荐按 Markdown 标题做结构化切分把同一小节完整保留。第四条关于成本检索阶段的性能优化空间比生成阶段大得多。瓶颈往往不出在模型推理而出在 embedding 计算、向量检索索引构建和文档解析这些脏活累活。把向量化做成异步管道、给向量库加缓存体感响应速度能快很多。每次做完一个 RAG 项目我都会翻回去看最初那版跑通主流程的代码很多东西都已经换过了——切分参数改了、检索器加了混合、提示词变成了动态模板。但核心流程没变文档进 → 切块 → 向量化 → 检索 → 增强生成。这个骨架是很稳定的后续的 Agentic 改造也只是在这样的骨架上加路由、加重写、加评估、加决策。所以别急着一步到位先把基础版本跑起来数据质量抓起来指标测起来再一步步往上叠能力。知识获取管道这件事慢就是快。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。