向量数据库
本页介绍 LLM 应用生态的底层存储基础设施——向量数据库(Vector Database):专门存储和检索高维向量的数据库,是 RAG 检索增强生成的”图书馆”。它解决了传统关键词搜索无法理解语义的问题。
向量数据库 = RAG 的”图书馆”,存的是数学向量而不是文字,用”语义距离”而非”关键词匹配”来检索。
- 传统搜索(关键词匹配):搜”手机”时找不到写着”智能手机”或”mobile phone”的文档——因为字面不同。
- 向量搜索(语义匹配):先把每段文字变成一个数学向量(几百到几千维的浮点数数组),语义相近的文字向量也相近。搜”手机”时,“智能手机”的向量离得很近,自然被检索到——理解了意思,而不只是匹配字面。
核心工作流:文字 → 嵌入模型 → 向量 → 存入向量数据库 → 查询时用向量距离找最相似的。
为什么需要专门的向量数据库
Section titled “为什么需要专门的向量数据库”传统数据库(MySQL、PostgreSQL)擅长精确查找——“查找 user_id = 42 的用户”。但语义搜索需要的是相似性查找——“找和这段话意思最接近的 10 段文本”,这要求计算查询向量与数据库中每一个向量的距离。
在百万级甚至十亿级向量中做精确的逐一比较(brute-force)是不可行的:假设有 100 万个 1536 维向量(OpenAI 嵌入维度),每次查询需要 100 万次距离计算,每次涉及 1536 次乘加——即使在现代 CPU 上也需要数秒。向量数据库通过近似最近邻索引将这个时间压缩到毫秒级。
精确最近邻 vs 近似最近邻:精确方法(如 FLAT 索引)逐一比较所有向量,结果 100% 准确但速度慢;近似方法(如 HNSW、IVF)牺牲少量精度(通常 recall@10 > 95%)换取几个数量级的速度提升。实际应用中,ANN 的精度损失几乎不影响 RAG 效果。
嵌入向量(Embedding)是一个固定长度的浮点数数组,例如 [0.023, -0.145, 0.891, ..., 0.034]。这个数组由嵌入模型(如 OpenAI text-embedding-3-small)生成,把文本的语义信息”压缩”到高维空间中。
关键直觉:在这个高维空间中,语义相近的文本对应的空间位置也相近。例如:
- “猫在睡觉” 的向量 和 “小猫在打盹” 的向量 → 距离很近
- “猫在睡觉” 的向量 和 “股市今日大跌” 的向量 → 距离很远
这种”语义空间”的几何结构是嵌入模型在训练过程中自动学到的——它通过阅读海量文本,学会了把意思相近的句子映射到相近的坐标。
向量数据库支持多种距离度量(衡量两个向量”远近”的数学函数),选择哪种取决于嵌入模型的训练方式:
- 余弦相似度(Cosine Similarity):计算两个向量夹角的余弦值,范围 [-1, 1]。值越接近 1 表示方向越一致(语义越相似)。文本嵌入最常用,因为它只关注方向不关注长度,对文本长度变化更鲁棒。公式:
- 欧氏距离(L2 Distance):两点间的直线距离,值越小越相似。适用于图像嵌入等需要考虑向量”幅度”的场景。公式:
- 内积(Inner Product / Dot Product):当向量已做 L2 归一化(即长度归为 1)后,内积等价于余弦相似度,但计算更快(省去除法步骤)。很多向量数据库默认假设向量已归一化。
⚠️ 距离度量必须与嵌入模型匹配:OpenAI 嵌入模型推荐余弦相似度,部分图像模型推荐 L2 距离。用错度量会导致检索质量大幅下降。
ANN 索引算法详解
Section titled “ANN 索引算法详解”向量数据库的核心技术是近似最近邻(ANN, Approximate Nearest Neighbor)索引。主流 ANN 算法分为三大流派:
1. HNSW(分层可导航小世界图)
Section titled “1. HNSW(分层可导航小世界图)”HNSW(Hierarchical Navigable Small World)是目前最广泛使用的 ANN 索引算法,几乎所有主流向量数据库都支持。它的核心思想是构建一个多层的近邻图,通过”跳表式”搜索快速逼近目标向量。
直觉理解:想象你在地图上找一家餐厅。你会先看全国地图(最上层,只有少数大城市标记),定位到城市;再看城市地图(中间层,标记了街区),定位到街区;最后看街道地图(最底层,标记了每栋建筑),找到精确位置。HNSW 的多层图结构就是这个思路——上层稀疏(“长途跳转”),下层密集(“精确搜索”)。
算法要点:
- 多层图结构:每个向量是一个节点。最底层包含所有节点,上层逐层抽样保留少量节点(类似跳表 Skip List)。每个节点与其最近的若干邻居建立边。
- 搜索过程:从最顶层的某个入口节点开始,贪心地走向离查询向量最近的邻居;到顶层尽头后下降一层继续贪心搜索,直到到达最底层。在最底层做精细的邻居遍历,收集 Top-K 结果。
- 关键参数:
M(连接数):每个节点保留的邻居数,通常 16-48。M 越大,精度越高但内存越大。ef_construction(建图搜索宽度):建图时的候选列表大小,通常 200-500。越大建图越慢但质量越好。ef_search(查询搜索宽度):查询时的候选列表大小,通常 50-200。越大精度越高但查询越慢。
HNSW 的优缺点:
- ✅ 查询速度极快(通常 < 10ms / 百万级数据)
- ✅ 召回率高(recall@10 可达 99%+)
- ✅ 支持动态插入(无需重建索引)
- ❌ 内存占用大(需要存储图结构 + 原始向量)
- ❌ 不适合超大规模(10 亿+),因为内存是瓶颈
2. IVF(倒排文件索引)
Section titled “2. IVF(倒排文件索引)”IVF(Inverted File Index)采用先聚类再搜索的策略:
- 训练阶段:用 k-means 聚类将向量空间划分为
nlist个簇(cluster),每个簇有一个中心点(centroid)。 - 分配阶段:将每个向量分配到最近的簇,形成倒排表(inverted list)——每个簇维护一个向量列表。
- 查询阶段:先计算查询向量与所有
nlist个中心的距离,选出最近的nprobe个簇,然后只在这些簇内做精确搜索。
直觉理解:像图书馆按主题分区——查”机器学习”相关的书时,不需要翻遍整个图书馆,只需去”计算机科学”区域找。
关键参数:
nlist(簇数):通常设为 到 (N 为向量数量)。簇越多,每簇数据越少但中心搜索开销越大。nprobe(探测簇数):查询时搜索的簇数。nprobe 越大精度越高但越慢。通常从nlist / 100开始调参。
IVF + PQ 组合:IVF 常与 PQ(Product Quantization,乘积量化)组合使用——先用 IVF 缩小搜索范围,再用 PQ 压缩向量降低内存。这是 FAISS 的经典方案,适合十亿级超大规模数据。
3. 量化压缩(PQ 与 SQ)
Section titled “3. 量化压缩(PQ 与 SQ)”当向量数量达到千万级以上时,内存成为瓶颈。量化技术(Quantization)通过压缩向量来降低内存占用:
- 乘积量化(PQ, Product Quantization):将高维向量切分成若干子段,每段独立做 k-means 聚类(通常 256 个簇),用簇 ID(1 字节)替代原始浮点数。例如 1536 维向量切分为 8 段,每段 192 维,压缩后只需 8 字节(原始 6144 字节的 0.13%)。精度有损但内存节省巨大。
- 标量量化(SQ, Scalar Quantization):将 32 位浮点数量化为 8 位整数,直接节省 4 倍内存,精度损失极小。更简单实用,2024 年后被越来越多数据库采用。
- 二值量化(Binary Quantization):将每个维度的值量化为 1 bit(正数为 1,负数为 0),压缩 32 倍。Milvus 和 Qdrant 在 2024 年都加入了此功能。配合高效的位运算(Hamming 距离),查询速度极快,适合超大规模初筛。
索引算法对比
Section titled “索引算法对比”| 特性 | HNSW | IVF | IVF+PQ |
|---|---|---|---|
| 查询速度 | 极快 | 快 | 快 |
| 召回率 | 极高(99%+) | 高(95%+) | 中(90%+) |
| 内存占用 | 大 | 中 | 小 |
| 构建速度 | 慢 | 中 | 中 |
| 动态更新 | 支持 | 支持 | 需重建 |
| 最佳场景 | 百万-千万级 | 千万-亿级 | 十亿级 |
混合检索(Hybrid Search)
Section titled “混合检索(Hybrid Search)”纯向量搜索并非万能——它擅长语义匹配,但在精确术语、人名、编号等场景下不如关键词搜索。例如搜”GPT-4o-mini”时,向量搜索可能返回 “GPT-4” 或 “GPT-3.5” 的内容(语义相近),而关键词搜索能精确匹配这个型号。
混合检索 = 关键词搜索 + 向量搜索的融合,是 2024-2025 年 RAG 系统的标准实践:
融合方法:
- RRF(Reciprocal Rank Fusion,倒数排名融合):对每个文档,在两个检索结果中的排名取倒数求和。公式:,其中 通常取 60。RRF 的优势是无需归一化分数,对不同检索器的分数尺度不敏感。
- 加权平均:对向量相似度和关键词匹配分数做加权平均(如
0.7 × 向量分数 + 0.3 × BM25 分数),权重需调参。
BM25(Best Matching 25):经典的关键词检索算法,基于词频(TF)和逆文档频率(IDF),是 Elasticsearch、Lucene 等搜索引擎的核心。它比纯 LIKE 查询更智能——常见词权重低、罕见词权重高。
实践建议:2025 年的最佳实践是”混合检索 + 重排序”(Hybrid Search + Reranking)。先用混合检索召回 Top-50 候选,再用 Cross-Encoder 重排序模型(如
bge-reranker-v2-m3)精排出 Top-5 喂给 LLM。详见 RAG 检索增强生成。
过滤检索(Filtered Search)
Section titled “过滤检索(Filtered Search)”实际应用中,纯语义搜索往往不够——用户可能只想搜”2024 年的文档”或”技术部的知识库”。向量数据库支持在向量检索的基础上叠加元数据过滤:
# Qdrant 示例:只在过去一年的技术文档中搜索results = client.query_points( collection_name="docs", query=query_vector, query_filter={ "must": [ {"key": "year", "range": {"gte": 2024}}, {"key": "department", "match": {"value": "技术"}}, ] }, limit=5,)过滤的实现策略有两种,各有优劣:
- Pre-filtering(先过滤后搜索):先按元数据筛出候选集,再在候选集中做向量搜索。过滤性强时效率高,但如果过滤后候选集太小,可能找不到足够的相似向量。
- Post-filtering(先搜索后过滤):先做向量搜索取 Top-K,再按元数据过滤。可能过滤后结果不足 K 个,需要过度召回。
- Native filtering(原生前置过滤):Qdrant 等数据库在 HNSW 图遍历时直接跳过不满足条件的节点,效率最高但实现复杂。
关键词搜索 vs 向量语义搜索
Section titled “关键词搜索 vs 向量语义搜索”向量数据库在 RAG 中的位置
Section titled “向量数据库在 RAG 中的位置”HNSW 多层图搜索示意
Section titled “HNSW 多层图搜索示意”向量数据库的核心技术是近似最近邻(ANN)索引:百万级向量里精确计算每个距离太慢,ANN 算法(HNSW、IVF 等)用空间换时间,在”几乎不影响精度”的前提下把检索速度提升几个数量级。
用 ChromaDB 实现文本存储与语义检索
Section titled “用 ChromaDB 实现文本存储与语义检索”import chromadb
# 1. 创建内存向量库client = chromadb.Client()collection = client.create_collection("docs")
# 2. 存入文档(ChromaDB 内置嵌入模型,自动转向量)collection.add( ids=["1", "2", "3"], documents=[ "Python 是最流行的数据科学编程语言。", "机器学习需要大量标注数据来训练模型。", "今天天气很好适合户外运动。", ],)
# 3. 语义检索:找和"深度学习用什么语言"最相关的段落results = collection.query( query_texts=["深度学习用什么编程语言?"], n_results=2, # Top-2)for doc, dist in zip(results["documents"][0], results["distances"][0]): print(f"[距离 {dist:.3f}] {doc}")# 输出: Python 是最流行的数据科学编程语言。(距离最近)用 Qdrant 实现带元数据过滤的混合检索
Section titled “用 Qdrant 实现带元数据过滤的混合检索”from qdrant_client import QdrantClientfrom qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue
client = QdrantClient(":memory:") # 内存模式,生产环境用 QdrantClient(host="localhost", port=6333)
# 1. 创建 Collection,指定向量维度和距离度量client.create_collection( "knowledge_base", vectors_config=VectorParams(size=4, distance=Distance.COSINE),)
# 2. 插入向量(附带元数据 payload)client.upsert( "knowledge_base", points=[ PointStruct(id=1, vector=[0.1, 0.2, 0.3, 0.4], payload={"category": "tech", "year": 2024}), PointStruct(id=2, vector=[0.15, 0.25, 0.35, 0.45], payload={"category": "tech", "year": 2023}), PointStruct(id=3, vector=[0.9, 0.8, 0.7, 0.6], payload={"category": "sports", "year": 2024}), ],)
# 3. 带过滤条件的向量搜索:只在 2024 年的 tech 类文档中搜results = client.query_points( "knowledge_base", query=[0.1, 0.2, 0.3, 0.4], query_filter=Filter( must=[ FieldCondition(key="category", match=MatchValue(value="tech")), FieldCondition(key="year", match=MatchValue(value=2024)), ] ), limit=5,)for point in results.points: print(f"ID={point.id}, score={point.score:.3f}, payload={point.payload}")用 pgvector 在 PostgreSQL 中做向量检索
Section titled “用 pgvector 在 PostgreSQL 中做向量检索”pgvector 的优势是不需要额外部署向量数据库——直接在现有的 PostgreSQL 上安装扩展即可:
-- 1. 安装扩展CREATE EXTENSION vector;
-- 2. 创建带向量列的表CREATE TABLE documents ( id SERIAL PRIMARY KEY, content TEXT, category TEXT, embedding VECTOR(1536) -- OpenAI text-embedding-3-small 维度);
-- 3. 创建 HNSW 索引CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);
-- 4. 插入数据(embedding 由应用层生成后传入)INSERT INTO documents (content, category, embedding)VALUES ('Python 是数据科学的首选语言', 'tech', '[0.1, 0.2, ...]');
-- 5. 语义搜索 + 元数据过滤,一条 SQL 搞定SELECT content, 1 - (embedding <=> '[0.15, 0.25, ...]') AS similarityFROM documentsWHERE category = 'tech'ORDER BY embedding <=> '[0.15, 0.25, ...]' -- <=> 是余弦距离操作符LIMIT 10;pgvector 0.7+(2024 年发布)支持 HNSW 索引和半精度浮点存储,性能已接近专用向量数据库。对于中小规模数据(< 1000 万向量),“PostgreSQL + pgvector” 是性价比最高的选择。
用 FAISS 构建高性能单机向量检索
Section titled “用 FAISS 构建高性能单机向量检索”import faissimport numpy as np
# 生成模拟数据:100 万个 768 维向量dimension = 768n_vectors = 1_000_000vectors = np.random.random((n_vectors, dimension)).astype('float32')faiss.normalize_L2(vectors) # L2 归一化,使内积 = 余弦相似度
# 方案一:HNSW 索引(高精度,内存大)index = faiss.IndexHNSWFlat(dimension, 32) # M=32index.hnsw.efConstruction = 200index.hnsw.efSearch = 64index.add(vectors)
# 方案二:IVF + PQ 索引(省内存,适合超大规模)quantizer = faiss.IndexFlatIP(dimension)index_ivf = faiss.IndexIVFPQ(quantizer, dimension, nlist=4096, m=64, nbits=8)index_ivf.train(vectors)index_ivf.add(vectors)index_ivf.nprobe = 64 # 查询时探测 64 个簇
# 查询query = np.random.random((1, dimension)).astype('float32')faiss.normalize_L2(query)distances, indices = index.search(query, k=10)print(f"Top-10 索引: {indices[0]}")print(f"相似度分数: {distances[0]}")- 选择合适的距离度量:文本嵌入用余弦相似度(或归一化后的内积),图像嵌入用 L2 距离。度量选错会严重拖垮检索质量。务必查看嵌入模型的文档确认推荐度量。
- HNSW 是默认首选:如果你不确定用哪种索引,就用 HNSW。它在大多数场景下提供了最佳的精度-速度平衡。只有当数据量超过内存容量时,才考虑 IVF+PQ。
- 批量插入而非逐条插入:向量数据库的索引构建有批量优化。逐条插入数万条数据可能比批量插入慢 10 倍以上。建议每批 1000-10000 条。
- 嵌入向量要归一化:使用余弦相似度时,确保向量已 L2 归一化。很多嵌入模型(如 OpenAI
text-embedding-3)默认输出已归一化的向量,但开源模型不一定。 - 注意嵌入维度与成本:嵌入维度越高,存储和检索开销越大。OpenAI
text-embedding-3-large支持”降维”参数(如从 3072 维降到 256 维),在精度损失可控的前提下大幅降低成本。 - 合理设置 Top-K:RAG 场景通常召回 Top-5 到 Top-20 喂给 LLM。K 太大会引入噪声(降低回答质量),K 太小可能漏掉相关信息。配合重排序模型时可以先召回 Top-50 再精排。
- 评估检索质量用 Recall@K:不要只看速度。构建一个标注好的问答测试集,测量”正确答案在 Top-K 结果中的比例”(Recall@K),这是检索系统最核心的指标。
- 监控索引碎片化:频繁的插入和删除会导致 HNSW 图碎片化,查询性能逐渐下降。定期重建索引或使用支持自动合并的数据库(如 Qdrant)。
- 考虑多租户隔离:SaaS 场景下不同用户的数据应隔离。大多数向量数据库支持 Collection 级别或 Payload 过滤级别的隔离。Collection 级隔离更安全但管理开销大。
- RAG 知识库:企业文档、FAQ、手册全部嵌入向量库,用户提问时秒级检索相关段落喂给 LLM——所有 RAG 产品的存储底座。详见 RAG 检索增强生成。
- 推荐系统:把用户和商品都表示为向量,找”最相似的商品”推荐——向量检索是现代推荐引擎的核心组件。
- 图片语义搜索:用 CLIP 模型(OpenAI 的多模态嵌入模型,能同时编码图像和文本)把图片编码为向量,“以图搜图”或”以文搜图”——Pinterest、电商平台的相似商品推荐都基于此。
- 去重与相似度检测:在海量文本/代码中找出语义重复或高度相似的内容——论文查重、代码抄袭检测、新闻聚类。
- AI Agent 的长期记忆:Agent 将历史交互存为向量,后续从过往经验中检索相关案例——这是 Agent 记忆系统的主流实现方案。详见AI Agent 与多智能体。
- 多模态 RAG:文本、图片、音频、视频统一嵌入到同一向量空间,用户可以用文字搜图片、用图片搜文档——跨模态检索是 2024-2025 年的热门方向。
典型类库与工具
Section titled “典型类库与工具”| 类库 | 语言 | 说明 |
|---|---|---|
| ChromaDB | Python | 轻量开源向量数据库,开发原型首选,内置嵌入模型 |
| Pinecone | SaaS | 托管型向量数据库,生产级规模与低延迟,免运维 |
| Weaviate | Go / Python | 开源向量搜索引擎,支持混合检索(关键词 + 向量)和模块化嵌入 |
| Milvus | Go / Python | 开源分布式向量数据库,支持十亿级向量,多种索引类型 |
| Qdrant | Rust | 高性能开源向量数据库,Rust 编写,过滤能力强,支持 Binary Quantization |
| FAISS | Python / C++ | Meta 开源的高效向量检索库,单机性能标杆,无服务端,适合算法研究 |
| pgvector | SQL | PostgreSQL 向量扩展插件,在已有数据库上加向量检索,0.7+ 支持 HNSW |
| LanceDB | Python / Rust | 基于 Lance 列式存储格式的嵌入式向量数据库,适合多模态数据 |
| Vespa | Java | 开源搜索与推荐引擎,支持向量检索 + 排序 + 实时更新,适合复杂搜索场景 |
| 术语 | 英文 | 解释 |
|---|---|---|
| 向量嵌入 | Embedding | 把文本/图像转换为固定长度的数值向量,语义相近则向量相近 |
| 余弦相似度 | Cosine Similarity | 衡量两个向量方向一致性的指标,值越接近 1 越相似 |
| 欧氏距离 | Euclidean Distance (L2) | 两点之间的直线距离,值越小越相似 |
| 近似最近邻 | ANN (Approximate Nearest Neighbor) | 牺牲少量精度换取大幅加速的向量检索算法 |
| HNSW 索引 | HNSW (Hierarchical Navigable Small World) | 基于分层图的高效 ANN 索引,查询速度与精度的主流选择 |
| 倒排文件索引 | IVF (Inverted File Index) | 先聚类再在簇内搜索的 ANN 方法,适合超大规模数据 |
| 乘积量化 | PQ (Product Quantization) | 将向量切分为子段独立压缩,大幅节省内存的量化技术 |
| 标量量化 | SQ (Scalar Quantization) | 将 32 位浮点数量化为 8 位整数,节省 4 倍内存,精度损失极小 |
| 二值量化 | Binary Quantization | 将每个维度量化为 1 bit,压缩 32 倍,配合 Hamming 距离极速查询 |
| 混合检索 | Hybrid Search | 关键词检索与向量检索的融合,兼顾精确匹配与语义理解 |
| 倒数排名融合 | RRF (Reciprocal Rank Fusion) | 将多个检索结果列表按排名倒数融合的经典算法 |
| BM25 | BM25 (Best Matching 25) | 基于词频和逆文档频率的经典关键词检索算法 |
| 维度 | Dimension | 向量的长度,嵌入模型通常输出 768-3072 维 |
| 召回率 | Recall@K | 衡量检索质量的指标:正确答案出现在 Top-K 结果中的比例 |
- FAISS:Johnson et al., “Billion-scale similarity search with GPUs”(2017),Meta 开源的高效向量检索库,单机/单 GPU 上性能标杆。
- HNSW:Malkov & Yashunin, “Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs”(2018/2020),现代向量数据库最广泛采用的索引算法,论文详细描述了多层图的构建和搜索策略。
- Product Quantization:Jégou et al., “Product quantization for nearest neighbor search”(IEEE TPAMI 2011),PQ 量化的奠基论文,解释了如何通过子空间分解实现高压缩比。
- 向量数据库综述:Pan et al., “Survey of Vector Database Management Systems”(2024),系统对比 ChromaDB / Pinecone / Milvus / Weaviate / Qdrant 等主流方案的功能和性能。
- 混合检索:Cormack et al., “Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods”(SIGIR 2009),RRF 算法的原始论文,证明了简单的排名融合优于复杂的机器学习方法。
- pgvector:Greenplum/pgvector 仓库,2024 年 0.7 版本引入 HNSW 索引和半精度浮点支持,使 PostgreSQL 成为中小规模向量检索的实用选择。
- FAISS 教程:Meta AI Research 维护的 FAISS Wiki,包含从入门到十亿级索引的完整教程和性能调优指南。