1. 为什么知识获取管道是 AI Agent 的分水岭
做 AI Agent 开发的人,绕不开一个尴尬的现实:模型本身很聪明,但它不知道你公司上个月刚改的报销制度,不知道你手里那份三百页的设备维护手册写了什么,更不知道你昨天刚录入 CRM 的那条客户特殊需求。大模型的知识截止在训练完成那一刻,而真实业务的知识每天都在变。这个矛盾不解决,Agent 就只能是个"聊天玩具",进不了生产环境。
知识获取管道要干的事,说白了就是给 Agent 装一套"随时能查资料"的本事。用户问一个问题,Agent 先去知识库里把相关的资料捞出来,塞进上下文,再让模型基于这些资料回答。这套机制就是RAG(Retrieval-Augmented Generation,检索增强生成)。我在实际项目里踩过的坑告诉我,RAG 看起来简单——不就是"检索+生成"两步吗——但真正决定效果的是中间那一堆细节:文档怎么切、向量怎么选、检索怎么排、上下文怎么拼。任何一个环节偷懒,最后都会变成"答非所问"或者"一本正经地胡说"。
这篇是"走进 AI Agent"系列的第四篇,专门聊知识获取管道的基础设施。我会把 RAG 的核心链路拆开讲透,包括稠密嵌入和稀疏嵌入这两种检索路线的取舍、文档切分的实操参数、检索结果的重排策略,以及怎么把这些东西接进 Agent 的工作流。适合正在从 0 到 1 搭建 AI Agent 的开发者,也适合已经跑通了 demo 但效果不稳定、想搞清楚问题出在哪的朋友。不管你是用 LangChain、Spring AI 还是 AgentScope,底层的道理是通的。
2. RAG 到底解决了什么问题,又没解决什么
2.1 从"模型不知道"到"模型查得到"
先把这个逻辑理清楚。大模型的能力来自训练时见过的海量文本,这些知识被压缩进了几千亿个参数里。压缩是有损的,而且训练完成之后参数就冻结了。你没法通过对话让模型"记住"一份新文档——它顶多能在当前这轮对话的上下文里临时用一下,对话一结束就忘了。这就是所谓的"知识割裂":模型的能力和你的业务知识是两张皮。
RAG 的思路很直接:既然模型记不住,那就不让它记,改成每次需要的时候现查。具体来说分三步走。第一步是离线索引,把你所有的文档——PDF、Word、网页、数据库记录——处理成可以快速检索的形式,存进向量数据库。第二步是在线检索,用户提问时,把问题也转成同样的形式,去数据库里找最相关的若干条资料。第三步是增强生成,把检索到的资料和用户问题一起拼成 prompt,交给模型生成答案。
这个流程的价值在于,知识更新只需要重新索引文档,不用重新训练模型。你改了一份制度文件,几分钟后 Agent 就能用上新版本。成本低、响应快,这是 RAG 能成为企业级 AI Agent 标配的根本原因。
2.2 RAG 不是万能药,边界要清楚
但我得泼盆冷水。RAG 擅长的是"事实性问答"——问什么答什么,答案就在文档里。它不擅长的是需要多步推理、跨文档综合、或者理解隐含逻辑的问题。比如你问"根据这三份合同,哪一份对我们最有利",这不是检索能解决的,得靠 Agent 的推理能力配合。
还有一个常见误解是"上了 RAG 就不会幻觉了"。错。RAG 只是把相关资料喂给模型,模型仍然可能曲解资料、张冠李戴、或者在没有相关资料时硬编一个答案。所以生产环境里必须加一层"检索置信度判断"——如果检索回来的东西相关度太低,宁可让 Agent 说"我没找到相关资料",也不要让它瞎猜。
提示:判断一个场景适不适合 RAG,问自己一个问题——"这个问题的答案,能不能在某份具体文档里找到原话或近似表述?"能,就适合;不能,就得考虑别的方案。
2.3 知识获取管道在 Agent 架构里的位置
放到整个 AI Agent 架构里看,知识获取管道是一个"工具"。Agent 在思考过程中判断"我需要查资料",然后调用检索工具,拿到结果,继续推理。这跟 Agentic RAG 的思路是一致的——检索不再是固定流程,而是 Agent 自主决定何时检索、检索什么、检索几次。
这意味着知识获取管道的接口设计要足够灵活。它不能只是一个"输入问题返回答案"的黑盒,而应该暴露更细粒度的能力:按关键词检索、按语义检索、按元数据过滤、获取某篇文档的完整内容等等。Agent 根据当前任务的需要,自己组合这些能力。后面讲实操的时候我会具体说接口怎么设计。
3. 稠密嵌入与稀疏嵌入:两条检索路线的取舍
3.1 稠密嵌入:语义相似度的主力
稠密嵌入(Dense Embedding)是现在 RAG 的主流方案。它的做法是把一段文本通过一个神经网络模型,映射成一个固定长度的向量,比如 768 维或 1536 维。这个向量里的每一个数字都是浮点数,整个向量稠密地编码了这段文本的语义信息。
关键在于,语义相近的文本,它们的向量在空间里的距离也近。你搜"怎么申请年假",一篇标题是"休假流程说明"的文档虽然字面上没有"年假"两个字,但语义上很接近,稠密检索能把它找出来。这是稠密嵌入最大的优势——理解语义,不受字面措辞限制。
常用的稠密嵌入模型有 BGE、M3E、text-embedding-3 系列等。选型的时候主要看三个指标:检索准确率(通常看 MTEB 榜单)、向量维度(维度越高越准但存储和计算成本越大)、以及推理速度。中文场景我一般推荐 BGE 系列,在中文语义理解上表现稳定,而且有不同尺寸的版本可以按算力选。
稠密嵌入的短板也很明显。它对精确匹配不敏感。比如你搜一个产品型号"XR-2000A",稠密检索可能返回一堆"XR 系列产品"的文档,但就是漏掉了那个精确提到"XR-2000A"的。因为模型在训练时见这种型号见得少,编码出来的向量区分度不够。这时候就需要稀疏嵌入来补位。
3.2 稀疏嵌入:关键词精确匹配的守门人
稀疏嵌入(Sparse Embedding)走的是另一条路。它的向量维度等于词表大小,可能几万到几十万维,但绝大多数位置是 0,只有文本里出现过的词对应的位置才有值。这个值通常是这个词的权重,比如 TF-IDF 或者 BM25 算出来的分数。
传统的关键词检索(比如 Elasticsearch 的 BM25)本质上就是稀疏检索。它的优势是精确——你搜"XR-2000A",它一定优先返回包含这个精确字符串的文档。对于专有名词、产品型号、错误码、人名这类需要精确匹配的场景,稀疏检索比稠密检索靠谱得多。
但稀疏检索的问题是"词汇鸿沟"。用户搜"年假",文档里写的是"带薪休假",字面不匹配,稀疏检索就抓瞎了。而且它不理解同义词、上下位词的关系。
3.3 混合检索:成年人全都要
实际项目里,我基本不会只用一种。混合检索(Hybrid Search)把稠密和稀疏的结果融合起来,兼顾语义理解和精确匹配。融合的方法有几种,最常用的是 RRF(Reciprocal Rank Fusion,倒数排名融合)。
RRF 的逻辑很简单:不看具体分数,只看排名。假设稠密检索返回的文档排名是 1、2、3,稀疏检索返回的排名是 2、1、4,那每个文档的融合分数就是 1/(k+排名) 的累加,k 通常取 60。最后按融合分数重新排序。这样做的好处是不用操心两种检索的分数尺度不一样的问题——稠密检索的余弦相似度是 0 到 1,BM25 的分数可能是 0 到 30,直接加权平均会出问题,RRF 绕开了这个坑。
| 检索方式 | 优势 | 短板 | 适用场景 |
|---|---|---|---|
| 稠密嵌入 | 语义理解强,容忍措辞差异 | 精确匹配弱,专有名词易漏 | 概念性问答、自然语言提问 |
| 稀疏嵌入 | 精确匹配强,可解释性好 | 词汇鸿沟,不懂同义词 | 型号查询、错误码检索、法律条文 |
| 混合检索 | 兼顾两者,召回率高 | 实现复杂,需要调融合参数 | 生产环境通用方案 |
注意:混合检索不是简单地把两边的结果拼起来。如果不去重和重排,你会得到一堆重复文档,白白占用上下文窗口。RRF 之后通常还要接一个重排模型,这个后面细说。
4. 文档处理:RAG 效果的地基
4.1 文档解析:别在第一步就丢信息
很多人做 RAG 效果不好,问题根本不在检索,而在文档解析这一步就把信息弄丢了。PDF 里的表格、Word 里的多级标题、网页里的导航栏,这些如果处理不当,要么丢失关键信息,要么引入大量噪声。
我的经验是,解析工具要按文档类型分开选。纯文本和 Markdown 直接读就行。PDF 分两种:文字型 PDF 用 PyMuPDF 或 pdfplumber 提取,扫描型 PDF 得先走 OCR。表格是重灾区,pdfplumber 能提取表格结构,但复杂合并单元格经常出错,必要时得人工校对。Word 文档用 python-docx,注意保留标题层级,这对后面的切分很重要。
解析完之后要做清洗。去掉页眉页脚、页码、重复的水印文字,把全角半角统一,把连续的空白字符合并。这些看似琐碎,但直接影响检索质量。我见过一个项目,因为没去页眉,每段文本开头都带着"XX公司内部资料 第X页",导致所有文档的向量都变得很像,检索区分度直线下降。
4.2 文档切分:粒度决定成败
切分(Chunking)是 RAG 里最需要经验的一步。切得太粗,一个 chunk 里混了好几个主题,检索出来噪声大;切得太细,一个完整的论述被拆散,模型拿到半截话也答不好。
基础做法是固定长度切分,比如每 500 个 token 一个 chunk,相邻 chunk 之间重叠 50 个 token。重叠是为了防止一句话正好被切断,导致语义不完整。这个方案简单,但缺点是它不管语义边界,可能把一段完整的话从中间劈开。
进阶做法是递归字符切分,按优先级依次尝试用段落分隔符、句子分隔符、空格来切,尽量在语义边界处断开。LangChain 的 RecursiveCharacterTextSplitter 就是这个思路。再进一步是语义切分,用嵌入模型计算相邻句子的相似度,在相似度骤降的地方切开,这样每个 chunk 内部主题更集中。
具体参数怎么定?我的经验值是这样的:中文文本,chunk 大小 300 到 500 字,重叠 50 到 80 字。为什么是这个范围?因为嵌入模型通常有最大输入长度限制(比如 512 token),超过会被截断;而太小的 chunk 又缺乏上下文。300 到 500 字大概是一到两个自然段的量,既能表达完整意思,又不会太杂。
| 切分策略 | 实现难度 | 效果 | 适用场景 |
|---|---|---|---|
| 固定长度 | 低 | 一般 | 快速原型、结构规整的文本 |
| 递归字符 | 中 | 较好 | 通用场景,推荐默认 |
| 语义切分 | 高 | 好 | 对精度要求高的知识库 |
| 按文档结构 | 中 | 好 | 有明确标题层级的文档 |
4.3 元数据:被低估的检索利器
每个 chunk 除了文本内容,还应该带上元数据。元数据包括来源文档名、章节标题、创建时间、文档类型、权限标签等等。这些信息在检索时能派上大用场。
举个例子,用户问"2025 年的差旅标准是多少",你可以先用元数据过滤出"差旅制度"这个文档、且"年份=2025"的 chunk,再在里面做语义检索。这样检索范围一下子缩小了,准确率和速度都上去了。再比如权限控制,不同部门的用户只能检索到有权限的文档,这在元数据层面加个过滤条件就实现了。
元数据的另一个用途是引用溯源。Agent 回答完问题,附上"根据《差旅管理制度》第三章",用户一看就知道答案从哪来,信任度立刻不一样。这在企业场景里特别重要。
5. 从检索到生成:把管道串起来
5.1 向量数据库选型:别一上来就上重型武器
向量数据库这两年冒出来一大堆,选型的时候容易挑花眼。我的建议是按数据规模和团队情况来。
数据量在十万条 chunk 以内,用 FAISS 就够了。它是 Facebook 开源的库,本地跑,不需要额外部署服务,检索速度极快。缺点是它只是个索引库,不支持增删改的实时更新,也不支持元数据过滤,适合离线批处理的场景。
数据量上去了,或者需要实时更新、元数据过滤、多租户隔离,就得上专业的向量数据库。Milvus 功能全、社区活跃,但部署运维有一定门槛。Qdrant 轻量一些,Rust 写的,性能好,单机就能跑。pgvector 是 PostgreSQL 的扩展,如果你本来就用 PG,直接加个扩展最省事,还能和业务数据做联合查询。
提示:选型时别只看性能 benchmark。考虑你的团队能不能维护、有没有现成的运维体系、数据需不需要和关系型数据库做 join。技术选型是综合题,不是单科竞赛。
5.2 重排:检索质量的最后一道闸
初步检索回来的 top-k 结果,通常不能直接用。因为向量检索是基于向量距离的近似匹配,排在前面的不一定真的最相关。这时候需要一个重排模型(Reranker)来做精排。
重排模型和嵌入模型的区别在于,嵌入模型是"双塔"结构,问题和文档分别编码,速度快但精度有限;重排模型是"交叉编码"结构,把问题和文档拼在一起过一遍模型,能捕捉更细粒度的交互,精度高但速度慢。所以典型流程是:先用向量检索快速召回 top-50,再用重排模型精排出 top-5,喂给大模型。
常用的重排模型有 BGE-Reranker、Cohere Rerank 等。实测下来,加一层重排,检索准确率能提升 10 到 20 个百分点,这个投入非常值。代价是增加了几十到几百毫秒的延迟,看你的场景能不能接受。
5.3 上下文组装:怎么把资料喂给模型
检索到相关 chunk 之后,怎么拼进 prompt 也有讲究。最朴素的做法是把 top-k 个 chunk 直接拼接,前面加一句"请根据以下资料回答问题"。但这样有几个问题:chunk 之间可能重复、可能矛盾、可能顺序混乱。
我的做法是:先去重,把内容高度相似的 chunk 合并;然后按相关度排序,最相关的放最前面(模型对开头的内容注意力更高);每个 chunk 前面标注来源,方便模型引用;最后加一句明确的指令,告诉模型"如果资料中没有答案,就直说不知道,不要编造"。
上下文长度也要控制。不是塞得越多越好,无关内容会稀释模型的注意力,还可能超出模型的上下文窗口。一般 top-3 到 top-5 就够了,具体看 chunk 大小和模型窗口。
6. 实操中踩过的坑与排查手册
6.1 检索不准:先别怪模型
检索效果差,很多人第一反应是换个更强的嵌入模型。但根据我的经验,八成的问题不在模型,而在前面几步。
排查顺序应该是这样的:先看文档解析有没有丢信息,特别是表格和图片里的文字;再看切分粒度合不合适,把几个 chunk 打印出来读一读,看是不是被切得莫名其妙;然后看检索时用的 query 和索引时的文本是不是同一种语言、同一种表述风格;最后才考虑换模型或者加混合检索。
我遇到过一个典型案例:用户搜"报销要多久到账",怎么都检索不到相关文档。查了半天发现,文档里写的是"费用核销周期为 15 个工作日"。字面上完全不搭,但语义上是一回事。这种情况稠密检索应该能搞定,之所以失败,是因为嵌入模型对"报销"和"核销"这两个词的语义关联学得不够好。解决办法是换一个在财务领域语料上微调过的嵌入模型,或者在 query 前面加一句"用户想问的是费用报销相关的问题"来做查询扩展。
6.2 常见问题速查表
| 现象 | 可能原因 | 排查方向 | 解决思路 |
|---|---|---|---|
| 检索结果完全不相关 | 嵌入模型不匹配语种/领域 | 检查模型是否支持中文 | 换 BGE 等中文模型 |
| 精确词搜不到 | 只用了稠密检索 | 测试稀疏检索能否命中 | 上混合检索 |
| 答案答非所问 | chunk 太大混入噪声 | 打印 chunk 内容检查 | 减小 chunk 或语义切分 |
| 答案不完整 | chunk 太小切断语义 | 检查是否在句子中间切断 | 增加重叠或按结构切 |
| 重复回答同一内容 | 检索结果有重复 chunk | 检查去重逻辑 | 加相似度去重 |
| 响应特别慢 | 重排模型或检索量太大 | 看各阶段耗时 | 减少召回数量或换轻量模型 |
6.3 几个容易被忽略的细节
第一个是查询改写。用户的原始提问往往口语化、有指代、有错别字。直接拿去检索效果不好。可以在检索前加一步,让大模型把用户问题改写成几个更适合检索的查询。比如"它多少钱"改写成"XX 产品的价格是多少"。这一步能明显提升召回率。
第二个是多路召回。同一个问题,用不同的表述检索多次,把结果合并。比如原问题、改写后的问题、提取出的关键词,各检索一遍,然后 RRF 融合。这样能覆盖更多角度的相关资料。
第三个是缓存。高频问题没必要每次都走完整流程。把"问题-答案"对缓存起来,下次同样的问题直接返回。注意缓存要设过期时间,文档更新后旧缓存要失效。
第四个是评估。RAG 系统必须有一套评估机制,否则你根本不知道改动是变好了还是变坏了。最基本的指标是命中率(检索结果里有没有正确答案所在的 chunk)和答案准确率。可以人工标注一批测试问题,每次改动后跑一遍,看指标变化。没有评估的优化就是瞎调。
7. 把知识管道接进 Agent 工作流
7.1 检索作为工具,而非固定流程
前面提到 Agentic RAG 的思路,这里展开说。传统 RAG 是"用户提问→检索→生成"的固定流水线,Agent 没有选择权。Agentic RAG 把检索封装成一个工具,Agent 在推理过程中自己决定要不要用、用几次、用什么参数。
这样做的好处是灵活。比如用户问"对比一下 A 产品和 B 产品的保修政策",Agent 可以先检索 A 的保修政策,再检索 B 的,然后自己对比。固定流程做不到这种多步检索。再比如用户问"你好",Agent 判断不需要检索,直接回答,省了一次检索开销。
实现上,你需要给 Agent 提供一个检索工具的接口,描述清楚这个工具能干什么、参数是什么。Agent 框架(LangChain、AgentScope、Spring AI 等)都支持工具调用,把检索函数注册进去就行。关键是工具的返回结果要结构化,包含内容、来源、相关度分数,方便 Agent 判断和引用。
7.2 多轮对话中的知识管理
多轮对话里,知识获取会更复杂。用户第一轮问"差旅标准是多少",第二轮问"那住宿呢"。第二轮的问题里没有"差旅"两个字,直接检索会跑偏。这时候需要结合对话历史来改写查询,把"那住宿呢"补全成"差旅住宿标准是多少"。
另一个问题是上下文里的知识会累积。如果每一轮都把检索结果塞进上下文,很快就会超出窗口。我的做法是只保留最近几轮的检索结果,更早的做摘要压缩。或者干脆每轮重新检索,不依赖历史上下文里的知识。
7.3 和 Skill 的结合
现在很多 Agent 框架有 Skill(技能)的概念,把一组相关的能力打包。知识获取管道本身可以是一个 Skill,也可以被其他 Skill 调用。比如一个"合同审查"Skill,内部会调用知识检索来查相关法条和公司规定,然后结合审查逻辑给出结论。
这种组合的关键是接口要清晰。知识检索 Skill 对外暴露的是"给我一个问题,我还你相关资料",至于资料怎么用,是调用方的事。这样解耦之后,同一个知识管道能服务多个上层 Skill,不用重复建设。
8. 一些关于选型和演进的个人看法
RAG 这个领域变化很快,每隔几个月就有新东西出来。GraphRAG、Ontology RAG、Agentic RAG,概念一个接一个。我的态度是:先把基础链路做扎实,再考虑上高级特性。
基础链路就是:文档解析干净、切分合理、嵌入模型选对、检索用混合、加重排、上下文组装得当、有评估机制。这几步做到位,大部分场景的效果就够用了。GraphRAG 这类方案适合的是需要多跳推理、实体关系复杂的场景,实现成本高,不是所有项目都需要。
还有一个趋势是 RAG as a Service,把知识管道做成独立服务,多个 Agent 共享。AgentScope 2.0 就在往这个方向走。这样做的好处是知识统一管理、避免重复索引、方便权限控制。如果你的组织里有多个 Agent 项目,值得考虑这种架构。
最后说个心态问题。RAG 没有"一次调好"的说法,它是一个需要持续迭代的系统。文档在变、用户在变、问题在变,你的管道也得跟着调。建立一套评估和监控机制,比追求某个"最优参数"重要得多。我自己的项目里,每周都会看一遍检索失败 case,从中找改进点,这个习惯坚持下来,效果提升是肉眼可见的。
知识获取管道是 AI Agent 从"能聊"到"能用"的关键一步。它不性感,但它是地基。地基打不牢,上面盖什么都是空中楼阁。