Chapter 03

Embedding 模型原理

把文字变成数字的魔法——理解向量嵌入如何捕捉语义,以及如何选择最适合的 Embedding 模型

什么是向量嵌入(Vector Embedding)

人类理解文字,计算机理解数字。Embedding 模型的核心任务是:将任意长度的文本映射到一个固定维度的数值向量,并且语义相近的文本对应的向量在空间中彼此接近。

举一个直觉性的例子:

核心直觉

向量空间中的"距离"反映了语义的"相似度"。RAG 检索的本质是:把用户问题也编码成向量,然后在向量空间中找距离最近的文档向量,即找语义最相关的文档片段。

Embedding 模型的工作原理

Transformer 编码器
主流 Embedding 模型基于 BERT 等 Transformer 编码器架构。输入文本经过多层 Self-Attention 处理,最终 [CLS] Token 或平均池化后的隐藏状态被用作句子向量表示。
对比学习(Contrastive Learning)
Embedding 模型的训练范式:用大量"语义相似文本对"和"不相似文本对"训练,让相似对的向量尽量靠近(正样本),不相似对的向量尽量远离(负样本)。
双编码器(Bi-Encoder)
查询和文档分别独立编码为向量,再计算相似度。速度快,可以预先计算文档向量存储,检索时只需编码查询。是 RAG 中向量检索的主流架构。
交叉编码器(Cross-Encoder)
查询和文档拼接后共同编码,直接输出相关性分数。精度高于双编码器,但无法预计算,速度慢。通常作为 Reranker 对双编码器检索结果二次排序。
余弦相似度
最常用的向量相似度度量:cos(θ) = (A·B) / (|A| × |B|)。值域 [-1, 1],越接近 1 越相似。多数 Embedding 模型输出已归一化的向量,此时余弦相似度等价于点积(内积)。

语义相似度的计算

import numpy as np
from openai import OpenAI

client = OpenAI()

def get_embedding(text: str, model: str = "text-embedding-3-small") -> np.ndarray:
    resp = client.embeddings.create(model=model, input=text)
    return np.array(resp.data[0].embedding)

def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
    """余弦相似度"""
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

def euclidean_distance(a: np.ndarray, b: np.ndarray) -> float:
    """欧几里得距离(值越小越相似)"""
    return np.linalg.norm(a - b)

# 测试语义相似度
sentences = [
    "如何构建 RAG 系统?",        # 查询
    "RAG 检索增强生成的实现步骤",   # 高度相关
    "向量数据库的基本概念",         # 相关
    "今天天气怎么样",               # 不相关
]

query_vec = get_embedding(sentences[0])
for sent in sentences[1:]:
    vec = get_embedding(sent)
    sim = cosine_similarity(query_vec, vec)
    print(f"相似度 {sim:.3f}: {sent}")

# 输出:
# 相似度 0.891: RAG 检索增强生成的实现步骤
# 相似度 0.743: 向量数据库的基本概念
# 相似度 0.312: 今天天气怎么样

主流 Embedding 模型对比(2025)

模型 维度 最大 Token 语言 价格 特点
text-embedding-3-large 3072 8191 多语言 $0.00013/1K OpenAI 最强,支持维度缩减
text-embedding-3-small 1536 8191 多语言 $0.00002/1K 性价比极高,推荐生产使用
BAAI/bge-m3 1024 8192 多语言 免费(自托管) 支持稠密+稀疏+多向量,开源最强
BAAI/bge-large-zh-v1.5 1024 512 中文为主 免费(自托管) 中文场景表现优秀
moka-ai/m3e-base 768 512 中文 免费(自托管) 专为中文优化,轻量快速
jina-embeddings-v3 1024 8192 多语言 免费额度+付费 任务感知 Embedding,支持指令
voyage-3-large 1024 32000 多语言 $0.00018/1K Anthropic 推荐,超长上下文

使用 BGE-M3(开源本地部署)

# 安装:pip install sentence-transformers
from sentence_transformers import SentenceTransformer
import numpy as np

# BGE-M3:支持稠密、稀疏、多向量混合检索
model = SentenceTransformer("BAAI/bge-m3")

sentences = [
    "RAG 检索增强生成",
    "向量数据库 Qdrant",
    "Embedding 模型对比",
]

# encode 支持批量,默认返回归一化向量
embeddings = model.encode(
    sentences,
    batch_size=32,
    normalize_embeddings=True,  # L2 归一化后点积=余弦相似度
    show_progress_bar=True,
)
print(embeddings.shape)  # (3, 1024)

# BGE 模型的特殊用法:query 前加指令前缀
query = "Represent this sentence for searching relevant passages: RAG 的核心流程"
query_vec = model.encode([query], normalize_embeddings=True)[0]

# 计算相似度矩阵
sim_matrix = embeddings @ embeddings.T
print(sim_matrix)

OpenAI Embedding 维度缩减(Matryoshka)

text-embedding-3 系列支持 Matryoshka 表示学习:可以截断向量维度,以更低存储成本换取略微下降的精度,非常适合大规模生产场景。

from openai import OpenAI

client = OpenAI()

# 请求缩减维度(3072 → 512)
response = client.embeddings.create(
    model="text-embedding-3-large",
    input="检索增强生成 RAG",
    dimensions=512   # 缩减到 512 维,存储减少 83%
)
embedding_512d = response.data[0].embedding
print(f"向量维度:{len(embedding_512d)}")  # 512

# 维度 vs 性能权衡(MTEB 基准):
# 3072d → MTEB 0.641  存储 100%
# 1536d → MTEB 0.638  存储  50%
#  512d → MTEB 0.624  存储  17%
#  256d → MTEB 0.608  存储   8%

维度选择:越大越好?

高维度的优势

  • 表达能力更强,捕捉更细腻的语义差异
  • 在复杂专业领域(法律/医疗)精度更高
  • 长文档的语义信息损失更少

高维度的代价

  • 存储成本线性增长(百万向量差异显著)
  • 检索速度变慢(HNSW 索引构建时间增加)
  • 维度诅咒:超高维空间中距离趋于均匀
  • API 费用:按 token 计费,不受维度影响
推荐组合

中文场景:优先选 BGE-M3 或 bge-large-zh-v1.5(免费,中文优化),或 text-embedding-3-small(稳定好用)。英文/多语言:text-embedding-3-small 性价比最高,若需要极致精度用 text-embedding-3-large。隐私敏感:一定用本地模型(BGE 系列 / M3E),数据不出内网。

Embedding 的重要特性:任务感知

部分现代 Embedding 模型支持"指令式"(Instruction-following)调用:可以在 Embedding 前添加任务描述,引导模型针对特定任务优化向量表示。

# Jina v3:支持任务指令
from sentence_transformers import SentenceTransformer

model = SentenceTransformer("jinaai/jina-embeddings-v3", trust_remote_code=True)

# 查询时用 retrieval.query 任务类型
query = model.encode(
    ["RAG 系统如何处理多跳推理?"],
    task="retrieval.query",
    prompt_name="retrieval.query"
)

# 文档索引时用 retrieval.passage 任务类型
docs = model.encode(
    ["多跳推理需要将问题分解为子问题,逐步检索..."],
    task="retrieval.passage",
)

# E5 系列(微软)同样支持指令前缀
# 查询:前缀 "query: "
# 文档:前缀 "passage: "

评估 Embedding 模型:MTEB 基准

MTEB(Massive Text Embedding Benchmark)是评估 Embedding 模型最权威的标准,覆盖 56 个数据集、8 类任务。

检索
Retrieval Task(RAG 最关键)
聚类
Clustering(文档分类)
重排
Reranking(结果排序)
语义
STS(语义文本相似度)
MTEB 的局限性

MTEB 主要以英文数据为主。中文 Embedding 模型应参考 C-MTEB(中文版 MTEB)排行榜,地址:https://huggingface.co/spaces/mteb/leaderboard,选择 Chinese 标签页。

本章总结