嵌入模型对比 — 从 Word2Vec 到现代 Embedding
#嵌入模型 · #Embedding · #bge · #m3e · #向量检索 · #语义搜索
嵌入模型是 RAG 和语义搜索的基石。选错嵌入模型,再好的检索架构也白搭。本文对比主流通用嵌入模型和中文嵌入模型的性能、维度和适用场景。
嵌入模型的核心作用
mermaid
graph LR
subgraph "嵌入模型的角色"
DOC1["文档: Go 的 GMP 调度模型..."] --> ENC["嵌入模型<br/>Encoder"]
DOC2["文档: Python async/await..."] --> ENC
QUERY["查询: goroutine 如何调度?"] --> ENC
ENC --> V1["向量₁<br/>[0.12, -0.45, 0.78, ...]"]
ENC --> V2["向量₂<br/>[0.89, 0.32, -0.11, ...]"]
ENC --> V3["向量₃<br/>[0.15, -0.42, 0.75, ...]"]
V3 --> SIM["余弦相似度<br/>sim(V3, V1) = 0.92 ✅<br/>sim(V3, V2) = 0.18 ❌"]
V1 --> SIM
V2 --> SIM
end
style ENC fill:#e74c3c,color:#fff嵌入模型的核心任务:把变长的自然语言文本映射到固定维度的稠密向量,使语义相似的文本在向量空间中距离更近。
嵌入模型的关键指标
| 指标 | 含义 | 影响 |
|---|---|---|
| 维度 | 输出向量的长度 | 维度越高表达能力越强,但存储和检索成本越大 |
| 最大长度 | 能处理的最大 Token 数 | 决定能否一次编码长文档 |
| MTEB 得分 | Massive Text Embedding Benchmark 综合分 | 通用嵌入质量的权威指标 |
| C-MTEB 得分 | 中文版 MTEB | 中文嵌入质量指标 |
| 推理速度 | tokens/s 或 sentences/s | 大批量索引时的吞吐 |
| 模型大小 | 参数量和磁盘占用 | 影响部署成本和启动速度 |
国际主流嵌入模型
模型对比总览
| 模型 | 维度 | 最大长度 | MTEB 均分 | 模型大小 | 推理速度 | 特点 |
|---|---|---|---|---|---|---|
| text-embedding-3-large | 3072/256/1024 | 8191 | 64.6 | 闭源 | ⭐⭐⭐⭐⭐ | OpenAI 旗舰,支持维度缩减 |
| text-embedding-3-small | 1536/512 | 8191 | 62.3 | 闭源 | ⭐⭐⭐⭐⭐ | 性价比最高 |
| voyage-3-large | 1024 | 32000 | 66.8 | 闭源 | ⭐⭐⭐⭐ | 超长上下文 |
| voyage-3-lite | 512 | 32000 | 63.0 | 闭源 | ⭐⭐⭐⭐⭐ | 轻量高速 |
| bge-large-en-v1.5 | 1024 | 512 | 64.2 | 1.3 GB | ⭐⭐⭐ | 开源标杆 |
| bge-m3 | 1024 | 8192 | 64.4 | 2.2 GB | ⭐⭐⭐ | 多语言 + 稠密+稀疏混合 |
| gte-Qwen2-7B-instruct | 3584 | 32768 | 69.5 | 14 GB | ⭐⭐ | 最强开源(需 GPU) |
| e5-mistral-7b-instruct | 4096 | 32768 | 66.6 | 14 GB | ⭐⭐ | Mistral 基座 |
各模型详细分析
text-embedding-3 (OpenAI)
python
from openai import OpenAI
client = OpenAI()
# 亮点: 支持动态维度缩减,不损失太多质量
response = client.embeddings.create(
model="text-embedding-3-large",
input="Go 语言的 goroutine 是一种轻量级线程",
dimensions=256, # 从 3072 压缩到 256,存储省 12 倍
)
vector = response.data[0].embedding
print(f"向量维度: {len(vector)}") # 256| 维度 | MTEB 得分 | 存储 (1M 条) |
|---|---|---|
| 3072 (原始) | 64.6 | ~12 GB |
| 1024 | 64.1 | ~4 GB |
| 256 | 62.0 | ~1 GB |
voyage-3 (Anthropic)
突出优势是超长上下文(32K tokens),适合直接编码整个文档而无需切分:
python
import voyageai
vo = voyageai.Client()
# 获取嵌入
result = vo.embed(
texts=["Go 语言的 GMP 调度模型...(长文档)"],
model="voyage-3-large",
input_type="document", # 文档模式: 全局摘要
)
# 查询时用 input_type="query" 获得更精准的匹配中文嵌入模型
模型对比
| 模型 | 维度 | 最大长度 | C-MTEB 均分 | 模型大小 | 特点 |
|---|---|---|---|---|---|
| bge-large-zh-v1.5 | 1024 | 512 | 64.5 | 1.3 GB | 中文开源首选 |
| bge-m3 | 1024 | 8192 | 66.2 | 2.2 GB | 多语言混合训练 |
| m3e-large | 1024 | 512 | 62.8 | 430 MB | 轻量中文专用 |
| m3e-base | 768 | 512 | 60.7 | 210 MB | 最轻量中文 |
| stella-large-zh-v3-1792d | 1792 | 1024 | 67.2 | 1.3 GB | 中文最高分 |
| gte-large-zh | 1024 | 512 | 66.7 | 1.3 GB | 阿里通义系 |
| text2vec-large-chinese | 1024 | 512 | 59.3 | 1.3 GB | 老牌中文模型 |
| Conan-embedding-v1 | 1792 | 4096 | 63.5 | 1.3 GB | 专为检索优化 |
bge-m3 详解
bge-m3 是目前最强的中文开源嵌入模型之一,支持三种检索模式:
python
from FlagEmbedding import BGEM3FlagModel
model = BGEM3FlagModel("BAAI/bge-m3", use_fp16=True)
sentences = [
"Go 语言的 GMP 调度模型详解",
"Python 的 asyncio 异步编程",
"goroutine 和 channel 的使用",
]
# 1. 稠密向量(Dense)— 通用语义检索
dense_embeddings = model.encode(sentences)["dense_vecs"]
print(f"稠密向量维度: {dense_embeddings.shape}") # (3, 1024)
# 2. 稀疏向量(Lexical)— 关键词匹配
lexical_weights = model.encode(sentences)["lexical_weights"]
# 输出: [{"GMP": 0.8, "调度": 0.6, ...}, ...]
# 结合稠密向量做混合检索,解决专有名词召回问题
# 3. 多向量(ColBERT)— token 级交互
colbert_vecs = model.encode(sentences)["colbert_vecs"]
# 每个 token 一个向量,实现精细匹配
# 存储成本高,但检索精度最高| 检索模式 | 精度 | 存储成本 | 检索速度 | 适用 |
|---|---|---|---|---|
| 稠密 (Dense) | 高 | 低 (1024 float32/条) | 快 | 通用场景 |
| 稀疏 (Lexical) | 中 | 极低 (词表大小) | 极快 | 专有名词/代码 |
| 多向量 (ColBERT) | 最高 | 极高 (n_tokens × 1024) | 慢 | 精度优先 |
| 混合 (Dense+Sparse) | 最高 | 低+极低 | 中 | 推荐生产方案 |
嵌入模型选型决策
mermaid
graph TD
START["选择嵌入模型"] --> Q1{"语言?"}
Q1 -->|"纯中文"| Q2{"数据量?"}
Q1 -->|"多语言混合"| A1["bge-m3<br/>or voyage-3"]
Q1 -->|"纯英文"| A2["text-embedding-3-large"]
Q2 -->|"< 10万条"| A3["m3e-base<br/>210MB 轻量"]
Q2 -->|"10-100万条"| A4["bge-large-zh-v1.5<br/>or stella-large"]
Q2 -->|"> 100万条"| Q3{"需要长上下文?"}
Q3 -->|"是 (长文档)"| A5["bge-m3 (8192 tokens)<br/>or voyage-3 (32K)"]
Q3 -->|"否"| A6["bge-large-zh-v1.5<br/>+ 混合检索"]
style A1 fill:#2ecc71,color:#fff
style A5 fill:#e74c3c,color:#fff
style A3 fill:#3498db,color:#fff嵌入模型的训练范式
mermaid
graph LR
subgraph "对比学习 (Contrastive)"
Q1["查询: 什么是GMP?"] --> ENC1["Encoder"]
D1["正样本: GMP调度详解"] --> ENC1
D2["负样本: Python异步"] --> ENC1
ENC1 --> LOSS1["拉近正样本<br/>推远负样本"]
end
subgraph "预训练 → 微调"
PT["预训练<br/>BERT/GTE/Qwen"] --> FT1["无监督对比<br/>SimCSE"]
FT1 --> FT2["有监督对比<br/>标注数据"]
FT2 --> FT3["指令微调<br/>任务描述前缀"]
end
style LOSS1 fill:#e74c3c,color:#fff
style FT3 fill:#2ecc71,color:#fff现代嵌入模型的标配:指令前缀 (Instruction Prefix)。同样的文本,带不同前缀可获得不同用途的向量。
python
# bge 和 gte 系列支持的指令前缀
task_prefixes = {
"query": "为这个搜索查询生成表示: ",
"document": "", # 文档编码不需要前缀
"classification": "为这段文本生成用于分类的表示: ",
"clustering": "为这段文本生成用于聚类的表示: ",
"pair": "为这段文本对生成表示: ",
}
# 使用
queries = ["Go GMP 调度"]
docs = ["Go 语言的 GMP 调度模型..."]
q_embs = model.encode(
[task_prefixes["query"] + q for q in queries]
)
d_embs = model.encode(docs) # 文档不加前缀
similarity = q_embs @ d_embs.T性能基准实测
中文检索精度 (MTEB Retrieval 子集)
| 模型 | NDCG@10 | 推理速度 (sent/s) | 内存占用 |
|---|---|---|---|
| stella-large-zh-v3-1792d | 71.3 | 85 | 2.6 GB |
| bge-large-zh-v1.5 | 70.8 | 92 | 2.4 GB |
| bge-m3 | 70.2 | 58 | 4.4 GB |
| gte-large-zh | 69.5 | 90 | 2.4 GB |
| m3e-large | 67.2 | 120 | 1.2 GB |
| text2vec-large | 63.1 | 95 | 2.4 GB |
结论:stella 精度最高但不支持长文本;bge-m3 功能最全但速度最慢;m3e 速度最快但精度略低。实战中 bge-large-zh-v1.5 是性价比之选。
OpenAI vs 开源成本对比 (100 万条文档)
| 方案 | 模型 | 成本 | 耗时 |
|---|---|---|---|
| OpenAI API | text-embedding-3-large | ~$130 | ~15 min |
| OpenAI API | text-embedding-3-small | ~$20 | ~15 min |
| 自建 GPU | bge-large-zh | ~$0.5 (电费) | ~3 hours |
| 自建 CPU | m3e-base | ~$0.02 (电费) | ~6 hours |
参考
- MTEB Leaderboard — 嵌入模型排行榜
- C-MTEB — 中文嵌入评测
- BGE (BAAI General Embedding) — 北京智源
- M3E — 中文嵌入模型
- Voyage AI — Anthropic 嵌入服务
- OpenAI Embeddings
登录后即可发表评论 👇