ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI Agent知识获取管道:RAG全链路详解与踩坑指南

AI Agent知识获取管道:RAG全链路详解与踩坑指南 这个系列走到第四篇前面的内容基本把AI Agent的主体框架拆得差不多了——规划、工具调用、记忆管理都聊过。但你很快会发现不管框架搭得多漂亮Agent一遇到实际问题还是会翻车它不知道你公司的内部制度不知道你产品的参数表不知道昨天刚发布的行业数据。原因在于大模型的知识是训练时固化的它不会自己主动去找资料。想让Agent真正“知道”该知道的东西就得给它铺一条“知识获取管道”而当前最主流的实现方式就是RAGRetrieval-Augmented Generation检索增强生成。这篇我打算把RAG的基础讲透从它在Agent架构里的定位到数据入库、切分、向量检索、生成的全链路再给出一套能直接跑起来的最小实现最后把实战里踩过的坑一并列出来。适合两类人一类是刚学完Agent基础、准备给Agent接知识库的开发者另一类是已经在用LangChain、Spring AI或LangChain4j做RAG、但总感觉效果不稳定的朋友。内容偏实践理论部分我用大白话讲清楚尽量不让概念卡住你。1. 为什么AI Agent需要一条“知识获取管道”1.1 Agent的短板不是不会说而是不知道大模型本身就是一个“知识会被冻结”的系统。训练结束那天它知道的东西就定格了之后的世界它一概不知。你问它昨天刚发布的行业数据它要么含糊其辞要么一本正经地编。更麻烦的是企业内部的知识——财务制度、接口文档、售后话术——这些根本不在模型训练数据里模型天生就不可能知道。所以Agent如果不对接外部知识它所有的推理都是建立在“猜”的基础上。我用一个类比讲给新手听你请来一位见多识广的顾问他逻辑缜密、能说会道但一天都没在你公司上过班。你问他“我们公司的报销流程是什么”他答不上来只能根据通用常识给你编一套流程。RAG解决的事情就是在你问他之前把公司的《报销管理制度》递到他手上让他照着内容归纳、复述。这个“递资料”的动作本质上就是一条知识获取管道。这里有必要把RAG和微调Fine-tuning分清楚。微调是让模型把知识“背”进参数里成本高、更新慢而且新知识和旧知识容易打架RAG是让模型“开卷考试”知识放在外部库里随时可以替换、增补、下线。在Agent场景里我几乎总是优先推荐RAG因为Agent要面对的知识往往是来源多、变化快的让模型逐一背下来不如给它一条随时可查的管道。1.2 知识管道在Agent架构里的位置回看Agent的典型决策循环规划Plan→ 动作Act→ 观察Observe→ 反思Reflect。在这个循环里知识获取管道通常有两种身份。第一种是工具。你把一个“查询知识库”的工具注册给AgentAgent在规划阶段判断出“这个问题需要查资料”于是触发这个工具把返回的内容作为观察结果再送回推理链路。第二种是长时记忆的底层存储。Agent的长期记忆如果落在向量库里本质上也是一个RAG系统写入时把经验向量化读取时按相关性召回。所以把RAG理解成“啃知识的工具”或者“长期记忆的读写通道”都不算错。这也是我特意把这篇独立成一课的原因。前几篇我们讨论工具调用、记忆管理是在解决“Agent能把动作做得多复杂”这一篇解决的是“Agent依据什么来做决策”。没有可靠的知识获取工具越强越容易一本正经地办错事——检索回来的前提是错的后面所有推理都会跟着跑偏。顺便提一个热词“Agentic RAG”。基础RAG是一条“用户问一次、系统查一次”的流水线Agentic RAG则是把检索的决定权交给Agent自己让它判断要不要查、查几次、拆成几个子问题查。判断的自主性向前移了但底层依赖的仍然是基础RAG那套检索能力所以基础必须扎实。这篇文章讲的东西是所有高阶RAG玩法共同的地基。2. RAG核心链路拆解从入库到生成五个环节一个都不能少2.1 先记住这条流水线不管用LangChain、LlamaIndex、Spring AI还是LangChain4jRAG的主链路基本一致总共五步加载Load从PDF、Word、Markdown、网页、数据库里把原始文本读出来。切分Split把长篇文档切成大小合适的文本块chunk。向量化Embedding用embedding模型把每个文本块转成向量。存储与索引Store把向量、原始文本和元数据一起存进向量库。检索与生成Retrieve Generate用户提问时把问题转成向量在库里做相似度检索取回Top-K个文本块连同问题一起交给LLM生成答案。还是用“开卷考试”来类比第一步是决定带哪些资料进考场第二步是给资料分章节、编目录第三步是给每个章节做索引卡片第四步是把卡片按主题分类放进检索柜第五步是开考后按题目快速抽出最相关的几张卡片再照着卡片写答案。不少新手把重点放在embedding模型和向量库选型上但我做了几个项目之后发现翻车现场大多集中在前两步——数据没洗干浄、文档切得不合理。数据怎么进库直接决定了检索效果的上限。2.2 文档加载与切分把资料切成“能查的样子”先说加载。常见的坑是把PDF直接丢给程序就完事。PDF分两种文字版和扫描版。文字版可以直接抽文本扫描版其实就是图片不做OCR的话进去的全是乱码。我处理扫描版一般先过一遍OCR开源可以用PaddleOCR云端用各家文档理解API把图片转成带位置信息的文本再进后续流程。Office文档、网页、数据库同理格式越乱清洗工作量越大。这是RAG项目里最不性感、但最花时间的部分。接下来是切分chunking。为什么不把整篇长文塞进去两个原因一是上下文窗口有限二是检索粒度太粗。你想查“2024年销售奖励政策的适用范围”如果把整篇文档作为一个检索单元模型拿到一大坨内容相关段落被无关信息淹没回答质量必差。切分的目的就是把知识切成合适的“最小可检索单元”。切分策略没有银弹但有几条朴素的实操经验纯文本按固定大小切我常用400到800个token一块overlap设50到100。重叠是为了防止句子在切分边界被拦腰截断让相邻块保留上下文尾巴。打个比方你读一本每一页都重复印了上一页最后一行的书顺畅度会高很多overlap就是干这个的。有结构的文档优先按结构切。Markdown标题、HTML标签、Word标题样式都可以作为切分点这比按字符数硬切干净得多。代码、表格、对话这类特殊格式默认切法基本都会切坏需要单独写解析逻辑。为什么是“400到800 token”而不是精确数字因为太小信息量不足太大又让相似度计算被无关词稀释。给个具体感受一篇3000字的中文文档假设按500 token切大约会生成6到8个块加上overlap存储量会比原文多出零星几个百分点这是正常开销不用心疼。切分的同时一定要维护元数据metadata。来源文件名、章节标题、页码、更新时间这四样我建议至少存前三样。作用有两个一是检索时可以按元数据过滤比如只查2025年的制度二是回答时能附上引用来源用户看到“来源《XX制度》第三章第2节”信任感完全不一样。这个细节在实际交付时特别加分。2.3 向量化与向量存储选模型就是选“怎么理解语义”embedding模型的作用是把文本变成一串数字向量让语义相近的内容在数学空间里距离也近。它比关键词匹配强的地方在于理解“语义相似”。你写“今年业绩第一名”文档里写的是“2025年销售冠军”字面完全不同但在好的embedding模型下向量距离会非常近。一个生活化类比embedding模型就像给每块内容写“索书标签”但不是按书名的死标签而是按“它大概在说什么事”的活标签。检索时把你的问题也写成一份标签然后在书库里找标签最像的几页。选embedding模型我主要看三个维度语言中文场景优先选中文优化过的模型bge系列在中文语义上的表现一直比较稳。向量维度越高通常越精细但存储和计算成本也更高。OpenAI的text-embedding-3-large有3072维一些轻量开源模型只有384维。部署方式有私有化要求就选开源模型本地部署省心且数据不出域。向量库选型可以参考这张表向量库适合场景特点Chroma / FAISS个人练手、原型验证轻量、安装快本地就能跑pgvector已有PostgreSQL的业务系统复用PG运维体系不用多引一套中间件Qdrant中小规模生产功能全支持过滤和Payload部署简单Milvus大规模生产、海量向量分布式能力强但运维成本也高检索环节的关键参数是Top-K。为什么只取前几个而不把相似的全都返回因为LLM上下文有限塞太多无关资料反而冲淡重点还会增加成本和延迟。K值一般取3到10具体看知识粒度每块只有一两句话K可以大一点每块是完整章节K就得小一点。2.4 生成环节把资料变成答案检索回来后生成环节的核心是“组装Prompt”和“约束模型行为”。我常用的Prompt模板大致是这样你是一名助手。请仅根据下面提供的资料回答问题。如果资料中没有相关信息请直接回答“资料中未找到相关信息”不要编造。回答时尽量引用资料的来源。资料 [来源《2025年销售政策》第三章]......问题...这句话有两层用意一是给模型划边界明确不让它用训练记忆里的通用知识来补充发挥二是给它引用钩子因为资料里带了元数据模型回答时就有据可附。当然模型不总是听话所以生产环境我会再加一层轻量校验看答案里的关键数字、专有名词是否能在返回的资料里找到找不到就标记“低置信度”或触发二次检索。这不能完全消灭幻觉但能把明显离谱的回答拦下来。3. 从基础RAG到Agentic RAG检索这件事情也需要思考3.1 基础RAG的局限基础RAG最大的问题是“用户问什么系统就原样查什么”缺少对问题的判断和转化。现实提问往往带口语、省略、指代和歧义。比如用户问“今年的情况怎么样”不结合上下文系统根本不知道“今年”是哪年、“情况”指什么指标。再比如多跳问题“目前卖得最好的产品是哪一年发布的”这需要先查出“卖得最好的产品是谁”再拿产品名去查“发布时间”一次检索根本解决不了。热词里的“hit rate”检索命中率衡量的就是这件事在所有测试问题里正确答案所在的文档块被成功召回的占比。基础RAG的hit rate不稳定主要因为它只做了一次“按相似度盲查”缺少问题拆解和转换。3.2 让Agent介入检索决策Agentic RAGAgentic RAG的核心思路是把“要不要查、怎么查”变成Agent的推理动作。典型做法是给Agent注册一个知识库检索工具由Agent在规划循环里决定调用。相比基础RAG它能做到几件很实际的事情查询改写先把口语问题改写成适合检索的表达。例如“去年卖得最好的那款产品是啥”改写成“2025年销售额最高的产品名称”再用改写后的query去向量库查。子问题分解“卖得最好的产品是哪年发布的”拆成“找出销售额最高的产品”和“查询该产品的发布时间”两个子检索串行执行。多轮补查第一轮检索结果不够充分时Agent自己决定再查一次甚至换一个角度查比如先查实体再查该实体的关联数据。热词里频繁出现的GraphRAG和本体RAGOntology RAG本质上是“用结构增强检索”的进阶路线。基础RAG把文本切成块块与块的关系是隐性的GraphRAG把实体和关系显式抽出来建图检索时可以沿着关系路径找“知识之间的连接”。当你处理的知识密集且关系复杂比如公司组织架构、产品家族、法规条款互相引用时这条路线的价值会很明显。学习路线上我建议先把基础RAG做扎实再上图谱不要一上来就上重型方案。3.3 多路召回与重排序把“检得到”变成“检得准”另一个让hit rate大涨的组合拳是“混合检索 重排序”。混合检索指的是同时用BM25关键词召回和向量相似度召回。为什么需要关键词召回因为向量模型对专有名词、型号、代码、缩写经常表现不稳定。比如用户搜“Q7-F2型传感器”文档里写的是“Q7/F2 series”语义相近但字符差异大纯向量可能排不上而BM25是精确字符匹配对这种查询非常友好。两条路各召回一批合并去重就是“多路召回”。但多路召回之后必须面对噪声。向量检索Top-100里可能有大量相似但真正不相关的块直接塞给LLM会灾难性拉低回答质量。这时用Rerank模型把粗召回结果重新精排一遍只保留最相关的10个。我实测下来加Rerank后hit rate普遍能再涨10到20个百分点。在很多场景里Rerank对最终效果的影响比换一个更强的LLM还大。4. 从0到1跑通一个最小RAG附可抄的配置4.1 为什么我推荐LangChain Chroma这套起手组合讲完原理直接上实战。这个最小实现用Python LangChain Chroma向量库embedding调用本地模型接口。选这套组合是因为依赖少、好理解Chroma是嵌入式向量库不需要单独启服务LangChain把加载、切分、检索的组件都封装好了适合看清整条链路。如果你用的是Java技术栈参照Spring AI或LangChain4j里对应的Retriever、EmbeddingModel、VectorStore组件即可用.NET的话Semantic Kernel里也有对应的Memory和VectorStore抽象核心思路完全一致。先装依赖pip install langchain langchain-community langchain-ollama langchain-text-splitters langchain-chroma chromadb再准备embedding模型。我这里以Ollama本地部署的bge-m3为例你也可以用任何OpenAI兼容接口只是换一下配置ollama pull bge-m34.2 三步实现入库、检索、生成第一步加载文档并切分入库。假设你有一个policy.md内容是一段内部制度from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.embeddings import OllamaEmbeddings from langchain_chroma import Chroma # 1. 加载文档 loader TextLoader(policy.md, encodingutf-8) documents loader.load() # 2. 切分块大小500 token重叠50 token splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , ], ) chunks splitter.split_documents(documents) # 3. 向量化并写入Chroma embeddings OllamaEmbeddings(modelbge-m3) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db, ) print(f已入库 {len(chunks)} 个文本块)第二步构建检索器加上相似度阈值过滤避免把太不相关的资料捞回来retriever vectorstore.as_retriever( search_typesimilarity_score_threshold, search_kwargs{k: 4, score_threshold: 0.5}, )注意score_threshold的取值取决于embedding模型的相似度分布不是一个万能值。我的做法是先不设阈值跑一遍打印检索结果的得分观察相关和不相关的分界线再回填这个数。第三步组装问答链路from langchain_ollama import OllamaLLM from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough llm OllamaLLM(modelqwen2.5:7b) prompt ChatPromptTemplate.from_messages([ (system, 你是一名助手。请仅根据下面提供的资料回答问题。如果资料中没有相关信息请直接回答资料中未找到相关信息不要编造。\n\n资料\n{context}), (human, {question}), ]) def format_docs(docs): return \n\n.join(f来源{d.metadata.get(source, 未知)}\n{d.page_content} for d in docs) rag_chain ( {context: retriever | format_docs, question: RunnablePassthrough()} | prompt | llm ) answer rag_chain.invoke(2025年的销售目标是多少) print(answer)这套代码跑通之后你就有了一个能回答“内部制度问题”的最小Agent。再进一步把整个rag_chain包装成一个函数注册成Agent的工具交给Agent在规划中自主决定何时调用这就是从基础RAG迈向Agentic RAG最简单的一步。技能skill和RAG的结合通常也是从这个入口开始的。4.3 落地到本地知识库数据更新与离线部署很多人做本地知识库想把ERP里的产品数据、企业内部Wiki、客服话术接进来。这种场景我提醒三个实操要点。第一先拿小规模数据验证。第一次跑通一两份文档就够全量数据要等链路稳定之后再灌。我见过不少项目一上来就灌几十万份文档结果检索慢、结果乱问题都没法定位最后还是退回小样本验证。第二更新策略要提前想清楚。向量库不像关系型数据库有完整的事务能力删改一条数据需要同步清理对应块的向量和元数据。简单方案是“全量重建 增量追加”低频变化的文档用定时全量重建高频新增内容用增量写入并且记录每个数据块的来源版本号方便失效数据下架。具体怎么设计跟数据变化频率强相关没有统一标准。第三离线部署要控制模型规模。本地知识库通常还要求LLM也本地跑硬件有限时尽量选小参数模型加RAG的组合效果反而比裸用大模型更可控。我自己的体会是在8GB显存的机器上量化为Q4的7B模型配合RAG对“内部知识准确性”的满足度能高出不少因为资料是从你自己库里来的模型只需要规规矩矩做归纳就行。5. 常见问题与排查技巧实录最后把这几年做RAG最常见的翻车现场整理成一张排查表方便对照处理症状常见原因排查思路解决参考检索结果明显不相关切分太碎或太粗embedding模型与领域不匹配打印检索Top-5的chunk和得分调整chunk size换领域匹配的embedding加Rerank完全检索不到扫描PDF没OCR编码乱码加载器漏字段先确认原始文档文本是干净的补OCR清洗数据检查loader配置回答答非所问Top-K太大无关内容冲淡上下文查看最终拼进Prompt的context减小K提高score_threshold加Rerank回答有明显幻觉Prompt约束不够资料确实缺失让模型输出引用来源人工抽查强化“只根据资料回答”约束加引用验证环节检索延迟高向量库没建索引embedding调用串行看慢在检索还是模型调用给向量建索引embedding走批量或缓存知识更新不生效向量库里旧块没有清理检查数据版本号增量删除加重建维护好元数据再说两个容易踩的大坑。第一个切分方案不合适造成的“假性失效”。有次我把一份合同按固定500 token切结果“违约责任”条款被拦腰切开一半在上一个块、一半在下一个块检索时模型只看到前半句答得驴唇不对马嘴。后来改成按条款结构切分问题立刻消失。切分不是为了满足某种参数审美而是为了对齐内容的天然结构。第二个忽略评估环节。没有评估的RAG项目效果好坏全靠感觉。至少准备20到50个“问题-正确答案所在文档”的测试样例每次跑一遍看hit rate改一个参数就重跑一次用数据说话。“hit rate”现在在面试里已经是常见考点了能讲清楚这个概念本身就是加分项。再补充一个成本与延迟的调优心得。生产环境里embedding调用是最容易被忽略的成本项特别是文档量大时。我的做法是把所有chunk离线批量embedding存成文件再批量入库避免在线逐条调用线上检索时只embedding用户问题这一条成本几乎可以忽略。向量库如果数据量大可以启用量化比如把float32向量压成int8检索精度损失通常在可接受范围内但存储能降四倍。最后说点大实话。我见过太多人花大量时间研究向量库选型、对比embedding模型最后效果不好发现是文档解析乱码、切分把上下文切断了。RAG做得好不好八成取决于数据侧的处理而不是模型多高级。先把一条数据从“原始文档”到“能被正确检索回来”的整条链路跑通再谈优化。这篇按基础版把链路拆开讲了一遍接下来的查询改写、重排序、GraphRAG都会在这条链路上继续做文章。如果你正在给Agent搭知识库照这个最小实现先跑起来再回来对照问题表自查会省掉很多弯路。
返回列表