Day 1|向量检索的盲区:Embedding 单独使用时为什么会搜不准?

每个写过 RAG 的工程师都踩过这个坑:用户问”苹果公司2025年Q3财报”,召回的却是”苹果种植技术”。明明语义相近,却南辕北辙。本文深入剖析向量检索失效的根本原因,从算法机制上解释为什么 Embedding 单独使用有无法克服的盲区。


一、真实案例:一个搜索引发的”水果灾难”

让我们从一个具体的生产故障开始:

搜索词"苹果公司2025年Q3财报"
预期结果:苹果公司财务报表、营收数据、分析师解读
实际召回 Top-5

  1. score=0.91 — “苹果公司新款 iPhone 16 发布会,定档9月” ❌
  2. score=0.89 — “苹果手机电池续航横评,iPhone 16 Pro Max 排名第三” ❌
  3. score=0.87 — “2025年春季水果丰收:苹果主产区产量增长12%” ❌❌
  4. score=0.86 — “Apple Park 游客参观预约全攻略” ❌
  5. score=0.85 — “Q3 2025 财报解读:服务业务收入创历史新高” ✅

为什么水果相关内容排到了前面? 这个问题背后有四层原因,层层递进。


二、第一层:Bi-Encoder 的”信息隔离”——各自为战的双塔困境

2.1 双塔架构的工作方式

当前几乎所有向量检索都使用 **Bi-Encoder(双编码器)**架构:

1
2
3
4
5
6
7
8
9
10
11
12
13
查询 Q:"苹果公司2025年Q3财报"

查询编码器

向量 q ∈ R⁷⁶⁸ (独立生成)

文档 D₁:"苹果公司新款iPhone发布会"

文档编码器

向量 d₁ ∈ R⁷⁶⁸ (独立生成)

q · d₁ = 相似度分数(余弦相似度)

关键问题:查询编码器和文档编码器是完全独立的两个 BERT,训练时它们之间没有任何信息流通

2.2 信息隔离的后果

在 BERT 的自注意力机制中:

1
2
3
4
Bi-Encoder 的注意力范围:
- q 只能看到 q 自己的 token 序列
- d 只能看到 d 自己的 token 序列
- 两者在编码阶段没有任何交互

这就像两个素未谋面的评委:评委 A 只看过查询的剧本,评委 B 只看过文档的剧本,两人独立打分,从未交流过。

具体例子

1
2
3
4
5
6
7
8
9
查询:"苹果公司Q3财报"
分词:[苹果, 公司, Q, 3, 财报]
编码:"苹果" → 位置向量 P₁ + 词向量 V₁ → 注意力计算 → 仅与[公司,Q,3,财报]交互
"公司" → 位置向量 P₂ + 词向量 V₂ → 注意力计算 → 仅与[苹果,Q,3,财报]交互
...(每个词只能看到查询内部的其他词)

文档:"苹果丰收了"
分词:[苹果, 丰收, 了]
编码:"苹果" → 注意力计算 → 仅与[丰收,了]交互

“苹果”在这个查询中和”公司/Q/财报”一起出现,所以在向量空间中靠近公司、Q3、财报的方向。

“苹果”在这个文档中和”丰收/了”一起出现,所以在向量空间中靠近农业的方向。

两个”苹果”在训练时因为上下文不同,被拉向了不同的向量方向。但这种”方向”是相对的——“苹果”的语义取决于它周围的词,而 Bi-Encoder 在编码查询和编码文档时,永远看不到对方的信息

2.3 为什么水果”苹果”还能排到前面?

因为训练语料中”苹果”大多数时候指水果,所以水果方向的向量非常强健。”苹果公司”的”苹果”虽然语义不同,但在向量空间中只是偏移了一小段,方向的差异不够大,水果方向的向量和公司方向的向量之间的余弦相似度依然很高。

这就好比:一个在全国水果比赛上拿过冠军的苹果,和一个在公司比赛中表现平平的苹果,在评分体系里都叫”苹果”,很难区分。


三、第二层:Embedding 空间的各向异性——向量被”挤”在一起

3.1 什么是各向异性(Anisotropy)

训练好的 Embedding 向量空间并非均匀分布,而是存在严重的各向异性问题

1
2
3
4
5
6
7
8
9
10
11
理想状态(各向同性):
所有方向的向量分布密度相同,向量均匀填充整个空间

实际情况(各向异性):
常见词向量占据空间中心区域,方向密集
罕见词/专业词向量被"挤"到边缘角落,方向稀疏

导致问题:
- "苹果"(常见词)向量很大
- "Q3"(专业词)向量很小
- 两者不在同一个"量级",余弦相似度被 magnitude 误导

3.2 具体表现

向量范数(长度)语义类型
苹果8.7常见词 → 向量很长,方向明确
GAAP2.1专业术语 → 向量很短,容易被忽略
Q3 20253.4缩写 → 训练不足,向量方向模糊

结果:在比较”苹果公司Q3财报”和”苹果丰收了”时,两个查询中的”苹果”虽然方向略有差异,但 magnitude 的差异掩盖了方向的差异,水果方向的文档依然得到高分。


四、第三层:余弦相似度的本质局限——方向≠语义

4.1 余弦相似度衡量的是什么

1
cosine(q, d) = (q · d) / (||q|| × ||d||)

几何意义:两个向量夹角的余弦值。值 = 1 表示方向完全相同,值 = 0 表示正交。

问题所在

1
2
3
4
5
6
向量 q = [1.0, 0.0]  (x轴正方向)
向量 d₁ = [0.9, 0.1] (几乎在x轴,方向几乎相同)
向量 d₂ = [0.7, 0.7] (45度方向)

cosine(q, d₁) = 0.995 ← 方向几乎相同
cosine(q, d₂) = 0.990 ← 方向有差异,但分数差异极小

余弦相似度对方向的微小差异极不敏感,但在 RAG 场景中,方向的微小差异往往代表语义的巨大差异。

4.2 语义相似度 ≠ 相关性

这是最关键的思想转变:

语义相似(similar):两个文本谈论的是否是同一个主题
相关性(relevant):两个文本是否能共同回答用户的问题

1
2
3
4
查询:"苹果公司2025年Q3财报"
文档A:"苹果公司Q3营收949亿元,服务业务创新高" → 相似✓ 相关✓
文档B:"2025年水果丰收:苹果主产区产量增长" → 相似✓ 相关✗
文档C:"苹果新款iPhone 16发布会实录" → 相似✓ 相关✗

三者都与”苹果”相关,但只有 A 真正能回答用户的财务问题。Bi-Encoder 无法区分相似和相关——因为训练目标是预测语义相似性,而不是预测答案相关性


五、第四层:HNSW 近似最近邻的误差——底层算法也有代价

5.1 为什么不用精确检索

向量数据库(Qdrant/Milvus)面对海量向量时,不可能做精确的线性扫描(O(N) 复杂度)。采用 HNSW(Hierarchical Navigable Small World) 分层图索引,将检索复杂度降到 O(log N)。

5.2 HNSW 的近似误差

1
2
3
4
5
6
精确检索:
查询 → 计算与所有 N 个向量的距离 → 取 Top-1 → 真实最近邻

HNSW 近似检索:
查询 → 从顶层入口沿图搜索 → O(log N) 步 → 返回近似最近邻
代价:可能漏掉真正的最近邻,或者返回方向"差不多"但语义不相关的文档

5.3 具体例子

1
2
3
4
5
构建 HNSW 图时:
- "苹果种植技术" 和 "苹果公司财报" 在向量空间中相距较远(方向不同)
- 但水果方向的向量簇和公司方向的向量簇都靠近"苹果"这个词的中心
- 图的边连接了相似的节点,水果簇和公司簇之间可能有边,也可能没有边
- 搜索时从某个入口进入,如果水果簇入口更近,可能先遍历水果簇

结果:HNSW 的搜索路径不是全局最优的,而是”走得通就算”的近似图遍历,可能漏掉真正的相关文档。


六、思想总结:为什么没有银弹

理解了这四层原因,我们得到一个核心认识:

向量检索的盲区是结构性的,无法通过单点优化彻底解决。

问题层次根因单靠 Embedding 能解决吗
信息隔离Bi-Encoder 训练目标
各向异性训练数据分布不均
方向≠语义余弦相似度的本质局限
HNSW 近似误差工程优化的取舍

这就是为什么我们需要混合检索 + 重排序的组合方案

  • 混合检索:引入关键词检索(BM25)弥补精确匹配的缺失
  • 重排序:引入 Cross-Encoder 做精排,在小范围(Top-100)内实现真正的交互式语义判断
  • GraphRAG:引入知识图谱,从文本块层面建模实体关系,弥补语义漂移

七、第二天预告

理解了”为什么 Embedding 不够”,下一篇文章我们来看:如何用混合检索(Hybrid Search)弥补向量检索的盲区。核心问题:

  1. BM25/SPLADE 的算法原理是什么?它凭什么能补向量检索的缺?
  2. 双路召回时,分数怎么融合?RRF 为什么有效?
  3. Qdrant 原生混合检索的 alpha 参数怎么调?

参考来源:微软 GraphRAG 官方文档(2026-04),智源研究院 BGE-Reranker-v2-m3 技术报告(2026-03),ACM Computing Surveys — “Neural Information Retrieval: A Literature Survey”(2024)