恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
从0搭建RAG管道:解决AI Agent私有知识库检索与幻觉问题
首页
资讯中心
/
从0搭建RAG管道:解决AI Agent私有知识库检索与幻觉问题
从0搭建RAG管道:解决AI Agent私有知识库检索与幻觉问题
发布时间:2026/9/30 23:22:14
很多人在搭 AI Agent 时会遇到同一个困惑模型明明很能聊一碰到自己业务里的具体问题就开始胡说八道。原因很简单大模型的“记忆”是训练时固化的它记不住你的私有文档也拿不到实时更新的业务数据。这个系列前面几篇聊了 Agent 的规划、记忆和工具调用这一篇我聚焦 Agent 体系里最容易被低估的一个环节——知识获取管道也就是 RAG 的基础实现。所谓 RAG全称 Retrieval-Augmented Generation检索增强生成本质上就是给模型配一个随时可查的档案库让它回答问题时先翻资料再开口。这篇文章面向正在自己动手搭 Agent、被知识库命中率不高和数据割裂折磨的朋友我会把 RAG 这条管道的核心环节、参数选择和常见坑都过一遍尽量做到看完了能直接照着落地。1. 知识获取管道在智能体里的位置1.1 为什么智能体不能只靠模型自带的“记忆”把大模型想象成一个阅读量很大、但记忆有截止日期的员工他读书的时候确实知道很多通用常识但公司内部的上架规范、某款产品的具体参数、上周刚更新的售后流程他不可能凭空知道。这不是模型能力的问题而是信息时效和私有性的问题。模型的参数是训练完成的瞬间冻结的之后发生的任何变化模型本身都不知道唯一能改变这个状态的办法是让它在推理阶段从外部拿信息。所以在一个完整的 Agent 系统里知识获取管道承担的角色就是“让模型在正确的时间拿到正确的资料”。它不是把一堆文档直接塞给模型而是要做索引、检索、筛选、组织最后把最相关的内容拼进上下文里让模型基于这些事实去推理和回答。没有这条管道的 Agent本质上只是一个包装过的语言模型接口很多业务场景根本没法用。这里有个常见的误区有人觉得既然模型上下文窗口已经很大了把全部文档都塞进去不就行了。窗口大不等于可以乱堆上下文太长会稀释注意力让模型分不清重点而且每次都全量塞入的成本和时间都不可接受。RAG 的核心价值恰恰在这里——按需取用只在回答问题时拉取那几段真正相关的内容。1.2 RAG 与其它知识接入方式的取舍知识获取管道不是只有 RAG 一种实现至少还有微调和缓存两种路径可选但它们解决的问题完全不同。微调改变的是模型本身的权重适合让模型学习某种固定的风格、格式或者特定的领域知识结构但每次数据更新都要重新训练成本高、周期长不适合频繁变化的内容。缓存方案适合那些高频且答案固定的问题比如“退货政策是什么”直接命中缓存返回结果省时省力但对新问题没有生成能力。RAG 的不可替代性在于它把“存储”和“推理”解耦了。文档更新时只需要重新跑一遍索引模型本身不用动回答时可以引用原文片段方便溯源和修正。它在知识获取管道里的地位就像一个总能把最新版文件递到你手边的资料员。当然它不是银弹上下文里的资料如果没有被正确检索到模型再聪明也只能干瞪眼。这也是我把它称为管道而不是组件的原因——RAG 是一条完整的链路任何一个环节掉了链子整个回答的质量都会崩。2. RAG 核心链路拆解索引、检索、生成2.1 索引阶段切分、向量化、存储RAG 的第一步是给文档建立索引这个阶段决定了后续检索的上限。常见做法是读入文档 → 切成文本块 → 用 embedding 模型把每块转成向量 → 存入向量数据库。听起来简单但每一步都有讲究。先说切分。我见过很多人直接把整个 PDF 当成一块塞进去这样检索出来的“相关段落”往往是一整篇大杂烩模型根本无法定位答案。反过来切得太碎也不行几百条片段互相之间丢失了上下文检索出来也读不懂。比较稳妥的做法是使用递归字符切分器按照\n\n、\n、句号、逗号这样的优先级逐层往下拆保证尽量把完整段落或完整句子保留在一起。块大小我常用 512 到 800 字之间重叠区设 64 到 128 字。512 这个值对中文比较友好一段话大概覆盖几百 token既不至于把相关语义切散也不至于让冗余信息污染结果。然后是向量化。选择 embedding 模型时优先看它在目标语言上的表现中文场景下直接用英文为训练主力的模型会吃亏建议选对中文支持较好的模型。一个容易被忽略的点是embedding 模型一旦选定后期不要频繁更换因为换模型意味着向量空间变了旧索引全部作废必须重建。存储方面向量数据库的选择很多简单项目可以直接用 FAISS 或者 Chroma量大了再考虑 Milvus、PGVector 或者 ES 的向量插件。不用一上来就上重型武器我见过很多项目连数据量都没有就急着搭集群完全是浪费精力。2.2 检索阶段向量检索和关键词检索的配合索引建好之后查询时把用户的提问也转成向量然后到库里找最相似的前 K 条这就是最基本的向量检索。向量检索擅长捕捉语义相似用户问“产品怎么退换货”即使文档里没有出现“退换货”三个字只要存在语义接近的描述也能被找到。但向量检索有个很实际的毛病——它对专有名词和精确 ID 极不友好用户问“SN 码在哪里”向量会把“码”和“哪里”当语义重点反而忽略 SN 这个关键限定词。所以成熟一点的 RAG 管道都会做混合检索向量检索召回语义相似的关键词检索BM25 或全文索引召回精确匹配的然后把两路结果合并去重再统一评分。这套组合的思路其实和搜索引擎一样——语义召回兜底长尾表达关键词召回保证精确命中。个人项目里如果不想额外引入 Lucene 这类索引库可以考虑在 SQLite 里用 FTS5 做关键词检索配合向量库一起用效果比单路检索好很多。检索质量的好坏业界常用 hit rate命中率来衡量正确相关的那条文档是否出现在检索结果的前 K 条里。我在实践中有一条经验如果 Top-5 里都找不到正确答案就别指望大模型能脑补出来这时候要排查的是切分和 embedding 的问题而不是生成端的问题。这个指标在设计评测集的时候就要预留最好准备几十条真实问题每条标注对应的文档位置每次改动完管道就跑去跑一遍用数据说话。2.3 生成阶段上下文组装与提示词设计检索完成的最后一步是把命中的片段拼进提示词交给大模型生成回答。这里有一个很多人容易忽略的细节原始片段不能直接原样塞进去最好做一层格式化处理。引用内容可以加上“以下是参考材料”这样的边界标记让模型知道哪些是事实来源、哪些是标准回答方便它区分和引用。对模型来说清晰的上下文结构和指令说明会直接影响输出质量。提示词里除了放资料和问题还应该明确两件事一是“如果资料里没有答案必须如实说明不要编造”这一点是抑制幻觉的关键二是“回答中尽量引用提供的原文信息”确保输出的每个结论都能回溯到资料库。很多人以为只要把资料塞进去模型就会乖乖用这是不对的不写约束模型经常会把资料里没有的东西也一本正经地讲出来。上下文组装还有个实际约束窗口和成本。每次问答都把所有相关资料塞进去是不现实的我一般设置 Top-K 为 4 到 6超过这个数量对回答质量的提升非常有限反而增加 token 消耗和响应延迟。在这个环节还可以加一道 Rerank重排先粗召回几十条再用一个更精准的排序模型挑出最合适的几条能显著提升最终命中质量。如果项目预算有限也可以不做 Rerank但至少要在提示词里按相似度降序排列好资料的顺序模型会习惯性地更关注前面的内容。3. 实操一条最小可用的 RAG 管道3.1 工具选型与两种实现路径纸上谈兵说完我们直接动手。先说工具选型。目前搭建 RAG 管道的路径大致分两类一类用 LangChain、LlamaIndex 这类框架把加载、切分、向量化、检索、生成串成现成的组件另一类不依赖框架直接用 API 手动实现各个环节。我的建议是第一次尝试先用框架快速跑通但一定要理解每个组件背后的逻辑否则出了问题只能瞎猜。下面以 LangChain 为例配合 OpenAI 的 embedding 和 chat 模型跑一条最小可用的中文 RAG 管道。为什么用这个组合教程多、资料全、出错容易排查适合建立对管道的直觉。生产环境可以根据预算和合规要求换成本地模型但逻辑是一样的。先安装依赖pip install langchain langchain-community langchain-openai chromadb pypdf3.2 建立索引从 PDF 到向量库我拿一份常见的企业操作手册 PDF 作为例子。第一步把 PDF 加载进来然后切块然后向量化然后存进 Chroma。代码如下from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.embeddings import OpenAIEmbeddings from langchain_community.vectorstores import Chroma # 1. 加载 PDF loader PyPDFLoader(./操作手册.pdf) documents loader.load() # 2. 递归字符切分 text_splitter RecursiveCharacterTextSplitter( chunk_size512, # 每块最大字符数 chunk_overlap64, # 相邻块重叠字符数 separators[\n\n, \n, 。, , , , , ], ) chunks text_splitter.split_documents(documents) # 3. 向量化并写入 Chroma 本地库 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db, # 索引持久化目录 ) print(f已索引 {len(chunks)} 个文本块)这段代码里最值得解释的是切分器的 separators 顺序它决定了文本优先按什么层级断开。我把\n\n放在最前面是为了尽量保留完整段落随后才是\n和句号。如果一开始就把句号当最高优先级段落里的每个句子都会被拆散检索出的片段上下文严重缺失。chunk_overlap 的作用是保留切分边界的语义衔接防止关键信息恰好落在切口上比如某句话被从中间劈开导致前后都读不通。3.3 检索与回答拼上下文、设约束索引建好后把用户问题转为查询取回 Top-K 块再拼进提示词。下面是一段完整的问答代码from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # 4. 创建检索器 retriever vectorstore.as_retriever( search_kwargs{k: 4} ) # 5. 组装提示词 prompt ChatPromptTemplate.from_template( 你是一个企业知识助手。请优先根据下面提供的资料回答用户问题。 如果资料中没有相关信息请直接说明“资料中未找到相关内容”不要编造。 参考资料 {context} 用户问题{question} 回答 ) # 6. 执行问答 def ask(question: str): docs retriever.invoke(question) context \n\n.join([f[片段 {i1}] {d.page_content} for i, d in enumerate(docs)]) chain prompt | ChatOpenAI(modelgpt-4o-mini, temperature0) answer chain.invoke({context: context, question: question}) return answer.content # 示例 print(ask(产品的外包装尺寸是多少))有几个细节值得认真对待。temperature 我设置成 0在知识问答场景里不需要模型发挥创造性稳定的输出比花哨的表达有价值得多。提示词里“没有相关信息就说明”这段约束是幻觉控制的第一道防线它直接告诉模型资料是你的唯一事实来源。给片段编号也有实际用处模型在回答时可以引用片段编号方便人工溯源。3.4 参数对照与调参优先级动手的时候很多人会问这些参数到底怎么设。我给一张常用对照表大家可以根据自己的数据情况微调参数建议值作用调节优先级chunk_size512-800字符控制语义块的粒度高chunk_overlap64-128防止关键信息跨界丢失高k召回条数4-6决定进入上下文的片段数中embedding 模型通用型即可决定语义表达效果中后期勿换temperature0-0.3控制输出随机性低Rerank 模型按需引入二次筛选精排结果低预算充足再上从我的经验看大部分命中率问题都出在 chunk_size 和检索条件上先调这两个再考虑模型层面的升级。召回条数 k 也不是越大越好k 过大会把不相关的内容也带进上下文反而干扰判断。有一次我把 k 从 4 调到 10准确率不仅没升还因为噪音变多导致模型开始从无关片段里找答案这就是典型的过度召回反效果。4. 从“能用”到“好用”命中率、上下文与智能体编排4.1 检索命中率上不去先查这三件事基础管道跑通之后你很快会面临一个真问题几十个测试问题里总有几条检索不到正确答案。我排查命中率低的情况几乎都是三个原因。第一个是切分粒度不对这是最常见的问题某些文档的关键信息横跨多个块切分后完整内容被拆成碎片向量检索只能命中其中一半导致信息残缺第二个是提问表达和文档表达差异过大用户习惯口语化提问而文档写得非常正式纯向量检索有时无法跨越这个距离这种情况下混合检索能显著提升命中率第三个是 embedding 模型的语义捕捉能力不够同一个词组在不同语境下的含义层次不够深的模型分辨不出来。定位是哪一类问题有个很直接的办法把检索回来的原始片段打印出来看一眼。如果返回内容和问题有明显语义关联但缺少关键细节是切分问题如果返回内容完全偏了是检索策略问题如果返回内容看起来都对但模型还是答错那就得看生成端的提示词和模型选型。别一上来就怀疑大模型RAG 的绝大多数质量问题根源都在检索端也就是在“有没有把正确答案拿出来”这一步。4.2 Agentic RAG让模型自己决定查什么前面介绍的是单次检索的 RAG管道是直线型的问题进来、检索一次、拼上下文、输出回答。这种形式解决单点问题没问题但一旦用户的提问涉及多跳推理比如“最近涨价的那个品类的售后政策是什么”需要先定位哪个品类涨价了、再查这个品类的售后政策单次检索就会顾此失彼。Agentic RAG 的思路是把检索能力接入 Agent 的工具列表让模型自己判断需要查几次、用什么样的查询词去查。实际落地的时候我倾向于让 Agent 在执行中维护一个“查询计划”先拆解问题成子任务每执行一次检索就检查一遍结果是否足够回答问题不够就继续追加查询。这种行为模式的代价是响应变慢但换来了对复杂问题更可靠的回答。有一种折中方案是先用单次 RAG 快速回答同时让模型给一个“置信度”判断如果置信度低再自动转入多轮检索。这种在有真实业务压力时非常实用。Skill 与 RAG 的结合也有类似的逻辑RAG 负责非结构化文档的理解Skill 负责调用数据库、API 做结构化查询两者组合起来智能体才能真正覆盖业务场景里混合查询的需求。4.3 知识割裂问题多个文档源如何统一RAG 落地一段时间后你会开始碰到数据源变多带来的“知识割裂”问题。比如公司文档既有产品手册、又有售后规范、还有同事沉淀的零散笔记三个来源对同一件事的说法可能不一致或者各自只管自己的一部分。这时候只管把文档丢进向量库会发现两个毛病一是不同来源的相似内容检索时互相打架难以去重二是用户问一个跨领域问题时检索结果可能只来自某一个源另一个源里的关键信息被淹没了。我的处理经验是层层治理。首先在索引阶段就给每个文档块打上元数据标签比如来源、更新时间、文档类型这样检索时可以加权过滤其次在检索阶段引入混合检索后再做一轮来源层面的多样性约束尽量让结果覆盖不同的文档源而不是全被同一份文档霸占最后如果是长期负责的知识库可以考虑用图结构组织实体和概念之间的关系这种演进路线常被叫做 GraphRAG能弥补纯向量索引缺乏全局关联的短板。但说实话大部分团队连前两步都还没做好先别急着上知识图谱。5. 常见问题与排查实录5.1 症状、原因与解法速查表我把实际操作中遇到的高频问题整理成一张表方便大家对照排查症状可能原因排查方法解决办法检索结果相关但答案不准上下文关键信息缺失打印返回片段查看调整切分块与重叠区检索结果完全不相关向量索引未正确切换模型检查 embedding 版本重建索引统一模型精确 ID 查不到纯向量检索忽略精确词打印相似度得分接 BM25 混合检索回答编造资料外内容提示词缺少约束检查 prompt 指令明确“无资料即不知道”多个来源互相矛盾缺少来源优先级策略查看引用来源标签按文档类型加权加权威源优先同一问题每次结果不同温度设置过高检查生成参数将 temperature 调低这张表基本覆盖了从“跑通”到“可用”之间会遇到的主要障碍。我在实际排查中有一个习惯先用一条已知正确答案的问题做回归测试把检索片段、相似度分数、模型输出三级日志全部打印出来这样做一次问题在哪个环节基本就一目了然了。多数时候问题并不是出在最引人注意的模型身上而是出在那些不起眼的中间环节。5.2 我踩过的一些细节坑最后分享几个很具体、但几乎不会写在教程里的坑。第一个是换 embedding 模型后忘记重建索引。有个阶段我觉得某个检索效果不好直接把 embedding 配置换成了新模型然后继续用旧索引查询结果命中率暴跌。原理很简单新旧模型的向量空间完全不一致旧索引里的向量表达已经失效。换模型不是改个配置的事必须全量重新跑一遍索引。第二个是切分器把中文排比句拆得七零八落。初期我的 separators 里没有放顿号遇到一段“包括但不限于防潮、防尘、防震、防腐蚀”时切分器把整段当成一个块检索长尾问题时会漏掉细节。之后我在分隔符列表里调整了顺序中文标点的优先级需要根据文档风格做适配。第三个是上下文顺序影响模型关注度。模型对上下文开头的部分注意力更强如果一个问题需要多个片段我会按相关性从高到低排列片段顺序把最相关的放在最前面。一开始我按数据库返回顺序直接拼接等于把最优的答案放在最后模型注意力分配不均匀回答效果明显打折。还有一个容易被忽略的点PDF 加载时经常出现表格被解析变形的问题。比如一张规格表在 PDF 里是行列整齐的解析出来可能变成一行行文本切分后表格上下文彻底丢失。这种场景我一般会先用工具做一次表格抽取手动清洗后再进索引不能指望通用加载器直接给出一份堪用的数据。数据进管道的那一刻输入质量就已经决定了大模型的回答上限。6. 结尾的话RAG 说到底是“把资料递给模型之前先帮它把资料挑好”的艺术。这条管道看起来只有索引、检索、生成三段但每一段里都有足够多的细节值得打磨。我自己搭过不少 Agent 项目最大的体会是不要急着把框架越整越复杂先把一条最简单的链路跑通然后用评测数据找出瓶颈再逐步加混合检索、Rerank、多轮决策这些进阶能力。知识获取管道的核心指标不是 tps而是那一个朴实无华的 hit rate——它上去了后面生成端的事情就好办了。如果你正在为检索结果不理想发愁建议先打印一条查询的完整链路看看大概率能发现答案就藏在那些你认为“没必要”的小细节里。