
向量检索碰到总述枚举结构时容易出现系统性漏检根源不在模型在分块策略。本文从可视化实验入手逐步拆解多路召回和 ReACT Agent 闭环方案在召回率和 token 成本之间找到较优的平衡点。适合正在做 RAG、知识库或信息抽取的后端和算法同学参考。一个真实的翻车现场最近在做一个政务信息抽取的项目需要从网页里提取中国人民银行的职责听起来很简单对吧把文档切成句子灌进向量数据库用关键词检索取topK个最相似的片段。结果翻车了。我写了个小工具把每个切分后的句段和查询关键词的匹配度可视化出来。提取中国人民银行的编制时效果不错匹配度曲线很漂亮。但换成中国人民银行的职责就只有开头那句总述主要职责是匹配度比较高后面紧跟着的一二三……全漏了。这不是个例。只要文档里有总述枚举这种结构逐句切分的向量检索就会系统性漏检。这篇文章讲的就是为什么会漏、怎么缓解、目前公认的最优解是什么。内容偏实战后面有完整的方案对比和排查清单建议先收藏等上线RAG系统时能直接对照着用。先说结论向量数据库提供的是一个渐进式的匹配度分布它本质上是快速召回的工具不是精准截止的工具。问题的根源在于向量相似度是连续的不存在一条客观的分割线告诉你到这里就够了。而枚举条目比如职责第一条、第二条它们同总述句之间的语义距离往往比想象中远得多。单独拿制定和执行货币政策和中国人民银行的职责来比较在embedding空间里的余弦相似度可能还不如一句完全无关但措辞相近的话。所以截止判断必须由具备理解力的主体来完成——人或者LLM。向量数据库负责缩小范围LLM负责判断边界。这是ReACT Agent方案背后的逻辑。为什么逐句切分必然漏检打个比方。你去图书馆找一本书管理员把每本书的每一页都拆开单独编号放到不同抽屉里。你问关于货币政策的内容在哪管理员只能告诉你哪几页提到了货币政策这几个字。但如果某一页写的是三维护金融稳定它跟货币政策这个查询在字面和语义上关联都不强管理员就不会把它递给你——哪怕它就在你要找的那一章里。回到技术层面这个问题叫语义孤立Semantic Isolation。文档逐句切分后每个chunk丢失了它所处的上下文。三维护金融稳定这句话脱离了前面的主要职责是就变成一个孤立的陈述句embedding模型无从判断它属于职责列表的一部分。有人会说把chunk切大一点不就行了问题是切多大算合适切太大检索精度下降切太小上下文丢失。这是个工程上的两难不存在万能的切分粒度。缓解手段一滑动窗口与重叠分块最直觉的修补方案是切分时让相邻chunk之间保留一段重叠区域。比如每段设定为400 token前后各重叠50 token。这种做法能在一定程度上缓解问题但治标不治本。原因很简单一个枚举列表包含10条内容每条大约30 token整体跨度达到300 token50 token的重叠区域根本覆盖不到后面那些条目。重叠区域设置得越大存储和计算开销越高索引膨胀也越严重。适用场景文档结构简单、枚举跨度短、对召回率要求不极端的场景。比如FAQ问答、短文档检索。不适用场景长枚举、嵌套结构、法规条文、技术规范文档。缓解手段二父子文档检索LlamaIndex 和 LangChain 都内置了这套方案思路如下预处理阶段做双层切分大块Parent Chunk是整个段落包含总述和所有枚举内容小块Child Chunk通常是单句只对小块做 embedding 入库每个小块带一个指向父块的 ID检索命中小块后不返回小块本身而是把整个父块拉出来举例搜索中国人民银行的职责命中了总述句小块系统返回包含所有枚举条目的完整段落父块。这个方案有一个前提预处理阶段要能正确识别哪些句子属于同一个父块。HTML 页面可以靠标签结构判断纯文本则需要语义分块或人工规则。文档结构混乱时父子关系本身就难以定义。成本预处理复杂度中等存储空间大约翻倍大块小块都要存检索时延几乎不增加。缓解手段三BM25 混合召回与上下文注入向量检索擅长语义匹配但对关键词不敏感。BM25 擅长关键词精确匹配但不理解语义。两者结合做多路召回是目前比较标准的做法。具体操作PYTHON# 伪代码多路召回 分数融合 vector_results vector_db.search(query_embedding, top_k20) bm25_results bm25_index.search(query_keywords, top_k20) # RRF (Reciprocal Rank Fusion) 融合排序 final_results rrf_merge(vector_results, bm25_results, k60)另一个有效手段是上下文注入Contextual Retrievalchunk 入库前把所属标题、章节名称、父段落首句拼到 chunk 文本前面。这样三维护金融稳定变成[中国人民银行-主要职责] 三维护金融稳定embedding 时自带上下文身份信息。如果你的团队在做 RAG 系统可以对照自己的实现是不是只用了单路向量召回有没有做上下文注入很多看起来偶现的漏检问题本质上不是偶现——只是触发条件没完全凑齐。为什么这些手段都不够前面提到的三种方案——重叠分块、父子文档、混合召回——本质上都是在入库前和检索时两个阶段做优化。它们能把召回率从 60% 拉到 85% 左右但要突破 95%就很难了。根本原因是向量相似度是连续分布的数值没有天然的截止阈值。取 top10可能漏掉排第 11 的关键信息取 top50又会灌入大量噪声。程序自己判断不了信息够不够。这里有个悖论如果需要先理解文档内容才能正确切分、判断合理边界那向量数据库本身就多余了。但反过来想向量数据库的价值不在于一次给出完美答案而在于从海量数据中快速缩小搜索范围。真正的判断工作该交给有理解能力的主体。在 2024-2025 年的技术栈里这个主体就是 LLM Agent。最优解向量数据库 ReACT Agent 闭环这套方案是目前业界公认的最佳实践路径也是从 Cursor 这类纯 RAG 工具演进到 Claude Code 这类 Agent 工具背后的核心逻辑转变。核心思路向量数据库负责快速召回候选集合LLM Agent 通过多轮观察-思考-行动ReACT循环自主判断是否需要扩展检索范围。一个典型的交互轨迹如下YAMLThought 1: 任务是抽取中国人民银行的职责先用混合检索看看相关片段。 Action 1: search_chunks(query中国人民银行 职责, top_k20, modehybrid) Observation 1: 返回了总述句和前3条枚举但看起来后面还有更多条目。 Thought 2: 当前结果出现了一二三的模式可能还有四五。 基于已命中 chunk 的位置向后扩展上下文。 Action 2: expand_window(chunk_ids[101,102,103], window5) Observation 2: 拿到了完整的一到六全部条款。 Thought 3: 枚举看起来完整了再做一次验证性搜索确认没有遗漏。 Action 3: search_chunks(query中国人民银行 负责 承担, top_k30, excludealready_found) Observation 3: 没有发现新的职责条目只有解释性文字。 Final: 抽取完成共6条职责写入结构化数据。这里的关键点Agent 不是盲目扩大 top_k而是根据已有结果中的模式——比如发现了编号序列这样的线索——来决定下一步动作。这就是理解力介入的地方。方案对比与选型建议把上面所有方案放在一起做个对比方案召回率提升实现成本token 消耗适用场景重叠分块低低无额外FAQ、短文档父子文档中中无额外结构清晰的文档BM25 混合召回中中无额外关键词明确的场景上下文注入中高中入库时少量通用场景ReACT Agent高高运行时消耗高召回率要求、复杂文档选型时几条原则文档结构规整HTML、Markdown这类有明确层级的格式父子文档加BM25混合召回基本够用不需要再引入Agent文档是非结构化纯文本业务上对漏检零容忍适合用ReACT Agent只做一次性检索、不需要反复查询的场景直接把全文丢给LLM处理可能更划算token预算紧张先把上下文注入和混合召回做好Agent留作兜底第3点值得单独说一下不是所有场景都需要向量数据库。文档总量小、查询次数少的情况下向量数据库反而多了一个中间层白白增加运维负担。实战落地的关键细节如果你决定用 ReACT Agent 方案有几个实操中容易忽略的要点meta 信息要带位置每个 chunk 入库时除了文本内容还要把它在原文中的绝对位置存进去比如第几段、第几句。Agent 靠这个位置信息判断该向前扩展还是向后扩展。expand_window 工具单独实现不要让 Agent 每次重新检索而是提供一个根据已知 chunk 的位置向前后扩展 N 句的工具函数。比重新检索快也省 token。设最大轮次上限ReACT 循环不能无限跑。通常 3-5 轮够用超过说明查询本身有问题或数据质量太差。用示例向量做枚举召回如果已经找到了一制定货币政策拿这条的 embedding 当新查询向量去检索结构相似的二三……。比直接用原始查询词召回效果好。DeepSeek 的缓存价格优势多轮 Agent 交互中前几轮的 context 会被缓存后续轮次只为新增 token 付费。实测 5 轮 ReACT 总成本约为单次全文输入的 1.5 到 2 倍但召回率能从 70% 提到 95% 以上。什么时候别用向量数据库前面讲了这么多优化手段最后聊聊边界问题。以下场景中向量数据库未必是好选择文档总量不到 100 篇每篇不超过 5000 字直接把全文丢给 LLM省掉预处理和检索环节查询模式是精确匹配法规编号、文件字号之类传统数据库的全文索引或正则匹配更靠谱信息只需要提取一次后续不会反复查询向量化的前期投入摊不回来文档更新极其频繁实时新闻流这种向量索引重建的成本可能比收益还高向量数据库解决的问题是数据量大的时候用语义快速缩小检索范围。如果数据量不大、查询不频繁、或者匹配模式本身就是确定性的传统方案更简单也更可靠。技术选型最怕的不是选错而是不知道自己为什么选。把数据规模、查询频率、召回率要求、token 预算这几个因素摆出来答案基本就明确了。带走这张清单下面是一份可以直接贴到项目文档里的决策清单入库前检查[ ] chunk 是否携带上下文 meta标题、章节、位置[ ] 是否做了双层切分父块 子块[ ] 是否同时建了 BM25 索引[ ] chunk 粒度是否经过可视化验证建议写一个匹配度可视化工具辅助判断检索时检查[ ] 是否用了多路召回向量 BM25[ ] 是否有融合排序策略RRF 或加权[ ] top_k 是否根据文档类型动态调整Agent 层检查[ ] 是否提供了 expand_window 工具[ ] 是否设置了最大轮次上限[ ] 是否用已召回结果作为示例向量做二次检索[ ] 是否有最终的完整性验证步骤成本检查[ ] 单次查询平均 token 消耗是否在预算内[ ] 是否用了 LLM 缓存机制降低多轮交互成本[ ] 是否评估过直接全文输入的性价比如果你团队里有人在做 RAG 或知识库项目上面的清单和方案对比表能省不少踩坑时间。实际项目中遇到过更棘手的召回问题评论区聊聊你的场景和解法。