本文是「从零搭建私人 RAG 知识库」专栏的基础篇。我们先理解 Vector Store 解决什么问题、它如何完成语义检索,再认识目前常见的向量数据库,为后续使用 LanceDB 做准备。
前言
假设知识库中保存了下面三句话:
text
登录状态保存在 Redis 中。
订单支付成功后会发送通知。
系统使用 Docker 容器部署。
用户搜索:
text
用户会话存在哪里?
原文没有出现"用户会话"这个词,但"用户会话"和"登录状态"的语义比较接近。传统关键词搜索可能无法直接命中,向量检索却有机会找到第一句话。
这正是 Vector Store 最核心的作用:
保存文本对应的语义向量,并找出与用户问题最相近的内容。
一、从 Vector 开始理解
Vector 中文叫"向量"。在程序中,可以先把它理解为一组按照固定顺序排列的数字:
text
[0.12, -0.37, 0.88, ..., 0.24]
在 RAG 中,我们通常使用 Embedding 模型把文本转换成向量:
text
"用户会话存在哪里?"
↓ Embedding
[0.12, -0.37, 0.88, ..., 0.24]
这组数字不是文本的加密结果,也不是人工定义的标签。它可以理解为文本在某个语义空间中的坐标。
Embedding 模型会尽量让含义相近的文本彼此靠近,例如:
text
"用户会话存在哪里?"
"登录状态保存在 Redis 中。"
同时让含义差异较大的文本彼此远离,例如:
text
"用户会话存在哪里?"
"系统使用 Docker 容器部署。"
因此,即使问题和原文没有使用相同关键词,也可以通过向量之间的距离判断它们是否相关。
向量维度是什么
一个向量包含多少个数字,就称为多少维向量。例如:
text
[0.2, 0.5, -0.1]
它是一个三维向量。实际 Embedding 模型生成的向量通常有数百或数千维,具体维度由模型决定。
同一个向量字段中的数据必须具有相同维度。更换 Embedding 模型后,向量维度或语义空间可能发生变化,因此通常需要重新生成全部文档向量。
二、什么是 Vector Store
Vector Store 可以翻译为"向量存储"。它通常负责以下工作:
- 保存 Embedding 模型生成的向量;
- 保存向量对应的原始文本;
- 保存来源、分类和权限等元数据;
- 建立向量索引;
- 查找与查询向量最接近的记录。
一条记录通常类似下面这样:
json
{
"text": "登录状态保存在 Redis 中。",
"vector": [0.12, -0.37, 0.88],
"metadata": {
"source": "auth.md",
"docType": "FADR"
}
}
其中:
text是最终返回给用户或大模型的正文;vector用于计算语义相似度;metadata用于展示来源、分类和过滤结果。
Vector Store 和 Embedding 的分工
这两个概念很容易混淆,可以用一句话区分:
text
Embedding:把文本转换成语义向量
Vector Store:保存向量并查找相近向量
Vector Store 本身不会直接理解自然语言。真正把文本编码成向量的是 Embedding 模型。
三、Vector Store 和向量数据库有什么区别
"Vector Store"和"向量数据库"经常被混用,但二者的关注点略有不同:
- 向量数据库更强调底层的数据存储、索引、查询、扩展和运维能力;
- Vector Store更强调应用层统一的向量写入和检索接口。
例如,在 LangChain 中,VectorStore 是一种统一抽象。应用可以通过相似的接口操作 LanceDB、Pinecone、Milvus 等不同数据库。
在初学阶段,可以先把二者统一理解为:
用于保存向量,并执行相似度检索的组件。
四、它和传统数据库有什么不同
传统数据库擅长处理明确条件。
例如,关系型数据库可以查询来源为 auth.md 的记录:
sql
SELECT * FROM documents WHERE source = 'auth.md';
关键词搜索擅长查找包含指定词语的内容:
text
查找包含"Redis"的文档
向量数据库解决的问题则是:
text
哪些内容与"用户会话存在哪里"在语义上最接近?
三种查询方式各有用途:
| 查询方式 | 适合的问题 | 示例 |
|---|---|---|
| 结构化查询 | 条件明确、字段固定 | 查询 docType = FADR 的记录 |
| 关键词搜索 | 需要精确匹配词语 | 查找包含"Redis"的文档 |
| 向量检索 | 表达不同但语义相近 | "用户会话"匹配"登录状态" |
向量检索并不是传统数据库的替代品。真实系统经常把向量检索与关键词搜索、元数据过滤结合起来,形成混合检索。
五、相似度检索如何工作
向量检索通常分为写入和查询两个阶段。
1. 写入阶段
text
原始文档
↓
文本分块
↓
Embedding 模型生成文档向量
↓
正文、向量和元数据写入 Vector Store
2. 查询阶段
text
用户问题
↓
同一个 Embedding 模型生成查询向量
↓
Vector Store 比较查询向量与文档向量
↓
按照相似程度排序
↓
返回 Top-K 条结果
这里有一条重要规则:
写入文档和查询问题必须使用同一个 Embedding 模型及兼容配置。
不同模型使用的语义空间可能不同。即使两个模型生成的向量维度相同,也不能说明它们的向量可以直接比较。
常见的距离度量
向量之间是否接近,需要通过距离或相似度进行计算。常见方式包括:
- 余弦相似度:关注两个向量的方向是否一致;
- 欧氏距离:计算两个点之间的直线距离;
- 点积:计算两个向量对应位置乘积之和。
实际开发时,应优先采用 Embedding 模型和向量数据库推荐的度量方式,而不是自行猜测。
什么是 Top-K
Top-K 表示一次查询最多返回多少条结果。
text
Top-1:返回最相关的一条
Top-3:返回最相关的三条
Top-10:返回最相关的十条
K 太小可能漏掉有用内容,K 太大则可能引入噪声,并占用更多大模型上下文。
六、为什么需要专门的向量索引
如果数据库中只有几十条记录,可以逐条比较查询向量和文档向量。但当数据量增长到几十万甚至更多时,全量比较的成本会越来越高。
向量数据库通常会使用近似最近邻搜索,也就是 ANN(Approximate Nearest Neighbor),在检索速度、内存占用和召回率之间取得平衡。
常见的索引思路包括:
- HNSW:构建多层图结构,沿着邻近节点快速寻找结果;
- IVF:先把向量划分到不同区域,再在可能相关的区域中搜索;
- PQ:对向量进行压缩,降低存储和计算成本。
初学时不需要立即掌握算法细节。先记住:
向量索引的目标,是避免每次查询都与全部向量逐一比较。
不同数据库支持的索引类型和默认策略并不相同,选型和调优时应参考对应版本的官方文档。
七、目前常见的向量数据库
向量数据库没有绝对的"最好",不同产品面向的场景并不相同。下面列出 RAG 项目中经常见到的选择。
1. Pinecone
Pinecone 是托管式向量数据库。使用者主要通过云服务和 API 管理向量数据,不需要自行部署数据库集群。
适合:
- 希望减少数据库运维工作;
- 需要快速上线云端应用;
- 可以接受托管服务成本和数据上云。
需要考虑:网络依赖、服务费用、数据合规以及平台绑定。
2. Milvus
Milvus 是面向大规模向量检索的开源向量数据库,具有分布式部署和多种索引能力。其生态中也常见轻量级或托管形态。
适合:
- 数据规模较大;
- 需要分布式扩展;
- 团队具备相应的部署和运维能力。
对于小型本地 Demo,完整的分布式方案可能偏重。
3. Weaviate
Weaviate 是开源向量数据库,提供向量检索、关键词检索、过滤和模块化集成能力。
适合:
- 希望组合语义检索与关键词检索;
- 需要较完整的服务端能力;
- 希望通过 API 使用数据库。
使用前需要评估部署方式、资源占用和模块配置。
4. Qdrant
Qdrant 使用 Rust 开发,重点提供向量检索和较强的元数据过滤能力,同时提供开源部署与云服务。
适合:
- 检索时需要复杂的条件过滤;
- 希望自行部署独立服务;
- 关注性能和 API 使用体验。
它通常以独立服务运行,相比嵌入式数据库会多一层部署工作。
5. Chroma
Chroma 是面向 AI 应用的开源向量数据库,API 简单,常用于原型、教程和本地实验。
适合:
- 快速验证 RAG 想法;
- 数据量较小;
- 希望用较少代码完成本地检索。
进入生产环境前,需要根据实际数据规模、并发和部署要求进一步评估。
6. LanceDB
LanceDB 基于 Lance 列式数据格式,可以作为嵌入式数据库直接读写本地目录,也提供其他部署形态。它对 Python、TypeScript 等开发环境较友好。
适合:
- 本地知识库和个人项目;
- 希望数据库随应用一起运行;
- 不想额外部署独立数据库服务;
- 需要保存向量、正文和结构化元数据。
CorpRAG 当前使用的就是 LanceDB。下一篇文章会用最小 TypeScript 示例完成文档写入和语义检索。
7. pgvector
pgvector 是 PostgreSQL 的向量扩展,让现有 PostgreSQL 数据库可以保存向量并执行相似度搜索。
适合:
- 项目已经大量使用 PostgreSQL;
- 向量数据需要和业务表关联;
- 希望继续使用 SQL、事务和现有运维体系。
当向量规模或检索要求继续增长时,需要结合 PostgreSQL 配置、索引和实际负载进行测试。
八、如何选择
可以先从部署方式、数据规模、过滤需求和现有技术栈四个方面判断。
| 产品 | 常见使用形态 | 主要特点 | 更适合的起点 |
|---|---|---|---|
| Pinecone | 托管云服务 | 免运维、API 化 | 快速上线云端应用 |
| Milvus | 自建或托管 | 分布式、大规模检索 | 大数据量与集群场景 |
| Weaviate | 自建或托管 | 向量、关键词与过滤能力 | 完整的检索服务 |
| Qdrant | 自建或托管 | 性能与元数据过滤 | 独立向量检索服务 |
| Chroma | 本地或服务模式 | 简单、开发友好 | 原型和教学实验 |
| LanceDB | 嵌入式或服务形态 | 本地运行、开发集成简单 | 个人知识库与本地应用 |
| pgvector | PostgreSQL 扩展 | 与关系型数据结合 | 已使用 PostgreSQL 的项目 |
可以使用下面的简化思路:
text
只想快速学习和本地实验
→ Chroma 或 LanceDB
项目已有 PostgreSQL
→ 先评估 pgvector
需要独立服务和较强元数据过滤
→ 评估 Qdrant 或 Weaviate
需要大规模分布式检索
→ 评估 Milvus
希望尽量减少运维
→ 评估 Pinecone 等托管服务
这只是初步筛选,不是固定答案。正式选型前还应使用真实数据测试:
- 检索准确率和召回率;
- 写入与查询延迟;
- 数据规模和并发量;
- 元数据过滤能力;
- 备份、权限和高可用;
- 部署、运维和服务成本;
- SDK 与现有技术栈的兼容性。
九、Vector Store 在 RAG 中的位置
Vector Store 是 RAG 的检索组件,不负责生成最终答案。
text
用户问题
↓
Embedding 生成查询向量
↓
Vector Store 检索相关片段
↓
把问题和相关片段交给大模型
↓
大模型组织最终答案
三类组件的分工是:
- Embedding 模型负责把文字转换成向量;
- Vector Store 负责找到相关资料;
- 大模型负责根据资料组织答案。
因此,Vector Store 返回的结果最相似,并不等于最终答案一定正确。检索效果还会受到文档质量、分块方式、Embedding 模型、查询表达和 Top-K 等因素影响。
总结
本文需要记住的核心结论有:
- Vector 是文本在语义空间中的数字表示;
- Embedding 模型负责把文本转换成向量;
- Vector Store 负责保存正文、向量和元数据,并执行相似度检索;
- 写入和查询必须使用同一个 Embedding 模型及兼容配置;
- 向量检索与结构化查询、关键词搜索各有用途,也可以组合使用;
- 不同向量数据库面向的部署方式和数据规模不同,选型要从实际需求出发。
最后用一句话概括:
Embedding 把文字转换成语义坐标,Vector Store 保存这些坐标,并找到距离用户问题最近的内容。
下一篇文章将使用 TypeScript、Ollama、LangChain.js 和 LanceDB,完成一个可以直接运行的最小向量检索示例。