Chapter 04

自测与辨析

前三章铺完了四个面(01)、数据与租户设计(02)、检索与新鲜度(03)。这一章不讲新东西,只把它们逼成"在一个真实系统里同时拍板"——三层梯度 + 跨章选型辨析 + 一次手画。

这一章怎么用

  • 三层梯度:概念层(四个面记得住)→ 设计层(每个决策的取舍讲得清)→ 应用判别层(真实场景里同时定六个决策)。
  • 判别题是重点——生产 RAG 的难,正在于四个面相互牵制,单题答得对不代表能合到一起。
  • 答案集中在文末折叠块。合上前三章作答,写完再对照。
难度递增 → 概念层 · 四个面 对应 01 · 记得住、说得出 设计层 · 取舍 对应 02 + 03 · 讲得清代价 应用判别层 跨章 · 同时拍板
图 4.1题库三层,自下而上越来越难。注意:真正检验落地能力的是顶层——它逼你在一个系统里同时定下隔离、检索、一致性、过滤,而不是单点答题。能背出四个面不代表能把它们合起来。

A概念层(对应 01)

  1. demo RAG 跳过了哪四个决策?各对应哪个"面"?提示:01 §1.1
  2. partition-key 多租户里,为什么限定租户的 filter 是安全边界而非优化?RBAC 为什么不够?提示:01 §1.2
  3. 「融合 rerank(RRF/Weighted)」和「模型 rerank(交叉编码器)」各解决什么问题?是不是二选一?提示:01 §1.3
  4. 默认一致性是哪档?它等于 read-your-writes 吗?灌库后同会话自查该用哪档?提示:01 §1.4
  5. "过滤条件越严越快"在关系库成立,为什么到向量检索就反了?提示:01 §1.5

B设计层(对应 02 + 03)

  1. 要给 5000 个租户做强隔离,Collection-per-tenant 的隐患是什么?硬限制在哪?提示:02 §2.2
  2. RAG 的 schema 里为什么要存 parent_doc_id?它支撑哪两个操作?提示:02 §2.1
  3. 一个 source 字段(基数几十)和一个 timestamp 字段,分别建什么标量索引?提示:02 §2.3
  4. 生产默认检索栈是什么形状(召回 → 融合 → 精排 → final-k)?top-100 和 top-5~10 各在哪一步?提示:03 §3.2
  5. RRFRanker 和 WeightedRanker 怎么选?为什么 RRF 在融合 BM25 与 cosine 时更稳?提示:03 §3.2
  6. upsert 在 Milvus 里实际是什么操作?为什么一批 upsert 之后检索会短暂掉速?提示:03 §3.5
  7. 换嵌入模型时,为什么通常要新建 collection?哪条铁律不遵守会"不报错但答案全错"?提示:03 §3.5

C应用判别层(跨 01–03,重点)

每题都要在多个面之间同时取舍,并说清依据——这是这份教程真正训练的能力。

  1. 选隔离:一个 SaaS 客服 RAG,预计 5 万个中小租户、单租户文档量都不大。隔离选哪一级?为什么不是看起来"更安全"的 Collection-per-tenant?
  2. 选检索栈:知识库里大量精确标识符(错误码、API 名、版本号),用户经常精确搜这些。纯 dense 够吗?该怎么搭?召回 top-k 与 final-k 怎么定?
  3. 选一致性:场景 A——每晚批量灌入新文档、白天只读检索;场景 B——用户上传文档后,在同一会话里立刻提问要能查到。两个场景各选哪档一致性?默认那档在 B 为什么不行?
  4. 过滤 × 索引:查询固定带 tenant_id == x AND ts >= now-7d,命中行很少(高选择性)。无脑用 HNSW 会出什么问题?怎么办?
  5. 合成系统:把上面四题合成一个系统——为这个"多租户 + 精确词重 + 持续更新 + 带时间过滤"的 RAG,列出 Milvus 侧六个关键决策(隔离级、schema 标量字段、各字段索引、检索栈、一致性、更新方式),并指出哪两个决策相互牵制。
亲手画一张图

合上教程,在纸上画出一次多租户 RAG 查询从 query 到 LLM 的链路,并在链路上标出四个面各在哪一步生效——只画 6 个节点。

画完翻回 01 的概念地图对照:你画的链路里,租户 filter 在检索之前还是之后?两个 rerank 阶段都画出来了吗?一致性级别挂在哪一步?这三点最容易漏。

D答案

三层都做完再展开。瞄一眼答案,这一章就退化成了再读一遍。

展开全部答案

概念层

  1. 租户隔离、检索质量、新鲜度/一致性、元数据过滤。demo 因为单租户、dense 够用、语料不变、无元数据,把四者全跳过。
  2. RBAC 只到 collection/database 粒度,管不到 partition-key collection 内部的单租户;隔离全靠应用层那个 tenant_id filter,漏一次就跨租户泄漏,所以它要像鉴权一样被测试强制。
  3. 融合 rerank 把 dense 与 sparse 两个分数体系合并成一个排序;模型 rerank 用交叉编码器对 query×候选成对精排,纠正 ANN 粗排。不是二选一,生产常先融合再精排。
  4. 默认 Bounded(有界滞后),不等于 read-your-writes。同会话灌库后自查用 Session。
  5. 向量检索靠图/簇结构找近邻;一个极严的 filter 把大部分点排除后,HNSW 图在剩下的稀疏点之间走不动、找不到连通候选,召回反而塌——和关系库"扫得越少越快"相反。

设计层

  1. Collection-per-tenant 官方测试上限约 10000、建议 <5000,且有效数 = collections × shards × partitions 计入总容量;5000 已逼近墙,再加分片/分区会爆。强隔离的代价是扩展性。
  2. parent_doc_id 支撑:删整篇文档的所有 chunk、取相邻块(命中一个 chunk 后扩展上下文)。一个 chunk 一行,靠它把行重新关联回源文档。
  3. source(低基数)→ BITMAP;timestamp(范围查询)→ STL_SORT / range。要 filter 的字段都要建,否则 filter 退化成全扫。
  4. 形状:dense + sparse/BM25 两路 → 融合(RRF)出 top-100(宽、便宜)→ 交叉编码器精排 → top-5~10(窄、准)进 LLM。
  5. RRF 只用排名、免归一、scale-free,融合 BM25(分数尺度大)与 cosine(0~1)不会被尺度带偏,所以更稳;要主动调 dense/sparse 影响力时才用 Weighted。
  6. upsert = 按 pk 删(tombstone)+ 插。新行落进 growing segment(未建索引、暴力扫),删除要等 compaction 回收——所以一批 upsert 后短暂掉速 + 占用上涨。
  7. 向量维度建表即固定,换模型常意味着换维度 ⇒ 新 collection。铁律:query 和 doc 必须用同一模型重嵌入,只换一边会静默返回垃圾、不报错。

应用判别层

  1. Partition-Key(用 tenant_id)。5 万租户远超 Collection-per-tenant 的 ~10000 墙;Partition-Key 无硬上限、单租户小最适合。代价是隔离变成应用层契约——所以那个 tenant_id filter 必须强制(呼应面①)。
  2. 纯 dense 不够:精确标识符是 dense 的弱项。搭 dense + BM25 全文(schema 加 VARCHAR text + sparse 字段)→ hybrid_search + RRF 召回 top-100 → 交叉编码器精排 → final-k 5~10。精确词重的场景,sparse/BM25 这一路是质量的关键。
  3. A 用默认 Bounded 足够(离线灌、白天只读,容忍秒级滞后换吞吐);B 必须 Session(同会话 read-your-writes)。默认 Bounded 在 B 不行,因为它是有界滞后,刚上传的文档可能短时不可见。
  4. 无脑 HNSW 会在这个高选择性 filter 下召回塌(图遍历被饿死)。办法:用可迭代过滤策略,或对这类高过滤场景改用 IVF 类索引 / 预过滤+扫描;同时 tenant_id、ts 都要建标量索引(BITMAP / range)否则先变成全扫。
  5. 六个决策:① 隔离=Partition-Key(tenant_id);② schema 标量字段=tenant_id、timestamp、source、parent_doc_id(+ dense/sparse/text);③ 索引=tenant_id 与 source 用 BITMAP/INVERTED、timestamp 用 range;④ 检索栈=dense+BM25 → RRF → 交叉编码器;⑤ 一致性=Session(要自查)或 Bounded(纯离线灌);⑥ 更新=upsert + parent_doc_id 批删 + model_version 标签。相互牵制的典型一对:④检索的索引选择 ↔ ③那个"租户+7天"高过滤比——过滤越严越逼你离开纯 HNSW,否则召回塌。(另一对:⑤一致性=Session 要求新段尽快可见 ↔ ⑥ upsert/flush 策略。)
进阶挑战 · 刚好够不着

一句话本质,自己复述

不翻教程,用三到四句话向一个"RAG demo 已跑通、但没上过生产"的同事解释:从 demo 到生产 RAG,为什么真正的工作是设计四个 Milvus 默认值留给你的面,以及这四个面如何在一条真实查询里相互牵制。

对照点(说完再展开)

一份合格的复述应点到:① demo 把租户隔离/检索质量/新鲜度/过滤四件事用默认值跳过了;② 每个面都是某个 Milvus 机制按 RAG 场景做取舍(隔离=数据模型、检索=索引/度量、新鲜度=一致性、过滤=标量索引+段裁剪);③ 它们相互牵制——过滤比影响索引、索引影响召回旋钮、一致性影响更新策略;④ 最危险的是"不报错但答案错"的那几个(漏租户 filter、换模型只换一半、默认 Bounded 当 read-your-writes)。能把这串成因果链,就过了。