Embedding 的全部承诺是一句话:语义相近的文本,在向量空间里距离也近。这句话里每个词都有代价——“语义”由训练目标定义,”相近”有三种不同的度量,”距离”要付出维度和算力的预算。理解了这些代价,选型和调优才有依据。
一、Embedding 是什么
Embedding 把一段文本映射成固定长度的向量。检索系统拿它做召回,分类器拿它当特征,聚类和去重拿它算距离——同一份向量,服务着完全不同的下游任务。
这个想法比大模型早了十年。Word2Vec(Mikolov 等,2013)先把词映射成向量,训练目标是”用周围的词预测当前词”—— King − Man + Woman ≈ Queen 这样的线性关系首次说明,词义可以被向量运算捕捉。但它有一个结构性缺陷:每个词只有一个静态向量。”苹果发布手机”和”苹果很甜”里的”苹果”共享同一个向量,一词多义无解。
BERT(NAACL 2019)的上下文表示解决了多义问题:同一个词在不同上下文里得到不同的向量。但直接拿 BERT 做句子检索效果很差——它的预训练目标是 token 级的完形填空,句级的相似度从来没有被训练目标对齐过。Sentence-BERT(EMNLP 2019)就是为了补这个缺口:在 BERT 之上加池化层,用孪生结构在句子对上微调,让”句子语义相近”显式地成为训练目标。
这条线索串起来就是嵌入模型的三代演进:词向量(静态、词粒度)→ 上下文表示(动态、token 粒度)→ 句子嵌入(动态、句子粒度、为相似度任务对齐)。今天的嵌入模型都是第三代的形态,但训练方法回到了第一代用过的老技术——对比学习。
二、向量空间的”语义”从哪来
Embedding 最常被误解的地方是把它当成一种”压缩”或”编码”。它不是。嵌入空间的结构完全由训练目标塑形:训练信号奖励什么,空间里就形成什么几何结构。
主流的训练方法是对比学习。给定一个句子(anchor)、一个语义相近的正样本(positive)、一批不相关的负样本(negatives),训练目标是用温度参数 τ 缩放后的 InfoNCE 损失:
$$\mathcal{L} = -\log \frac{\exp(\text{sim}(a, p)/\tau)}{\exp(\text{sim}(a, p)/\tau) + \sum_{i=1}^{n} \exp(\text{sim}(a, n_i)/\tau)}$$
直觉是:在所有候选里,正样本应该”赢”过全部负样本。这个损失对空间施加的塑形是全局的——每一步更新都在推开所有负样本、拉近正样本,最终空间的拓扑就是”语义关系的形状”。
三个训练细节决定空间的实际质量。
负样本的质量。随机的负样本太容易(”体育新闻”和”菜谱”一眼就能区分),对空间的塑形很弱。难负样本——主题相似但语义不同的句子(”如何安装 Windows”和”如何卸载 Windows”)——才是真正训练出精细边界的东西。难负样本的挖掘策略(BM25 高位命中但不相关的、同义但反义的)对最终效果的贡献常常超过换模型。
温度参数。τ 越小,softmax 越尖锐,损失越聚焦于”最难的那个负样本”;τ 越大,分布越平,所有负样本均匀参与。它控制的是学习信号在难易之间的分配。
正样本的来源。无监督路线(SimCSE,EMNLP 2021)给了一个漂亮的答案:把同一句话过两遍编码器,两次随机 dropout 的掩码不同,两次输出就构成一对正样本——预测自己的输入,dropout 本身就是最小代价的数据增强。有监督路线用标注的句子对(NLI 数据集的蕴含对是经典来源),质量更高但受限于标注。
SimCSE 的这张示意图值得对着看:同一个句子进入两次编码器,dropout 掩码不同,两次输出互为正样本——“预测自身输入”是无监督句子嵌入最简洁的设计。

图源:Gao 等,SimCSE: Simple Contrastive Learning of Sentence Embeddings(EMNLP 2021)论文原图
三、池化:从 token 到句子
BERT 类模型的输出是 token 级的,要得到句子向量需要一步池化。两条常见路线:取 CLS 位置的输出(BERT 预训练时该位置聚合了整句信息)和 对所有 token 取平均(mean pooling)。实践里两者都能工作,哪个更好没有定论—— Sentence-BERT 时代的实验显示 mean pooling 在多数任务上更稳,后来带指令训练的模型又多回到特殊 token。结论是:用哪个池化方式是模型定义的一部分,换池化方式等于换了一个模型,必须重新评测。
Sentence-BERT 的结构图把这件事画得很清楚:左边是训练时的分类目标(孪生结构,两个句子共享同一编码器),右边是推理时的相似度计算(两个独立编码后算余弦)——训练和推理用同一套池化,向量空间才是一致的。

图源:Reimers 与 Gurevych,Sentence-BERT(EMNLP 2019)论文原图
四、双塔与交叉编码器:两种必须共存的形态
双塔结构(查询和文档各自独立编码)是检索规模的唯一解:文档向量离线算好存进索引,在线只算查询向量,代价是一次 ANN 查询。它的天花板也来自结构——两个文本从未在模型内部交互,细粒度的语义差别无法建模。
交叉编码器把两个文本拼在一起送进模型,让注意力自由交互,精度明显更高,但每个候选对都要跑一次前向,无法预计算。
工程上的分工因此是固定的:双塔负责从百万级到百级,交叉编码器负责从百级到十级。这个分工还有一层训练上的含义:双塔模型的训练也在为交叉编码器铺路——双塔召回的难负样本,正是交叉编码器最需要学习的边界样本。
多向量路线(ColBERT 一线,SIGIR 2020)介于两者之间:每个 token 一个向量,相似度按 token 对齐后聚合,精度接近交叉编码器、速度接近双塔,代价是存储膨胀一到两个数量级。
五、维度与表示容量
嵌入向量的维度从 384 到 4096 不等,它直接决定三件事:索引内存、单次查询延迟、以及模型能承载的信息量。
维度和效果的关系不是越高越好,而是”任务的语义复杂度需要多少自由度”。Matryoshka 表示学习(MRL)给出了一个漂亮的方案:训练时让向量的前 k 维自身就是一个合格的嵌入——一个 4096 维的模型,取前 256 维也能工作,像套娃一样层层嵌套。这让”存储受限时用小向量、资源充足时用全维度”成为同一个模型的两种用法,而不是两个模型。

图源:Kusupati 等,Matryoshka Representation Learning(arXiv 2022)论文原图
维度截断的损失分布不均匀:前若干维承载了主要语义,末尾的维度贡献边际价值很小。实践中常用的做法是把 MRL 模型截断到 256 或 512 维,先测召回,再决定是否用全维度。
六、指令化与多任务
新一代嵌入模型普遍支持任务指令:在输入前加一句任务描述(”为这个问题检索相关文档”),同一个模型在不同任务上的表现都会变化。INSTRUCTOR(WWW 2023)把这条路推到极致——任务指令直接作为模型输入的一部分。
多任务训练是嵌入模型的新常态:同一个模型同时训练检索、聚类、分类、STS(语义文本相似度)等多种任务,靠任务指令或训练阶段区分。好处是一个模型覆盖多种用途,代价是单一任务上不如专精模型——这也是 MTEB 排行榜上不同模型各有强项的原因。
选型的实用结论:先看自己的主任务是什么,再找在该任务上验证过的模型。检索任务的模型未必适合聚类,STS 强的模型做分类可能平平——“通用”嵌入模型不存在。
七、选型与评测
选型的信息来源有两层:公开榜单和自己的数据。
MTEB(EACL 2023)把嵌入评测标准化为八类任务(分类、聚类、检索、重排、STS、配对分类、摘要、双向检索),C-MTEB 是中文版本。榜单的问题和所有榜单一样:任务分布与真实业务不同、会被针对性优化、不同模型的评测设置可能不一致。正确的用法是把榜单当候选筛选器——从榜单上挑三五个模型,进入第二层。
第二层是自己的评测集。构造方法:每个业务场景收集 50 到 200 条”查询 + 正确文档”对(从真实查询日志、人工标注或大模型合成,合成后必须人工过一遍),然后量 recall@k——正确文档出现在 top-k 里的比例。这个数字直接对应 RAG 的召回率上界,比任何公开榜单都有说服力。
模型形态的选择按三问展开:
- 数据能不能出内网——不能就排除 API,选开源模型本地部署
- 主任务是什么——检索选带非对称指令的模型,聚类和分类看对应子任务的评测
- 维度预算多少——索引内存 = 向量数 × 维度 × 4 字节,百万级 1024 维就是 4 GB;MRL 模型可以在同一模型上权衡
八、工程实践
批量的幂等。嵌入计算按”文本内容哈希 + 模型版本”作为键缓存,重跑不重复计费。换嵌入模型等于全量重算,所以模型版本号必须和向量存在一起。
归一化。入库前统一 L2 归一化,距离度量选内积或余弦——余弦和内积在归一化后等价,混用则会得到不一致的排序。
长文本。嵌入模型有输入上限(常见 512 token,长上下文模型 8k 以上)。超长文档先切块再嵌入,或用”分层聚合”——句子级嵌入平均成段、段平均成篇。切块策略与检索粒度一致,别用全文嵌入一个向量。
指令前缀。带指令的模型,查询侧和文档侧的前缀必须严格按模型文档来——文档侧常需要 “passage: “ 前缀而查询侧不带(或反过来),漏加会让召回率静默下降,且没有任何报错。
成本。自托管开源模型没有按次费用但有 GPU 占用;API 按 token 计费,一亿 token 的语料量级要提前算。两者的切换成本是一次全量重建——所以模型选择要在重建之前敲定。
九、常见误解
“维度越高越好。” 高维承载更多信息,但索引更贵、更容易过拟合训练任务的表面特征。维度应该按”任务的语义复杂度”选,配合 MRL 截断灵活调整。
“余弦相似度可以跨模型比较。” 0.8 在 A 模型里和 0.8 在 B 模型里是完全不同的相似程度——不同模型的空间不可比,甚至同一模型不同版本的分数也不可比。跨模型只能比排名,不能比分值。
“语义相近就能互相替代。” “猫”和”狗”在嵌入空间里很近,但问答系统里问”猫的寿命”召回狗的文档是错的。语义近是检索的必要条件,不是充分条件——精确的实体和事实查询仍然需要词法匹配兜底。
“嵌入是大模型的压缩版。” 嵌入向量不是知识的压缩表示,是特定任务训练目标下的投影——投影掉的信息无法从向量恢复(有研究证明嵌入可以部分还原原文,但那是攻击,不是功能)。用嵌入替代生成模型做知识问答,是类别错误。
“换池化方式或归一化是小细节。” 它们是模型定义的一部分。池化方式、归一化与否、指令前缀——任何一个与训练时不一致,空间的几何结构就偏了。
参考
- 1301.3781 — Efficient Estimation of Word Representations in Vector Space(Word2Vec)— arXiv 2013
- 1310.4546 — Distributed Representations of Words and Phrases and their Compositionality — NeurIPS 2013(CCF-A)
- 1810.04805 — BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding — NAACL 2019
- 1908.10084 — Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks — EMNLP 2019
- 2104.08821 — SimCSE: Simple Contrastive Learning of Sentence Embeddings — EMNLP 2021
- 2212.03533 — Text Embeddings by Weakly-Supervised Contrastive Pre-training(E5)— 预印本 2022
- 2402.03216 — M3-Embedding: Multi-Linguality, Multi-Functionality, Multi-Granularity(BGE-M3)— ACL 2024
- 2205.13147 — Matryoshka Representation Learning — arXiv 2022
- 2210.07316 — MTEB: Massive Text Embedding Benchmark — EACL 2023
- 2004.12832 — ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction — SIGIR 2020(CCF-A)
- 2212.09741 — One Embedder, Any Task: Instruction-Finetuned Text Embeddings(INSTRUCTOR)— WWW 2023