向量维度、距离函数,如何影响召回结果

很多“召回不准”,其实不是模型不行

在向量检索项目里,常见的抱怨包括:

  • “这个 embedding 好像不太行”

  • “换个模型试试?”

  • “是不是 TopK 太小了?”

 

但有一个问题,经常被直接跳过:

 

**我们到底是在一个什么样的“空间”里,

定义什么叫“相似”?**

 

向量检索的整个系统,

其实建立在两个非常底层、但经常被默认的选择之上:

  • 向量维度

  • 距离函数

 

而这两个选择,一旦定下:

 

**你就已经决定了:

哪些东西更容易被找出来,

哪些东西会被系统性忽略。**

 

先给一个必须先接受的结论(非常重要)

在展开之前,我先把全文最重要的一句话写出来:

 

**向量维度和距离函数,

不是“精度调节器”,

而是“相似性定义器”。**

 

如果你把它们当成“技术参数”,

而不是“世界观选择”,

那你几乎一定会被召回结果反复背刺。

 

第一层:向量检索,本质上是在一个“人为构造的几何世界”里生活

我们先把一件事说清楚。

 

向量检索并不是在“发现相似性”,

而是在:

 

**一个你亲手定义的空间里,

计算点与点之间的关系。**

 

这个空间的性质,来自于:

  • embedding 的训练目标

  • 向量维度

  • 距离函数

 

你可以把它理解成:

 

**你先决定了“世界长什么样”,

然后才问“谁离谁更近”。**

 

第二层:向量维度,决定了“相似性表达的自由度”

很多人对向量维度的直觉是:

 

“维度越高,信息越多,效果越好。”

 

这在某些条件下成立,

但在工程里,这句话非常危险

 

向量维度到底代表什么?

你可以把每一维理解为:

 

模型用来区分语义差异的一条“坐标轴”。

 

维度越多,意味着:

  • 可表达的差异类型越多

  • 空间越“稀疏”

  • 点之间的关系越复杂

 

但这并不意味着:

 

相似性会更可靠。

 

第三层:维度过低时,召回结果会“塌缩”

当向量维度太低时,常见的问题是:

  • 很多不太相关的内容

  被压在同一个方向上

  • 相似度分布过于集中

  • TopK 看起来“都差不多”

 

这会导致:

  • 召回缺乏区分度

  • 系统很难把真正相关的内容排到前面

 

从工程角度看,这种情况的风险是:

 

**模型看到了东西,

但看到的全是“泛泛相关”。**

 

第四层:维度过高时,召回结果会“失去直觉”

高维空间的问题,恰恰相反。

 

在高维空间中,一个非常经典但反直觉的现象是:

 

“距离集中”(distance concentration)。

 

简单说就是:

  • 在高维空间里

  • 最近的点和最远的点

  • 距离差异会变得越来越小

 

这意味着什么?

 

意味着:

  • 排名对噪声非常敏感

  • 微小扰动,就会改变 TopK

  • 召回结果稳定性下降

 

你会发现:

  • 同一个 query

  • 不同批次召回的结果差异很大

 

这不是系统抖动,

而是高维空间的自然后果

 

第五层:维度,其实在决定“你更容易犯哪种错”

这是一个非常重要、但很少被这样表述的点。

 

  • 维度偏低

 

  * 更容易召回“主题相关但不够具体”的内容

  * 风险偏向:证据不足

 

  • 维度偏高

 

  * 更容易召回“看似很近但语义不稳”的内容

  * 风险偏向:不稳定排序 + 冲突证据

 

换句话说:

 

**向量维度,不是在变好或变坏,

而是在改变系统的错误形态。**

 

第六层:距离函数,才是真正定义“什么叫近”的地方

如果说向量维度决定了“空间大小”,

那距离函数决定的就是:

 

**在这个空间里,

什么样的差异是重要的。**

 

常见的距离函数包括:

  • L2(欧氏距离)

  • Cosine(余弦相似度)

  • Dot Product(内积)

 

它们看起来只是数学公式不同,

但在工程里,含义完全不一样。

 

picture.image

不同距离函数 → 不同相似性观

 

第七层:L2 距离 —— 把“幅度”和“方向”一起算进去

L2 距离关心的是:

 

两个向量在空间中的“绝对距离”。

 

这意味着:

  • 向量长度(norm)会影响相似度

  • 不只是方向,还包括“强度”

 

在以下情况下,L2 往往表现不稳定:

  • embedding 未归一化

  • 不同文本长度差异大

  • 模型对某些输入给出“更强激活”

 

你可能会发现:

 

**不是最相关的内容排在前面,

而是“数值更大”的内容。**

 

第八层:Cosine 相似度 —— 忽略幅度,只看方向

Cosine 相似度关注的是:

 

两个向量指向是否一致。

 

它天然做了一件事:

  • 把向量长度的影响抹掉

  • 专注于“语义方向”

 

这也是为什么:

  • 大多数文本检索

  • 默认更偏好 Cosine

 

但 Cosine 也有自己的代价:

  • 它忽略了“强相关 vs 弱相关”的差异

  • 很多“勉强相关”的内容

  可能被放到相似的位置

 

工程上的常见后果是:

 

召回更稳,但区分度不够。

 

第九层:Dot Product —— 把“自信度”也算进相似性

Dot Product 本质上是:

 


cosine × 向量长度

 

这意味着:

  • 方向一致 + 激活强

  → 非常高的相似度

 

这在某些 embedding 设计中是刻意为之的

  • 模型用向量长度表示“自信度”

  • dot product 用来放大这种差异

 

但在通用检索系统中,这也很危险:

  • 某些内容会被系统性偏好

  • 长文档 / 高频表达更容易被召回

 

你会看到一种现象:

 

**召回结果“看起来很确定”,

但并不一定更适合当前问题。**

 

第十层:向量维度 × 距离函数,是一个“耦合选择”

很多人犯的一个错误是:

 

只讨论维度,

或者只讨论距离函数。

 

但在真实系统中,这两者是强耦合的

 

举几个典型组合:

  • 高维 + Cosine

 

  * 稳定,但排序区分度有限

 

  • 高维 + Dot Product

 

  * 排名极不稳定,容易放大噪声

 

  • 低维 + L2

 

  * 空间塌缩风险高

 

这也是为什么:

 

**同一个 embedding,

在不同向量库配置下,

表现可以天差地别。**

 

picture.image 维度 × 距离函数 组合效应矩阵

 

第十一层:为什么“换个距离函数”,TopK 会完全变样

这是一个很多人亲眼见过、但说不清原因的现象。

 

原因其实很简单:

 

TopK 排名是距离函数的直接产物。

 

你一旦换了距离函数,相当于:

  • 换了一套“价值排序规则”

  • 换了一种“相似性定义”

 

于是你看到的不是:

  • 结果略有变化

 

而是:

 

整个召回世界被重新排序。

 

这不是 bug,

而是系统按你的新规则,

在“忠实执行”。

 

第十二层:一个极简示意,理解“世界观切换”

 

 


# 同一组向量

query = q

vectors = docs

 

# 不同距离函数

rank_l2 = sort_by_l2(query, vectors)

rank_cos = sort_by_cosine(query, vectors)

rank_dot = sort_by_dot(query, vectors)

 

 

这三行代码的差异,

不是“计算方式不同”,

而是:

 

**你在问三个不同的问题:

 

  • 谁绝对最近

  • 谁方向最像

  • 谁又像又“自信”**

 

第十三层:什么时候这些选择开始“主导系统行为”

你可以留意一些非常工程化的信号:

  • 调 TopK 已经救不了效果

  • rerank 越来越重

  • 同类 query 结果差异极大

  • 系统对输入微调异常敏感

 

这些都在暗示:

 

**问题已经不在“召回多少”,

而在“什么被认为相似”。**

 

一个非常实用的判断问题(强烈建议)

在你准备换 embedding 或距离函数之前,问自己一句话:

 

**我现在更怕哪一种错误?

 

  • 找不到该找的

 

  • 找到一堆“看起来像但用不了的”**

 

  • 前者 → 关注维度表达能力

 

  • 后者 → 重新审视距离函数

 

这个问题,比任何 benchmark 都真实。

 

很多团队在向量检索效果不稳定时,第一反应是换 embedding 模型,却忽略了向量维度和距离函数本身就在重塑召回空间。用LLaMA-Factory online对不同向量配置下的召回与生成结果进行对照,更容易看清:问题是出在“模型能力”,还是出在“相似性定义”。

 

总结:你不是在调参数,而是在定义“相似的意义”

我用一句话,把这篇文章彻底收住:

 

**向量维度和距离函数,

不是技术细节,

而是你告诉系统:

这个世界里,

什么值得被靠近。**

 

当你开始:

  • 把向量空间当成设计对象

  • 把召回结果当成几何后果

  • 在调参数前先想“我想放大哪种相似”

 

你才真正开始工程化地使用向量数据库

0
0
0
0
评论
未登录
暂无评论