Embedding 模型:把文本变成向量的核心组件
RAG 系统里,Embedding 模型负责把「文本」变成「向量」:一段文字输入模型,输出一个固定长度的浮点数组(比如 768 维或 1024 维),语义相近的文本,向量距离就近。向量检索的本质就是在向量空间里找「最近邻」——把用户问题向量化,在库里找最接近的文档向量。所以 Embedding 模型的质量,直接决定检索「能不能召回对的文档」,是整个 RAG 管线的第一道闸门。
Embedding 模型和使用体验最相关的两个特性是「维度」与「对比学习训练」。维度影响存储和检索成本:1024 维比 768 维需要更多索引内存和更多计算,但通常能装下更细的语义差异。几乎所有现代 Embedding 模型都用对比学习训练:训练时给模型看「匹配的正样本对」和「不匹配的负样本对」,让它学会把正样本拉近、负样本推远——这就是 Embedding 模型能力的来源,也是我们后续微调的理论基础。
- Embedding文本向量化是 RAG 检索的第一道闸门。
- 对比学习正负样本对训练是 Embedding 能力的来源。
- 微调用领域数据继续训练可以显著提升召回质量。
- 评估召回率、MRR 等指标决定能否上线。
选型评估:MTEB、领域适配与成本
选 Embedding 模型,第一步看通用能力:MTEB(大规模文本嵌入基准)汇总了多语言检索、相似度、重排、分类等几十个子任务,是行业通用的横向对比榜单。第二步看领域适配:通用榜单第一的模型,到了你所在的垂直领域(医疗、法律、电商、代码)未必最好——你的语料里满是专业术语和特有表达,通用模型可能理解不到位。第三步看成本和工程约束:模型大小(参数量与推理速度)、向量维度(存储与检索成本)、最大输入长度(长文档要不要切块)都要纳入考量。
有一个容易被忽略的点是「输入输出的不对称性」:检索场景里,用户问题通常是短查询,文档是长文本。很多模型对短文本和长文本的语义空间并不完全一致。如果你的场景是「短问题检索长文档」,选型时优先看模型在「短查询→长文档」匹配任务上的表现,而不是只看整体平均分。做完初步选型,用一批真实业务问题做人工抽样评测,比任何榜单数字都可靠。
# 用开源库快速对比候选模型(示意)
# 1. 准备 50 条真实业务 query + 每条对应 1 条相关文档
# 2. 候选模型:bge-large-zh、m3e、text-embedding-3 等
# 3. 对每个模型:文档批量向量化 → 建索引 → query 检索 Top5
# 4. 人工判定 Top5 里相关文档是否出现在前几位
# 5. 记录命中率,结合维度/速度/价格综合决策
对比学习微调的原理:正样本、负样本与损失函数
为什么通用模型在垂直领域会「失灵」?因为训练数据里你的行业表达很少。微调就是用「你的领域数据」继续训练 Embedding 模型,让它把你的术语、简称、特有表达映射到正确的语义位置。Embedding 微调和 LLM 微调(比如 LoRA 微调大模型)不同:LLM 微调学「怎么回答」,Embedding 微调学「什么和什么是一回事」——训练目标是把匹配的文本对拉近、不匹配的推远。
核心是「对比损失」:一个训练批次里有正样本对(query 和它的相关文档)和一批负样本(不相关的文档),模型要学到正样本对相似度尽量高、负样本对相似度尽量低。实现上用 InfoNCE 损失:把「正样本对的相似度」除以「正样本加所有负样本的相似度之和」,让这个比值尽量接近 1。负样本的质量比数量更重要:随机负样本太容易区分,模型学不到东西;「难负样本」——和 query 很像但答案不同的文档——才是真正逼模型进步的关键。
# InfoNCE 对比损失(PyTorch 风格伪代码)
# sim = 余弦相似度矩阵(batch 内 query × doc)
# 对角线是正样本对,其余是批内负样本
# labels = arange(batch) 表示每行应该匹配的 doc 下标
loss = cross_entropy(sim / temperature, labels)
# 难负样本:把容易混淆的文档显式加入负样本集
# 再配合 in-batch 负样本一起参与 loss 计算
训练数据准备:query-doc 对与难负样本挖掘
微调 Embedding 模型,数据质量决定上限。最基础的数据是「query-doc 正样本对」:一条真实用户问题,对应一篇应该被召回的文档。来源可以是搜索日志(用户点了哪个结果)、业务标注(专家标记的相关文档)、或者用 LLM 从文档生成问题(合成数据)。正样本的数量要求不算高,几千到几万条就能看到明显效果,关键是「覆盖面」:你的领域里有哪些典型问法,都要有对应的样本。
负样本有三类来源。随机负样本:任意不相关的文档,提供基础区分能力。批内负样本:同一个训练批次里其他 query 对应的文档,零成本获得。难负样本:用当前模型先检索,把「相似度高但答案错误」的文档挖出来当负样本——这是效果提升最明显的一类。难负样本可以迭代挖掘:微调一轮后重新检索、重新挖负样本、再训一轮,效果会越来越好,这就是业界常说的「负样本迭代挖掘」。
# 难负样本挖掘流程(伪代码)
# 1. 用当前模型向量化全部文档,建索引
# 2. 对每条 query 检索 Top20
# 3. 标注或规则判断:Top20 中与 query 相关但答案不同的 → 难负样本
# 4. 每条 query 配 1 正 + 若干随机负 + 1~2 条难负
# 5. 训练一轮后重新挖掘,循环 2~3 轮
微调实践:从开源模型到 LoRA 训练
工程上微调 Embedding 模型有两个层面。轻量层面:用现成框架(如 sentence-transformers)在领域数据上继续训练,脚本简单、几十分钟就能跑通,适合大多数团队。进阶层面:用 LoRA 在开源基座模型上微调——和微调大模型同一个思路,只训练一小部分低秩适配参数,显存占用小、训练快,还能保留基座模型的通用能力。选哪个看数据量和算力:数据几万条以内、追求快速见效,用轻量训练;数据量大、对效果要求极致,用 LoRA。
训练配置有四个关键点。一是池化方式:模型输出的 token 向量怎么聚合成句向量(均值池化 / CLS),保持和原模型一致。二是归一化:训练和推理时向量都要归一化,余弦相似度才稳定。三是温度与学习率:对比学习的温度参数影响收敛,学习率要比预训练小(通常 1e-5 到 5e-5)。四是保存与部署:导出后要确认向量维度和原模型一致,否则索引重建。微调后务必在同一套评估集上对比「微调前 vs 微调后」,别凭感觉上线。
# sentence-transformers 微调骨架(示意)
from sentence_transformers import SentenceTransformer, losses
model = SentenceTransformer("BAAI/bge-large-zh")
train = load_contrastive_pairs("domain_pairs.jsonl") # 正负样本对
loss = losses.MultipleNegativesRankingLoss(model)
model.fit(train_objectives=[(train, loss)], epochs=3,
warmup_steps=100, output_path="./ft-embedding")
# 上线前:同一评估集对比微调前后 MRR/召回率
检索质量评估:召回率、MRR 与上线验证
微调有没有效,要用「检索指标」说话,而不是模型 loss。最常用的三个指标:召回率(Top-K 里包含相关文档的比例,回答「该有的有没有召回来」)、MRR(第一个相关结果位置的倒数平均,回答「相关文档排得够不够靠前」)、NDCG(考虑相关文档的排序质量,相关性分级的场景用)。评估集要和训练集严格分开:用一批没参与训练的 query-doc 对来测,否则会虚高。
上线前除了离线指标,还要做线上验证:小流量 A/B,对比「旧 Embedding vs 新 Embedding」的用户点击、回答采纳率、无召回率。离线指标好,线上不一定好——因为线上 query 分布会漂移,评估集覆盖不到。所以建议把「线上抽样 query + 人工标注」做成持续评估集,每次模型迭代都在上面跑分,形成回归体系:新模型必须不比旧模型差,才允许上线。
| 指标 | 定义 | 关注点 |
|---|---|---|
| Recall@K | Top-K 命中相关文档的比例 | 有没有召回到位 |
| MRR | 首个相关结果排位的倒数平均 | 相关文档是否靠前 |
| NDCG | 按相关性分级加权的排序质量 | 整体排序是否合理 |
| 无召回率 | 完全没有相关结果的 query 占比 | 检索失败的比率 |
常见坑与工程落地建议
Embedding 微调最常见的坑有四个。一是「训练和推理不一致」:训练时加了前缀(如 bge 模型的「为这个句子生成表示以用于检索相关文章」),推理时忘了加,向量空间对不上,效果崩盘。二是「正样本太脏」:query-doc 对里混入弱相关样本,模型学到错误的相似标准。三是「评估集和训练集同源」:效果虚高,上线打回。四是「只训不测」:没有和微调前的模型做同评估集对比,改了半天不知道改没改好。
落地建议按三步走。第一步:先把「评估集」建好——50 到 200 条真实业务 query,人工标注相关文档,这是整个项目的地基。第二步:用现成模型 + 轻量微调跑通链路,对比微调前后指标,验证「微调这条路在你的场景上是否值得」。第三步:有效则扩展数据、引入难负样本迭代、考虑 LoRA 进阶训练,并建立上线回归体系。记住:Embedding 只是 RAG 的一环,检索质量还要配合重排、混排与语义缓存一起优化,别把所有希望押在模型本身。
Embedding 微调的价值 = 好评估集 × 好数据 × 迭代机制。地基打牢,后面的每一步才有意义。