前置知识: 自然语言处理

嵌入模型深入

00:00
7 min Intermediate

理解Sentence-BERT、E5、BGE和ColBERT等嵌入模型的架构与训练

嵌入模型深入 — Sentence-BERT、E5、BGE、ColBERT

Word2Vec给每个词一个向量。句子嵌入给每个句子一个向量。RAG、检索和语义搜索依赖后者。模型选择是系统中最有影响力的单一决策。

类型: 学习 语言: Python 前置条件: Phase 5 · 03(Word2Vec),Phase 5 · 14(信息检索) 时间: ~60 分钟

问题

你有100万份文档。用户输入一个查询。你需要毫秒级返回前5个最相关的文档。你无法每次都运行LLM。你需要一个快速编码器,将查询和文档映射到向量,使语义相似的项目在向量空间中靠近。

这就是句子嵌入。2026年,模型选择是检索系统中最有影响力的单一决策。选错模型,你的RAG流水线在每个查询上都检索到错误的文档,无论下游LLM有多好。

概念

架构家族。

  • 双编码器(Sentence-BERT、E5、BGE)。 独立编码查询和文档。点积或余弦相似度评分。查询时快速,因为文档嵌入可以预计算。2026年默认。
  • 后期交互(ColBERT)。 独立编码但保留token级嵌入。评分是MaxSim:每个查询token找到最相似的文档token,求和。比双编码器更准确但更慢且存储更多。
  • 交叉编码器。 一起编码查询+文档。最准确但太慢无法用于初始检索。用作重排序器。

训练方法。

  • 对比学习(SimCSE、Sentence-BERT)。 正对(相似句子)拉近,负对(不相似句子)推远。SBERT在NLI对上训练:蕴含 = 正,矛盾 = 困难负。
  • 指令微调(E5、BGE)。 添加前缀如”query:“或”passage:“,使同一模型区分查询和文档。在标注数据上微调。
  • 知识蒸馏。 从交叉编码器教师向双编码器学生蒸馏。学生获得教师的排序质量,速度提升100倍。

2026年模型地图

模型维度最大长度训练数据MTEB排名
all-MiniLM-L6-v238425610亿对快速默认
bge-small-en-v1.538451210亿对小型最佳
bge-large-en-v1.5102451210亿对双编码器SOTA
e5-large-v2102451210亿对强通用
gte-Qwen2-7B-instruct358432768大规模整体SOTA
ColBERTv2128/token512MS MARCO检索SOTA

MTEB基准

大规模文本嵌入基准(MTEB)跨7个任务(分类、聚类、成对分类、重排序、检索、语义文本相似度、摘要)评估嵌入模型。56个数据集。排行榜在Hugging Face上持续更新。

困难负例挖掘

训练嵌入模型时,随机负例太简单。模型学不到细粒度区分。解决方案:困难负例挖掘。对每个查询,找到BM25或初始嵌入模型返回但不相关的文档。这些”困难负例”迫使模型学习更细粒度的语义区分。

构建它

步骤 1:使用Sentence-BERT

from sentence_transformers import SentenceTransformer

model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

embeddings = model.encode([
    "The cat sat on the mat",
    "A feline rested on the rug",
    "The stock market crashed today",
], normalize_embeddings=True)

from sklearn.metrics.pairwise import cosine_similarity
print(cosine_similarity(embeddings))

步骤 2:使用E5进行检索

model = SentenceTransformer("intfloat/e5-large-v2")

queries = ["query: What is machine learning?"]
docs = ["passage: Machine learning is a subset of artificial intelligence.", "passage: The weather is sunny today."]

q_emb = model.encode(queries, normalize_embeddings=True)
d_emb = model.encode(docs, normalize_embeddings=True)
scores = cosine_similarity(q_emb, d_emb)
print(scores)

注意 query:passage: 前缀。E5在训练时使用这些区分查询和文档。省略它们会降低检索质量。

步骤 3:微调嵌入模型

from sentence_transformers import InputExample, losses, SentenceTransformer

model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

train_examples = [
    InputExample(texts=["query: flight change", "passage: How to modify your booking"], label=1.0),
    InputExample(texts=["query: flight change", "passage: Weather forecast for today"], label=0.0),
]

train_dataloader = torch.utils.data.DataLoader(train_examples, shuffle=True, batch_size=16)
train_loss = losses.CosineSimilarityLoss(model)

model.fit(train_objectives=[(train_dataloader, train_loss)], epochs=3)

步骤 4:评估检索质量

def recall_at_k(retrieved_ids, relevant_ids, k=5):
    return len(set(retrieved_ids[:k]) & set(relevant_ids)) / len(relevant_ids) if relevant_ids else 0

使用它

场景选择
快速原型,通用all-MiniLM-L6-v2
生产检索,英语bge-large-en-v1.5 或 e5-large-v2
语言paraphrase-multilingual-MiniLM-L12-v2
检索质量ColBERTv2 + 重排
文档gte-Qwen2-7B-instruct (32k上下文)
自定义领域数据上微调

交付它

结果保存为 outputs/skill-embedding-picker.md

练习

  1. 简单 在10个查询-文档对上比较all-MiniLM-L6-v2和bge-small-en-v1.5。测量检索recall@5。
  2. 中等。领域特定数据上微调嵌入模型。与基础模型比较检索质量
  3. 困难。 实现ColBERT MaxSim评分。与双编码器余弦比较检索质量。测量延迟差异。

关键术语

术语通俗说法实际含义
编码独立编码查询文档独立编码评分
后期交互token匹配保留token嵌入,MaxSim评分。
交叉编码一起编码查询+文档一起编码。最准确,最慢。
MTEB嵌入基准规模文本嵌入基准,56个数据集。
困难负例棘手的反例BM25返回但不相关文档,用于训练

延伸阅读

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式