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 成本,需要收敛与预算控制 |
| D3 | Wiki 与非严格图不做第一阶段的硬依赖 | 18 条用例不要求预编译形态;两者成本高且回源要补 | 若缺口提前出现,补编译会打断节奏——需保留接入口 |
一句话:先用"块 + 元数据 + 双索引"把取块做对,再用 Agentic 循环把"取全、跨源、证否"补齐;预编译等实测缺口出现再说。
严格图单独排除:它要求用户对资料所属领域足够熟悉,与"学习者"目标天然冲突;成本是第二重理由。
6. 质量属性核验:只查冲突,不承诺满足
一个架构决定要过一遍质量属性,但这里只做冲突检查:看这个决定会不会和质量属性打架。不冲突就算通过——它不负责证明每条属性都被满足;满足与否,要靠后续的模块与机制去落实。
实例|一个文档学习问答 Agent
对照 Q1–Q8 与成本、安全、隐私、可靠性、可观测、可测试、可复现、可维护、易用性、并发共 18 条:✅ 5 条、⚠️ 7 条、➖ 6 条、❌ 0 条——没有冲突,本节通过。✅/⚠️/➖ 只表示本决策覆盖到哪一步,不代表属性已经满足或未满足。
7 个 ⚠️ 缺口里,三条最要紧:
| 缺口 | 风险 | 需要谁承接 |
|---|---|---|
| 安全 | 文档是不可信输入;RAG 会把文档内容带进提示词,提示注入面真实存在;工具权限与出站限制也未落地 | 后续架构决策 |
| 延迟(Q8) | 检索本身不慢,但 Agentic 多轮会增加首字延迟;没有轮次上限与预算就守不住目标 | 编排设计 |
| 可靠性降级 | 检索为空、解析失败、截断都必须有信号,否则重演"静默失败" | 后续设计 |
其余四个 ⚠️ 是:正确性的排除性、一致性(多轮带来的路径差异)、可观测性、可复现性——都在结构上不冲突,但需要后续机制补齐。
7. 什么情况下再引入 Wiki 或图
| 演进 | 接在哪 | 触发条件 |
|---|---|---|
| Wiki | 预编译层 + 检索的一条新通道 | 实测出现"面状覆盖/跨页概念归集"缺口,且块+元数据+Agentic 反复解决不了;接入时必须带"页面段落 → 块"的引用,否则可溯源红线在新路径上失效 |
| 非严格图 | 预编译层 + 关系查询通道 | 关系型/条件取全类持续失败,且接受抽取与编译成本 |
两者都不是"看起来更好就上",而是"实测出现解决不了的缺口才上"。
8. 留给下一层
本部分只定了存储形态与检索策略;下面三组问题尚未分析,按顺序推进:
- 检索侧(优先分析) :查询理解与路由(越界/消歧)、经典与 Agentic 的触发条件与多轮规划、覆盖检查与停止条件、证据组装(去重/排序/跨源保证/枚举上限)、参数(top-k/RRF/轮次/预算,由实测决定)、是否引入重排。
- 入库侧:解析、清洗、切分、语言识别、去重、增量更新;元数据字段清单(与检索过滤的契约)。
- 技术选型(在 ①② 之后) :向量/关键词/embedding/元数据存储/编排实现的具体组件。选型依据是前两步的结论,不先行拍板。
评测技术与模块划分也留到后面。
9. 一页速查
原则:存储由检索需求决定。
五条要求:R1 可溯源/R2 范围限定/R3 语义召回/R4 精确锚点/R5 按范围取全。
候选筛选:九种做法 → 剔除五种(原文直读/严格图/结构化/参数化/缓存)→ 三种比较(增强向量块/Wiki/非严格图)。
结论:D1 存储=增强的向量块;D2 检索=经典+Agentic;D3 Wiki 与图按缺口后置(Wiki 必须带页→块引用)。
质量核验:只查冲突——✅ 5/⚠️ 7/➖ 6/❌ 0;三条最要紧缺口=安全、延迟、可靠性降级。
一句话:先把块取对、取全、取准;预编译的知识形态,等实测缺口出现再说。