主题
14.06-Embedding向量化
要点
- Embedding 模型决定了向量空间的语义质量——选错模型等于在地基歪了的楼上盖房子
- 不同模型生成不同语义空间,向量不可跨模型比较,索引和查询必须锁定同一模型
- 统一维度比较:Gemini Embedding 2 精度领先、Qwen3-Embedding 多语言开源最强、BGE-M3 是最实用的全能工作马、OpenAI text-embedding-3 性价比最高
- 选型决策由四个条件决定:语言、成本、部署模式、数据规模——没有通用最优解
- 文档和查询的编码模式必须一致,否则检索效果显著下降
- 批处理 + 缓存 + 重试是把 Embedding 从 demo 推到生产的三个关键工程动作
1. Embedding 模型选错,整条 RAG 链路白搭
上一章(14.05-文本切分)把文档切成了 chunks。下一步是把每个 chunk 变成向量——这一步叫 Embedding。
一个真实的工程场景:RAG 搭完了,chunk 切好了,向量数据库跑起来了,但检索准确率就是上不去。排查切分策略没问题,排查 Rerank 没问题,最后发现是 Embedding 模型选错了——用英文优化的模型处理中文内容,语义空间从一开始就是歪的。
Embedding 模型的选择是整个 RAG 系统里杠杆最大的决策。 它决定了向量空间的语义质量。后续所有检索、排序、上下文拼接都建立在这个空间之上。模型选错了,后面的优化都是在补救一个本可以避免的问题。
这一节回答三个问题:Embedding 的底层机制是什么,主流模型各有什么优劣,以及你的场景应该选哪个。
2. 语义空间:Embedding 到底在做什么
Embedding 模型把一段文本映射到一个高维向量空间。你可以把它想象成一张语义地图:意思相近的文本在这张地图上的坐标离得近,意思远的坐标离得远。
"今天天气真好" → [0.12, -0.34, 0.88, ..., 0.05] (768 维)
"阳光很棒" → [0.11, -0.32, 0.85, ..., 0.07] (距离很近——语义相似)
"今天股票跌了" → [-0.45, 0.67, -0.12, ..., 0.33] (距离很远——语义无关)向量之间的距离用余弦相似度衡量(RAG 检索场景几乎都用这个指标)。距离越接近 1,语义越相似。
关键认知:不同模型生成的是不同的语义空间。 同一段文本用 OpenAI 和 BGE 编码,得到的向量完全不同。两个模型的向量不能直接比较——就像两张不同投影方式的地图,经纬度数值不一样,不能直接拿尺子量。
这个认知直接影响工程决策:一旦选定了 Embedding 模型,所有向量(文档和查询)必须用同一个模型编码。 中途换模型意味着全部重新向量化。
Embedding 模型的训练数据决定了它的语义空间怎么划分。通用模型(如 OpenAI text-embedding-3)在大规模通用语料上训练,擅长日常语义。领域专用模型在特定语料上训练,对专业术语的区分更精细。
三个关键参数决定了一个模型的能力边界:
- 向量维度——768、1024、1536、3072 等。维度越高表达力越强,但存储和计算成本也越高。text-embedding-3 系列支持降维(通过 Matryoshka Representation Learning),可以在存储成本和语义精度之间灵活取舍
- 最大输入长度——512 到 128K token 不等。超过限制的文本需要先切分(这就是上一章做的事)。长上下文模型(如 Cohere embed-v4 的 128K)对大块文本更友好,减少了因切分过碎导致语义丢失的风险
- 训练语料——决定了模型擅长什么语言、什么领域。中文语料占比高的模型(如 BGE、Qwen3)在中文任务上明显优于纯英文训练的模型
3. 主流方案比较
把四类主流方案放在同一张表里,用统一维度比较。
| 方案 | 模型 | 维度 | 最大输入 | MTEB 参考分 | 价格(/1M token) | 中文能力 | 核心特点 |
|---|---|---|---|---|---|---|---|
| Gemini Embedding 2 | 3072(可降维) | 32K | — | $0.20 | 跨语言 0.997 | 精度最高,支持 5 种模态,2026 年跨语言基准冠军 | |
| OpenAI | text-embedding-3-small | 1536(可降维) | 8K | — | $0.02 | 可用 | 极致性价比,维度可调 |
| OpenAI | text-embedding-3-large | 3072(可降维) | 8K | ~64.6 | $0.13 | 良好 | 精度高,维度可调 |
| Cohere | embed-v4 | 1536(可降维) | 128K | ~65.2 | $0.12 | 良好(0.955) | 多模态,超长上下文,区分文档/查询编码 |
| Alibaba | Qwen3-Embedding-8B | 可变 | 8K | 70.58(多语言) | 自托管 | 优秀 | 开源,MTEB 多语言榜首,中英双强 |
| BAAI | bge-m3 | 1024 | 8K | ~63.0 | 自托管 | 优秀(0.940) | 同时输出稠密 + 稀疏 + ColBERT 三种表示 |
| Cloudflare | Workers AI(bge 系列) | 768 | 512 | — | 按 Workers 计费 | 可用 | 与 Vectorize 原生集成,零额外运维 |
几个值得展开说的点:
Gemini Embedding 2 是 2026 年跨语言检索的精度标杆——在中文-英文跨语言基准上拿到 0.997,是唯一在 Hard 难度(含复杂中文成语)上拿到满分的模型。缺点是需要 Google Cloud,且 3072 维向量存储成本不低。
Qwen3-Embedding 是开源阵营的新王者。8B 模型在 MTEB 多语言排行榜排名第一(70.58),但 8B 对推理硬件要求高(至少需要 16GB 显存)。它的 0.6B 小模型在精度和部署成本之间取得了不错的平衡,适合资源有限的自托管场景。
BGE-M3 是最实用的开源全能选手。它的独特能力是一次推理同时输出稠密向量、稀疏向量和 ColBERT 多向量三种表示——这意味着你可以用它同时支持向量检索、关键词检索和多向量精排,不需要额外部署稀疏检索引擎(如 BM25)。MIT 协议,商用无顾虑。
OpenAI text-embedding-3-small 以 $0.02/1M token 的价格提供了够用的精度。如果你的场景对检索准确率没有极致要求,它是最省心的选择——不用管模型部署、不用管版本升级、不用管显存。
embed-v4 相对 embed-v3 的主要升级是多模态支持(文本 + 图片)和 128K 上下文窗口。如果你的知识库包含图片内容,embed-v4 是目前少数能直接处理图片 Embedding 的商业模型。
4. 选型决策框架
选型不是一个「哪个最好」的问题,而是一个「在什么条件下选什么」的决策。四个条件依次过滤。
4.1 内容是什么语言?
- 纯英文 → text-embedding-3-small 够用,精度优先选 Gemini Embedding 2
- 中文为主 → 自托管选 Qwen3-Embedding(精度最高)或 BGE-M3(最均衡);API 选 Gemini Embedding 2 或 embed-v4
- 多语言混合 → Gemini Embedding 2(跨语言精度最高)或 BGE-M3(自托管多语言最佳)
4.2 精度和成本怎么取舍?
- 成本优先 → text-embedding-3-small($0.02/1M token)或 BGE-M3(自托管免费)
- 精度优先 → Gemini Embedding 2 或 Qwen3-Embedding-8B
- 均衡 → text-embedding-3-large($0.13/1M token,精度可观)或 BGE-M3
4.3 能接受第三方依赖吗?
- 接受 API → OpenAI、Cohere、Google 最省心
- 需要私有部署 → Qwen3-Embedding 或 BGE-M3,配合 vLLM / TEI 部署推理服务
- 已有 Cloudflare 技术栈 → Workers AI 省去跨服务集成的麻烦
4.4 数据规模多大?
- < 100 万 chunk → 任何方案都行,优先选最省心的
- 100 万 - 1 亿 → 关注 API 成本和向量存储成本,text-embedding-3-small 的降维功能在这里很有用
- > 1 亿 → 自托管 + 量化压缩几乎是必选项,BGE-M3 的 1024 维比 3072 维省 3 倍存储
5. 边界条件
模型选型能解决 80% 的问题,剩下的 20% 来自边界条件:领域术语、多语言混合和数据规模。
5.1 领域术语
通用 Embedding 模型可能不认识你的领域术语。「RAG」「向量检索」在通用模型的语义空间里可能和「一个字母组合」「一种搜索方式」差不多——因为它在训练语料里很少见到这些概念的精确用法。
处理方式:用领域数据微调模型。成本不低(需要构造训练对和训练流程),但在垂直领域(法律、医疗、金融)效果提升明显。
更经济的做法是先确保切分策略合理——检索效果不好时,先检查 chunk 粒度是不是太粗或太细,Embedding 模型是最后才优化的环节。
5.2 中英文混合内容
中英文混合的技术文档很常见。用纯英文模型处理中文段落,语义空间会严重失真。
多语言模型(Gemini Embedding 2、BGE-M3、Qwen3-Embedding)在训练时对齐了不同语言的语义空间,能正确处理混合文本。实测数据:Gemini Embedding 2 跨语言检索准确率 0.997,BGE-M3 为 0.940。
如果你发现多语言模型效果仍不理想,可以考虑「先翻译后 Embedding」——把所有内容翻译成同一种语言再编码。代价是索引成本翻倍(翻译 + 向量化),且翻译可能引入错误。
5.3 规模带来的工程约束
百万 chunk 以下,任何模型都跑得动。超过一亿 chunk,向量存储本身就成了瓶颈——3072 维(text-embedding-3-large)比 1024 维(BGE-M3)多 3 倍存储。这时候降维或选低维模型就成了工程必需,而不只是精度取舍。
6. 编码一致性:一个容易忽略的硬约束
索引和查询必须用同一个模型编码,这一点在前面的「语义空间」里已经说过。但还有一个更细的坑:有些模型对文档和查询用不同的编码模式。
Cohere embed 系列要求设置 input_type:
typescript
// 索引文档时
const docEmbedding = await cohere.embed({
texts: ['这是一段文档内容...'],
model: 'embed-v4',
inputType: 'search_document', // 文档编码模式
})
// 查询时
const queryEmbedding = await cohere.embed({
texts: ['用户的问题'],
model: 'embed-v4',
inputType: 'search_query', // 查询编码模式
})为什么需要区分?文档通常更长、信息更完整;查询更短、更聚焦。模型对两者用不同的编码策略,让查询向量和文档向量在同一个空间里更好地对齐。如果不区分,检索效果会明显变差。
E5 系列用前缀区分:
typescript
const docText = `passage: ${documentText}`
const queryText = `query: ${queryText}`如果你用的模型不需要区分(如 text-embedding-3、BGE-M3),那文档和查询用同一种编码方式就行。但如果模型需要区分而你没设置,检索效果会悄悄下降——不会报错,只是结果不好。 这是排查 RAG 检索质量时容易忽略的地方。
7. 统一 Embedding 服务与工程实践
把模型选择、批处理、缓存和重试封装成统一接口,业务代码不直接依赖具体模型。
typescript
// 统一接口
export type EmbeddingProvider = {
name: string
dimensions: number
embed(texts: string[]): Promise<number[][]>
}
// 封装服务:批处理 + 重试 + 缓存
export class EmbeddingService {
private provider: EmbeddingProvider
constructor(provider: EmbeddingProvider) {
this.provider = provider
}
get dimensions() {
return this.provider.dimensions
}
async embed(texts: string[]): Promise<number[][]> {
const BATCH_SIZE = 100
const allEmbeddings: number[][] = []
for (let i = 0; i < texts.length; i += BATCH_SIZE) {
const batch = texts.slice(i, i + BATCH_SIZE)
let attempts = 0
while (attempts < 3) {
try {
const embeddings = await this.provider.embed(batch)
allEmbeddings.push(...embeddings)
break
} catch (err) {
attempts++
if (attempts >= 3) throw err
// 指数退避
await new Promise((r) => setTimeout(r, 1000 * attempts))
}
}
}
return allEmbeddings
}
}批处理是成本控制的基本功。 逐条调用 API 和批量调用,成本差异可达 10-100 倍。每批不要超过 API 限制(OpenAI 最多 2048 条,Workers AI 最多 100 条)。
缓存避免重复计算。 用文本内容的哈希值作为缓存 key,相同文本不需要重复向量化。更新文档时只计算新增或修改的 chunk。查询缓存可以在短时间内复用同一问题的 Embedding。
成本估算
以 text-embedding-3-small 为例:
typescript
// 索引成本(一次性)
const totalChunks = 100_000
const avgChunkTokens = 200
const indexCost = (totalChunks * avgChunkTokens / 1_000_000) * 0.02 // = $0.04
// 查询成本(每月)
const dailyQueries = 1000
const queryTokensPerQuery = 50
const monthlyQueryCost = (dailyQueries * queryTokensPerQuery * 30 / 1_000_000) * 0.02
// = $0.03
// 月总成本 ≈ $0.07中小规模应用下,Embedding 成本几乎可以忽略。真正的成本大头在 LLM 生成环节(第 13 章)。
但当规模上到亿级 chunk,情况完全不同:
typescript
// 亿级 chunk 的索引成本
const totalChunks = 100_000_000
const indexCost = (totalChunks * 200 / 1_000_000) * 0.02 // = $400
// 加上存储:3072 维 × 1 亿 × 4 字节 ≈ 1.2TB$400 的索引成本 + 1.2TB 的存储,这时候自托管模型的成本优势就很明显了。 判断阈值:当月 Embedding API 费用超过一台 GPU 实例的月租(约 $200-500),就该认真评估自托管。
8. 下一步:选完模型,存在哪里
Embedding 模型的选型不是做一次就不变的事。随着数据规模增长、语言覆盖扩展、检索精度需求变化,你可能需要重新评估。以下是几个升级信号:
- 检索准确率不达标 → 先查切分粒度(回到 14.05),再查 Embedding 模型是否匹配内容语言
- 内容从单语变多语 → 切换到多语言模型,所有向量需要重新编码
- 数据规模突破百万 → 评估 API 成本,考虑自托管或降维
- 领域术语检索差 → 考虑领域微调,或先用 Rerank(第 12 章)补救
选定了 Embedding 模型,下一步是把向量存起来。第 7 节(14.07-向量数据库选型)讨论 pgvector、Qdrant、Milvus 的选择。