新闻详情

新闻详情

首页 / 资讯中心 / 详情

RAG基础实战:为AI Agent搭建可靠的知识获取管道

发布时间:2026/9/30 9:53:50来源:尧图网络
RAG基础实战:为AI Agent搭建可靠的知识获取管道
做 AI Agent 项目做得多了你会发现一个很拧巴的现象模型能力越强用户越喜欢拿它当知识库用问的全是你岗位里那点内部文档、历史项目、数据口径。可模型自己根本没见过这些东西它只能靠训练时学来的常识硬撑结果就是答得流利却错得离谱。这一篇我们专门聊 AI Agent 的知识获取管道也就是 RAG检索增强生成基础。标题里的管道两个字我要重点强调一下很多人把 RAG 理解成接个向量数据库就完事但一个真正能在 Agent 里长期运转的知识获取链路远比搜到就返回要复杂。前几篇我们把 Agent 的工具调用、任务编排讲了一遍这次把知识这块补上属于整个系列里最偏地基的一篇。适合已经写过简单 Agent、准备给它接私有知识的同学。1. 为什么 Agent 不能只靠模型自己知道的内容先从我实际接手过的一个项目说起客户做企业内部知识助手知识库里有产品手册、售后流程、财务制度、架构成档总共几百篇文档。最开始没人想过做 RAG方案是把文档全塞进提示词里让模型读结果第一条上线反馈就把我钉在耻辱柱上——用户问退货周期是多久文档里写的是售后退款时限模型翻遍提示词找不到退货两个字愣是答出了一般情况下 1-2 周实际业务标准是 3 个工作日内必须出审批结果。这就是典型的知识割裂词面不匹配语义却完全是一回事。模型的能力再强它也做不了自己不知道的知识的检索因为它在生成回答时根本没有办法判断该去哪里取证据。这不是提示词能解决的问题而是需要一条管道把用户的问法转成知识库里能被定位的证据。1.1 模型权重里存的是能力不是你要的答案这里要先给一个基础认知模型训练学到的知识和业务系统里的知识是两个完全不同的东西。前者是语言规律公共知识的统计压缩后者是你所在组织独有的、动态变化的、需要交叉验证的事实。你可以通过微调让模型记住一部分内部术语但你没法通过微调让它实时跟上文档更新更没法在每次回答时告诉你这个答案出自哪一篇、第几节。我自己做过一次对照组测试同一批公司制度文档A 组只靠微调B 组用 RAG。结果在涉及具体数字、流程节点、责任人这类低容错问题上A 组的正确率只有 51%B 组可以达到 88% 以上。微调适合让模型变专业RAG 适合让模型查得到。Agent 要落地二者不是二选一而是各管一段。本文的核心场景是把 RAG 这段做到可维护、可观察、可升级。1.2 Agent 需要的不是搜索框而是一条管道你可能会说企业内部早就有全文搜索直接搜索复制给模型不就行了这是个很容易踩的误区。关键词搜索返回的是网页列表它不知道哪一段是回答问题的关键证据更不会做语义改写。用户问订单被拒了怎么处理文档里写的是支付状态异常时的申诉流程词面匹配大概率漏掉。管道的价值在于它把提问到证据到回答之间的所有环节都拆成了可替换的组件用户提问 → 查询改写/理解 → 知识库切块召回 → 候选结果重排 → 组装上下文 → 交给生成模型 → 返回回答。这里面每一个箭头都是一个可以通过测试来优化的环节。搜索框只有一个步骤而管道是一整条流水线。RAG 基础阶段你不用把每个环节都做到极致但你要先知道这条线上有哪些阀门。1.3 一个最小管道里每段分别解决什么问题按我的经验给零基础同学讲 RAG最好先画清楚四个模块文档预处理把 PDF、Word、Markdown 清洗成干净的文本块去掉页眉页脚、水印干扰索引构建把文本块切分成合适的片段再用嵌入模型转成向量存进向量库召回阶段用户提问也转成向量去向量库里找最相似的若干片段重排与生成取回 Top N 片段用重排器精排最后拼进提示词让模型只依据这些片段作答。下面几节我会把每一段为什么这么做、不这么做会怎样讲透再给一个能在你本机直接跑通的最小实现。2. 拆开 RAG嵌入、切分、召回、重排每一环都有自己的脾气很多人跑通第一个 RAG demo 只需要一小时但跑通之后一测真实问题命中率马上就露馅。原因通常是他们把所有希望押在了嵌入模型上以为向量相似度高就等于回答正确。实际上四段里任何一段偷懒整条管道都会变傻。2.1 嵌入模型把语言变成空间里的位置嵌入模型做的事是把一段文本映射成一个高维向量让语义相近的句子在向量空间里距离更近。比如退货周期和售后退款时限如果嵌入模型够好两个向量的距离应该很近。选嵌入模型时我建议你直接做一个小实验拿 20 条用户真实问题分别用两三个候选模型编码再去知识库里跑一遍召回看谁先召回正确片段。不要只看榜单分数因为榜单是在通用语料上评的你的语料有自己的行业黑话。中文场景下我现在常用的是bge-m3这类多语言或者中文优化模型效果稳定部署也不重。还有一个常被忽略的点嵌入模型对输入长度有窗口限制。一般 512 token 左右超过之后会截断。这直接决定了你的知识块不能无限长——块太长语义被稀释向量全往中间靠检索结果跟随机差不多。2.2 切分策略召回上限在切分那一步就决定了切分是 RAG 基础里最容易被低估的环节。你切出来的块就是将来模型能看到的最小证据单元。块太小证据不完整比如一个流程的三个步骤被拆到三个块里模型只拿到第一步块太大一个问题对应十几个块向量相似度被无关文字拉低精确答案反而不突出。我的起步参数一般是chunk_size600字符、chunk_overlap100字符然后根据文档类型调整。普通企业制度文档、项目文档这个范围基本够用如果文档里有大量表格我会把它转成 Markdown 表格句式再切避免表格结构被拦腰斩断。更好的做法是结构感知切分Markdown 文档按标题层级切PDF 按章节切代码文档按函数边界切。一句话原则宁可让一个块稍长一点也不要让一个语义单元被切散。2.3 召回与重排宽召回精排序召回阶段最常见的错误是k值设得太小——只取 Top 3 就交给模型。向量检索的召回率本身不是百分百正确证据有时排在第五、第八位。你只取前三等于把正确答案直接扔了。我的习惯是召回 10 到 20 个候选然后用一个重排模型Cross Encoder逐对打分再取 Top 3 到 5 个放进提示词。为什么不能一开始就用重排模型扫全库因为重排模型要对每一对问题文档做一次完整推理几千个文档下来耗时不可接受。向量检索是快速粗筛重排是精判两段分工成本和效果都友好。这里把两个阶段的定位整理成一张表方便你对照排查阶段常用工具/模型目标常见翻车点嵌入bge-m3、text-embedding 类语义向量化窗口截断、行业词不敏感切分RecursiveCharacterTextSplitter 等语义单元完整表格被切开、标题与正文分离召回向量库 TopK、MMR提高召回率k 值太小、相似度阈值形同虚设重排CrossEncoder、bge-reranker提高精确率跳过重排直接塞 TopK生成任意 LLM依据证据作答提示词未限制只依据资料有的项目为了省事直接用向量距离当最终排序效果也能用但一旦知识量上来、文档间相似度变高你就知道重排这一环省不得。3. 从零搭一个最小 RAG索引、检索、重排和生成跑通一遍说再多理论不如直接跑一个能用的 demo。下面这套是我在自己笔记本上验证过的流程依赖少、不烧钱适合作为你后续扩展的骨架。我用的是 LangChain 做胶水FAISS 做本地向量库嵌入和重排都用本地模型整个索引过程不依赖任何外部 API。3.1 环境准备和选型原因先说明为什么这样选本地嵌入模型可以离线跑避免你每一轮实验都花 API 费用FAISS 是单机向量库不需要启动服务最适合起步阶段LangChain 在这里只是把加载、切分、检索串起来你完全可以不用它但用了能少写很多样板代码。需要安装的依赖pip install langchain langchain-community langchain-huggingface faiss-cpu sentence-transformers如果你机器上没有 GPUfaiss-cpu也够用我测过几十万条向量的检索毫秒级返回单机起步完全没压力。3.2 构建索引加载、切分、嵌入、入库假设你有一个docs目录里面是整理好的 Markdown 或文本文件。下面这段代码会读进来、切块、向量化、存成本地索引import os from langchain_community.document_loaders import DirectoryLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS loader DirectoryLoader( ./docs, glob**/*.md, loader_clsTextLoader, loader_kwargs{encoding: utf-8}, ) docs loader.load() splitter RecursiveCharacterTextSplitter(chunk_size600, chunk_overlap100) chunks splitter.split_documents(docs) embedding HuggingFaceEmbeddings(model_nameBAAI/bge-m3) index_path ./faiss_index if os.path.exists(index_path): vectorstore FAISS.load_local(index_path, embedding, allow_dangerous_deserializationTrue) else: vectorstore FAISS.from_documents(chunks, embedding) vectorstore.save_local(index_path)注意allow_dangerous_deserializationTrue这个参数FAISS 本地文件可能包含序列化的对象只在你完全信任本地文件来源时才开。别人的索引文件不要乱加载。3.3 检索、重排与答案生成索引建好后核心的检索逻辑如下query 智能体在什么情况下应该调用外部工具 hits vectorstore.similarity_search_with_score(query, k10) for doc, score in hits[:5]: print(f向量距离: {score:.4f} | 来源: {doc.metadata.get(source, unknown)}) print(doc.page_content[:80]) print(---)向量距离越接近 0 代表越相似但具体阈值因嵌入模型而异不要拿一个固定值套所有模型。接下来用重排器把候选重新排序from sentence_transformers import CrossEncoder reranker CrossEncoder(BAAI/bge-reranker-base) pairs [(query, doc.page_content) for doc, _ in hits] scores reranker.predict(pairs) ranked sorted(zip(scores, hits), keylambda x: x[0], reverseTrue) top_docs [doc for _, (doc, _) in ranked[:4]]重排分数越高代表越相关。把重排后的 Top 4 拼进提示词context \n\n.join([doc.page_content for doc in top_docs]) prompt f你是企业内部知识问答助手。 请只依据下面的“参考资料”回答问题不要编造资料中没有的信息。 如果资料不足以回答直接回复“知识库中未找到相关信息”。 参考资料 {context} 问题 {query} 最后接一个兼容 OpenAI 接口的模型。我本地用的是 Ollama 跑 qwen2.5代码同样适用 OpenAI 的接口from openai import OpenAI client OpenAI(base_urlhttp://localhost:11434/v1, api_keyEMPTY) resp client.chat.completions.create( modelqwen2.5:14b, messages[{role: user, content: prompt}], ) print(resp.choices[0].message.content)到这里一个文档问答的最小 RAG 已经通了。注意整套流程里真正需要调模型的只有检索后的重排和最终生成两步其他环节都是确定性的。这条特性很重要后面讲 Agent 集成时会反复用到。3.4 用一个命中率指标给自己打分demo 跑通不等于有效。我习惯在起步阶段就建立一个小型评测集准备 20 到 30 个你业务里真实会出现的问题每个问题人工标注正确证据出现在哪一段。然后跑一遍检索看正确证据是否出现在 Top 5 返回结果里统计命中比例这就是检索命中率Hit Rate。我见过太多团队把全部精力花在调生成模型上结果其实是召回环节根本没把证据找回来。先测检索命中率如果连这一步都不及格后面无论换什么模型都救不回来。评测集不用多每个迭代周期维护二三十条就够关键是这些问题是真实的不是你自己编出来的顺风问题。4. RAG 文献踩坑记录四个问题,完整排查链路这一节我不想干巴巴地列注意事项直接把我遇到过的几个真实故障和排查思路写出来你照着排查手法走一遍比背结论管用。4.1 症状一同一段知识换个问法就查不到项目初期用户问结算周期查得到问多久结算一次就空手而归。第一反应是换嵌入模型换完之后依旧不行。后来我冷静下来没有继续在模型上使劲而是去翻索引文本本身原文档里把结算周期定义在一篇很长的合同模板中而这份模板 60% 的篇幅是法律条款和公司抬头。切块策略就是根因chunk_size是 1000整段模板被切成四五块真正的定义句只有十几个字被埋进了一大堆无关文本里向量特征被稀释。排查链路是先确认其他问题能否正常召回排除向量库损坏再打印召回的前十条发现正确块并非没被召回而是排在第八位然后检查该块的完整内容发现大量噪音。修复方式是退回 600 字切分把切分逻辑改成按章节先切一次再对超长章节按 600 字二次切分。换模型之前先看看你的证据块干不干净这是最省钱的排查顺序。4.2 症状二答案答得流利但引用来源是错的这个问题更隐蔽生成答案看着通顺可你去看它引用的原文片段会发现跟答案对不上。我一直强调RAG 不是模型自己会找证据而是你给它什么它用什么。模型擅长顺着上下文把话圆过去所以当 Top 1 结果里有一段语义相近但并非答案的文本时它可能就顺着编了。排查时我用了最笨但最有效的方法把提示词里的只依据参考资料作答换成你必须在答案末尾列出依据片段编号如果参考中没有依据只能回答不知道。模型行为立刻发生改变很多幻觉其实是提示词给了它发挥空间而不是检索出了问题。另一个修复手段是引用回溯要求模型在答案里用编号标注用了哪段参考程序端再做一次校验看答案中的关键数字或结论是否真的出现在标号片段里。即使做不到全自动校验至少人工 review 时有据可查。4.3 症状三知识库更新后老答案依旧阴魂不散有一次我们整体替换了产品手册版本删掉了旧文档也重建了索引但测试时模型依然会提到已经废弃的功能名。查了一圈原因出在更新流程上我们的旧索引并没有被清空新索引是追加写入的旧块还躺在向量库里检索时偶尔被捞回来。排查链路先确认检索返回文档的元数据发现另一份文件名去docs目录确认该文件已删除代码里定位到from_documents每次都是全量重建但因为我的save_local多次执行没有覆盖旧目录。修复方式每次重建索引前先删除旧索引目录并且在加载时给索引加上一个构建批次号元数据检索结果里过滤掉非当前批次。4.4 症状四PDF 导进来不少但检索时永远找不到几页的内容这个坑最基础也最容易被新人忽略有些 PDF 是扫描件没有文字层。DirectoryLoader读进来的文本是空白或乱码嵌入进去的向量全是噪音。推荐做法是起步阶段统一用PyPDFLoader或pypdf先校验每页是否提取到足够文本低于阈值就标记出来人工处理或接入 OCR。这几类问题的通用排查顺序我整理成了这张表现象先查什么再查什么最后考虑差得远完全无关文档加载是否正常切分是否把语义切碎嵌入模型是否适配行业相关但排位靠后召回 k 值是否太小块内噪音是否太多是否缺少重排环节生成答案引用不准提示词是否有只能依据资料参考片段是否包含答案是否缺失引用校验更新后无效索引是否全量重建是否存在旧文件残留检索是否有批次过滤5. 把 RAG 接进 Agent它不是后台脚本而是要变成一件工具基础 RAG 跑通后你要把它嵌进 Agent。很多人的第一反应是把 RAG 当作一个retrieve(query)函数直接丢给 Agent 调用但这样做的效果并不好。问题在于Agent 在编排层它本身不擅长判断哪些问题该走向量检索。5.1 给 Agent 一个检索工具而不是一个后台函数正确的做法是把 RAG 封装成一个带明确描述的工具让 Agent 在需要外部知识时主动调用。工具描述里要写清楚三个信息这个工具解决什么问题、什么情况下不要调用它、返回结果长什么样。比如工具名企业内部知识检索 用途查询公司制度、产品手册、项目文档中的事实信息 禁忌不处理代码运行问题、不处理需要登录系统的实时数据 返回格式JSON包含证据片段、来源文件名、相关度分数Agent 收到用户问题时会先判断这要不要查知识库再决定调用。这一步的价值是让 Agent 把我该不该查和如何作答两件事拆开避免所有问题都先查一遍再自由发挥。5.2 检索上下文要设定边界不能让 Agent 无限取块把检索结果直接交给 Agent 时一个常见失控场景是Agent 越权决定再查十个块结果把上下文塞满还混进大量无关片段生成质量反而下降。你应该在封装工具时就固定上游配置召回 20 条、重排取 3 到 4 条、证据总长度限制在 1500 字以内。Agent 只负责决定查或不查怎么改写提问至于取多少证据、如何拼接这些要由工具内部决定。把不确定性留在可控范围内是 Agent 工程稳健性的关键。5.3 权限、更新与缓存是一套知识服务的标配当多个部门共用一套 Agent 时权限问题会迅速浮出水面。最简单的做法是给每个知识库分配一个检索域在工具描述中带上workspace_id检索时按这个字段过滤。别指望模型自己自觉不越权你要在索引元数据里就隔离干净。更新方面我见过最稳妥的方案是文档级版本号每次知识库重建给所有文档打上批次号Agent 检索时只看最新批次。缓存则要小心同一问题短期内可以命中缓存但知识库一旦更新缓存必须同步失效否则旧答案会比新知识还活跃。5.4 观测你的 AgentRAG 出问题到底是哪一段的锅基础 RAG 的日志至少要包含这几项原始问题、改写后的问题如果有、召回的候选片段 ID、重排后的最终片段、生成答案、耗时。我排查线上幻觉问题几乎全靠这六项日志。看到答案错误先定位是候选片段压根没有证据还是证据在但生成阶段歪曲了它这两种情况的修复手段完全不同。这其实是把 RAG 当服务来运营的思维。基础 RAG 是一本流水账而 RAG 服务是一套可观测、可控制、可独立的系统。等你的 Agent 开始对外服务时才会发现这个抽象有多救命。6. 基础 RAG 的上限遇到哪些情况该考虑升级方案了RAG 基础并不复杂但它在某些问题上确实有天然短板。我自己的判断标准很简单如果 20 条评测问题的命中率和正确率连续两个迭代周期没有提升往往不是调参的问题而是这个方案本身就触碰了上限。6.1 基础 RAG 的典型失灵场景跨文档综合题需要把三个文档里的信息拼成一个结论A 文档定义流程B 文档定义负责人C 文档定义时限基础 RAG 很难把三块证据稳定凑齐同义词/多源冲突两份文档口径不一致基础 RAG 只会取相似度最高的一段不会主动发现矛盾需要全局理解知识库整体讲了一个为什么但答案需要站在全局总结只靠局部片段回答必然以偏概全强调 schema 一致性比如需要严格按某个字段结构输出向量检索本身不保证这一点。6.2 升级方向Agentic RAG、GraphRAG、Ontology RAG 怎么选你很可能在热搜词里看到过这几个名词。简单说Agentic RAG让 Agent 自己决定检索策略比如先查一次发现证据不足再换关键词查第二次或者把问题拆成多个子问题分开检索。适合跨文档综合题GraphRAG把文档里的实体和关系抽成图再做全局或社区级别的检索。适合知识之间有网状联系、需要全局总结的场景Ontology RAG先用一套本体约束实体的类型和关系再基于图谱检索。适合对输出结构要求严格的领域比如医疗、制造、法规LLM Wiki把知识持续沉淀成渐进式条目类似人工维护的 Wiki由模型不断整理合并。适合需要长期积累、持续修正的知识体系。我的建议很明确如果你现在只是单点事实问答还没做好就不要上任何升级方案。先把基础 RAG 的切分、召回、评测、日志做到位你会发现它已经解决了 Agent 知识获取的七成问题。剩下的三成等你真正遇到具体瓶颈时再按需升级而不是提前架构。这套基础管道你在本地用几百行代码就能完整跑通。我个人的体会是别急着把 Agent 编排得花团锦簇先让知识获取这件最朴素的事变得可靠。等你哪天深夜被用户叫起来改 bug发现能快速定位到是召回没召到、还是生成没用好你就知道今天这五千字没有白写。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

2015年五一数学建模B题复盘:空气污染数据分析与预测建模全流程 2026/9/30 10:39:43

2015年五一数学建模B题复盘:空气污染数据分析与预测建模全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
HPC高性能计算架构设计:计算、存储、网络与集群软件选型及调优指南 2026/9/30 10:39:35

HPC高性能计算架构设计:计算、存储、网络与集群软件选型及调优指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
十款代码表白特效:单文件HTML爱心粒子与互动玩法合集 2026/9/30 10:39:29

十款代码表白特效:单文件HTML爱心粒子与互动玩法合集

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
联合互信息与三元互信息:I(X,Y;Z)和I(X;Y;Z)的区别详解 2026/9/30 10:39:29

联合互信息与三元互信息:I(X,Y;Z)和I(X;Y;Z)的区别详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
罗尔定理推论与辅助函数构造:考研中值定理证明题的核心思路 2026/9/30 10:39:28

罗尔定理推论与辅助函数构造:考研中值定理证明题的核心思路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
EMQX ACL实战:多租户MQTT权限控制、外部授权与排障 2026/9/30 10:39:22

EMQX ACL实战:多租户MQTT权限控制、外部授权与排障

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉