Embedding 与向量数据库
AI 技术 ⭐⭐ 中级 🔥🔥 中频
💡 核心要点
Embedding(嵌入)是将文本、图像等非结构化数据映射到稠密向量空间的技术,使得语义相近的内容在向量空间中距离更近。向量数据库则是专门用于高效存储和检索这些高维向量的基础设施。二者共同构成了 RAG、语义搜索、推荐系统等现代 AI 应用的底层支撑。
什么是 Embedding
从离散到连续
传统文本表示(如 One-Hot 编码)将每个词映射为一个高维稀疏向量,无法捕获词与词之间的语义关系。Embedding 则将文本映射到低维稠密向量空间,使得:
- 语义相近的文本在向量空间中距离更近
- 语义无关的文本在向量空间中距离更远
传统表示 (One-Hot):
"猫" = [1, 0, 0, 0, 0, ...] 维度 = 词表大小(数万)
"狗" = [0, 1, 0, 0, 0, ...] 无法反映"猫"和"狗"的语义相近
Embedding 表示:
"猫" = [0.21, -0.35, 0.68, ...] 维度 = 768~3072
"狗" = [0.23, -0.31, 0.65, ...] 向量相近 → 语义相近
"汽车" = [-0.45, 0.82, -0.12, ...] 向量远离 → 语义不同发展历程
| 阶段 | 方法 | 特点 |
|---|---|---|
| 2013 | Word2Vec(CBOW / Skip-gram) | 首次将词映射到稠密向量,发现向量算术(king - man + woman ≈ queen) |
| 2014 | GloVe | 基于全局词共现统计训练词向量 |
| 2018 | ELMo / BERT | 上下文相关的动态 Embedding,同一个词在不同语境中有不同向量 |
| 2022 | 专用 Embedding 模型 | 针对检索优化的 Embedding(对比学习训练),如 E5、BGE |
| 2024-2025 | 多模态与任务自适应 Embedding | Matryoshka 表示学习(灵活维度)、任务特定 LoRA 适配器(Jina v3)、多模态 Embedding(Cohere embed-v4 支持图文混合)、开源模型在 MTEB 榜单上全面追平甚至超越闭源 API(NV-Embed-v2、BGE-en-icl) |
在 Word2Vec 时代,每个词有一个固定的向量。现代 Embedding 模型基于 Transformer 编码器,生成的是上下文相关的句子/段落级 Embedding。2024 年以来,Embedding 领域的关键趋势包括:支持灵活维度截断(Matryoshka Representation Learning,OpenAI text-embedding-3 系列率先采用)、任务自适应(通过 LoRA 适配器针对检索/分类/聚类等不同任务优化)、以及多模态嵌入(将文本和图像映射到同一向量空间)。
Embedding 模型原理
编码器架构
现代 Embedding 模型通常基于 BERT 类编码器架构,通过双向注意力机制理解完整上下文:
Text --> Tokenizer --> Transformer Encoder --> Pooling --> Embedding Vector
[0.12, -0.34, ...]训练方法:对比学习
现代 Embedding 模型主要通过**对比学习(Contrastive Learning)**训练:
其中 是查询, 是正样本(相关文档), 是负样本(不相关文档), 是温度参数。
核心思想:拉近查询与相关文档的距离,推远查询与不相关文档的距离。
负样本挖掘策略
对比学习的效果高度依赖负样本的质量:
| 策略 | 说明 | 效果 |
|---|---|---|
| 随机负样本 | 从语料库随机采样 | 简单但效果有限 |
| 批内负样本 | 同一批次中其他样本的正样本作为负样本 | 高效,广泛使用 |
| 困难负样本 | 用 BM25 或初步模型检索出的"似是而非"的文档 | 显著提升模型区分能力 |
相似度度量
将文本转为 Embedding 后,需要定义"距离"来衡量两个向量的相似程度。
余弦相似度(Cosine Similarity)
- 范围:,值越大越相似
- 忽略向量的长度,只关注方向
- 最常用的相似度度量
欧氏距离(Euclidean Distance)
- 范围:,值越小越相似
- 受向量长度影响
- 适合已归一化的向量
点积(Dot Product / Inner Product)
- 范围:,值越大越相似
- 同时考虑方向和长度
- 当向量已归一化时,等价于余弦相似度
如何选择
| 场景 | 推荐度量 | 原因 |
|---|---|---|
| 通用语义搜索 | 余弦相似度 | 对向量长度不敏感,跨文档稳定 |
| 已归一化的向量 | 点积 | 计算更快,结果等价余弦 |
| 需要考虑"重要性"差异 | 点积 | 向量模长可编码重要性信息 |
主流 Embedding 模型
| 模型 | 开发者 | 维度 | 最大长度 | 特点 |
|---|---|---|---|---|
| text-embedding-3-large | OpenAI | 3072 | 8191 Token | 英文综合性能优异,支持 Matryoshka 维度截断 |
| text-embedding-3-small | OpenAI | 1536 | 8191 Token | 性价比高,支持 Matryoshka 维度截断 |
| Cohere embed-v4 | Cohere | 1024 | 128K Token | 多模态(文本+图像),支持压缩和搜索类型 |
| Voyage-3 | Voyage AI | 1024 | 32K Token | 检索性能顶尖,代码与法律领域表现突出 |
| Voyage-3-lite | Voyage AI | 512 | 32K Token | 轻量低延迟版本,适合对速度敏感的场景 |
| NV-Embed-v2 | NVIDIA | 4096 | 32K Token | MTEB 榜单领先的开源模型 |
| BGE-en-icl | BAAI(智源) | 4096 | 32K Token | 支持 In-Context Learning 示例提升检索效果 |
| BGE-M3 | BAAI(智源) | 1024 | 8192 Token | 最佳开源多语言模型,同时支持稠密、稀疏和 ColBERT 多粒度检索 |
| GTE-Qwen2 | 阿里云 | 1536-8192 | 128K Token | 长文本、中文表现优异,可选多种维度 |
| Jina Embeddings v3 | Jina AI | 1024 | 8192 Token | 内置任务特定 LoRA 适配器,多语言支持 |
选择要点
- 中文场景:优先 BGE-M3 或 GTE-Qwen2,中文语义捕获更精准
- 多语言场景:BGE-M3(最佳开源多语言)或 Jina Embeddings v3
- 英文检索:Voyage-3 检索效果领先,BGE-en-icl / NV-Embed-v2 在 MTEB 榜单表现最优
- 多模态(图文混合):Cohere embed-v4 支持文本与图像统一嵌入
- 成本敏感:text-embedding-3-small 性价比最高,支持 Matryoshka 灵活降维进一步节省成本
- 长文本:GTE-Qwen2 支持 128K Token 上下文
- 私有部署:BGE、GTE、NV-Embed 均为开源模型,可本地部署
向量数据库
为什么需要向量数据库
传统数据库(MySQL、PostgreSQL)擅长精确匹配查询(WHERE id = 123),但无法高效处理"找到与这个向量最相似的 K 个向量"的查询。
向量数据库解决的核心问题:
- 高维向量的高效相似度搜索——在数百万到数十亿向量中,毫秒级返回 Top-K 结果
- 索引优化——使用 ANN(近似最近邻)算法,用微小精度损失换取数量级的速度提升
- 混合查询——结合向量相似度搜索和元数据过滤(如
category = 'AI' AND similarity > 0.8)
主流向量数据库
| 数据库 | 类型 | 特点 | 适用场景 |
|---|---|---|---|
| Chroma | 嵌入式 | 轻量、Python 原生、零配置 | 原型开发、小规模应用 |
| Pinecone | 云托管 | 全托管、自动扩缩容、无需运维 | 生产环境、无运维团队 |
| Milvus | 分布式 | 高性能、支持十亿级向量、开源 | 大规模生产、私有化部署 |
| pgvector | PostgreSQL 扩展 | 复用现有 PG 基础设施、支持 SQL 混合查询 | 已有 PG 技术栈的团队 |
| Qdrant | 独立部署 | Rust 实现、性能优异、过滤灵活 | 高性能需求的生产环境 |
| FAISS | 库(非数据库) | Meta 开发、纯向量检索、不含持久化 | 研究实验、自建存储层 |
向量数据库选型实战
"为什么选 X 而不选 Y" 是 2025-2026 年 AI 系统设计面试的高频追问。回答的关键不是背特性,而是按规模 → 数据形态 → 团队栈 → 成本 四步推导。
决策树
五维深度对比
| 维度 | pgvector | Qdrant | Milvus | Pinecone | Chroma |
|---|---|---|---|---|---|
| 规模上限 | 千万级 | 亿级(单机) | 百亿级(分布式) | 数十亿(托管) | 百万级 |
| 写入吞吐 | 中 | 高 | 极高 | 高 | 低 |
| 混合过滤 | SQL 原生,最强 | 灵活 payload 过滤 | 强 | 中等(仅 metadata) | 弱 |
| 多向量字段 | 一行多列 | 命名向量 | 多 collection | 不支持 | 不支持 |
| 运维成本 | 低(同 PG) | 中 | 高 | 极低 | 极低 |
| 是否支持稀疏向量/混合检索 | pgvector 0.7+ | ✅ | ✅ | 部分支持 | ❌ |
容量与成本估算(口诀)
💡 一段口诀算清显存/磁盘
向量数据库的存储估算公式(HNSW 索引 + float32 向量):
存储 ≈ N × D × 4 字节 × (1 + 0.3)
↑ ↑ ↑
向量数 维度 HNSW 图结构开销
示例 1: 1000 万 × 1536 维 = 80 GB → pgvector 单机够
示例 2: 1 亿 × 1024 维 = 533 GB → 必须分布式 (Milvus)
示例 3: 10 亿 × 768 维 = 4 TB → 必须分片 + SSD压缩三连(亿级以上必备):
- 量化(PQ/SQ8):float32 → int8,存储减 4×,召回损失 < 2%
- Matryoshka 截断:3072 维截到 768 维,存储减 4×,损失 5-10%
- 二者叠加:理论可压缩到原始的 1/16
选型常见反模式
| 反模式 | 为什么坑 | 正确做法 |
|---|---|---|
| "反正都能用,就上 FAISS" | FAISS 不是数据库——无持久化、无并发、无元数据 | 生产用 Qdrant/Milvus,FAISS 留给实验 |
| "先上 Pinecone 再说" | 大规模后单价远高于自建(10× 起) | 流量稳定后评估自建 TCO |
| "上 Milvus 显得专业" | Milvus 运维门槛高,分布式部署 = etcd + MinIO + Pulsar | 千万级以下用 pgvector / Qdrant |
| "直接用 Redis 做向量库" | Redis Search 性能不如专用库,召回率也偏低 | 缓存层用 Redis,主库用专用向量库 |
ANN 索引算法
精确最近邻搜索(暴力遍历所有向量)的时间复杂度为 ,在大规模数据集上不可接受。ANN 算法通过构建索引结构,将搜索从线性扫描加速到对数级或亚线性级。
HNSW(Hierarchical Navigable Small World)
HNSW 是目前最流行的 ANN 索引算法,构建多层图结构:
查询过程:从最高层入口节点开始,在当前层贪心搜索最近邻,逐层下降,最终在底层返回 Top-K 结果。
- 时间复杂度:
- 优点:查询精度高(recall > 95%)、不需要训练
- 缺点:内存占用大(需存储图结构),构建索引较慢
- 适用场景:数据量 < 1 亿、对精度要求高
IVF(Inverted File Index)
IVF 先将向量空间聚类成 个区域,查询时只搜索最相关的 个区域:
IVF 将向量空间划分为多个聚类(Voronoi cells),查询时只搜索最近的几个聚类,将搜索范围从全量缩小到 。
- 时间复杂度:
- 优点:内存效率高、适合大规模数据
- 缺点:需要训练聚类中心、精度受 影响
- 适用场景:数据量 > 1 亿、需要平衡速度和内存
PQ(Product Quantization)
PQ 将高维向量切分为多个子段,每个子段独立量化压缩:
PQ 将高维向量切分为多个子空间,每个子空间独立量化为码本索引,大幅压缩存储空间(如 128 维 float32 → 16 字节)。
- 优点:极大减少内存占用(可压缩 32~64 倍)
- 缺点:精度损失相对较大
- 适用场景:十亿级以上数据、内存受限环境
- 通常与 IVF 结合使用(IVF-PQ)
索引选择对比
| 算法 | 查询速度 | 内存占用 | 精度 | 构建速度 | 推荐规模 |
|---|---|---|---|---|---|
| 暴力搜索 | 慢 | 低 | 100% | 无需构建 | < 10 万 |
| HNSW | 最快 | 高 | 最高 | 慢 | < 1 亿 |
| IVF | 快 | 中 | 高 | 中 | 1 亿+ |
| PQ | 快 | 最低 | 中 | 中 | 10 亿+ |
| IVF-PQ | 快 | 低 | 中高 | 中 | 10 亿+ |
实践:构建语义搜索
以下示例演示使用 OpenAI Embedding 和 FAISS 构建一个简单的语义搜索系统:
import numpy as np
import faiss
from openai import OpenAI
client = OpenAI()
def get_embeddings(texts: list[str], model: str = "text-embedding-3-small") -> np.ndarray:
"""批量获取文本的 Embedding 向量"""
response = client.embeddings.create(input=texts, model=model)
return np.array([item.embedding for item in response.data], dtype="float32")
# 1. 准备文档
documents = [
"Transformer 是一种基于自注意力机制的深度学习架构",
"RAG 通过检索外部知识来增强语言模型的生成能力",
"向量数据库使用 ANN 算法实现高效的相似度搜索",
"LoRA 是一种参数高效的模型微调方法",
"Docker 是一个开源的容器化平台",
"Redis 是一个高性能的内存键值数据库",
]
# 2. 生成 Embedding 并构建索引
doc_embeddings = get_embeddings(documents)
dimension = doc_embeddings.shape[1]
index = faiss.IndexFlatIP(dimension) # 内积索引(向量已归一化时等价余弦)
faiss.normalize_L2(doc_embeddings) # L2 归一化
index.add(doc_embeddings)
# 3. 查询
query = "如何优化大模型的训练效率"
query_embedding = get_embeddings([query])
faiss.normalize_L2(query_embedding)
scores, indices = index.search(query_embedding, k=3)
print("查询:", query)
for i, (score, idx) in enumerate(zip(scores[0], indices[0])):
print(f" Top-{i+1} (相似度: {score:.4f}): {documents[idx]}")生产环境最佳实践
索引调优
| 参数 | 影响 | 建议 |
|---|---|---|
| HNSW: M(每节点连接数) | M 越大精度越高,但构建越慢、内存越多 | 通常 16~64 |
| HNSW: ef_construction | 构建时搜索范围,越大索引质量越高 | 100~500 |
| HNSW: ef_search | 查询时搜索范围,越大精度越高 | 50~200 |
| IVF: nlist(聚类数) | 聚类越多查询越快但精度可能下降 | 到 |
| IVF: nprobe | 搜索聚类数,越多精度越高但越慢 | nlist 的 1%~10% |
元数据过滤
生产中通常需要结合结构化过滤和向量搜索:
# Qdrant 示例:结合元数据过滤
from qdrant_client import QdrantClient
from qdrant_client.models import Filter, FieldCondition, MatchValue
results = client.search(
collection_name="articles",
query_vector=query_embedding,
query_filter=Filter(
must=[
FieldCondition(key="category", match=MatchValue(value="AI")),
FieldCondition(key="language", match=MatchValue(value="zh")),
]
),
limit=10,
)关键决策
| 决策点 | 选项 | 建议 |
|---|---|---|
| Embedding 模型 | 开源 vs API 调用 | 小规模用 API(如 OpenAI),大规模或隐私敏感用开源(BGE) |
| 向量数据库 | 嵌入式 vs 独立部署 vs 云托管 | 原型用 Chroma,生产用 Milvus/Qdrant/Pinecone |
| 索引类型 | HNSW vs IVF vs PQ | 数据量小选 HNSW,数据量大选 IVF-PQ |
| 维度选择 | 高维 vs 低维 | 效果:高维 > 低维,速度:低维 > 高维。平衡点在 768~1536。支持 Matryoshka 的模型可灵活截断维度 |
⚠️ 常见误区
认为向量数据库可以替代传统数据库:向量数据库专注于相似度搜索,不擅长精确匹配、事务处理、复杂 SQL 查询。两者是互补关系。
忽视 Embedding 模型的选择:不同 Embedding 模型对不同语言和领域的效果差异很大。中文场景使用英文模型可能导致检索质量大幅下降。
混淆精确搜索和近似搜索:ANN 算法返回的是近似最近邻,可能遗漏真正的最近邻。recall 参数的调优直接影响搜索质量。
盲目追求高维 Embedding:更高维度不一定带来更好效果,但一定会增加存储和计算成本。实际应用中 768~1536 维通常足够。支持 Matryoshka 表示学习的模型(如 text-embedding-3 系列)允许灵活截断维度,可根据场景在效果和成本间取舍。
面试真题详解
Q1:解释 HNSW 索引算法的工作原理及其优缺点
要点:
HNSW(Hierarchical Navigable Small World)是一种基于多层图结构的近似最近邻搜索算法:
构建过程:
- 为每个向量随机分配一个层级(概率指数递减,高层节点少)
- 在每层中,将新向量与最近的 M 个节点建立双向连接
- 形成一个从稀疏(高层)到稠密(底层)的多层导航图
查询过程:
- 从最高层的入口节点出发
- 在当前层进行贪心搜索,找到局部最近邻
- 下降到下一层,以上一层的结果为起点继续搜索
- 在底层(Layer 0)找到最终的 Top-K 结果
优点:查询速度快()、召回率高(> 95%)、无需训练、支持动态插入。 缺点:内存占用大(需存储图连接关系)、构建索引慢。
Q2:对比余弦相似度和点积,什么场景下结果一致?
要点:
- 余弦相似度只衡量向量的方向,忽略模长
- 点积同时考虑向量的方向和模长
当向量已经过 L2 归一化(即 )时,两者结果完全一致:
大多数 Embedding 模型输出的向量默认已归一化,因此实际应用中两者通常等价。使用点积计算更快(少一步归一化),所以生产环境中常用点积代替余弦相似度。
Q3:如何为千万级文档的语义搜索系统选择向量数据库和索引方案?
要点:
规模分析:千万级(~10M)文档,假设 1536 维 Embedding。
向量数据库选择:
- 有 PostgreSQL 基础设施 → pgvector(简单,但性能到千万级可能瓶颈)
- 需要高性能 → Qdrant 或 Milvus
- 不想自运维 → Pinecone
索引方案:
- 千万级在 HNSW 的最佳适用范围内(< 1 亿)
- 推荐 HNSW:M=32, ef_construction=200, ef_search=100
- 内存估算:10M × 1536 × 4 bytes ≈ 60GB(原始向量)+ ~30GB(HNSW 图结构)≈ 90GB
- 如果内存受限,可选择 IVF-PQ:nlist=10000, 128 子段,内存可降至 ~10GB
其他考虑:
- 元数据过滤需求 → 选择支持 pre-filtering 的数据库(Qdrant、Milvus)
- 实时更新需求 → HNSW 支持动态插入,IVF 需要定期重建聚类
- 多副本高可用 → Milvus 或 Pinecone
延伸阅读
- Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs
- Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks
- Text Embeddings by Weakly-Supervised Contrastive Pre-training (E5)
- C-Pack: Packaged Resources To Advance General Chinese Embedding (BGE)