1. 向量 #
1.1 为什么需要向量 #
- 计算机只能理解数字,但人类日常交流依赖文字、图片等抽象信息。向量的本质,就是把一段文字、一张图片或一个概念,变成一串有顺序的数字,让计算机能处理这些信息。大模型和 AI 应用常把向量称为 Embedding(嵌入向量),都是用数字来表达「含义」。
- 由于大模型内部只能进行加减乘除,无法直接理解汉字或英文单词,所以首先要把这些内容转换成数字,才便于模型进行运算、比较和搜索。
- 向量不是随便一串数字,而是有语义结构的数字序列:意思相近的内容会被映射为距离相近的数字。你可以把向量理解成每个词或每句话在「意义地图」上的坐标。只要掌握一点直觉:意思越接近,向量越接近,就能理解向量在 AI 里的核心作用。
- 演示:选一句话,看「文字 → 向量 → 相似度运算」三步流程,以及意义地图上的位置关系。
1.2 一个生活化的比喻 #
- 假设只用两个数字描述水果:甜度 和 脆度。
- 苹果 可能是
(8, 8)——又甜又脆。 - 梨 可能是
(6, 4)——和苹果很接近。 - 篮球 可能是
(1, 1)——既不甜也不脆,和水果差很远。 - 在这张二维「地图」上,距离近 ≈ 意思近;距离远 ≈ 不相关。这就是向量的核心思想。
- 演示:试试看,拖动点的位置,感受「距离越近,意思越相近」!
1.3 高维向量是什么 #
- 真实大模型不会只用 2 个数字,而是用几百甚至上千个数字,称为高维向量。
- 我们无法「画」出上千维的空间,但数学规则不变:相近仍然表示相似。
- 维度越多,模型能编码的特征越细(类别、语气、领域、上下文等)。
- 演示:拖动维度滑块,看 2 维平面图 → 3 维立体 → 高维数字条,相似度计算规则始终不变。
2. 向量从哪来 #
- 向量不是人手写出来的,而是大模型在海量文本上训练得到的。
- 理解来源有助于你知道:为什么「国王」和「女王」的向量会比较接近。
2.1 大模型如何学会向量 #
- 训练时,模型反复做「完形填空」:给前半句,猜下一个词。
- 例如:
今天__很蓝→ 模型要学会填「天空」。 - 每猜错一次,就微调词的向量坐标,让相关词在空间中更合理。
- 训练亿万次后,上下文相关的词会自然聚在一起。
- 演示:触发完形填空训练,看猜错时向量远离、猜对时向量靠近。
3. 相似度度量类型 #
3.1 欧几里得距离 #
欧几里得距离是最直观、最常用的一种相似度度量方法。简单说,它就是两个点之间直线距离。
3.1.1. 核心定义 #
在几何中,欧几里得距离衡量的是两点之间的真实“直线”长度。在AI中,我们把数据点(如图像、文本的数值表示)视为多维空间中的点,用这个距离来判断它们的相似程度。
- 距离越小,表示两个向量在空间中越接近,即越相似。
- 距离越大,表示两个向量越疏远,即差异越大。
3.1.2. 数学公式 #
对于两个n维向量 $ A $ 和 $ B $:
二维空间 (点 (x1, y1) 和 (x2, y2)):
$$ d(A,B) = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} $$
这就是我们熟悉的勾股定理求斜边长度。
3.1.3 演示 #
- 演示:拖动两点、看直角三角形与 Δx/Δy 分步计算,直观理解「距离越小越相似」。
3.1.4 python 代码 #
# 导入numpy库,用于数值计算
import numpy as np
# 定义计算两个向量欧几里得距离的函数
def euclidean_distance(a, b):
# """多行注释,描述函数功能"""
"""
计算两个向量的欧几里得距离
:param a: 一维list或numpy数组
:param b: 一维list或numpy数组
:return: 距离(float)
"""
# 将输入a转换为numpy数组
a = np.array(a)
# 将输入b转换为numpy数组
b = np.array(b)
# 计算欧几里得距离并返回
return np.sqrt(np.sum((a - b)**2))
# 示例
# 定义第一个向量
vec1 = [0,0]
# 定义第二个向量
vec2 = [3,4]
# 调用函数计算两个向量的欧几里得距离
distance = euclidean_distance(vec1, vec2)
# 打印欧几里得距离的结果
print(f"欧几里得距离: {distance}")3.2 余弦相似度 #
余弦相似度衡量的是两个向量方向的夹角,而不是两点之间的直线距离。在语义搜索里,它比欧几里得距离更常用。
3.2.1 核心定义 #
把每个向量看成从原点出发的箭头。余弦相似度看的是两支箭头是否指向同一方向:
- 接近 1:方向几乎一致,含义很相似。
- 接近 0:几乎垂直,关系不大。
- 接近 -1:方向相反。
与欧几里得距离的关键区别:
- 欧几里得距离看「两点离多远」——向量长度变长,距离也会变。
- 余弦相似度看「朝哪指」——只拉长或缩短向量,方向不变则相似度不变。
3.2.2 数学公式 #
对于两个 $ n $ 维向量 $ A $ 和 $ B $:
$$ \text{similarity}(A,B) = \cos(\theta) = \frac{A \cdot B}{|A| \times |B|} $$
其中:
- $ A \cdot B $ 是点积(对应位置相乘再求和)。
- $ |A| $ 是向量 $ A $ 的长度(模)。
二维情形下,若 $ A=(x_1,y_1) $,$ B=(x_2,y_2) $:
$$ \cos(\theta) = \frac{x_1 x_2 + y_1 y_2}{\sqrt{x_1^2+y_1^2} \times \sqrt{x_2^2+y_2^2}} $$
3.2.3 演示 #
- 演示:拖动向量端点、观察夹角与点积分步计算;拉长向量长度,看余弦相似度为何不变。
3.2.4 python 代码 #
# 导入numpy库用于数值计算
import numpy as np
# 定义第一个向量
vec1 = np.array([1, 2])
# 定义第二个向量
vec2 = np.array([2, 3])
# 定义计算余弦相似度的函数
def cosine_similarity(a, b):
# 计算两个向量的点积
dot_product = np.dot(a, b)
# 计算第一个向量的范数
norm_a = np.linalg.norm(a)
# 计算第二个向量的范数
norm_b = np.linalg.norm(b)
# 返回余弦相似度的计算结果
return dot_product / (norm_a * norm_b)
# 调用余弦相似度函数计算vec1和vec2的相似度
similarity = cosine_similarity(vec1, vec2)
# 打印余弦相似度结果
print(f"余弦相似度: {similarity}")/ 输出一例结果 余弦相似度: 0.992583 /
4. 获取文本向量 #
- 把指定文本交给
Embedding模型,拿回一串数字 - 使用
sentence-transformers库加载中文 Embedding 模型BAAI/bge-small-zh-v1.5(体积小、中文效果好)。
4.1 准备环境 #
- 安装依赖(会自动带上 PyTorch 等运行库):
uv add sentence-transformers- 或:
pip install sentence-transformers - 首次运行脚本时,会从 HuggingFace 下载模型(约百兆级),请保持网络畅通。
- 若下载较慢,可先设置国内镜像再运行:
4.2 单条文本转向量 #
- 核心步骤:加载模型 → 调用
model.encode()→ 得到向量。 encode()返回numpy数组,可用.tolist()转成 Python 列表。model.get_sentence_embedding_dimension()可查看向量维度(bge-small-zh-v1.5为 512 维)。encode()返回numpy.ndarray;存入 JSON 或数据库时用.tolist()转成普通列表。- bge-small-zh-v1.5
# 导入 os,用于设置环境变量
import os
# 从 sentence_transformers 导入 SentenceTransformer
from sentence_transformers import SentenceTransformer
# 加载本地 Embedding 模型(首次运行会自动下载)
model = SentenceTransformer("C:/Users/Administrator/.cache/modelscope/hub/models/BAAI/bge-small-zh-v1.5")
# 指定要转成向量的文本
text = "苹果是一种甜甜的水果"
# 编码为向量(numpy 数组)
vector = model.encode(text)
# 打印文本、向量维度和前 5 个数字
print(f"文本: {text}")
print(f"向量维度: {len(vector)}")
print(f"前 5 维: {vector[:5].tolist()}")4.3 用拿到的向量算相似度 #
- 拿到向量后,用第 3 章的余弦相似度比较文本是否相近。
# 导入 numpy 包
import numpy as np
# 导入用于句子嵌入的 SentenceTransformer 模型
from sentence_transformers import SentenceTransformer
# 定义一个计算两个向量之间余弦相似度的函数
def cosine_similarity(a, b):
# 将输入 a 转为 numpy 数组
a = np.array(a)
# 将输入 b 转为 numpy 数组
b = np.array(b)
# 计算余弦相似度并返回
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
# 加载本地保存的中文句嵌入模型
model = SentenceTransformer("C:/Users/Administrator/.cache/modelscope/hub/models/BAAI/bge-small-zh-v1.5")
# 定义第一个要比较的文本
text_a = "我喜欢吃苹果"
# 定义第二个要比较的文本
text_b = "梨是很好吃的水果"
# 定义第三个要比较的文本
text_c = "篮球打起来很过瘾"
# 将三段文本编码为向量
vectors = model.encode(
[text_a, text_b, text_c]
)
# 获取第一个文本的向量
vec_a, vec_b, vec_c = vectors[0], vectors[1], vectors[2]
# 计算 vec_a 与 vec_b 的余弦相似度
sim_ab = cosine_similarity(vec_a, vec_b)
# 计算 vec_a 与 vec_c 的余弦相似度
sim_ac = cosine_similarity(vec_a, vec_c)
# 打印 text_a 和 text_b 的余弦相似度
print(f"「{text_a}」vs「{text_b}」:", round(sim_ab, 4))
# 打印 text_a 和 text_c 的余弦相似度
print(f"「{text_a}」vs「{text_c}」:", round(sim_ac, 4))- 通常「苹果」和「梨」的相似度会明显高于「苹果」和「篮球」,说明向量确实编码了语义。
5. 向量的用途 #
- 知道「怎么算」「怎么获取」之后,再看应用场景会更容易。
- 下列场景都遵循同一逻辑:先转向量,再比相似度。
5.1 语义搜索 #
- 传统关键词搜索:搜「苹果」可能同时出现水果和 iPhone 新闻。
- 语义搜索:把用户问题和文档都转成向量,找含义最接近的内容。
- 优点:即使用词不同(如「降雨」和「下雨」),也能匹配到。
5.2 推荐系统 #
- 把「用户兴趣」和「商品/内容」都表示成向量。
- 用户向量和某商品向量越近,越可能推荐该商品。
- 短视频、电商「猜你喜欢」背后都有类似机制。
5.3 检索增强生成 #
- 大模型有时会「编造」答案,检索增强生成用来缓解这个问题。
- 流程分三步:
- 用户提问;
- 系统先在知识库里做向量检索,找出最相关段落;
- 把这些段落和问题一起交给大模型,让它「带着资料回答」。
- 你可以把检索增强生成理解成:先翻参考书,再答题。
5.4 多模态 #
- 多模态模型可以把「猫的图片」和「一只猫」的文字映射到相近向量。
- 这样模型就能做「看图说话」「以文搜图」等任务。