ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI Agent知识获取管道:RAG稠密与稀疏嵌入混合检索实战

AI Agent知识获取管道:RAG稠密与稀疏嵌入混合检索实战 1. 为什么知识获取管道是 AI Agent 落地的第一道分水岭做 AI Agent 的人迟早会撞上同一堵墙模型本身很聪明但你问它公司内部的报销标准、上周刚更新的产品参数、某个客户的特殊约定它要么一本正经地胡说要么干脆说不知道。这不是模型不行而是它的知识边界停在了训练数据截止的那一天。知识获取管道要解决的就是把这个边界往后推、往深挖让 Agent 在运行时能拿到外部知识。而 RAGRetrieval-Augmented Generation检索增强生成目前是这条管道里最成熟、最通用的一段。我见过太多项目卡在这里。Demo 阶段用几个 PDF 喂进去效果惊艳老板拍板立项真到了生产环境几千份文档、几十个数据源、每天还在更新检索命中率断崖式下跌Agent 开始答非所问。问题往往不在大模型而在管道本身没搭对。RAG 听起来简单——检索加生成但检索什么、怎么检索、检索出来怎么用每一步都有大量工程细节。这篇是走进 AI Agent系列的第四篇专门讲知识获取管道的基础设施。我会把 RAG 的核心链路拆开重点讲清楚稠密嵌入和稀疏嵌入这两条技术路线的差异与配合以及从 0 到 1 搭建一个能用的 RAG 管道时哪些环节最容易翻车。适合已经了解 Agent 基本概念、准备动手做知识库的开发者也适合正在评估 RAG 方案的技术负责人。读完你应该能判断自己的场景该用哪种检索策略管道里哪几个环节必须重点投入。先说一个反直觉的结论RAG 的效果瓶颈八成不在生成模型而在检索质量。很多人一上来就纠结用哪个大模型其实检索没做好再强的模型也只能拿着错误的上下文硬编。所以这篇的重心会放在管道的前半段——知识的表示与召回。2. RAG 管道的完整链路拆解从原始文档到可用上下文2.1 一条管道的五个阶段把 RAG 想象成一条流水线原料是各种格式的原始文档成品是喂给大模型的上下文片段。中间大致经过五个阶段文档加载与解析把 PDF、Word、网页、数据库记录等统一转成纯文本同时保留结构信息标题、表格、层级。切分Chunking把长文档切成适合检索和放入上下文窗口的小块。向量化Embedding把每个文本块转成向量存进向量库。检索Retrieval用户提问时把问题也转成向量从库里召回最相关的若干块。生成Generation把召回的内容拼进提示词交给大模型生成答案。这五步里切分和检索是决定成败的两个环节也是最容易被低估的。加载解析看起来是脏活累活但它决定了后面所有环节的信息质量——解析丢了的表格、错乱的层级后面再怎么优化都补不回来。2.2 每个阶段的常见坑与判断标准我按自己的经验把每个阶段最容易出问题的地方列一下阶段常见问题判断标准加载解析表格变乱码、多栏 PDF 顺序错乱、扫描件无文字层随机抽 20 份文档人工核对解析结果是否可读切分块太大检索不准块太小语义不完整单块 200-800 字且不切断完整语义单元向量化模型选错、维度不匹配、中英文混用效果差用真实问题做召回测试看 Top5 命中率检索只做向量检索忽略关键词精确匹配混合检索稠密加稀疏生成上下文塞太多、提示词没约束引用来源答案可溯源无来源时明确说不知道这张表不是让你照抄而是给你一个自查清单。我踩过最深的坑在切分早期图省事按固定字数硬切结果一个完整的操作步骤被切成两半检索时只召回前半段Agent 给出的答案缺了关键一步用户照着做直接出错。后来改成按语义边界切分——优先在段落、标题、列表项处断开实在超长再按句子切效果立刻不一样。2.3 为什么切分策略比嵌入模型更值得花时间这里要展开讲一个观点嵌入模型的选择对最终效果的影响往往小于切分策略。原因很简单嵌入模型决定的是能不能把语义相近的内容映射到相近的向量空间这是模型能力问题主流模型差距没那么大而切分决定的是每个向量到底代表什么语义单元这是信息组织问题切错了再好的模型也救不回来。举个具体例子。一份产品手册里有这么一段故障代码 E05 表示进水异常。排查步骤1. 检查进水阀是否打开2. 检查水压是否低于 0.05MPa3. 若以上正常更换水位传感器。如果按 100 字硬切很可能故障代码 E05 表示进水异常和排查步骤被分到两个块。用户问E05 怎么处理检索可能只召回排查步骤那块但缺了E05 是什么的上下文生成时容易张冠李戴。而按语义切分整段作为一个块信息完整召回即用。所以我的建议是在切分上多花两天比在嵌入模型上纠结两周更值。切分策略没有标准答案但有几个原则可以遵循——保持语义完整、控制块大小在合理区间、给每个块加上来源和标题等元数据方便后续过滤和溯源。3. 稠密嵌入与稀疏嵌入两条检索路线的本质差异3.1 稠密嵌入到底在做什么稠密嵌入Dense Embedding是把一段文本映射成一个固定长度的实数向量比如 768 维或 1024 维向量里每个维度都是一个浮点数整体表示这段文本的语义。它的核心能力是语义匹配用户问怎么退款文档里写的是申请退货流程字面没有重叠但稠密嵌入能把它们映射到相近的位置从而召回。稠密嵌入的底层通常是 Transformer 类模型经过大量文本对训练学会把语义相近的句子拉近、无关的推远。它的优势是泛化能力强能处理同义、近义、换一种说法的查询。缺点是对精确匹配不敏感——产品型号、错误代码、人名这类需要字面精确命中的内容稠密嵌入经常召回不准因为它关注的是整体语义不是具体词。3.2 稀疏嵌入为什么在 2026 年又火了起来稀疏嵌入Sparse Embedding走的是另一条路。传统做法是 BM25 这类基于词频的算法一个文档表示成一个高维稀疏向量绝大多数维度是 0只有出现的词对应的维度有值。它的核心能力是关键词精确匹配用户问E05文档里有E05就能命中没有就召不回。这几年稀疏嵌入重新受到重视是因为出现了学习型稀疏表示比如 SPLADE 这类方法。它不再单纯依赖词频而是用模型学习每个词的重要性权重既保留了关键词精确匹配的能力又引入了一定的语义泛化。实测下来在包含大量专有名词、代码、型号的场景里稀疏嵌入的召回质量明显优于纯稠密方案。3.3 一张表看清两者该在什么场景用维度稠密嵌入稀疏嵌入匹配方式语义相似关键词精确擅长场景口语化提问、同义改写型号、代码、专有名词短板精确词命中差语义泛化弱向量形态低维稠密如 1024 维高维稀疏词表维度典型算法双塔模型、句向量模型BM25、SPLADE存储开销中等视词表大小而定我的实际经验是别二选一做混合检索。用户的问题千奇百怪有人用大白话问有人直接甩一个错误代码单一检索路线必然有覆盖不到的地方。混合检索把两路召回的结果融合用加权或倒数排名融合RRF的方式合并命中率通常比单路高出一截。3.4 混合检索的融合策略怎么定融合策略听起来玄其实核心就一件事怎么把两路不同尺度的分数合并成一个可排序的分数。稠密检索的相似度分数和稀疏检索的 BM25 分数不在一个量纲上直接相加没有意义。常见做法有两种倒数排名融合RRF不看具体分数只看排名。某文档在稠密检索里排第 3在稀疏检索里排第 5按1/(krank)累加k 一般取 60。这种方法简单稳健不依赖分数校准我大多数项目默认用它。加权分数融合把两路分数归一化到 0-1 后加权求和。权重需要根据场景调比如专有名词多的场景给稀疏路更高权重。调参成本高但上限可能更高。提示融合后的 Top-K 不要直接全塞给大模型。先做一次重排Rerank用交叉编码器对候选做精细打分再取前 3-5 条。这一步对最终答案质量的提升往往比换嵌入模型更明显。4. 从零搭一条能用的 RAG 管道关键决策与实操细节4.1 向量库选型别被专用两个字绑架向量库的选择经常被过度讨论。我的观点是中小规模场景用你已有的数据库加向量扩展就够了没必要为了专用引入一套新组件。PostgreSQL 的 pgvector、Elasticsearch 的向量检索、甚至 SQLite 的向量扩展都能撑起百万级向量的场景。什么时候需要专用向量库当你的向量规模到千万级以上或者对检索延迟有极致要求或者需要复杂的分布式和分片能力。这时候 Milvus、Qdrant 这类专用库才有明显优势。选型时重点看三件事索引类型是否支持你的规模、是否支持混合检索、运维成本是否可接受。我见过一个团队为了一个内部知识库总共不到 5 万份文档上了分布式向量集群结果运维复杂度陡增检索延迟反而因为网络跳数变高。后来换回 pgvector性能没降运维省了一大半。规模没到别提前上重装备。4.2 嵌入模型的本地化与成本权衡嵌入模型分两类调用云端 API或本地部署开源模型。怎么选云端 API省事效果稳定按量付费。适合文档量不大、更新频繁、不想维护模型的场景。缺点是数据要出本地且长期成本随调用量线性增长。本地开源模型数据不出本地无调用成本但需要 GPU 资源且要自己处理模型版本、推理优化。适合数据敏感、调用量大、有运维能力的场景。我的建议是先 API 跑通再评估是否本地化。很多团队一上来就纠结本地部署结果卡在环境配置上项目迟迟出不了 Demo。先用 API 把整条管道跑通验证效果再根据成本和合规要求决定要不要换本地模型。切换时注意换嵌入模型必须重建整个向量库因为不同模型的向量空间不兼容这是硬约束。4.3 一个最小可用的检索代码骨架下面这段代码展示混合检索的核心逻辑用伪代码风格写方便你迁移到自己的技术栈# 1. 稠密检索问题转向量查向量库 query_dense dense_model.encode(question) dense_hits vector_store.search(query_dense, top_k20) # 2. 稀疏检索问题做分词/权重查倒排索引 query_sparse sparse_model.encode(question) sparse_hits inverted_index.search(query_sparse, top_k20) # 3. 融合用 RRF 合并两路结果 def rrf_fuse(dense_hits, sparse_hits, k60): scores {} for rank, doc in enumerate(dense_hits): scores[doc.id] scores.get(doc.id, 0) 1 / (k rank) for rank, doc in enumerate(sparse_hits): scores[doc.id] scores.get(doc.id, 0) 1 / (k rank) return sorted(scores.items(), keylambda x: -x[1]) fused rrf_fuse(dense_hits, sparse_hits) # 4. 重排交叉编码器精排取前 5 reranked reranker.rerank(question, [doc for doc, _ in fused[:20]]) final_context reranked[:5] # 5. 生成拼上下文交给大模型 answer llm.generate(question, contextfinal_context)这段骨架里每一步的 top_k 都值得调。稠密和稀疏各召回 20 条融合后取 20 条重排最终留 5 条。召回太少会漏太多会引入噪声且拖慢重排。我一般从召回 20、重排留 5起步再根据实测调整。4.4 元数据过滤被低估的召回加速器很多 RAG 项目忽略了元数据过滤。每个文本块除了向量还应该带上来源、时间、分类、权限等元数据。检索时先用元数据缩小范围再做向量匹配效果和速度都会提升。比如用户问2025 年第三季度的销售政策如果所有块都带时间戳检索时先过滤出第三季度的块再在里面做语义匹配命中率远高于全库盲搜。再比如多租户场景权限过滤必须在检索阶段做不能等生成后再筛否则会泄露不该看的内容。注意元数据过滤和向量检索的顺序会影响结果。先过滤再检索速度快但可能漏掉边界情况先检索再过滤召回全但慢。我的做法是先粗过滤按权限、大类再向量检索最后精过滤按时间、细分类兼顾两者。5. 检索命中率上不去时我会按这个顺序排查5.1 先确认问题出在检索还是生成命中率低第一步是定位问题环节。做法很简单拿一批真实问题人工标注每个问题的正确答案应该来自哪些文档块然后看检索结果里有没有这些块。如果检索没召回问题在检索如果召回了但答案还是错问题在生成或提示词。这个标注过程很枯燥但没有它后面所有优化都是盲猜。我一般标 50-100 个问题就能看出规律。标完你会发现问题往往集中在某几类查询上比如带型号的、带时间范围的、口语化严重的针对性优化这几类比全局调参有效得多。5.2 切分粒度与重叠度的重新校准如果检索召回率低先回头看切分。常见问题是块太大——一个块里塞了太多主题向量表示被平均化反而不精准。或者块太小——语义不完整召回了也没用。我的校准方法是抽一批问题看召回块的实际内容。如果召回块里只有一半内容和问题相关说明块太大需要切细如果召回块读起来缺头少尾说明块太小或切断了语义。调整时给相邻块加重叠overlap一般重叠 10%-20%避免边界信息丢失。5.3 查询改写让用户的问题更好被检索用户的提问方式千奇百怪直接拿原始问题去检索效果经常不理想。查询改写Query Rewriting是提升召回的有效手段常见做法有几种同义扩展把问题里的关键词扩展成多个同义表达一起检索。假设文档生成HyDE先让大模型根据问题生成一个假想的答案文档再用这个文档去检索。因为答案文档的表述更接近知识库里的内容召回效果往往更好。多查询生成让模型把一个问题改写成多个不同角度的查询分别检索后合并结果。这几种方法各有适用场景。HyDE 对口语化问题效果好多查询对复杂问题覆盖全。但都要注意别过度改写导致语义漂移改完的查询要能追溯到原问题。5.4 重排模型的引入时机重排不是万能的也不是必须的。当你的召回已经不错但 Top-K 里混了噪声重排能明显提升精度但如果召回本身就漏重排救不了。所以重排应该放在召回优化之后。重排模型通常是交叉编码器把问题和候选文档一起输入输出相关性分数。它比双塔模型的精度高但速度慢所以只对少量候选做。我一般对融合后的前 20 条做重排取前 5 条。实测下来重排能把最终答案的准确率提升 10-20 个百分点是性价比很高的一步。5.5 一个真实的排查案例之前有个项目用户反馈问产品参数经常答错。我按上面的顺序排查标注 50 个问题发现检索召回率其实有 80%问题出在生成——召回的块里有正确参数但模型选了另一个块的错误参数。看提示词发现没有明确要求优先使用最新版本参数。检查元数据发现参数块没有版本和时间标记模型无法判断哪个更新。修复给参数块加版本元数据检索时按版本排序提示词里明确要求使用最新版本。改完之后准确率从 60% 提到 90% 以上。这个案例说明命中率问题不一定是检索问题元数据和提示词同样关键。排查时别一上来就换模型先把链路走一遍。6. RAG 之外知识获取管道的延伸方向6.1 GraphRAG 与本体增强的适用边界普通 RAG 处理的是块与问题的匹配但有些问题需要跨块推理比如和 A 产品兼容的所有配件有哪些答案分散在多个文档里单块检索拼不出完整答案。这时候GraphRAG这类方案就有价值——它把知识组织成图结构实体是节点关系是边检索时沿着图遍历能召回关联的多跳信息。但 GraphRAG 不是银弹。它的构建成本高需要实体抽取、关系抽取、图维护而且对抽取质量敏感。我的判断标准是如果你的问题大量涉及多实体关系、跨文档推理且普通 RAG 确实拼不出答案才考虑上图结构。否则把普通 RAG 的切分和检索做扎实性价比更高。6.2 知识更新与增量索引的工程处理知识库不是一次建好就完事文档会更新、会新增、会删除。增量索引是生产环境必须解决的问题。常见做法是给每个文档块记录来源文档 ID 和版本文档更新时先删除旧块再插入新块。删除要彻底否则旧版本会和新版本一起被召回导致答案矛盾。我踩过的坑是早期没做版本管理文档更新后旧块还在库里检索时新旧混在一起模型经常引用过时信息。后来加了版本字段检索时只取最新版本问题才解决。增量更新不是可选项是必选项设计之初就要考虑。6.3 评估体系没有度量就没有优化最后强调一点RAG 必须有评估体系。没有度量你无法判断一次改动是优化还是劣化。评估指标至少包括召回率正确答案所在的块有多少被召回。精确率召回的块里有多少是真正相关的。答案准确率最终生成的答案是否正确。可溯源率答案是否能对应到具体来源。评估集要覆盖真实场景的各种问题类型定期跑跟踪变化。我一般用 100-200 个标注问题做基线每次改动后跑一遍看指标涨跌。这套体系搭起来费点功夫但它是 RAG 项目从能用走向好用的分界线。我个人在实际操作中的体会是RAG 的难点从来不是某个单点技术而是整条链路的协同。切分、嵌入、检索、重排、生成每一环都影响最终效果而优化时又要能定位到具体是哪一环出了问题。把评估体系建起来把排查顺序理清楚比盲目追新框架、新模型有用得多。知识获取管道搭扎实了上面的 Agent 才能真正跑起来。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进