架构设计RAG存储选型:用一个文档问答 Agent 演示“由检索需求反推存储”

10 阅读12分钟

30 秒判断:存储结构不是先挑技术,而是由"问答要取出什么"决定。先看 18 条用例对检索提出什么要求,再比候选存储,最后得出:第一阶段用增强的向量块,检索走经典 RAG + Agentic RAG;Wiki 与图按缺口后置。

适合谁读:正在做 RAG/知识库类 Agent、纠结"用向量库还是 Wiki 还是图谱"的人;习惯先选技术、再回头找适用问题的人;以及想给"存储选型"找一套可复核推导过程的人。

本文怎么读:和前两篇(需求定义、金标准)同一个结构——先讲方法,再用一个真实实例演示。实例是一个"文档学习问答 Agent"。标着「实例|」的段落可以跳过,不影响读方法。

前置阅读:系列四篇。①《Agent 开发为什么要测试驱动升级版》讲方法由来;②《需求定义四步:用一个文档问答 Agent 演示"先定义、再动工"》定下"用户会问什么、什么算答得好";③《金标准:用一个文档问答 Agent 演示"什么算对、怎么判"》把"什么算对"变成可执行的判定项;④ 本文接着前三篇,决定这些要求落在什么存储上。

结构速览:§1 为什么先定存储;§2 18 条用例需要什么检索;§3 候选存储有哪些;§4 逐条对照;§5 结论;§6 质量属性核验;§7 什么情况下再引入 Wiki 或图;§8 留给下一层;§9 一页速查。

证据标记:✅ 实测=有可复现实验数据支撑;🤔 推断=由实测或机制推出的判断。没标的多为框架性表述。

先交代两个名词

  • 增强的向量块:块存储 + 元数据(篇/节/来源/位置)+ 向量索引 + 关键词索引。它不是单纯的"向量库",而是"块 + 能过滤的元数据 + 两种召回"。
  • 经典 RAG/Agentic RAG:前者是"检索一次 → 直接生成";后者是"理解/澄清 → 规划 → 按范围检索 → 检查覆盖 → 再检索 → 生成"。

1. 为什么先定存储结构

这个产品对用户只有两个功能:把文档加进来,和基于这些文档问答。两个功能共享同一个底层选择——文档怎么拆、怎么存。这个选择不先定,后面的模块划分、接口、索引都没有落点。

而存储不能由"文档加入"一侧来定:文档加入只要求"能把内容读进来",真正决定结构的是问答要从存储里取出什么。所以顺序是:

问答需要检索出什么 → 决定检索要具备什么能力 → 决定存储要支持什么。

下面的推导就沿这条线走:先看 18 条用例对检索提出了什么要求,再看候选存储各自有什么特性,最后自然落到"第一阶段用哪一种"。


2. 18 条用例需要什么样的检索

判断标准是:含答案的目标块,在验证语料里能不能进入 top-k;对"有没有"这一类,还要能确认"确实没有" 。能进,说明一次检索就够;进不去,或需要证否,就说明还需要额外的手段。

实例|18 条用例按能力归组(编号对应《金标准》一文附录的 18 条用例)

能力用例检索要做什么
单点事实2、3、10、12用专名或数字锚,一次命中目标块
单点但需覆盖多块4、5同一节内的几个块要一起拿到
证否与归属1、14要能确认"没有",要能核对原文用词
跨源对照6、8、9、11多篇分别取证据,再合并
要全/枚举/整节7、13、15按范围取全,并检查有没有漏
消歧16向用户澄清
不涉及检索17、18路由与生成契约

把这张表读成一句话:单点类靠"一次命中",其余靠"多轮 + 范围限定 + 覆盖检查" 。单点类有专名或数字可锚,一次混合检索(向量+关键词)就能进 top-k;跨源、要全、整节、证否、消歧这几类,单次 top-k 天然不可靠——要么漏块、要么漏篇,要么根本无法证否。

所以检索不能只有一种用法。它需要在同一套索引上有两条路线:经典 RAG 覆盖单点类;Agentic RAG 覆盖其余。这不是两套系统,而是同一套数据上的两种调用方式。

把上面的能力要求,加上产品红线,可以归并成五条对存储的检索要求:

#要求来自哪里
R1可溯源:每个说法能回到原文位置产品红线——自称来自文档的必须真能找到
R2范围限定:能按篇、按节取跨源与要全类
R3语义召回:材料中英混合、查询也可能中英混合单点与解释类
R4精确锚点:数字、专名能精确命中83%、MCP、gVisor、AGENTS.md 这类锚
R5按范围取全:能把某个范围的全部块取出来,而不是只取 top-k要全/枚举/整节

R1 不是从 18 条用例里长出来的,而是产品红线;其余四条来自能力归组。


3. 候选存储有哪些,为什么是这三个

候选不是拍脑袋挑的。把"知识以什么形态存、检索怎么取"展开,能想到九种做法:

形态具体做法是否进入比较理由
原文直读查询时把全文/全库放进上下文;或由 agent 逐篇读不进入成本随语料线性增长、扩展性显然不够;10 篇只是验证集,不是产品规模
块级索引向量、关键词,或两者混合进入最直接支撑单点检索
摘要树(RAPTOR 类)层级摘要并入 Wiki 一族同属预编译摘要,差别只在层级
Wiki概念/实体/summary 页 + 页间链接进入预编译,面状覆盖
严格图预先定义实体类型与关系约束的图不进入需要用户对资料所属领域足够熟悉才能建模与使用;目标用户是学习者,天然冲突
非严格图(GraphRAG)自动抽取实体与关系建边进入关系/枚举
结构化存储关系库/表格不进入语料是非结构化文本;表格化会丢原文,无法溯源
参数化记忆微调/蒸馏进模型不进入用户文档是动态的;无法溯源
缓存/会话记忆运行时缓存不进入正交,不是知识存储

剔除五种:三种不适用或正交(结构化存储/参数化记忆/缓存)、原文直读(成本与扩展性不成立)、严格图(与学习者目标冲突);摘要树并入 Wiki 一族。剩下三种进入特性比较:

候选是什么特性(成本 + 支持的检索方式)
增强的向量块块存储 + 元数据 + 向量索引 + 倒排索引成本:最低,入库即用;检索方式:向量(语义、跨语言)+ 关键词(数字/专名)+ 元数据范围过滤;可承载经典与 Agentic RAG
预编译 Wiki概念/实体/summary 页 + 页间链接成本:高,编译 token 约为原文 10 倍(WeKnora 实验量级);检索方式:按页/按链接遍历,适合面状覆盖与跨页概念归集;页内是改写,回源需额外建立"页面段落 → 块"的引用
非严格图(GraphRAG)自动抽取实体与关系建边成本:最高,要做实体/关系抽取与建边,且抽取质量不稳定;检索方式:枚举、跨源连接、关系查询;效果取决于抽取质量

4. 用检索要求逐条对照

检索要求增强的向量块预编译 Wiki非严格图(GraphRAG)
R1 可溯源✔ 块级 provenance△ 页内改写,需建页→块引用△ 节点/边需回指块
R2 范围限定✔ 元数据过滤△ 按页组织△ 无原生范围过滤,只能靠实体/关系间接圈定
R3 语义召回✔ 向量索引△ 页面要另建索引△ 需实体归一
R4 精确锚点✔ 倒排索引△ 取决于是否保留原词△ 实体可、数字弱
R5 按范围取全✔ 按元数据遍历△ 页集合未必对应原文全集△ 可枚举,但覆盖依赖抽取质量
成本随语料增长基本不变(按查询取块)一次性编译,约 10 倍 token最高,且抽取质量不稳定

结果是:增强的向量块是唯一在满足全部五条要求的同时、把成本与语料规模解耦的候选。 Wiki 和图各自能补上一两项(Wiki 的面状覆盖、图的关系与枚举),但都建立在额外编译成本上,而且都多出一个共同的缺口——回源。

更关键的是:18 条用例里没有一条要求"预编译的知识形态"。 它们要的是"把块取对、取全、取准"——这正是增强向量块 + Agentic 检索能做的事。


5. 结论:第一阶段的存储与检索策略

#决策依据代价与风险
D1存储=增强的向量块(块 + 元数据 + 向量 + 倒排)唯一在最低成本下满足 R1–R5 的候选要维护双索引一致性;元数据质量直接决定范围检索
D2检索=经典 RAG + Agentic RAG,跑在同一套块索引上单点靠一次命中;跨源/要全/证否/消歧靠多轮多轮带来延迟与 token 成本,需要收敛与预算控制
D3Wiki 与非严格图不做第一阶段的硬依赖18 条用例不要求预编译形态;两者成本高且回源要补若缺口提前出现,补编译会打断节奏——需保留接入口

一句话:先用"块 + 元数据 + 双索引"把取块做对,再用 Agentic 循环把"取全、跨源、证否"补齐;预编译等实测缺口出现再说。

严格图单独排除:它要求用户对资料所属领域足够熟悉,与"学习者"目标天然冲突;成本是第二重理由。


6. 质量属性核验:只查冲突,不承诺满足

一个架构决定要过一遍质量属性,但这里只做冲突检查:看这个决定会不会和质量属性打架。不冲突就算通过——它不负责证明每条属性都被满足;满足与否,要靠后续的模块与机制去落实。

实例|一个文档学习问答 Agent

对照 Q1–Q8 与成本、安全、隐私、可靠性、可观测、可测试、可复现、可维护、易用性、并发共 18 条:✅ 5 条、⚠️ 7 条、➖ 6 条、❌ 0 条——没有冲突,本节通过。✅/⚠️/➖ 只表示本决策覆盖到哪一步,不代表属性已经满足或未满足。

7 个 ⚠️ 缺口里,三条最要紧:

缺口风险需要谁承接
安全文档是不可信输入;RAG 会把文档内容带进提示词,提示注入面真实存在;工具权限与出站限制也未落地后续架构决策
延迟(Q8)检索本身不慢,但 Agentic 多轮会增加首字延迟;没有轮次上限与预算就守不住目标编排设计
可靠性降级检索为空、解析失败、截断都必须有信号,否则重演"静默失败"后续设计

其余四个 ⚠️ 是:正确性的排除性、一致性(多轮带来的路径差异)、可观测性、可复现性——都在结构上不冲突,但需要后续机制补齐。


7. 什么情况下再引入 Wiki 或图

演进接在哪触发条件
Wiki预编译层 + 检索的一条新通道实测出现"面状覆盖/跨页概念归集"缺口,且块+元数据+Agentic 反复解决不了;接入时必须带"页面段落 → 块"的引用,否则可溯源红线在新路径上失效
非严格图预编译层 + 关系查询通道关系型/条件取全类持续失败,且接受抽取与编译成本

两者都不是"看起来更好就上",而是"实测出现解决不了的缺口才上"。


8. 留给下一层

本部分只定了存储形态与检索策略;下面三组问题尚未分析,按顺序推进:

  1. 检索侧(优先分析) :查询理解与路由(越界/消歧)、经典与 Agentic 的触发条件与多轮规划、覆盖检查与停止条件、证据组装(去重/排序/跨源保证/枚举上限)、参数(top-k/RRF/轮次/预算,由实测决定)、是否引入重排。
  2. 入库侧:解析、清洗、切分、语言识别、去重、增量更新;元数据字段清单(与检索过滤的契约)。
  3. 技术选型(在 ①② 之后) :向量/关键词/embedding/元数据存储/编排实现的具体组件。选型依据是前两步的结论,不先行拍板。

评测技术与模块划分也留到后面。


9. 一页速查

原则:存储由检索需求决定。

五条要求:R1 可溯源/R2 范围限定/R3 语义召回/R4 精确锚点/R5 按范围取全。

候选筛选:九种做法 → 剔除五种(原文直读/严格图/结构化/参数化/缓存)→ 三种比较(增强向量块/Wiki/非严格图)。

结论:D1 存储=增强的向量块;D2 检索=经典+Agentic;D3 Wiki 与图按缺口后置(Wiki 必须带页→块引用)。

质量核验:只查冲突——✅ 5/⚠️ 7/➖ 6/❌ 0;三条最要紧缺口=安全、延迟、可靠性降级。

一句话:先把块取对、取全、取准;预编译的知识形态,等实测缺口出现再说。