在 RAG 中,Cosine Similarity(余弦相似度)和 L2 Distance(欧氏距离)通常怎么选择?
在 RAG(检索增强生成)系统中,选择 Cosine Similarity(余弦相似度) 还是 L2 Distance(欧氏距离),主要取决于你使用的 Embedding 模型(嵌入模型) 以及数据的特性。
这里有一个简单的结论(TL;DR):
在绝大多数 RAG 文本检索场景下,首选 Cosine Similarity(或者归一化后的 Dot Product)。
以下是详细的决策逻辑和背后的原理:
1. 核心区别:关注“方向”还是“距离”?
Cosine Similarity (余弦相似度):
- 关注点:向量在空间中的方向(角度)。
- 含义:它衡量两个向量在语义上是否“指向同一个主题”。
- 特点:它对向量的长度(Magnitude)不敏感。
- 场景:在文本语义中,一篇关于“苹果公司”的短文和一篇关于“苹果公司”的长文,虽然词数不同(向量长度可能不同),但主题一致,余弦相似度会很高。
L2 Distance (欧氏距离):
- 关注点:向量端点在空间中的直线距离。
- 含义:它同时受方向和长度的影响。
- 特点:如果两个向量方向一致但长度差异巨大,欧氏距离会认为它们不相似。
- 场景:如果向量未归一化,长文本和短文本即使语义相同,欧氏距离也可能很大(被判定为不相关)。
2. 关键因素:归一化 (Normalization)
这是选择过程中最重要的一点:如果向量经过了归一化(Normalized,即模长为 1),那么 Cosine 和 L2 在数学上是等价的。
- 数学关系:
对于归一化向量 和 (即 ): - 结论:
如果你的 Embedding 向量已经归一化了,使用 Cosine 还是 L2,检索出来的排序结果(Ranking)是完全一样的。
3. 如何做具体选择?
尽管归一化后两者等价,但在工程实践中,建议遵循以下标准:
A. 看 Embedding 模型的训练方式(最重要)
你需要查阅你使用的 Embedding 模型(如 OpenAI text-embedding-3, BGE, BERT 等)在训练时使用的是哪种度量损失函数。
OpenAI Embeddings / Cohere / Most SBERT models:
- 这些模型通常使用 Cosine Similarity 或 Dot Product 进行训练(Contrastive Loss)。
- 推荐:Cosine Similarity。
- 注意:OpenAI 的向量输出通常已经是归一化的,所以他们经常建议直接用 Dot Product(计算更快)来代替 Cosine。
少数特定模型:
- 如果模型专门针对 L2 距离进行了优化(例如某些专门的度量学习模型),则应使用 L2。但在 NLP RAG 领域非常少见。
B. 看向量数据库 (Vector DB) 的性能优化
不同的向量数据库(如 Milvus, Pinecone, Weaviate, pgvector)对不同的度量方式有不同的索引优化。
Inner Product (IP) / Dot Product:
- 这是计算最快的方式(简单的矩阵乘法)。
- 在向量数据库中,如果你确定向量是归一化的,通常选择 IP (Inner Product) 模式。这在数学上等同于 Cosine Similarity,但计算开销略低(省去了除以模长的步骤)。
L2 Distance:
- 计算通常涉及平方和开方(虽然检索时可以只比平方),在某些硬件指令集下可能比点积稍慢,或者索引构建方式不同。
C. 看数据类型
- 文本 (Text):语义主要由方向决定。文本长度会导致向量模长变化(如果未归一化),这种模长通常是噪音。必须用 Cosine。
- 图像 (Images):如果是人脸识别等特征匹配,有时模长代表图像的亮度或对比度,但在现代多模态模型(如 CLIP)中,图像和文本对齐依然主要靠 Cosine。
- 其他数据:如果你在做异常检测,且向量的模长代表了某种“强度”或“严重程度”,那么 L2 可能更合适。
4. 常见误区与最佳实践
误区:
"我觉得 L2 距离更符合物理直觉,所以我要用 L2。"
现实:
在高维空间(High-dimensional space,如 768 维或 1536 维)中,"距离"的直觉往往会失效(维度灾难)。而基于角度的 Cosine Similarity 在高维语义空间中表现更稳定。
最佳实践流程:
- 检查模型:使用的是 OpenAI、HuggingFace (MTEB 排行榜模型) 吗?
- 如果是 -> 99% 的情况选择 Cosine。
- 数据预处理:
- 在存入向量数据库前,务必对向量进行 L2 归一化(OpenAI 等 API 返回的通常已归一化,但如果是自己跑 BERT 模型,记得手动
normalize())。
- 在存入向量数据库前,务必对向量进行 L2 归一化(OpenAI 等 API 返回的通常已归一化,但如果是自己跑 BERT 模型,记得手动
- 数据库配置:
- 如果数据库支持
Cosine,选Cosine。 - 如果数据库支持
IP(Inner Product) 且你的向量已归一化,选IP(通常性能最好)。 - 尽量避免在文本 RAG 中使用
L2,除非你有非常明确的理由。
- 如果数据库支持
总结
| 特性 | Cosine Similarity (余弦) | L2 Distance (欧氏) |
|---|---|---|
| 侧重点 | 语义方向 (Topic) | 绝对位置 (Magnitude + Direction) |
| 文本 RAG 适用性 | 高 (标准做法) | 低 (除非数据极其特殊) |
| 归一化后表现 | 与 L2 排序一致 | 与 Cosine 排序一致 |
| 推荐配置 | 选 Cosine 或 IP (若已归一化) | 仅在非归一化且模长有意义时使用 |