3710 字
19 分钟
01 向量与余弦相似度:AI 如何判断"意思相近"

复习文档 · ADHD友好 · 从零开始


🔧 准确术语速查#

术语准确含义本章对应
Vector向量,一组有方向和长度的数字[3, 2]
Component分量,向量里的每个数字32
Dot product点积,逐位相乘再求和a1*b1 + a2*b2
Norm向量长度,多维勾股定理sqrt(x^2 + y^2)
Cosine similarity余弦相似度,比较方向接近程度dot / (norm_a * norm_b)
Normalization归一化,消除尺度影响除以长度,保留方向

一、先记住这张速查表#

概念一句话类比
向量一根箭,等于一个列表/元组去超市路线:[向东3步, 向北2步]
分量列表里每个数字每个方向各走几步
平方自己乘自己3² = 3×3 = 9
开根号平方的反操作√9 = 3(因为3×3=9)
勾股定理横²+竖²=对角线²房间宽3长4,对角线=5
norm多维勾股定理,量箭的长度所有分量平方加起来再开根号
点积逐位相乘再求和两根箭在同上方向的”重叠量”
余弦相似度点积/(长度×长度),削掉长度比方向只看口味比例,不看吃多少

二、从零开始:向量是什么#

向量 = 一根箭 = 一个列表
vec_a = [3, 2]
意思是:向右走3步,向上走2步
画出来就是一根从原点出发的箭
2 ↑
│ ● ← 箭头
│╱
1 │
─────┼──────3──→
0 1 2 3
类比:
去超市的路线 = [3, 2]
第1个分量(3) = 向东走3条街
第2个分量(2) = 向北走2条街
去医院的路线 = [1, 4]
第1个分量(1) = 向东走1条街
第2个分量(4) = 向北走4条街
两根箭指向不同方向 = 两句话说的是不同内容
关键:Embedding模型生成的向量维度永远固定!
模型输出 1024 维 → 不管你输入什么句子,输出永远是1024个数字
模型输出 1536 维 → 永远是1536个数字
维度多 = 描述更精细 = 足以区分不同语义

三、平方和开根号#

平方 = 自己乘自己#

3² = 3 × 3 = 9
2² = 2 × 2 = 4
0.9² = 0.9 × 0.9 = 0.81
(-3)² = (-3) × (-3) = 9 ← 负数平方也变正数!

开根号 = 平方的反操作#

√4 = 2 因为 2×2=4
√9 = 3 因为 3×3=9
√25 = 5 因为 5×5=25
√2 ≈ 1.414 因为 1.414×1.414≈2
平方 = "放大":3 → 3×3 → 9
开根号 = "还原":9 → "谁×自己=9" → 3

注意区分!开根号 ≠ 除法#

开根号:√9 = 3 (问谁×自己=9)
除法: 9÷3 = 3 (把9分成3份)
数字碰巧一样,但操作完全不同!
验证:√15 ≈ 3.87,但 15÷3 = 5
→ 3.87 ≠ 5,显然不是一回事

四、勾股定理 = 量对角线#

一个房间宽3米、长4米
从左下角走到右上角的对角线有多远?
● ← 右上角
╱│
对角线╱ │4米(竖边)
╱ │
左下角 ●───┘
3米(横边)
对角线 = √(横边² + 竖边²)
= √(3² + 4²)
= √(9 + 16)
= √25
= 5米
一句话记一辈子:
横² + 竖² = 对角线²

五、norm = 多维勾股定理 = 量箭的长度#

2维向量:norm = √(分量1² + 分量2²)
vec_a = [3, 2]
norm = √(3² + 2²) = √(9+4) = √13 ≈ 3.61
横着走了3步,竖着走了2步
箭的长度 = 3.61步
5维向量:norm = √(分1² + 分2² + 分3² + 分4² + 分5²)
vec = [0.9, 0.8, 0.7, 0.1, 0.2]
norm = √(0.81 + 0.64 + 0.49 + 0.01 + 0.04)
= √(1.99)
≈ 1.41
逻辑完全一样!只是加了5个数字而不是2个
1024维也一样:√(分1² + 分2² + ... + 分1024²)
维度再多,本质不变
就是勾股定理的扩展版

六、点积 = 逐位乘再求和#

A = [3, 2]
B = [2.8, 1.9]
点积 = 3 × 2.8 + 2 × 1.9
= 8.4 + 3.8
= 12.2
步骤拆解:
第1步:同一位置的两个数字相乘
位置0:3 × 2.8 = 8.4
位置1:2 × 1.9 = 3.8
第2步:所有乘积加起来
8.4 + 3.8 = 12.2 → 点积
乘 = 该方向上两箭的重叠程度(都强→乘积大)
加 = 所有方向的总重叠量
5维向量也一样:
A = [0.9, 0.8, 0.7, 0.1, 0.2]
B = [0.85, 0.75, 0.65, 0.15, 0.25]
点积 = 0.9×0.85 + 0.8×0.75 + 0.7×0.65 + 0.1×0.15 + 0.2×0.25
= 0.765 + 0.6 + 0.455 + 0.015 + 0.05
= 1.885
逻辑完全一样!只是乘了5次而不是2次

注意:点积不能单独判断相似性!#

A = [3, 2] 长度 ≈ 3.61
B = [2.8, 1.9] 长度 ≈ 3.38 方向一致
点积 = 12.2
C = [100, 66.7] 长度 ≈ 121 方向也一致
点积 = 433.4
单看点积:12.2 vs 433.4 → 差很多!
但A vs B 和 A vs C 方向其实一样!
→ 点积混了"长度"信息,必须削掉

七、余弦相似度 = 削掉长度比方向 = 最终答案#

完整流程三步:
余弦相似度 = 点积 / (norm(A) × norm(B))
= 逐位乘再求和 / (A长度 × B长度)
= 削掉长度,只剩方向

走一个完整例子#

A = [3, 2] ← "代码质量"
B = [2.8, 1.9] ← "程序维护"
C = [0.5, 4] ← "天气"
步骤1:算长度(norm = 勾股定理)
norm(A) = √(3²+2²) = √13 ≈ 3.61
norm(B) = √(2.8²+1.9²) = √11.45 ≈ 3.38
norm(C) = √(0.5²+4²) = √16.25 ≈ 4.03
步骤2:算重叠(点积 = 逐位乘再求和)
dot(A,B) = 3×2.8 + 2×1.9 = 8.4 + 3.8 = 12.2
dot(A,C) = 3×0.5 + 2×4 = 1.5 + 8 = 9.5
步骤3:削掉长度得相似度
A vs B = 12.2 / (3.61 × 3.38) = 12.2 / 12.21 ≈ 1.00 ✅
A vs C = 9.5 / (3.61 × 4.03) = 9.5 / 14.49 ≈ 0.66

结果解读#

相似度含义例子
~1.0方向完全一致”代码质量” vs “程序维护”
0.8-0.9非常相似
0.6-0.7比较相似”代码质量” vs “天气”(不同,但有微弱关联)
0.3-0.5有点关系
<0.3基本无关
0完全无关垂直方向(手电筒照墙90度)

八、三步完整对比图#

A向量 B向量
[3,2] [2.8,1.9]
│ │
▼ ▼
┌──────────┐ ┌──────────────┐
步骤1 │ 勾股定理 │ │ 勾股定理 │
(量长度) │norm(A)= │ │ norm(B)= │
│√(3²+2²) │ │ √(2.8²+1.9²)│
│≈ 3.61 │ │ ≈ 3.38 │
└──────────┘ └──────────────┘
│ │
└───────┬───────┘
┌───────────────────────────┐
步骤2 │ 点积 │
(算重叠) │ dot = 3×2.8 + 2×1.9 │
│ = 12.2 │
└───────────────────────────┘
┌───────────────────────────┐
步骤3 │ 余弦相似度 │
(削长度) │ 12.2 / (3.61 × 3.38) │
│ = 12.2 / 12.21 │
│ ≈ 1.00 ✅ 非常相似! │
└───────────────────────────┘

九、Python 代码速查#

import numpy as np
# 两个向量
a = np.array([3, 2])
b = np.array([2.8, 1.9])
# 步骤1:算长度(norm)
len_a = np.linalg.norm(a) # √(9+4) ≈ 3.61
len_b = np.linalg.norm(b) # √(7.84+3.61) ≈ 3.38
# 步骤2:算点积
dot = np.dot(a, b) # 3×2.8 + 2×1.9 = 12.2
# 步骤3:余弦相似度
cosine = dot / (len_a * len_b) # ≈ 1.0

一句代码版#

def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

十、给 Embedding 的类比#

"如何提升代码质量" → Embedding模型 → 向量A → 一根箭(朝"编程"方向)
"今天天气真好" → Embedding模型 → 向量B → 一根箭(朝"天气"方向)
两根箭方向差很远 → 余弦相似度低 → 语义不同
两根箭方向很近 → 余弦相似度高 → 语义相近
这就是 AI 判断"意思相近"的数学原理!

✅ 检查清单#

  • 向量 = 一根箭 = 一个列表/元组
  • 分量 = 列表里的每个数字
  • 平方 = 自己乘自己;开根号 = 平方的反操作
  • 勾股定理 = 横²+竖²=对角线²(2维特殊版)
  • norm = 多维勾股定理 = 量箭的长度
  • 点积 = 逐位乘再求和 = 两根箭的重叠量
  • 余弦相似度 = 点积 ÷ (A长度×B长度) = 削掉长度比方向
  • 越接近1 → 越相似;越接近0 → 越无关
  • 同一模型输出的向量维度永远一样,不会出现长度不同

十一、深入理解:为什么除以长度能削掉倍数#

问题的核心#

A = [3, 2]
B = [100, 66.7] = 33.3 × A ← B是A放大33.3倍,方向完全相同
问:如何计算相似度,让结果不受"33.3倍"影响?

第一步:观察点积里的倍数#

np.dot(A, B)
= 3×100 + 2×66.7
= 3×(33.3×3) + 2×(33.3×2) ← 代入 B = k×A

用乘法交换律提取k:

3×(33.3×3)
= 3×33.3×3 ← 去括号(结合律)
= 33.3×3×3 ← 交换律:3和33.3换位置
= 33.3×(3×3)
= 33.3×9
2×(33.3×2)
= 2×33.3×2
= 33.3×2×2
= 33.3×(2×2)
= 33.3×4

提取公因数(分配律):

np.dot(A, B)
= 33.3×9 + 33.3×4
= 33.3 × (9 + 4) ← 提取公因数33.3
= 33.3 × 13
= k × np.dot(A, A) ← 点积里混进了倍数k!

第二步:观察norm里的倍数#

norm(B)
= √(100² + 66.7²)
= √((33.3×3)² + (33.3×2)²)
= √(33.3²×9 + 33.3²×4)
= √(33.3² × (9+4))
= √(33.3² × 13)
= 33.3 × √13
= 33.3 × norm(A)
= k × norm(A) ← norm里也混进了倍数k!

第三步:相除消掉k#

余弦相似度 = dot(A,B) / (norm(A) × norm(B))
分子:k × np.dot(A,A) = k × (3×3 + 2×2) = k × 13
分母:norm(A) × k × norm(A) = k × norm(A)² = k × (√13)² = k × 13
= (k × 13) / (k × 13) ← k在分子分母都有!
= k/k × 13/13
= 1 × 1
= 1.0 ← k被消掉了!
关键:norm(A)² = dot(A, A),等式两边严格相等!
norm(A)² = (√(3²+2²))² = 3²+2² = 9+4 = 13 = dot(A, A)
所以不需要用近似值3.61,用精确的13就能完美消掉!

一句话总结#

位置计算结果倍数k在哪
分子 dot(A,B)433.433.3 × 13 ← 这里!
分母 norm(A)3.61没有k
分母 norm(B)120.233.3 × 3.61 ← 这里!
相除结果1.0k/k=1,消了!
433.4 / (3.61 × 120.2)
≈ (33.3×13) / (√13 × 33.3×√13) ← 不用3.61,用精确的√13
= 33.3/33.3 × 13/(√13×√13) ← k/k 消掉,后面 √13×√13 = 13
= 1 × 13/13
= 1 × 1
≈ 1.0 ← 用精确值算出来就是严格的1

核心洞察:倍数k同时污染了分子和分母,一除就没了,结果只反映方向!


十二、数学定律速查#

乘法交换律#

a × b = b × a
例子:
3 × 5 = 15
5 × 3 = 15
→ 相同!
在点积中:
3 × (33.3 × 3) = 33.3 × (3 × 3)
把33.3提到前面

乘法结合律#

(a × b) × c = a × (b × c)
例子:
(2 × 3) × 4 = 6 × 4 = 24
2 × (3 × 4) = 2 × 12 = 24
→ 相同!
在norm中:
√((33.3×3)² + (33.3×2)²)
= √(33.3² × (3² + 2²))
= 33.3 × √(3² + 2²)

提取公因数(分配律逆用)#

a × b + a × c = a × (b + c)
例子:
5 × 7 + 5 × 3
= 5 × (7 + 3)
= 5 × 10
= 50
在点积中:
33.3×9 + 33.3×4
= 33.3 × (9 + 4)
= 33.3 × 13

十三、归一化的数学思想#

什么是归一化#

归一化 = 把不同尺度的东西拉到同一标准下再比较
例子1:打分
小明:85/100分
小红:42/50分
归一化:都转成百分制 → 85% vs 84%
例子2:房价
北京:800万/100平 = 8万/平
小城市:80万/100平 = 0.8万/平
归一化:每平米价格,公平比较

在向量里#

问题:两根箭长度不同,直接比不公平
A = [3, 2],长度3.61
B = [100, 66.7],长度120.2(是A的33.3倍)
但方向完全相同!
解决:除以norm,削成单位长度1
削后A = [3/3.61, 2/3.61] = [0.83, 0.55]
削后B = [100/120.2, 66.7/120.2] = [0.83, 0.55]
→ 削完完全相同!都是[0.83, 0.55]
结果:余弦相似度 = 1.0,正确反映方向相同!

一句话#

归一化 = 削掉长度的影响,只比方向
在AI中无处不在:
- 距离归一化
- 数据标准化
- 概率归一化(softmax)
- 余弦相似度
核心思想:只要标准一致,不管尺度大小

十四、代码 vs 数学原理#

层面做了什么看到k了吗
代码执行直接乘除❌ 看不到k
数学原理提取公因数、消掉k✅ 能看到k被消
# 代码:直接算
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# 数学原理:k被消掉了
cosine = (k × dot(A,A)) / (norm(A) × k × norm(A))
= k/k × dot(A,A)/norm(A)²
= 1 × dot(A,A)/norm(A)²
# 结果一样,原理解释了"为什么长度不影响结果"

结论:代码直接乘除,但背后的数学原理就是提取公因数和消掉倍数k。


十五、完整思维导图#

对比两句话相似度
调用Embedding模型 → 获得两个向量列表
┌─────────────────┐
│ A = [3, 2] │
│ B = [100, 66.7]│ ← B = k×A,k=33.3
└─────────────────┘
├─→ 点积 dot(A,B) = 3×100 + 2×66.7
│ = 3×(k×3) + 2×(k×2)
│ = k×(3×3) + k×(2×2) ← 交换律
│ = k × (9 + 4) ← 提取公因数
│ = k × 13 ← 混进k!
├─→ norm(A) = √(3²+2²) = 3.61
├─→ norm(B) = √(100²+66.7²)
│ = √((k×3)² + (k×2)²)
│ = √(k² × (3²+2²))
│ = k × √(3²+2²)
│ = k × 3.61 ← 也混进k!
余弦 = dot / (norm(A) × norm(B))
= (k×13) / (3.61 × k×3.61)
= k/k × 13/(3.61×3.61) ← k消掉了!
= 1 × 1
= 1.0 ✅ 方向相同!

✅ 完整检查清单#

基础概念#

  • 向量 = 一根箭 = 一个列表
  • 分量 = 列表里的每个数字
  • 平方 = 自己乘自己;开根号 = 平方的反操作
  • 勾股定理 = 横²+竖²=对角线²
  • norm = 多维勾股定理 = 量箭的长度
  • 点积 = 逐位乘再求和
  • 余弦相似度 = 点积÷(长度×长度)

数学定律#

  • 乘法交换律:a×b = b×a,可以换位置
  • 乘法结合律:(a×b)×c = a×(b×c),可以换括号
  • 提取公因数:a×b + a×c = a×(b+c),把相同提出来

核心原理#

  • 点积里混进了倍数k(因为B=k×A)
  • norm(B)里也混进了倍数k
  • 相除时k/k=1,倍数被消掉
  • 结果只反映方向,不受长度影响
  • 这就是归一化的数学思想

✅ 四条理解标准#

  • 思想是什么:把文本变成向量后,用方向是否接近来判断语义是否接近。
  • 干什么:给 RAG 检索、推荐、聚类等任务提供“相似度”计算方法。
  • 为什么这么干:只看点积会被长度影响,余弦相似度通过除以长度消掉倍数。
  • 怎么干:能写出 dot / (norm_a * norm_b),并能解释点积、norm、归一化各自的作用。

⚠️ 常见坑#

现象正确做法
把点积当相似度最终答案长向量天然分数更大用余弦相似度消掉长度影响
以为开根号是除法norm 推导卡住开根号是平方的反操作
忽略分母为 0空向量计算报错或无意义真实代码里先检查 norm 是否为 0
把数学公式和代码割裂会背公式但不会写函数对照 dotnormcosine_similarity 三步实现

下一章预告:用真实 Embedding 模型跑一遍,亲眼看”代码质量”和”天气真好”的相似度到底差多少!

01 向量与余弦相似度:AI 如何判断"意思相近"
https://enkiud.com/posts/math-01/
作者
Enkidu
发布于
2025-11-30
许可协议
CC BY-NC-SA 4.0