向量数据库存储 Embedding,并为语义搜索、推荐和 RAG 检索相近记录。当语义相似度属于产品契约时,它是一项必要能力;但这项能力不一定来自独立产品。精确检索、PostgreSQL + pgvector 或现有搜索引擎,往往是更小也更稳妥的起点。

本文只负责存储引擎决策:数据契约、精确检索与近似检索、ANN 索引、过滤与租户隔离、迁移、可靠性、基准测试和成本。Embedding 指南负责模型选型与向量空间兼容性;语义搜索指南负责召回与排序系统设计。

目录

核心要点

  • 向量数据库不只是 ANN 索引。围绕相似度召回,它还要保证 ID、元数据、权限、更新删除、持久化与可观测性。
  • 先做精确检索。它既可能直接满足小规模生产需求,也是测量 ANN Recall@K 必需的 Ground Truth。
  • HNSW、IVF 与乘积量化只是不同权衡,不存在按向量数量直接套用的万能结论。
  • 选型先选架构:进程内精确检索、pgvector、搜索引擎、专用数据库或托管服务。
  • Tenant 与 ACL 过滤属于正确性和安全边界,不能先全局召回,再要求 LLM 忽略未授权内容。
  • 更换 Embedding 模型等于创建新向量空间,应采用版本化 Generation、回填、双读评测、受控切换与回滚。

向量数据库到底负责什么

向量数据库回答的问题应完整表述为:「在当前调用方有权访问的记录中,按指定距离度量,哪些记录最接近查询向量?」生产查询从来不只是 nearest(query, k),还包含 Embedding 契约、授权范围、数据新鲜度,以及回到源记录的稳定关联。

向量索引不等于向量数据库

能力 向量索引或算法库 向量数据库或支持向量的数据库
最近邻检索 核心职责 核心职责
持久记录与稳定 ID 由应用补齐 通常内置
元数据过滤 有限或自建 通常支持,但执行语义不同
插入、更新与删除 取决于算法 作为数据操作暴露
副本与备份 由应用负责 由产品或平台承担
认证与租户隔离 由应用负责 与数据库及应用共同实现
可观测性与容量控制 由应用负责 随产品而异

Faiss 是相似度检索库,不是完整数据库。相反,PostgreSQL 通过 pgvector 获得向量能力后,仍保留 SQL、事务、Join、WAL 与时间点恢复。真正应该比较的不是「专用」和「传统」两个标签,而是应用最终获得了哪些可验证的运行契约。

一条向量记录需要哪些字段

可检索记录至少要能证明自身含义并回溯到源数据:

字段 作用
record_id 稳定幂等键与源记录定位
tenant_id 与 ACL 属性 强制授权范围
embedding 索引使用的数值表示
embedding_model 与 embedding_revision 防止不同向量空间被混用
source_version 与 chunk_version 识别过期或已替换内容
content_hash 支持去重与对账
deleted_at 或生命周期状态 防止删除后继续返回旧内容
检索元数据 承载查询真正使用的过滤条件

不要把源系统所有字段原样复制进向量库。权威原文应保存在 System of Record 中,向量侧只投影召回、授权、排序和追踪所需字段。如果向量数据库本身就是 System of Record,就必须明确承担更严格的备份、一致性和恢复要求。

写入与查询是两条链路

flowchart LR A["源记录"] --> B["解析与切片"] B --> C["按版本化契约生成 Embedding"] C --> D["写入向量与元数据"] D --> E["构建或更新向量索引"] F["用户查询与可信身份"] --> G["使用匹配版本生成查询向量"] G --> H["应用 Tenant 与 ACL 范围"] H --> I["精确或 ANN 候选召回"] I --> J["可选的词法融合与重排"] J --> K["读取源文档并返回证据"]

数据库无法修复错误的 Embedding 模型、破坏语义的切片策略、漏掉的 ACL,或把无关文档推到前面的重排器。它负责检索基础设施,不对最终答案正确性兜底。

精确检索、距离度量与 Ground Truth

精确最近邻检索会把查询与全部符合条件的向量比较,再按所选度量返回真实 Top-K。它的计算量随候选数线性增长,但「线性」不等于「一定慢」。语料较小、分区后候选范围有限、以批处理为主,或数值计算高度优化时,精确检索可能就是正确的生产方案。

精确检索还有第二个不可替代的作用:为 ANN 评测提供 Ground Truth。没有保留查询集上的精确 Top-K,就无法知道一个延迟很低的索引究竟漏掉了多少近邻。

距离度量必须匹配 Embedding 契约

度量 排序方式 适用条件
余弦相似度 方向越接近越靠前 模型明确使用 Cosine,或希望忽略向量模长
内积 点积越大越靠前 模型按内积训练,或参与比较的向量均已归一化
欧几里得距离 L2 越小越靠前 模型契约赋予几何距离明确含义

当所有向量都归一化为单位长度时,余弦相似度等于内积,平方 L2 距离等于 2 - 2 * inner_product,三者排序等价。没有归一化时,结果可能不同。因此正确做法是遵循并验证模型契约,而不是笼统地认为「文本都用 Cosine」或「点积一定最快」。

距离分数也不是经过校准的概率。一个模型上的 0.82,不能直接迁移到另一个模型、Revision、查询类型或语料。所有接受阈值都应基于标注数据调优,并与 Embedding Generation 一起版本化。

HNSW、IVF 与乘积量化

ANN 索引通过允许漏掉少量精确近邻来减少搜索工作量。正确比较对象是 Recall、延迟、内存形成的前沿,而不是「最快」「百万级首选」之类脱离条件的标签。

HNSW

HNSW 构建分层近邻图。查询从稀疏上层进入,沿着更接近查询的边移动,再逐层下降,最终在底层图中扩展候选。

HNSW 原始论文报告了该设计与实验中的对数复杂度扩展,但这不等于对任意数据分布、过滤条件、实现和参数都保证最坏情况 O(log N)。

常见控制参数包括:

  • M:图连接度。提高它可能改善可导航性与召回,同时增加内存和构建工作。
  • ef_construction:构建时的候选宽度。提高它可能改善图质量,但会减慢构建或插入。
  • ef_search:查询时的候选宽度。提高它通常改善召回,同时增加延迟与 CPU 消耗。

HNSW 在许多工作负载上能取得较好的 Recall/Latency 权衡,并可在常见实现中增量插入,但图索引会占用显著内存。删除和高频更新如何处理取决于具体实现,Tombstone、Vacuum、Compaction 或 Rebuild 都可能影响延迟与容量。

IVF

IVF 训练一组聚类中心,把向量分配到倒排 List;查询时先找到接近的中心,再只探测部分 List。主要参数是 List 数量与每次查询探测的 List 数量。

IVF 在许多实现中构建更快、索引内存更低,但召回依赖训练样本和 Probe 数量。数据分布漂移后,旧中心可能无法再合理划分新向量。因此「IVF 适合批量数据」只能作为待验证假设,仍要评估重建周期和更新后的召回变化。

乘积量化

乘积量化(Product Quantization,PQ)把向量切成多个子向量,再用码本编号替代每个子向量。它是一种有损压缩,可以减少内存,并在压缩域中执行近似距离计算。PQ 常与 IVF 组合,再用原始高精度向量对候选重排。

不存在通用的「压缩 10 倍」或「压缩 100 倍」结论。压缩比取决于原始精度与维度、编码长度、码本、是否存储残差,以及是否保留全精度向量用于重排。Faiss 研究资料列出了 PQ、IVF 与重排方法的原始论文,也明确展示了精度、速度和内存之间的权衡。

方法对比

方法 主要结构 核心优势 主要代价 必测项
精确或 Flat 全量扫描 返回真实 Top-K,无 ANN 构建 查询工作随候选数增长 尾延迟与吞吐
HNSW 分层近邻图 多类负载上有较好的 Recall/Latency 前沿 图内存、构建时间与更新碎片 不同 ef_search 下的 Recall、内存、删除
IVF 或 IVFFlat 聚类中心与倒排 List 多种实现中内存更低、构建更快 依赖训练质量和 Probe 分布漂移、nprobe、重建周期
IVF-PQ 或 PQ 压缩码,通常位于 IVF 后 缩小工作集 距离有损且需要训练 召回损失与重排成本

当前的 VIBE 基准使用现代 Embedding 数据集,并覆盖分布内与分布外查询。它明确只比较索引算法,不比较数据库或云服务。因此它适合帮助形成算法假设,不能直接当成产品采购榜单。

元数据过滤、权限与多租户

过滤属于检索正确性,而不只是性能优化。语义上相关但调用方无权读取的结果,就是安全事故。

预过滤、融合过滤与后过滤

策略 行为 风险
预过滤 先确定可访问子集,再执行向量检索 子集很小时精确检索可能更好;索引碎片增加运维负担
融合过滤 在 ANN 遍历过程中结合标量索引或过滤条件 各实现的能力与语义不同
后过滤 ANN 先召回候选,再移除不符合条件的记录 可能返回不足 K 条,或漏掉真正相关的合法记录
过采样后过滤 多召回候选再过滤 增加延迟,且不存在适合所有选择率的固定倍数

pgvector 官方文档给出了直接例子:近似索引查询可能先扫描索引、再应用过滤,选择率高的条件会让返回条数不足。pgvector 0.8 引入 Iterative Scan,可以继续扫描,直到找到足够结果或达到配置上限。其他引擎的过滤执行方式不同,因此必须对每个候选方案重复同一组测试。

权限规则

  1. 从服务端已认证身份推导 tenant_id、用户组与文档权限。
  2. 在检索查询内部或候选结果离开存储边界前完成授权过滤。
  3. 检索缓存 Key 必须包含完整授权范围。
  4. 覆盖拒绝、删除、跨租户、索引滞后、重试与故障转移测试。
  5. 保留从返回 Chunk 到源记录、源版本与权限决策的审计证据。

客户端提交的 Metadata 不能直接作为可信授权条件。攻击者不应通过修改请求中的 tenant_id 扩大检索范围。

租户数量少但单租户规模大时,独立分区或索引可能改善隔离与可预测性;租户很多且单租户较小时,共享索引配合强制过滤通常更节省资源。测试必须同时覆盖中位租户、最大租户和选择率最高的租户,平均值会掩盖噪声邻居和召回缺失。

如何选择存储架构

应选择满足实测要求的最小架构。仅凭向量数量无法决策,因为维度、过滤、查询结构、并发、写入率、硬件和 Recall 目标都会改变结果。

方案 适合条件 主要风险 升级信号
精确或进程内检索 语料小或候选范围有界;批处理;需要 Ground Truth 内存、并发、持久化均由应用负责 尾延迟或内存不再满足 SLO
PostgreSQL + pgvector 向量与关系行共存;依赖 SQL 过滤、Join、事务与现有运维 ANN 与 OLTP 争用,索引构建和 Vacuum 成本,纵向扩展边界 实测争用、规模或过滤召回超出运行边界
支持向量的搜索引擎 词法排序、Facet、过滤与向量需要共用检索栈 Refresh 语义、评分复杂度、内存与集群运维 向量专用规模或控制成为主要矛盾
专用向量数据库 ANN 规模、高写入、过滤感知召回或向量原生分布式能力最重要 第二套数据系统、对账、备份与团队经验 更简单的系统可满足同样 SLO 与质量
托管向量服务 免运维、弹性和支持价值高于平台约束 数据驻留、配额、网络外发、价格变化与迁移 成本或控制权超过托管收益

这是一项需要实证的架构决策:

  1. 写清查询契约与数据契约。
  2. 在合法候选集上测量精确检索。
  3. 加入复杂度最低的索引方案。
  4. 加载真实数据、过滤分布与更新负载。
  5. 同时评估质量、延迟、写入、恢复和成本。
  6. 只有证据指出明确瓶颈时,才增加第二套系统。

不要采用「低于一千万条就用 pgvector」或「超过一百万条必须专用数据库」这类阈值。它们忽略了真正决定系统能否工作的变量。

可运行的 Go 精确检索基线

下面的 Go 程序只依赖标准库,实现带 Tenant、ACL 与 Embedding Version 过滤的精确余弦检索,并计算 Recall@K。它刻意不调用某个数据库:其职责是定义一个确定的 Ground Truth,后续 pgvector、搜索引擎或专用服务适配器都必须保持相同语义。

go
package main

import (
	"errors"
	"fmt"
	"math"
	"sort"
)

type Document struct {
	ID               string
	TenantID         string
	Text             string
	EmbeddingVersion string
	Embedding        []float64
	AllowedUsers     map[string]bool
	Deleted          bool
}

type Result struct {
	ID    string
	Text  string
	Score float64
}

func cosineSimilarity(a, b []float64) (float64, error) {
	if len(a) == 0 || len(a) != len(b) {
		return 0, errors.New("vectors must have the same non-zero dimension")
	}

	var dot, normA, normB float64
	for i := range a {
		dot += a[i] * b[i]
		normA += a[i] * a[i]
		normB += b[i] * b[i]
	}
	if normA == 0 || normB == 0 {
		return 0, errors.New("cosine similarity is undefined for a zero vector")
	}

	return dot / (math.Sqrt(normA) * math.Sqrt(normB)), nil
}

func exactSearch(
	documents []Document,
	query []float64,
	tenantID string,
	userID string,
	embeddingVersion string,
	topK int,
) ([]Result, error) {
	if topK <= 0 {
		return nil, errors.New("topK must be positive")
	}

	results := make([]Result, 0, len(documents))
	for _, document := range documents {
		if document.Deleted ||
			document.TenantID != tenantID ||
			document.EmbeddingVersion != embeddingVersion ||
			!document.AllowedUsers[userID] {
			continue
		}

		score, err := cosineSimilarity(query, document.Embedding)
		if err != nil {
			return nil, fmt.Errorf("score document %s: %w", document.ID, err)
		}
		results = append(results, Result{
			ID:    document.ID,
			Text:  document.Text,
			Score: score,
		})
	}

	sort.Slice(results, func(i, j int) bool {
		if results[i].Score == results[j].Score {
			return results[i].ID < results[j].ID
		}
		return results[i].Score > results[j].Score
	})
	if len(results) > topK {
		results = results[:topK]
	}

	return results, nil
}

func recallAtK(exactIDs, approximateIDs []string) float64 {
	if len(exactIDs) == 0 {
		return 1
	}

	found := make(map[string]bool, len(approximateIDs))
	for _, id := range approximateIDs {
		found[id] = true
	}

	hits := 0
	for _, id := range exactIDs {
		if found[id] {
			hits++
		}
	}
	return float64(hits) / float64(len(exactIDs))
}

func main() {
	documents := []Document{
		{
			ID:               "access-control",
			TenantID:         "acme",
			Text:             "Derive ACL filters from trusted identity.",
			EmbeddingVersion: "embed-v2",
			Embedding:        []float64{0.82, 0.57, 0.05},
			AllowedUsers:     map[string]bool{"alice": true},
		},
		{
			ID:               "retrieval-evaluation",
			TenantID:         "acme",
			Text:             "Compare ANN results with an exact-search baseline.",
			EmbeddingVersion: "embed-v2",
			Embedding:        []float64{0.70, 0.68, 0.10},
			AllowedUsers:     map[string]bool{"alice": true},
		},
		{
			ID:               "private-runbook",
			TenantID:         "acme",
			Text:             "Internal incident response runbook.",
			EmbeddingVersion: "embed-v2",
			Embedding:        []float64{0.84, 0.54, 0.02},
			AllowedUsers:     map[string]bool{"bob": true},
		},
		{
			ID:               "other-tenant",
			TenantID:         "globex",
			Text:             "A document from another tenant.",
			EmbeddingVersion: "embed-v2",
			Embedding:        []float64{0.88, 0.47, 0.01},
			AllowedUsers:     map[string]bool{"alice": true},
		},
		{
			ID:               "old-embedding",
			TenantID:         "acme",
			Text:             "A vector from the previous embedding generation.",
			EmbeddingVersion: "embed-v1",
			Embedding:        []float64{0.90, 0.43, 0.01},
			AllowedUsers:     map[string]bool{"alice": true},
		},
	}

	results, err := exactSearch(
		documents,
		[]float64{0.80, 0.60, 0},
		"acme",
		"alice",
		"embed-v2",
		2,
	)
	if err != nil {
		panic(err)
	}

	for rank, result := range results {
		fmt.Printf("%d. %s score=%.4f\n", rank+1, result.ID, result.Score)
	}

	exactIDs := []string{"access-control", "retrieval-evaluation"}
	approximateIDs := []string{"access-control", "unrelated"}
	fmt.Printf("Recall@2: %.2f\n", recallAtK(exactIDs, approximateIDs))
}

运行命令:

bash
go run main.go

预期输出:

text
1. access-control score=0.9981
2. retrieval-evaluation score=0.9867
Recall@2: 0.50

注意程序在打分前排除了另一个用户的文档、另一个租户的文档,以及旧 Embedding Generation 的向量。生产 ANN 查询必须保持完全相同的语义。最后的 Recall@2 示例说明:即使近似检索返回很快,只要漏掉一个精确近邻,召回率就是 0.50。

如何对候选方案做基准测试

可信基准必须比较完整工作负载,而不是孤立 QPS。ANN-Benchmarks 论文强调统一数据集、参数扫描、质量指标与可复现集成;VIBE 将这一思路扩展到现代 Embedding 数据集与分布外查询。

先冻结实验输入

  • 语料快照、合法记录数、维度、精度与归一化方式。
  • Embedding 模型、Revision、Task Mode、预处理与距离度量。
  • 查询集的频率权重、Hard Negative、语言分布与相关性标注。
  • 过滤分布,包括典型租户、最大租户与最小租户的选择率。
  • Top-K、候选数、重排策略、并发与超时。
  • 硬件、Region、副本、内存上限、存储类型,以及冷启动与预热状态。
  • 测试期间的插入、更新与删除速率。

同时测量所有关键输出

层次 指标
ANN 正确性 相对精确近邻的 Recall@K;过滤后返回条数完整性
搜索相关性 Precision@K、MRR、nDCG、零结果与 Hard Negative 表现
延迟 p50、p95、p99、超时率、冷启动
容量 目标 Recall 下的 QPS、内存、CPU、存储与索引大小
新鲜度 写入或删除被接受后,到查询可见的时间
运维 构建、重建、备份、恢复耗时与故障转移行为
成本 稳态与峰值计算、存储、副本、网络、备份和运维人力

扫描 ANN 参数并绘制 Recall 与尾延迟曲线。产品对比必须固定 Recall@K,而不是直接拿各自默认参数比 QPS。之后还要跑应用层相关性评测,因为几何上的精确近邻不一定是用户问题的最佳证据。

RAG 场景可使用生产级 RAG 评估指南,分离检索召回、排序质量、忠实度、答案质量、延迟和成本。

Embedding 迁移与数据生命周期

更换 Embedding 是一次数据迁移,因为不同模型契约生成的向量并不处在可可靠比较的同一坐标系。直接覆盖旧向量会破坏回滚能力,还可能让查询向量与文档向量发生静默混用。

采用 Generation 迁移流程:

  1. 定义 embedding_generation = v2,固定模型、Revision、Task Mode、维度、归一化、距离度量与预处理。
  2. 为 v2 建立独立存储或索引范围。
  3. 从不可变源记录执行幂等回填。
  4. 对账记录数、内容哈希、失败任务与删除标记。
  5. 对 v1 和 v2 执行 Shadow 或双读,在同一标注集比较质量、延迟和成本。
  6. 离线门禁通过后,只把受控流量切到 v2。
  7. 原子切换读别名或 Generation Pointer。
  8. 保留 v1 作为限时回滚路径,再通过正常删除流程清理。

插入、更新与删除

需要定义外部可观察语义:

  • 写入新鲜度:写请求成功后,什么时候保证可以被搜索?
  • 更新原子性:元数据与向量 Revision 是否可能分别可见?
  • 删除传播:删除或撤权后的记录最多还能被检索多久?
  • 重试幂等性:重复 Upsert 是否产生重复记录?
  • 索引重建:构建新索引期间的写入会被捕获、暂停还是重放?

软删除有利于恢复,但不能代替权限控制。查询必须按产品契约立即排除已删除记录,后台 Compaction 最终回收对应存储和图边。

可靠性与总成本

只有在数据能被重建、恢复并在故障后完成对账时,向量数据库才算生产可用。仅备份索引不够;源记录、Metadata、模型版本或切片配置缺失时,索引无法被可信地解释。

恢复契约

需要记录并演练:

  • 哪份数据是权威源,哪些索引只是可重建投影。
  • 备份是否覆盖向量、Metadata、Alias、配置与源记录。
  • RPO 与 RTO。
  • 在隔离环境恢复后执行记录数、哈希、ACL 与样例查询校验。
  • 区域故障、部分写入、队列重放与索引重建期间的行为。
  • 访问、变更、删除与迁移审计日志。

当 PostgreSQL + pgvector 是存储层时,向量可以参与 PostgreSQL WAL、副本与时间点恢复。独立向量服务则需要自己的备份与对账路径;「托管」不代表可以跳过恢复演练。

成本模型

原始向量存储下限为:

text
raw_vector_bytes = vector_count * dimensions * bytes_per_component

这个数字没有包含图边或量化编码、记录 ID、Metadata 索引、副本、写缓冲、Compaction 空间、备份与网络流量。完整月成本至少包括:

text
total_cost =
  steady_compute + peak_headroom + primary_storage + index_storage
  + replicas + backups + network_egress + ingestion
  + operations_and_incident_time

必须在目标 Recall、p99 延迟、新鲜度和可用性下比较成本。不满足质量或安全门禁的低价配置,不是等价方案。

向量数据库在 RAG 中的边界

向量数据库只是 RAG 的候选召回层,不是完整 RAG 系统。

text
查询
  -> 查询归一化或改写
  -> 带授权的词法与向量召回
  -> 候选融合
  -> 重排
  -> 带来源标识的上下文组装
  -> 生成
  -> 引用与答案评估

稠密检索可能漏掉标识符、错误码、人名与低频词,词法检索可能漏掉同义表达。混合搜索合并两类候选,Reranker 则在较小候选集上投入更多计算。数据库应返回足够多、可以追踪来源的候选,而不是把向量相似度分数当作最终答案置信度。

重复且已授权的请求可以使用语义缓存,但 Cache Key 必须包含 Tenant、权限、Embedding Generation、检索配置、模型、Prompt 与来源版本。缓存命中不能绕过当前授权和删除状态。

常见失败模式

失败 原因 控制措施
检索很快但内容不相关 只优化几何近邻 Recall,没有评估用户相关性 保留应用标注查询与重排指标
过滤后不足 K 条 后过滤移除了 ANN 候选 测选择率;使用 Iterative Search、分区或精确检索
跨租户泄漏 Tenant/ACL 来自客户端,或缓存 Key 缺少权限 服务端推导范围并覆盖拒绝路径测试
换模型后质量下降 新旧 Embedding Generation 被混用 向量版本化并采用并行迁移
删除内容再次出现 源记录删除没有传播到索引、副本或缓存 定义删除 SLO 并持续对账所有投影
p50 稳定但 p99 恶化 索引换页、Compaction、过滤倾斜或队列积压 按租户、过滤与索引 Generation 观测尾延迟
基准冠军上线失败 数据集、度量、过滤、并发或硬件不同 在相同质量下重放真实工作负载
成本失控 只计算原始向量,遗漏索引、副本、外发与运维 按目标 SLO 比较总成本

常见问题

向量数据库和关系型数据库有什么区别?

关系型数据库是围绕结构化记录、约束、事务、Join 与标量索引构建的通用数据系统;向量数据库或支持向量的数据库增加了对高维 Embedding 的相似度检索。两类能力可以重叠:PostgreSQL + pgvector 可以执行向量搜索,而专用向量引擎可能只提供有限的关系语义。应比较运行契约,而不是产品标签。

每个 RAG 应用都需要独立向量数据库吗?

不需要。小语料可以直接用精确检索;向量与业务行需要共享事务和 SQL 过滤时,PostgreSQL + pgvector 很合适;关键词、Facet 与向量候选需要共用排序栈时,可以评估搜索引擎。只有专用或托管系统的规模、过滤、分布式或运维能力解决了实测瓶颈时,才值得增加一套系统。

HNSW 一定比 IVF 更好吗?

不一定。HNSW 往往有较好的 Recall/Latency 前沿,IVF 则可能降低稳定语料上的内存与构建成本。HNSW 的图内存和更新碎片可能无法接受,IVF 的聚类训练与分布漂移也可能无法接受。应使用相同语料、过滤、更新与 Recall@K 目标比较。

如何评估向量数据库的检索质量?

先把 ANN 结果与精确 Top-K 对比,计算 Recall@K;再使用标注查询测 Precision@K、MRR 或 nDCG;最后独立评估 RAG 答案质量。几何近邻召回、检索相关性和答案忠实度相互影响,但不能互相替代。

如何在不停机的情况下更换 Embedding 模型?

新建独立 Embedding Generation,保留旧向量;完成回填后,对两个 Generation 做 Shadow 或双读评测;质量、延迟与成本门禁通过后,再原子切换读别名。保留一段回滚窗口,并在迁移期间把更新和删除传播到两个版本。

权威资料

总结

可靠的向量数据库选型从带授权的查询契约和精确基线开始。先测清 ANN 的 Recall、延迟与内存权衡,再根据过滤、写入、恢复、迁移和总成本选择存储架构。Embedding 必须版本化,权限必须在检索内部执行,而 RAG 答案质量必须与几何近邻准确率分开评估。

相关资源