第六章:Embedding 原理与技术演进
6.1 Embedding 到底在做什么
可以先记住一句话:把文本映射成一个稠密向量,使得语义相近的文本在向量空间中距离更近。
这句话里有两个关键点,缺一个都不完整:
- 稠密:几百到几千维的实数向量,每一维没有独立的可解释含义,语义分布在整个向量上;
- 语义相近 → 距离近:这是靠训练目标刻意造出来的性质,不是自动出现的。
第二点是理解 Embedding 的关键。「猫」和「狗」的向量之所以接近,不是因为模型显式存着「它们都属于动物」这条知识,而是因为训练时它们大量出现在相似的上下文中,参数被优化成给出相近的表示。
6.2 为什么 RAG 需要它
关键词检索只能匹配字面。用户问「怎么请年假」,而文档写的是「带薪休假申请流程」——没有一个词重合,关键词检索直接失效。
Embedding 把两者都映射到「休假申请」这个语义区域,从而能匹配上。
这就是 RAG 用向量检索的根本原因:它跨越了「同一个意思的不同说法」这道鸿沟。
但也要提前说明:向量检索并非全面优于关键词检索。精确的产品型号、错误码、人名、专有术语,关键词检索反而更可靠——这是第十一章要展开的内容。
6.3 技术演进:四代
flowchart LR
G1[第一代
静态词向量] --> G2[第二代
上下文词向量]
G2 --> G3[第三代
句向量 双塔]
G3 --> G4[第四代
后期交互 多向量]
按代际看,更容易理解为什么后面的架构会变成这样。
6.3.1 第一代:静态词向量
代表:Word2Vec、GloVe、FastText。
核心思想:一个词的含义由它周围经常出现的词决定。通过预测上下文(或用上下文预测中心词)来学习词向量。
贡献:第一次让「语义相似度」变成可以计算的数值。
致命局限:一词一向量,无法处理多义词。
「苹果」在「吃苹果」和「苹果发布会」里是完全不同的意思,但静态词向量给它同一个表示——这个向量是两种含义的妥协平均,对两边都不准。
6.3.2 第二代:上下文相关的词向量
代表:ELMo、BERT。
核心突破:同一个词在不同句子里有不同的向量。BERT 通过双向 Transformer 编码整个句子,每个 Token 的表示都依赖于它的具体上下文。
多义词问题就此解决。
这里需要单独区分一个常见误解:
BERT 不能直接用于 RAG 检索。
原因有两个:
第一,原生 BERT 的句向量质量差。 直接取 [CLS] 位置的向量或对所有 Token 向量做平均,得到的句向量在语义相似度任务上表现很差——因为 BERT 的预训练目标(掩码语言建模)根本没有优化句子级的相似度。
第二,也是更致命的:交互式架构在检索场景下不可用。
BERT 判断两句话是否相似的标准做法,是把两句话拼在一起送进模型(cross-encoder)。这意味着:
flowchart TB
subgraph CE[Cross-Encoder 交互式]
Q1[Query] --> CAT[拼接]
D1[文档] --> CAT
CAT --> M1[模型] --> S1[相似度分数]
N1[必须对每个文档算一次
百万文档 = 百万次推理]
end
subgraph BE[Bi-Encoder 双塔]
Q2[Query] --> ME1[模型] --> V1[Query 向量]
D2[文档] --> ME2[模型] --> V2[文档向量
离线预先算好]
V1 --> SIM[向量距离]
V2 --> SIM
N2[文档向量离线算好
在线只算 Query]
end
百万级文档库中,cross-encoder 每次查询要做百万次模型推理,完全不可行。 这就是为什么必须有第三代。
6.3.3 第三代:专门优化的句向量模型(双塔)
代表:Sentence-BERT、SimCSE、BGE、E5、GTE、Qwen3-Embedding。
两个关键改进:
改进一:架构改成双塔(bi-encoder)。 Query 和文档分别独立编码,各自得到一个向量,用向量距离衡量相似度。这样文档向量可以在离线阶段全部算好并建索引,在线只需算一次 Query 向量。
这是让向量检索在工程上可行的决定性一步。
改进二:训练目标改成对比学习。 用「相似句子对」作为正样本、「不相似句子对」作为负样本,直接优化「相似的靠近、不相似的远离」这个目标。
SimCSE 展示了一个非常简洁的做法:同一个句子过两次模型,因为 Dropout 是随机的,会得到两个略有差异的向量,把这一对当作正样本;同一批次里的其他句子作为负样本。不需要人工标注就能大幅提升句向量质量。
这一代是当前 RAG 的标准配置。
代价:双塔的 Query 和文档从未"见面",无法建模细粒度的词级交互,所以精度低于 cross-encoder。
这正是 RAG 采用「双塔粗排 + cross-encoder 精排」两阶段架构的根本原因——用双塔的速度缩小范围,用 cross-encoder 的精度定顺序。第一章 1.5 节的漏斗结构,在这里得到了技术上的解释。
6.3.4 第四代:后期交互与多向量
代表:ColBERT、ColBERTv2、ColPali。
核心思想:在「单向量双塔」和「拼接式 cross-encoder」之间取中间路线。
文档不再压缩成一个向量,而是保留每个 Token 的向量。检索时计算 Query 每个 Token 与文档所有 Token 向量的最大相似度,再求和。
flowchart TB
A[单向量双塔] -->|精度低 速度快| B[后期交互 多向量]
B -->|精度接近 速度可接受| C[Cross-Encoder]
A -.->|文档压成 1 个向量| A1[细粒度信息丢失]
B -.->|文档保留 N 个向量| B1[存储成本高 N 倍]
C -.->|Query 文档拼接| C1[无法离线预计算]
优点:保留了词级匹配信息,精度显著高于单向量,同时文档表示仍可离线预计算。
缺点:存储开销是单向量的几十倍,且需要专门的索引支持。
第四代的一个重要衍生是把它用到视觉上:直接对文档页面图像做多向量嵌入,绕开 OCR 和版面解析(第三章 3.5 节讨论过)。
6.4 相似度怎么算
| 度量 | 说明 | 备注 |
|---|---|---|
| 余弦相似度 | 只看方向不看长度 | RAG 最常用 |
| 点积 | 同时受方向和模长影响 | 归一化后与余弦等价 |
| 欧氏距离 | 空间直线距离 | 归一化后与余弦单调等价 |
实践要点:多数 Embedding 模型输出的向量已经归一化,此时三者在排序上等价,选哪个不影响结果。但必须与向量库的索引配置保持一致——建库时用点积、查询时用余弦,会得到错误的排序。
6.5 使用时的几个硬性约束
6.5.1 建库和查询必须用同一个模型
不同模型的向量位于不同的语义空间,跨空间计算距离没有任何意义,且不会报错——只会静默地返回一堆不相关结果。
推论:换 Embedding 模型 = 全量重建索引。 这是选型时必须提前考虑的成本。
6.5.2 注意输入长度上限
多数模型有最大输入长度(常见 512 Token),超出部分被静默截断。第四章已经强调过,这里再次提醒:这是最隐蔽的一类 bug。
6.5.3 注意指令前缀
不少现代 Embedding 模型(E5、BGE、Qwen3-Embedding 系列)要求给 Query 加特定前缀(如 query: / 为这个句子生成表示以用于检索相关文章:),而文档不加或加另一个前缀。
不按模型卡的要求加前缀,会明显掉点。 这是实践中极常见的低级错误。
6.5.4 对称与非对称检索是两回事
| 类型 | 场景 | 说明 |
|---|---|---|
| 对称检索 | 句子 vs 句子 | 两侧长度和形式相近,如相似问题匹配 |
| 非对称检索 | 短 Query vs 长文档 | RAG 的典型场景 |
RAG 需要的是非对称检索能力。 用在对称任务上训练的模型做 RAG,效果会打折扣——这也是为什么不能只看模型在通用相似度榜单上的分数。
6.6 常见错误
6.6.1 说「BERT 就能做 RAG 检索」
原生 BERT 句向量质量差,且 cross-encoder 架构在大规模检索中不可用。这也是检索架构里最容易混淆的一点。
6.6.2 不知道为什么需要双塔
答不出「文档向量必须能离线预计算」,说明没理解检索的工程约束。
6.6.3 把 Embedding 模型和 Rerank 模型混为一谈
前者是双塔、离线可预计算;后者是 cross-encoder、必须在线成对计算。架构完全不同。
6.6.4 忘记加指令前缀
模型卡明确要求的前缀不加,会明显掉点。
6.6.5 混用不同模型的向量
不报错,但结果全错。
6.6.6 只记模型名不讲演进逻辑
「有 Word2Vec、BERT、BGE」这种罗列没有信息量。要说清每一代解决了上一代的什么问题。
6.7 本章总结
- Embedding 把文本映射为稠密向量,让语义相似度可计算;这个性质来自训练目标,不是自动出现的;
- 第一代静态词向量解决了「语义可计算」,但一词一向量、无法处理多义;
- 第二代上下文词向量(BERT)解决了多义问题,但句向量质量差 + cross-encoder 架构无法用于大规模检索;
- 第三代双塔句向量模型是当前 RAG 标配:架构上可离线预计算,训练上用对比学习直接优化相似度;
- 第四代后期交互(ColBERT 系)保留 Token 级向量,精度更高但存储成本高几十倍;其视觉版本可绕开文档解析;
- 两阶段架构的技术根源:双塔快但粗,cross-encoder 准但慢,所以粗排精排分离;
- 硬性约束:同一模型建库查询、注意长度上限、按模型卡加指令前缀、区分对称与非对称检索。
参考资料
- Efficient Estimation of Word Representations in Vector Space
- BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
- Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks
- SimCSE: Simple Contrastive Learning of Sentence Embeddings
- Dense Passage Retrieval for Open-Domain Question Answering
- ColBERTv2: Effective and Efficient Retrieval via Lightweight Late Interaction
- ColPali: Efficient Document Retrieval with Vision Language Models