做 RAG 系统时,很多人把时间花在调整 Prompt 上,却忽视了 Embedding 模型的选择——而后者对检索质量的影响往往更大。本文系统对比主流国产 Embedding 方案,帮你找到适合自己场景的那一个。
Embedding 的使用场景
在深入对比之前,先明确 Embedding 能用在哪里:
- RAG 知识库:最典型的场景,把文档和查询都向量化,用相似度匹配找相关片段
- 语义搜索:替代关键词搜索,"笔记本电脑" 能搜到 "便携式计算机"
- 文本分类:把文本向量化后训练轻量分类器(比直接微调大模型便宜得多)
- 聚类分析:对大量文本做 K-Means 或 DBSCAN,发现主题分布
- 去重和相似检测:合同、工单、工单等文档的近似匹配
不同场景对 Embedding 的要求不一样。RAG 更看重检索召回率,语义搜索更看重跨语义泛化能力,分类/聚类更看重向量空间的线性可分性。
国产 Embedding 模型全景
通义千问 text-embedding-v3
阿里云 DashScope 提供,目前是国内 API 方案里综合表现最好的之一。
核心参数
| 项目 | 参数 |
|---|---|
| 最大输入长度 | 8192 tokens |
| 输出维度 | 1024 维(默认)/ 2048 维(可选) |
| 计费 | ¥0.0007 / 千 token |
| API 端点 | https://dashscope.aliyuncs.com/compatible-mode/v1 |
支持动态指定输出维度(Matryoshka 技术),在维度降低时性能衰减很小,对存储敏感的场景很友好。
BAAI/bge-large-zh-v1.5
智源研究院开源,是目前中文 Embedding 开源方案的标杆。
核心参数
| 项目 | 参数 |
|---|---|
| 最大输入长度 | 512 tokens |
| 输出维度 | 1024 维 |
| 部署要求 | GPU 推荐(CPU 也能跑,较慢) |
| 许可证 | MIT(可商用) |
在 MTEB 中文榜单上长期排名前列。缺点是最大输入只有 512 tokens,长文档需要先切分再向量化。
智谱 embedding-3
智谱 AI 提供,随 GLM 系列一起发布。
核心参数
| 项目 | 参数 |
|---|---|
| 最大输入长度 | 8192 tokens |
| 输出维度 | 2048 维 |
| 计费 | ¥0.0005 / 千 token |
| API 端点 | https://open.bigmodel.cn/api/paas/v4 |
2048 维的高维度对复杂语义场景有帮助,价格也有竞争力。
关于 DeepSeek Embedding
DeepSeek 目前没有独立的 Embedding 模型对外提供服务。如果你的主要 LLM 是 DeepSeek,Embedding 环节可以选用上述任意一个方案,它们之间没有绑定关系——Embedding 模型和生成模型是独立调用的。
维度和成本对比
| 模型 | 类型 | 维度 | 最大长度 | 价格 | 中文支持 |
|---|---|---|---|---|---|
| text-embedding-v3 | API | 1024/2048 | 8192 tokens | ¥0.0007/千 token | 优秀 |
| bge-large-zh-v1.5 | 开源 | 1024 | 512 tokens | 服务器成本 | 优秀 |
| embedding-3(智谱) | API | 2048 | 8192 tokens | ¥0.0005/千 token | 良好 |
| bge-m3 | 开源 | 1024 | 8192 tokens | 服务器成本 | 优秀 |
bge-m3 是 bge 系列的升级版,支持 8192 tokens 长度,多语言效果也更好,如果要自部署首选它。
评测方法:Recall@K
选型不能只看参数,要用自己的数据测。标准做法是构建一个查询-文档对测试集,计算 Recall@K(前 K 个检索结果中包含正确答案的比例)。
构建测试集
从你的知识库文档里,人工或半自动地标注 50-100 组查询-正确文档对:
# 测试集格式
test_cases = [
{
"query": "年假申请需要提前多少天?",
"relevant_doc_id": "hr_policy_001_chunk_3" # 正确答案所在的文档块 ID
},
{
"query": "差旅费报销的发票要求是什么?",
"relevant_doc_id": "finance_policy_002_chunk_7"
},
# ...
]
评测脚本
# evaluate.py
from embedder import get_embeddings # 你的 embedding 封装
import chromadb
def evaluate_recall_at_k(
test_cases: list[dict],
collection,
k_values: list[int] = [1, 3, 5, 10]
) -> dict:
"""
计算不同 K 值下的 Recall
Recall@K = 正确文档出现在 Top-K 结果中的查询数 / 总查询数
"""
hits = {k: 0 for k in k_values}
for case in test_cases:
query_embedding = get_embeddings([case["query"]])[0]
results = collection.query(
query_embeddings=[query_embedding],
n_results=max(k_values),
include=["ids"]
)
retrieved_ids = results["ids"][0]
for k in k_values:
if case["relevant_doc_id"] in retrieved_ids[:k]:
hits[k] += 1
total = len(test_cases)
return {f"Recall@{k}": round(hits[k] / total, 4) for k in k_values}
# 使用示例
results = evaluate_recall_at_k(test_cases, collection)
print(results)
# 输出: {'Recall@1': 0.62, 'Recall@3': 0.78, 'Recall@5': 0.85, 'Recall@10': 0.91}
对于企业知识库,Recall@5 达到 0.80 以上就算可用。低于这个值,需要调整 chunk size 或者换更好的 Embedding 模型。
代码示例:接入 Embedding API 并存入 ChromaDB
以通义千问 text-embedding-v3 为例,完整的接入和入库流程:
# embedding_pipeline.py
import os
import chromadb
from openai import OpenAI
# 初始化客户端
embed_client = OpenAI(
api_key=os.environ["DASHSCOPE_API_KEY"],
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
chroma_client = chromadb.PersistentClient(path="./vector_db")
collection = chroma_client.get_or_create_collection(
name="docs",
metadata={"hnsw:space": "cosine"}
)
def embed_and_store(texts: list[str], ids: list[str], metadatas: list[dict] = None):
"""向量化并批量写入 ChromaDB"""
# 分批调用 API(每批 25 条,API 限制)
all_embeddings = []
for i in range(0, len(texts), 25):
batch = texts[i:i+25]
resp = embed_client.embeddings.create(
model="text-embedding-v3",
input=batch,
dimensions=1024
)
all_embeddings.extend([item.embedding for item in resp.data])
collection.upsert(
ids=ids,
documents=texts,
embeddings=all_embeddings,
metadatas=metadatas or [{} for _ in texts]
)
print(f"写入 {len(texts)} 条向量,当前总数:{collection.count()}")
def semantic_search(query: str, top_k: int = 5) -> list[dict]:
"""语义检索"""
resp = embed_client.embeddings.create(
model="text-embedding-v3",
input=[query],
dimensions=1024
)
query_vec = resp.data[0].embedding
results = collection.query(
query_embeddings=[query_vec],
n_results=top_k,
include=["documents", "metadatas", "distances"]
)
return [
{
"text": doc,
"meta": meta,
"similarity": round(1 - dist, 4)
}
for doc, meta, dist in zip(
results["documents"][0],
results["metadatas"][0],
results["distances"][0]
)
]
切换到 bge-large-zh-v1.5(自部署)只需替换 embedding 调用部分(在我们的 TheRouter 网关中,切换不同 embedding 模型只需改 model 参数,无需改动任何接入代码):
# 自部署 bge 方案(使用 sentence-transformers)
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-large-zh-v1.5")
def embed_local(texts: list[str]) -> list[list[float]]:
"""本地推理,无 API 调用"""
embeddings = model.encode(
texts,
normalize_embeddings=True, # 必须归一化,否则余弦相似度不准
batch_size=64,
show_progress_bar=True
)
return embeddings.tolist()
存入 ChromaDB 的代码完全一样,只需把 API 调用换成本地推理。
中文效果专项测试
中文 Embedding 面临的特殊挑战:
- 多义词:"苹果" 是水果还是手机品牌?上下文决定
- 口语 vs 书面语:"这个怎么弄" 和 "操作步骤是什么" 语义相同
- 缩写和俚语:"996"、"内卷"、行业专有名词
- 繁简混合:部分企业文档繁简混用
针对这些场景,可以构建专项测试用例:
# 中文专项测试用例
chinese_test_cases = [
# 口语 vs 书面语
{"query": "怎么请假", "doc": "员工请假申请流程:首先登录 HR 系统..."},
# 缩写
{"query": "OA 系统在哪", "doc": "办公自动化系统访问地址为 oa.company.com..."},
# 跨语义
{"query": "年终奖什么时候发", "doc": "绩效奖金发放时间为次年 1 月..."},
]
实测下来,bge-large-zh-v1.5 在纯中文场景下表现最稳定,text-embedding-v3 在需要长文档支持(>512 tokens)时占优,智谱 embedding-3 在多轮语义理解场景表现不错。
开源自部署 vs API 方案的 Trade-off
API 方案优势
- 零运维:没有 GPU 服务器、模型加载、版本管理等问题
- 快速上手:几行代码就能跑起来
- 自动更新:模型迭代升级不需要你操心
- 弹性扩容:并发高了 API 自动扛,不用手动加机器
自部署优势
- 数据不出境:对数据安全有严格要求的场景(金融、医疗、政务)
- 边际成本为零:入库一次,查询 N 次,不按 token 计费
- 可定制:可以在私有数据上继续微调,提升领域内效果
- 离线可用:不依赖外部网络
我的建议
数据量 < 500 万 token/月 → API 方案(成本可控,省心)
数据量 > 500 万 token/月 → 算一下 ROI,可能值得自部署
数据安全要求高 → 必须自部署,用 bge 系列
快速验证 MVP → 先用 API,跑通后再考虑迁移
以 text-embedding-v3 为例:500 万 token × ¥0.0007/千 = ¥3.5/月。这个量级完全不值得为了省这点钱去维护一套 GPU 推理服务。
而当你的日均 Embedding token 超过 500 万时(约等于每天处理 1 万份中等长度文档),一台配 A100 的推理服务月租 ¥3000 左右,服务起来就有成本优势了。
选型快速决策
├── 数据出境敏感?
│ ├── 是 → bge-large-zh-v1.5(512token)或 bge-m3(8192token)
│ └── 否 → 继续往下
│
├── 文档单段普遍超过 512 token?
│ ├── 是 → text-embedding-v3 或 embedding-3(支持 8192 token)
│ └── 否 → bge-large-zh-v1.5 也够用(开源免费)
│
├── 主要语言是中文?
│ ├── 是 → text-embedding-v3 或 bge-large-zh-v1.5 均可,实测决定
│ └── 多语言 → bge-m3(支持 100+ 语言)
│
└── 快速上线优先?
├── 是 → text-embedding-v3(API,零部署)
└── 否 → bge 系列(开源,需要部署)
小结
Embedding 选型没有银弹,关键点回顾:
- 先用自己的数据测,用 Recall@K 量化,别光看官方 benchmark
- 中文场景首推 bge-large-zh-v1.5(开源)或 text-embedding-v3(API),两者中文效果都很好
- 长文档支持是刚需:如果文档块普遍 > 500 字,选 text-embedding-v3 或 embedding-3
- 数据安全先于性能:数据不能出内网的场景,自部署 bge 是唯一选择
- 先 API 后自建:量小时用 API,量大了再评估迁移成本
下一篇会讲如何用 Reranker 进一步提升 RAG 检索精度,敬请关注。
有什么想补充的 Embedding 选型经验?欢迎评论区交流。
作者:TheRouter 开发者,专注 AI 模型路由网关。项目主页:therouter.ai