拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

从零搭建RAG知识管道:智能体知识获取与检索增强实践

从零搭建RAG知识管道:智能体知识获取与检索增强实践

1. 为什么编排智能体时,知识获取比推理能力更难

1.1 大模型的知识边界,决定了智能体的能力天花板

先说一个我这段时间反复体会到的点:很多人搭智能体,一上来就盯着模型选型、提示词打磨、工具调用流程设计,觉得只要推理链路顺了,智能体就聪明了。但真正把智能体推到业务场景里才发现,卡住它的往往不是"想不想得到",而是"知不知道"。

模型在训练时学到的那点世界知识是固定的,训练截止日期之后发生的事情,它一概不知。你自己的业务文档、私有数据库、内部流程规范,它更是从来没看过。这种情况下,你问它任何一个稍微具体的问题,它要么一本正经地编,要么客客气气地说不知道。编出来的东西在演示环境里还能糊弄过去,一旦放进真实业务,一个错误引用就可能引发连锁问题。

我在前几篇里聊过 Agent 的规划、工具使用、记忆设计,但一直没详细展开知识这一层。这一篇专门补上:AI Agent 的知识获取管道,也就是 RAG 基础。RAG 全称是 Retrieval-Augmented Generation,检索增强生成,通俗讲就是先让模型去一个外部知识库里捞相关片段,再把这些片段连同问题一起交给模型去组织回答。这样模型既不需要记住你的全部文档,也能在你指定的资料范围内做事实性回答。

1.2 为什么说是"管道",而不是"插件"

很多第一次接触 RAG 的人,直觉上把它理解成一个"把文档塞给模型"的过程。实际上,它是一条完整的处理链路:原始文档清洗 → 文本切分 → 向量化 → 索引存储 → 查询召回 → 上下文组装 → 生成回答。任何一个环节做得粗糙,最终效果都会打折,而且越靠前的环节出了问题,越难在后面找补。

打个比方,RAG 管道就像给一个外聘专家配一个实习助理。专家本人能力很强,但对你公司的内部情况一无所知。助理的工作就是提前把档案室里的资料整理成带编号的卡片,按主题分好类,专家提问的时候,助理先跑过去把相关的几张卡片翻出来,放在专家面前。专家对着卡片作答,而不是凭自己脑子里那点行业常识瞎猜。这个助理干得好不好,直接决定了专家答得准不准——哪怕专家本身是顶级的。

1.3 先把"RAG 能干什么、不能干什么"想清楚

在动手搭管道之前,我建议你花十分钟想清楚预期。RAG 解决的是"模型不知道但知识库里有"的问题。它不能解决"知识库里压根没有"的问题,也不能凭知识库生成超出资料范围的结论。它还怕一种情况:检索到的内容本身就彼此矛盾。这时模型依然可能挑一条看起来更像那么回事的,然后以非常自信的语气说出来。

所以,这一篇的所有内容都建立在同一个认识上:RAG 的目标是提高知识获取的成功率,而不是保证 100% 正确。我们后面聊的所有优化手段,都是围绕这个目标来的——尽量在检索环节把命中的概率推高,把噪声压下去。

2. 从零搭一条最简知识管道:文档切分与向量化才是重灾区

2.1 源文档清洗:脏数据没人帮你兜底

先把最无聊但最重要的一件事说了:文档清洗。我见过不少团队,兴致勃勃地把几百份 PDF、Word、Markdown 一股脑扔进向量数据库,跑通 demo 之后兴奋得不行,结果一测真实问题,返回的片段乱七八糟,格式残缺、目录页混进来、表格被切得七零八落。问题不在检索,而在源头的解析质量。

你用的解析工具要针对文档类型做选择。PDF 建议先用 PyMuPDF 或 pdfplumber 提取文本,遇到扫描件再上 OCR;Word 文档用 docx 库按段落读取;Markdown 或 HTML 反而要小心,因为里面的标记符号如果没清理干净,会被一起切进块里,污染向量。还有一类文档很容易踩坑——很多 PDF 的页眉页脚、页码、目录页,在提取时都会变成一段段孤立的文本。这些文本向量化之后几乎没有任何语义信息,但照样占据索引位置,检索时偶尔还会被莫名其妙地捞上来。

我现在的做法是,解析之后先跑一轮规则清洗:去页眉页脚、去目录页、去重复空行、把中英文标点统一。业务文档多的情况下,这个步骤不能省,它虽然枯燥,但能直接影响后面的命中率。

2.2 分块策略:块大小、重叠和分隔符要一起调

接下来是 RAG 管道里变量最多的一步:分块(chunking)。分块的核心矛盾在于:块太小,语义上下文不完整;块太大,噪声多,向量化时特征会被稀释,召回精度下降。常见的做法是按固定字符数切分,比如 500 字符一块。但固定切分有个明显的毛病:句子或段落会被拦腰截断,语义完整性被破坏。

更稳妥的方式是按语义边界切分。先用 Obsidian 或者 LangChain 里的 RecursiveCharacterTextSplitter 这类按分隔符递归切分的工具,它会优先从段落边界切,其次是句号、换行、长空格,最后才兜底按字符数硬切。我建议开发阶段把块大小设在 300 到 800 字之间,块与块之间留 50 到 100 字的重叠,这样切在文档中间时,上一块的结尾能在下一块开头出现,避免关键句被分隔符一分为二。

但记住一点:不同领域的文档,最适合的分块参数完全不同。代码类文档要按函数切,法律合同要尽量保持条款完整,纯叙述的技术博客按段落切就很自然。你最好把分块逻辑做成可配置的,然后建一个测试集,逐个参数组合跑一遍,看哪组的效果稳定。这不是一份努力一分收获的问题,是九分调整一分收获。

2.3 Embedding 选型:模型、维度与部署方式的取舍

分块完成后,每一块文本要变成向量。选 Embedding 模型,本质上是在找一个能把"语义相近"映射成"向量距离相近"的映射。这里有个很容易忽视的点:Embedding 模型的分词器和语义理解能力,直接决定你对中文长文本的支持效果。

现在国内可用的大语言模型生态里,有不少国产 Embedding 模型做得相当不错,比如 BGE 系列,对中文支持很好,而且开源可商用。如果你的文本是英文为主,OpenAI 的 text-embedding-3 之类也够用。但无论选哪个,我都建议设统一维度,比如 1024 或 1536,方便后面切换模型时不用重构整个向量库。

部署方式上,小规模项目直接调 API 就行,省心;数据量大了,或者有私密性要求,就本地部署一个 Embedding 服务。实测下来,本地部署 bge-large-zh 在一台普通 GPU 机器上,处理几百份文档基本无压力。别着急在 Embedding 模型上追求最强能力,先把管道跑通,再看检索质量决定要不要换。

3. 检索端才是决定 RAG 上限的地方

3.1 向量数据库选型:从轻量到重型,先别过度设计

很多人一听到向量数据库,第一反应就上 Milvus 或者 Elasticsearch 的向量插件,觉得这才叫专业。但对一个刚开始搭建的 Agent 项目来说,这属于过度设计。你的起步阶段数据量可能就几千个块,一个 FAISS 本地索引就够用了,甚至用 Chroma 或者轻量级的向量文件都能跑得很顺。

我给你的建议是分阶段选型:

阶段推荐方案理由
原型验证Chroma / FAISS 本地索引零运维,几分钟跑通,迭代快
小规模上线pgvector(在 PostgreSQL 里开向量字段)复用已有数据库,事务、权限一套带走
大规模生产Milvus / Qdrant / Elasticsearch分布式、高并发、可扩展

这里有个亲测有效的经验:在数据量没到百万级块之前,向量数据库选型对效果的影响远小于你对分块和检索策略的调优。别让基建问题分散了你的注意力,先把管道逻辑跑对。

3.2 相似度计算与 top-k:别把召回做成"猜谜"

检索的核心就是一句话:找到与问题语义最接近的若干块。常见相似度度量有三种——余弦相似度(Cosine)、欧式距离(L2)、内积(Inner Product)。对文本来说,用余弦相似度最直观,它只关注方向、不受向量模长影响,语义特征能在归一化后趋于稳定。很多向量数据库默认也是用余弦。

top-k 的选择也是门道。k 太小,比如只取 1,那相当于把宝全压在一段文本上,一旦这个块切得不够好,整轮回答就废了。k 太大,比如取 10,模型要消化大量噪声,生成质量反而下滑。我起步时通常用 top_k=4 到 6,然后在测试集上回调。另一个容易被忽略的参数是返回的分数阈值——低于某个相似度阈值的片段干脆不返回。这样可以避免用户问一个知识库完全没有的问题时,模型"矮子里拔将军"硬答。

3.3 混合检索与重排序:提升精度的两板斧

纯向量检索的问题在于,它理解的"相似"更多是语义层面的,对精确关键词匹配不敏感。举个例子,用户问的是"服务器的保修截止日期",知识库原文写的是"3 年质保服务到期时间"。向量检索大概率能命中,因为语义相近;但如果用户问一个非常具体的型号代码"R740-XD3",而原文恰好只出现过这个型号且没有任何上下文修饰,向量检索就可能把它淹没在语义噪声里。

实际生产中,我建议在向量检索之外再加一个 BM25 关键词检索,两边结果合并后再过一轮重排序(rerank)。BM25 负责把"字面命中"的文档捞回来,向量负责"意思相近"的文档,重排序模型再综合信号把最准确的结果往前提。三者配合,命中率提升非常明显。

重排序模型的接入很简单,向量库端返回候选集之后,把候选集文档和用户问题一起送入 rerank 模型,比如 BGE-reranker,它会给每个候选打一个相关度分数,你再按这个分数截断到最终 top-k。这一步对 RAG 质量的提升,往往比换一个更大的生成模型还要显著。这个发现是我自己踩了不少坑之后才确认的——之前一直以为"模型够聪明就能自己分辨相关片段",结果发现模型面对 6 段候选文本时,经常被不相关的段落带偏。加了重排序之后,问题基本消失。

4. 知识管道的出口:上下文组装与生成层的细节

4.1 "检索到什么"和"模型看到什么"是两回事

检索环节找到了相关块,不代表你就可以把这些块一股脑拼进提示词里。组装上下文是一个独立的细节层,做得不好,前面再好的检索也可能白费。

首先,块与块之间的顺序会影响模型的注意力。通常与问题最相关的块要放最前面。这里有个心理学的道理,模型跟人很像,对序列开头内容的注意力最强。如果不排序直接随机丢进去,模型容易被中间夹着的次要内容带偏。

其次,每段上下文前面最好加一个来源标记,比如"来源文档:[设备运维手册],章节:4.2"。这样做有两个作用:一是让模型知道这些片段来自哪里,回答时更倾向引用原文;二是方便你在生成结果后面挂引用链接,这在很多企业场景里是刚需——用户看到了答案,还得能点开原文确认。

4.2 Token 预算:一个常常被低估的约束条件

每组块的 token 长度、模型上下文窗口、最终回答需要占用的输出空间,这三者的平衡要认真算一算。假设模型上下文是 8K token,输出留 2K,那输入侧就只有 6K。如果每块约 300 字,大概占 500 token,那 top_k 就不能超过 10,否则上下文直接溢出。很多框架会自动截断超长的上下文,但截断策略很粗暴——从尾部直接砍。如果恰好把最相关的块放在尾部,那这轮回答基本就废了。

所以我的习惯是:先决定输出预算,再从后往前排上下文。核心块放最前面,越是辅助性的块越靠后,宁可牺牲一些辅助块,也要保证核心块完整进上下文。如果你是按相关度倒序排列,那其实天然就符合这个策略,只需要再确认一下总的 token 消耗不要超限。

4.3 提示词里的知识段约束怎么写

生成层的提示词,和普通 ChatGPT 对话的提示词有本质区别。普通对话的提示词目标是"规定角色和风格",RAG 场景的提示词目标是"规约信息的用法"。

我在提示词里固定加入这样几类约束:

  • 清晰说明检索片段是唯一的回答来源,暂用外挂背景时要不明确承认;
  • 规定回答要引用原文,不得掺入模型自己的预训练知识;
  • 给出当检索片段不足以回答时的处理方式——可以是"你说得对,知识库里没有这个信息"这种姿态的引导,让模型直接说明知识缺失,而不是强行拼接;
  • 要求输出格式上提供来源引用。

这几个约束看起来简单,但对回答质量的稳定性影响很大。尤其是"当信息不足时如何回应"这一点,很多小白会忽略,结果就是知识库明明资料不全,模型却在用自己脑补的内容和检索到的片混合编造答案。用了约束之后,模型更倾向于诚实地说"资料中没有直接提到这个信息",这在真实业务里比假装知道要重要得多。

5. 从命中率到忠实度:把 RAG 性能量出来再优化

5.1 盲调是不行的,先定义你的评估集

RAG 管道有太多环节可以调,如果没有一套固定的评估方法,你根本不知道改动是变好了还是变差了。我在实际项目中养成的习惯是:维护一个 50 到 100 条问答的测试集,覆盖各种常见问题、模糊问题、带否定词的问题、找不到对应资料的问题等等。这个测试集不追求数据量,追求的是问题的代表性。

然后每改一次分块参数、检索策略、提示词,就用同一套测试集跑一遍,把结果记下来对比。长期对比下来,你对"哪个环节最敏感"就会形成手感,而不是抓瞎。

5.2 三个关键指标:命中率、相关性与忠实度

多数人评估 RAG 只看一个指标:最后回答对不对。这其实把概念揉成一团了。我更建议拆成三层来看:

  • 检索命中率(Hit Rate):知识库中包含答案的文档,是否被检索端成功召回。这是检索环节的指标,和生成无关。
  • 相关性(MRR / NDCG):命中的结果是否排在候选列表的前列。如果答案排到第 10 位,即使被召回了,生成环节也可能被前面的噪声带偏。
  • 忠实度(Faithfulness):最终回答是否严格基于检索到的片段,有没有引入模型自己的臆测。

这三个指标对应管道上不同的环节。命中率低,去调分块和检索策略;相关性低,去调重排序和 top-k 截断;忠实度低,去调提示词约束和上下文排序。用指标定位问题,比拍脑袋改参数高效得多。

我强烈建议每个 RAG 项目至少跑一轮这样的评估。很多团队上线了 RAG 却一直觉得效果"怪怪的",说不出哪里不对,其实就是指标没拆开看,所有问题都混在一起了。

5.3 带反馈的知识管道:迭代周期怎么设计

单次优化是远远不够的。知识库里会不断补充新文档,用户问的问题也会越来越刁钻,RAG 管道必须能持续迭代。我的迭代节奏是:每周从真实对话日志里抽出那些"用户不满意"或"模型回答明显错误"的 case,人工标注一次,判断问题出在检索还是生成,然后针对性地小步调整。

这里我特别想强调一个点:用户满意度是一个粗糙但是极其有效的信号。如果用户在 Agent 回答后点了"踩",或者继续追问"不对吧",这些样本的价值比任何漂亮的离线指标都大。把这些 case 不断反哺评估集,你的测试集就会越来越贴合真实使用场景,优化方向自然也越来越准。

6. 从基础 RAG 到 Agentic RAG:知识管道演进的下一站

6.1 固定管道 vs 动态决策

聊完基础 RAG,我觉得有必要提一嘴它和 Agentic RAG 的差别,因为这是这两年的热点方向,也是我在实践中最看好的演进路径。

基础 RAG 是一条固定管道:问题来了,检索,拼上下文,生成回答。整个过程是单向的、一次性的。它的局限也很明显——遇到复杂问题,一锤子买卖往往捞不全信息。比如用户问"帮我对比一下 A 产品和 B 产品在运维成本上的差异",这个问题至少需要两轮检索:先查 A 的成本构成,再查 B 的成本构成,可能还需要再查一下两者的共同计价规则。固定管道一次只能捞一组片段,很容易丢信息。

Agentic RAG 的思路是让模型自己决定检索策略。它可以先根据初步检索结果判断信息够不够,不够就二次检索;可以拆解问题,分别检索再汇总;甚至可以在检索过程中发现新关键词,用它追搜下一批文档。基础 RAG 像一个只管执行查询的检索员,Agentic RAG 像是一个能自己判断"还要什么资料、去哪找"的研究助理。

6.2 我的实践建议:先把基础管道打磨透,再谈自适应

虽然 Agentic RAG 听起来美好,但我还是建议你把基础管道打磨透再上。原因很简单:Agentic RAG 的每次自适应决策,都是基于基础检索质量做的判断。如果基础管道召回质量差,Agent 反复检索也捞不回对的文档,只会让延迟变高、token 消耗变大,用户体感反而更差。

我自己目前的实践路线是:先把固定管道的命中率调到 80% 以上,再在检索模块外面加一层简单路由——先从问题里抽取关键词和问题类型,判断是单轮检索可以直接回答,还是需要拆成子问题多次检索。这一步不需要很复杂的思路,用一个大模型做路由器就行,但对复杂问题的覆盖率提升明显。

6.3 知识获取几乎是所有智能体的必经之路

回顾整个系列,前面几篇讲的规划、工具、记忆,本质上都是在优化 Agent 的"思考方式"。但一个智能体要想在真实业务里办成事,思考方式之外,还必须有一条可靠的知识获取管道。没有这条管道,Agent 就是一位能力很强但完全不了解你公司现状的外部顾问,聊得热闹,落不了地。

这一篇里我只聊了 RAG 基础,也就是"检索一段、拼一段、答一段"的骨架。接下来我打算再深入写一篇关于质检与知识保鲜的内容,也就是当文档更新、过时、出现矛盾时,管道怎么动态调整。反正做成一个能跑起来的智能体,知识侧的路还很长。希望这篇基础篇能帮你把第一段路铺稳。

返回列表