数据库基础体系 · 第 59/139 篇。文章以各产品官方稳定版本的公开语义为准;示例会明确引擎、事务与部署边界。
向量数据库基础:Embedding、距离度量、召回、过滤与一致性
向量数据库用于保存和检索向量。向量本身只是一个由浮点数或其他数值组成的数组,真正决定检索效果的,是以下几层共同作用:
- Embedding 模型把文本、图片或其他对象映射为向量;
- 距离度量定义两个向量“相似”的含义;
- 检索算法从数据集中找到距离最近的候选;
- 召回描述近似检索相对于精确结果找回了多少;
- 过滤把向量相似度与结构化条件结合起来;
- 一致性决定写入、更新和删除何时能被查询看到。
这些概念彼此相关,但不能互相替代。例如,换一个距离函数不会自动提高召回率;提高 ANN 索引的搜索参数也不会解决数据尚未可见的问题。
一、向量数据库到底保存什么
一条典型的向量数据至少包含四类信息:
主键:document-001
向量:[-0.12, 0.38, ...]
结构化字段:tenant_id = 42, language = "zh", year = 2024
原始内容或引用:文章 URL、分块文本、对象存储路径
向量通常不是原始数据的替代品,而是原始数据的检索表示。生产系统往往保存:
- 原文或原始对象;
- 文档分块后的文本;
- Embedding 模型名称和版本;
- 分块策略版本;
- 租户、权限、时间、语言等元数据;
- 向量数据库中的主键和索引状态。
这样做很重要,因为向量是模型输出,不是稳定的业务事实。模型升级、分块方式变化或预处理方式变化后,即使同一段文本也可能生成不同维度或不同语义空间的向量。
1. Embedding 的定义
Embedding 是一个映射函数:
其中:
- 是输入对象空间,例如文本集合;
- 是向量维度;
- 是对象 的向量表示。
例如,一个文本编码模型可能把一句话映射为 768 维向量:
"数据库事务保证一致性"
↓
[0.13, -0.42, 0.08, ..., 0.27]
Embedding 的目标通常不是让字面相同的文本拥有相同向量,而是让某种任务下“相关”的对象在向量空间中更接近。
因此,Embedding 不是通用的“语义坐标系”。以下向量通常不能直接混用:
- 不同模型生成的向量;
- 同一模型的不同版本;
- 文档编码向量与查询编码向量不匹配的模型;
- 使用不同文本预处理规则生成的向量;
- 训练目标不同的通用模型和领域模型。
如果文档向量使用模型 A,查询向量使用模型 B,即使两者维度相同,距离数值也通常没有可比性。维度相同只说明数组形状相同,不说明坐标语义相同。
2. 文本分块会改变检索结果
对长文档直接生成一个向量,可能把多个主题压缩到一个点中。常见流程是:
原文
↓
按标题、段落或 token 数分块
↓
为每个分块生成 Embedding
↓
写入向量数据库,并保存 document_id、chunk_id 和原文引用
分块太大,单个向量包含多个主题,查询时区分度下降;分块太小,上下文不完整,召回的片段可能无法回答问题。这个问题不能通过增加 HNSW 的搜索参数解决,因为索引只能在已有向量中搜索。
二、距离度量:什么叫“最近”
向量数据库通常执行 Top- 近邻搜索:
表示在数据集 中,按照距离函数 排序,返回距离最小的 个向量。
不同距离函数会产生不同的排序。选择距离函数不是数据库索引的装饰配置,而是检索语义的一部分。
1. 欧氏距离
欧氏距离定义为:
它表示向量空间中的直线距离。平方根不影响排序,因此实现中常使用平方欧氏距离:
优点是直观,适合模型明确使用欧氏空间训练的场景。缺点是它同时受方向和长度影响。
2. 内积
内积定义为:
如果向量长度没有归一化,内积既反映方向,也反映长度。对于最大内积搜索,内积越大越相似。
以 PostgreSQL 的 pgvector 为例,<#> 运算符返回的是负内积,原因是 PostgreSQL 索引扫描通常按升序处理距离:
embedding <#> query_vector
数值越小,实际内积越大。因此不能把 pgvector 的 <#> 返回值直接当作普通正向相似度。
3. 余弦相似度与余弦距离
余弦相似度是:
其中:
余弦距离通常定义为:
它只关注方向,不关注向量长度。文本语义搜索中常用余弦度量,因为向量长度有时更多反映文本形式或模型内部置信度,而不是语义方向。
4. 归一化后的等价关系
如果 和 都被归一化为单位向量:
则:
而单位向量的内积就是余弦相似度,因此:
- L2 距离越小;
- 内积越大;
- 余弦距离越小;
三者会产生相同的排序。
但是,只有在所有向量都已归一化时,这个结论才成立。
5. 完整算例
令查询向量:
四个候选向量为:
a = (1, 0)
b = (0.8, 0.6)
c = (0, 1)
d = (-1, 0)
其中 、 都是单位向量。
| 向量 | 内积 | 余弦相似度 | L2 距离 |
|---|---|---|---|
| a | 1.0 | 1.0 | 0 |
| b | 0.8 | 0.8 | 0.632 |
| c | 0.0 | 0.0 | 1 |
| d | -1.0 | -1.0 | 2 |
这里三种度量给出相同顺序。
再加入:
e = (10, 0)
此时:
- 内积:;
- 余弦相似度:;
- L2 距离:。
如果任务关注方向,e 与 a 的余弦相似度相同;如果任务关注欧氏位置,e 离 q 很远;如果直接使用内积,e 会因为长度大而排在 a 前面。
这就是“度量选择错误”的典型表现:检索结果并非数据库算错,而是排序标准与模型或业务目标不一致。
6. pgvector 中的距离运算符
pgvector 文档中常见的运算符包括:
| 运算符 | 含义 |
|---|---|
<-> |
L2 距离 |
<#> |
负内积 |
<=> |
余弦距离 |
<+> |
L1 距离 |
使用哪一个运算符,必须与创建索引时的 operator class 一致。例如:
CREATE INDEX documents_embedding_hnsw_cos_idx
ON documents
USING hnsw (embedding vector_cosine_ops);
查询余弦距离:
SELECT
id,
content,
embedding <=> '[0.2, 0.1, 0.7]'::vector AS distance
FROM documents
ORDER BY embedding <=> '[0.2, 0.1, 0.7]'::vector
LIMIT 5;
这里按升序取距离最小的五条记录。若需要显示余弦相似度,可以使用:
SELECT
id,
1 - (embedding <=> '[0.2, 0.1, 0.7]'::vector) AS cosine_similarity
FROM documents
ORDER BY embedding <=> '[0.2, 0.1, 0.7]'::vector
LIMIT 5;
这个转换只适用于这里定义的余弦距离语义,不能把 L2 距离或负内积也机械地写成 1 - distance。
三、精确搜索、近似搜索与召回
1. 精确 Top-
精确搜索会计算查询向量与所有候选向量的距离,然后排序或维护一个 Top- 集合。
数据量为 ,向量维度为 时,朴素计算大致需要 的距离计算。它的优点是结果可作为标准答案,缺点是数据量大时延迟和 CPU 成本较高。
在 pgvector 中,不创建近似索引时,可以通过顺序扫描执行精确搜索:
SELECT id, content
FROM documents
WHERE tenant_id = 42
ORDER BY embedding <=> $1
LIMIT 10;
这里的 $1 是参数化传入的查询向量。对于规模较小的数据集,精确搜索常常比维护复杂 ANN 索引更简单。
2. 近似最近邻
近似最近邻(ANN)不保证返回全局真实最近的向量,而是通过索引减少需要比较的候选数量。
常见方法包括:
- Flat:扫描全部向量,通常是精确搜索;
- HNSW:使用多层图快速导航;
- IVF:先选择若干聚类中心,只搜索部分簇;
- PQ:压缩向量或距离计算,节省内存,但通常引入误差。
这些方法的细节属于向量索引原理,但对本文主题有一个关键影响:ANN 的结果质量由“候选集是否包含真实近邻”决定。
3. 召回率的定义
给定查询 和 :
- :使用精确搜索得到的真实 Top-;
- :近似索引返回的 Top-。
常用的 Recall@k 为:
例如精确结果为:
G5 = {a, b, c, d, e}
ANN 结果为:
A5 = {a, b, c, x, y}
交集有三个元素,因此:
这不是“返回结果中有 60% 相关”的主观评价,而是相对于精确 Top- 的集合重合率。
实际评估时,应在代表性查询集上统计 Recall@k,而不是只看单条查询。还要固定:
- Embedding 模型;
- 距离度量;
- 数据集快照;
- 查询过滤条件;
- Top-;
- 索引参数;
- 是否包含尚未稳定的写入数据。
4. 召回率与相关性不是同一个概念
召回率只衡量 ANN 是否找回精确算法认为最近的向量。如果 Embedding 模型本身没有表达正确语义,精确搜索也可能返回业务上不相关的结果。
因此存在两种不同失败:
模型表达错误:
语义相关对象根本没有靠近,精确搜索也找不到。
ANN 近似误差:
语义相关对象已经靠近,但索引没有把它找出来。
前者应检查模型、文本清洗和分块;后者应调整索引构建或搜索参数。
四、过滤:向量相似与结构化条件如何结合
向量搜索通常不是“全库找最相似”,而是:
在满足业务条件的记录中,找向量最相似的 Top-k
形式化表示为:
其中:
- 是全部向量;
- 是过滤谓词,例如租户、权限、语言或时间;
- 只对满足 的向量进行 Top- 排序。
1. 后过滤为什么会返回不足 k 条
假设全库按距离排序为:
A(0.10), B(0.12), C(0.15), D(0.20), E(0.22)
过滤条件为:
tenant_id = 42
其中只有 A 和 E 属于租户 42。
如果系统先取全库 Top-3,再执行过滤:
全库 Top-3:A, B, C
过滤后:A
结果只有一条,而不是满足条件集合中的 Top-3。即使把候选扩大到 Top-5,也只能在候选足够覆盖过滤集合时得到正确结果。
因此,以下两种语义不同:
先取全库 Top-k,再过滤
与:
先限定候选集合,再取 Top-k
生产系统必须确认使用的是哪一种。
2. 过滤策略的三种形态
预过滤
先使用结构化索引筛选候选,再执行向量搜索:
tenant_id = 42 AND language = 'zh'
↓
候选集合
↓
向量 Top-k
优点是语义正确且适合高选择性条件;缺点是候选集合组织复杂,过滤条件不选择时收益有限。
后过滤
先执行 ANN,再在结果中应用过滤条件。
优点是实现简单;缺点是过滤条件严格时容易返回不足、结果偏差大,甚至无法得到真实的过滤集合 Top-k。
过滤感知的 ANN
把标量过滤条件纳入 ANN 搜索过程,在图遍历、分区选择或候选扩展时跳过不满足条件的实体。
这通常是系统实现中的折中方案:比简单后过滤正确得多,但其性能和结果仍取决于索引结构、过滤选择性和搜索参数。
pgvector 的 SQL 语义可以明确写成:
SELECT
id,
content,
embedding <=> $1 AS distance
FROM documents
WHERE tenant_id = $2
AND language = 'zh'
ORDER BY embedding <=> $1
LIMIT 10;
这条 SQL 的关系语义是先限定 WHERE 条件,再在符合条件的行上排序。不过是否使用近似向量索引、过滤发生在索引扫描的哪个阶段,则由 PostgreSQL 查询规划器、索引类型和 pgvector 版本能力共同决定。应使用 EXPLAIN (ANALYZE, BUFFERS) 验证,而不能仅凭 SQL 外观判断执行路径。
3. 过滤选择性会改变索引取舍
设过滤后只有全库的 :
- 如果索引能有效利用过滤条件,搜索空间大幅缩小;
- 如果 ANN 先找少量候选再后过滤,候选很可能全部被过滤掉;
- 如果为了补足结果而反复扩展候选,延迟可能突然上升;
- 如果过滤字段是租户隔离条件,错误的后过滤还可能带来数据越权风险。
tenant_id、权限范围等条件不能只当作性能过滤器。它们通常是结果正确性和安全边界的一部分。
4. 过滤字段的类型边界
结构化过滤字段应使用数据库可索引的类型,例如:
- 整数或字符串租户标识;
- 时间戳;
- 布尔状态;
- 标量数组或集合;
- 经过明确建模的标签字段。
不要把所有元数据都序列化成一段 JSON 文本后再依赖模糊字符串匹配。这样会使过滤语义、索引能力和类型检查都变得不明确。
五、pgvector 中的一个完整基础示例
以下示例以 PostgreSQL 加 pgvector 为边界。它展示的是小型数据集上的基本流程,距离是余弦距离,事务语义由 PostgreSQL 提供。
1. 建表和写入
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE documents (
id bigserial PRIMARY KEY,
tenant_id bigint NOT NULL,
language text NOT NULL,
content text NOT NULL,
embedding vector(3) NOT NULL,
model_name text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
INSERT INTO documents
(tenant_id, language, content, embedding, model_name)
VALUES
(42, 'zh', '事务提供原子性和隔离性', '[1,0,0]', 'demo-v1'),
(42, 'zh', '向量检索按照距离返回近邻', '[0.8,0.6,0]', 'demo-v1'),
(42, 'en', 'Transaction isolation levels', '[0,1,0]', 'demo-v1'),
(7, 'zh', '另一个租户的数据库文章', '[0.9,0.1,0]', 'demo-v1');
前置条件是所有向量必须有相同维度 3,并且由同一个示例模型空间产生。真实系统不应把不同模型的向量写入同一逻辑检索空间,除非有明确的模型分区和查询路由。
2. 精确过滤检索
SELECT
id,
content,
embedding <=> '[1,0,0]'::vector AS cosine_distance
FROM documents
WHERE tenant_id = 42
AND language = 'zh'
ORDER BY embedding <=> '[1,0,0]'::vector
LIMIT 2;
预期结果按距离升序大致为:
事务提供原子性和隔离性 0
向量检索按照距离返回近邻 0.2
tenant_id = 42 保证不会返回租户 7 的记录,language = 'zh' 排除英文记录。这里的结果是过滤集合内的精确 Top-2,前提是数据库执行的是精确排序而不是近似索引路径。
3. 创建 HNSW 索引
数据量增大后,可以创建 HNSW 索引:
CREATE INDEX documents_embedding_hnsw_cos_idx
ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
其中:
m控制图中连接数量,影响索引大小、构建成本和搜索质量;ef_construction影响构建阶段候选搜索范围;vector_cosine_ops表示该索引使用余弦距离操作类。
查询时可以调节搜索范围:
SET LOCAL hnsw.ef_search = 100;
SELECT id, content
FROM documents
WHERE tenant_id = 42
ORDER BY embedding <=> '[1,0,0]'::vector
LIMIT 10;
SET LOCAL 只在当前事务中生效,适合为某类查询临时增加搜索范围。搜索范围越大,通常越可能找回真实近邻,但延迟和 CPU 消耗也可能增加。它不能改变 Embedding 模型,也不能把错误的距离度量变正确。
不同 pgvector 版本对过滤后的迭代扫描、索引扫描策略等能力可能不同,应以所部署版本的官方文档为准,并通过执行计划和实际数据验证。
六、更新、删除与一致性
一致性回答的是:
一个写操作完成后,另一个读操作在什么时间、什么条件下必须或可能看到它?
它与召回率不同。
- 召回率低:数据可能已经可见,但近似索引没有找到真实近邻;
- 一致性较弱:数据可能根本还没有进入本次查询可见的范围;
- 过滤错误:可能返回了不应访问的数据;
- 模型错误:数据可见且检索正确,但语义空间表达不对。
1. PostgreSQL + pgvector 的事务边界
pgvector 是 PostgreSQL 的扩展,表数据、向量列、普通索引和向量索引都处于 PostgreSQL 的事务体系中。常见流程如下:
BEGIN;
INSERT INTO documents
(tenant_id, language, content, embedding, model_name)
VALUES
(42, 'zh', '新文档', '[0.99,0.01,0]'::vector, 'demo-v1');
-- 在当前事务中执行查询
SELECT id, content
FROM documents
WHERE tenant_id = 42
ORDER BY embedding <=> '[1,0,0]'::vector
LIMIT 1;
COMMIT;
在同一事务中,查询可以看到自己的写入;事务提交后,其他事务能否看到数据取决于 PostgreSQL 的隔离级别和快照建立时间。普通 PostgreSQL 事务不会因为向量列而失去 ACID 语义。
但需要区分数据库事务与应用层异步流程:
写入原文数据库
↓
异步生成 Embedding
↓
异步写入向量表
如果原文事务已经提交,而 Embedding 任务尚未完成,按“原文已存在”查询时,向量库中可能暂时没有对应记录。这不是 PostgreSQL 事务失效,而是两个独立事务之间存在处理延迟。
2. Upsert 不是所有系统中的同一种语义
应用常把“插入或更新”称为 upsert,但必须确认:
- 主键冲突时是覆盖、合并还是报错;
- 更新向量后旧向量是否立即从检索路径消失;
- 删除是否立即生效;
- 更新元数据和更新向量是否原子;
- 重试请求是否幂等。
例如文档重新分块后,旧的 chunk_id 如果没有删除,可能同时检索到旧分块和新分块。解决方法不是只调用一次 upsert,而是定义明确的版本状态:
document_id = 100
version = 3
status = active
查询只允许 status = active 且版本符合要求的记录,旧版本在确认新版本完整写入后再删除或标记失效。
3. Milvus 中的一致性级别
Milvus 是独立的分布式向量数据库,其写入、消息流、查询节点和持久化组件之间存在异步传播过程。Milvus 文档公开描述了多种一致性级别,常见包括:
- Strong:读取尽可能等待最新可见数据;
- Session:同一会话中通常保证能看到自己的写入;
- Bounded:允许一个有界的新鲜度窗口;
- Eventually:最终可见,不保证立即读到最新写入。
具体 API、默认值和可用配置应以部署版本和所用 SDK 文档为准。不能仅因为 insert 或 upsert 请求返回成功,就推断下一条查询必然立即看到新数据。
一个典型的可见性路径是:
客户端写入
↓
代理接收请求
↓
消息写入与分发
↓
查询节点获得对应时间戳的数据
↓
查询请求选择可见时间点
如果查询使用较弱的一致性级别,可能出现:
写入请求成功
查询暂时查不到新向量
稍后查询才能查到
这在异步索引构建、流式导入、批量导入和副本追赶时尤其常见。
4. 删除的延迟与旧结果
分布式向量系统通常通过删除标记、时间戳和后台压缩处理删除。删除请求被接受后,可能经历:
删除请求成功
↓
删除消息传播
↓
查询节点应用删除标记
↓
旧数据在查询中不可见
↓
后台 compaction 回收物理空间
“查询不可见”和“物理空间已经回收”是两个不同时间点。前者关系到业务正确性,后者关系到存储回收和性能。
如果系统返回了刚刚删除的对象,应先检查:
- 查询使用的一致性级别;
- 删除请求是否真正成功;
- 查询是否命中了旧副本或旧时间戳;
- 是否存在同一业务对象的旧版本;
- 是否发生了客户端缓存。
七、并发写入中的典型竞态
1. 新旧 Embedding 乱序到达
假设同一文档快速更新两次:
版本 2:先提交原文,Embedding 任务耗时较长
版本 3:后提交原文,Embedding 任务先完成
如果两个异步任务都直接写入同一主键,版本 2 可能最后到达并覆盖版本 3,产生“旧内容覆盖新内容”的结果。
解决方式是把版本写入请求中,并在数据库侧约束更新顺序。例如 PostgreSQL 中可使用带条件的更新:
UPDATE document_vectors
SET
content = $1,
embedding = $2,
version = $3
WHERE document_id = $4
AND version < $3;
如果受影响行数为零,说明该版本已经过期或存在并发冲突,应用不能把它当作成功覆盖。
2. 原文已删除,向量任务后来完成
另一条竞态路径是:
删除原文
↓
旧的 Embedding 任务仍在队列中
↓
任务完成并重新写入向量
最终系统可能出现“原文不存在,但向量还在”的幽灵记录。常见解决办法包括:
- 删除时写入 tombstone 或删除版本;
- Embedding 任务写入前检查对象当前版本;
- 使用幂等任务键;
- 查询时额外过滤对象状态;
- 定期对账原文表和向量表。
3. 多租户检索中的安全边界
错误的实现可能是:
先在全库取 Top-10
再在应用代码中过滤 tenant_id
当租户数据稀疏时,结果可能不足;更严重的是,如果日志、重排器或缓存先接触了全库结果,租户隔离边界已经被破坏。
正确的抽象应当是:
tenant_id 是检索候选集合定义的一部分
过滤应尽可能在数据库查询语义中表达,而不是依赖应用层事后删除结果。
八、诊断:结果不对时先区分哪一层出错
1. 先执行精确基线
对同一批查询,暂时关闭或绕过 ANN 索引,执行精确搜索,并记录:
查询向量版本
距离度量
过滤条件
精确 Top-k
ANN Top-k
Recall@k
如果精确结果就不符合人工判断,应检查:
- 查询和文档是否使用同一个 Embedding 模型;
- 文本是否被错误截断;
- 分块是否过大或过小;
- 查询是否使用了正确的指令模板;
- 向量维度和归一化方式是否一致;
- 距离度量是否与模型训练目标一致。
如果精确结果合理,而 ANN 结果缺失,则再检查:
- HNSW 的搜索参数;
- IVF 搜索的分区数量;
- PQ 压缩误差;
- 索引是否覆盖最新数据;
- 过滤是否在 ANN 阶段生效;
- 查询是否遇到了数据分布变化。
2. 检查距离数值和排序方向
常见错误包括:
把余弦相似度按升序排序
把余弦距离按降序排序
把 pgvector 的负内积当成正内积
把不同距离的数值阈值直接比较
例如 pgvector 中:
ORDER BY embedding <=> $1
是取余弦距离最小的结果;而 <#> 是取负内积最小的结果,也就是实际内积最大的结果。
3. 检查过滤后的候选数量
如果不加过滤能返回 10 条,加上租户或时间条件后只能返回 1 条,应区分:
- 过滤集合本身是否少于 10 条;
- ANN 是否只生成了很小的候选集;
- 系统是否采用后过滤;
- 是否启用了过滤感知或迭代候选扩展;
- 过滤条件是否使用了错误字段或错误类型。
不能简单地把 LIMIT 10 改成 LIMIT 100,然后认为结果已经正确。扩大候选数只是补救策略,只有在实际验证中确认候选覆盖率足够时才成立。
4. 检查可见时间而非只看写入返回值
新写入或删除结果异常时,应记录:
写入请求 ID
主键
版本号
提交时间
查询时间
一致性级别
客户端连接或会话标识
Milvus 等分布式系统还应检查查询所使用的时间戳和副本状态;PostgreSQL 则应检查事务是否提交、查询是否处于旧快照以及应用是否读取了缓存。
九、几个容易混淆的结论
“向量越近,语义一定越相似”
不成立。距离只是在指定 Embedding 空间中的几何关系。模型没有学到的语义,数据库无法凭距离补出来。
“余弦距离和 L2 距离总是等价”
不成立。只有向量都归一化时,二者才产生相同排序。
“提高召回率能解决过滤结果错误”
不一定。过滤发生在 ANN 之后时,即使提高搜索范围,也可能仍然无法得到过滤集合内的真实 Top-。应先确认过滤语义和执行阶段。
“写入成功后立即查询一定能看到”
取决于系统和一致性配置。PostgreSQL 的事务提交、Milvus 的一致性级别、查询副本追赶以及应用缓存都可能影响可见性。
“召回率高就代表回答质量高”
不成立。RAG 中还要考虑:
- 文本分块是否完整;
- 召回内容是否包含正确证据;
- 过滤是否满足权限;
- 重排模型是否正确;
- 最终生成是否引用了实际证据。
向量数据库负责在定义好的向量空间和候选约束下检索,不负责保证整个问答链路的事实正确性。
向量检索的基础可以归纳为一个严格的顺序:
确定对象和分块方式
↓
使用一致的 Embedding 模型
↓
选择与模型目标匹配的距离度量
↓
先定义过滤后的候选集合
↓
用精确搜索建立基线
↓
用 ANN 在延迟、内存和召回率之间取舍
↓
明确写入、更新、删除的可见性和版本规则
只要这条链路中任意一层没有明确,最终的“相似搜索结果”就很难解释,也很难稳定运维。
系列导航与关联阅读
- 系列入口:数据库完整学习路线:从关系模型、事务索引到分布式与向量检索
- 上一篇:MariaDB Server:与 MySQL 的差异、存储引擎、复制和迁移边界
- 下一篇:向量索引原理:Flat、HNSW、IVF、PQ 的精度、内存和延迟
- 延伸:混合检索与 RAG 数据层:全文、向量、融合、重排和引用
官方资料
本文依据数据库官方文档重新梳理;正文、示例与生产检查清单由 WR BLOG 编写。

评论
0 条讨论