返回 AI大模型从0到1——理论与实操

C2-02 Embeddings


🍞 思考:上次我们说了RAG就是"开卷考试",那么问题来了,要如何从海量的信息中找到有用的信息呢?

RAG完整两阶段

上次我们只说了在线阶段,这次补上离线阶段,在一个RAG开始进行在线检索之前,我们必须把检索引擎搞定,要把需要的离线知识灌入检索引擎!

这就是知识库

🥖 问题:那些AI搜索不需要我们处理离线知识库,为什么呢?

答案:AI搜索内部调用了百度/google/搜狗等搜索引擎,这些搜索引擎已经提前爬好数据完成知识库构建了。

好,进入关键概念。

Embeddings

什么是向量(Emebedding)

大白话版:向量就是一组数字。比如一个城市的位置可以用经纬度(两个数字)来表示。文字也可以用一组数字来表示,数字的值反映了文字的「含义」。

高中数学版:向量是有大小和方向的数学对象,用坐标表示。(3, 4)就是一个二维向量。文字被转换成高维坐标之后,「语义相近」的词在坐标空间中距离很近。

线性代数版:向量是高维实数空间中的点。文本 Embedding 将离散的语言符号映射到连续的向量空间 $\mathbb{R}^N$,使得语义相似的文本在余弦距离意义下靠近。

🍰 原理:大型多语言 Embedding 模型在海量多语言语料上训练,让不同语言的相同含义映射到向量空间中的同一个区域。

文本向量(Text Embeddings)

Embeddings 的核心思想:

  • 把每段文字转换成一组 N 维浮点数(N 通常是 768、1536、2048或更大)
  • 语义相近的文字,其对应向量在空间中距离很近
  • 语义不相关的文字,对应向量相距很远

直观理解

文本 向量(简化示意)
"猫" [0.8, 0.2, ..., 0.1]
"小猫" [0.78, 0.22, ..., 0.11]
"宠物" [0.6, 0.4, ..., 0.3]
"汽车" [0.1, 0.9, ..., 0.8]

注意:「猫」和「小猫」的向量非常接近,而「猫」和「汽车」的向量距离很远。

向量模型(embedding模型)

厂商 embedding模型名 地址
OpenAI text-embedding-3-small
text-embedding-3-large
https://developers.openai.com/api/docs/models/all
阿里Qwen text‑embedding‑v3
text‑embedding‑v4
https://bailian.console.aliyun.com/
智谱 embedding-2
embedding-3
https://docs.bigmodel.cn/cn/guide/models/embedding/embedding-3
智源 / BAAI BAAI/bge-large-zh-v1.5
bge-m3
https://github.com/FlagOpen/FlagEmbedding

🎼 现在你知道了开源embedding模型bge-m3,那你知道开源模型怎么使用吗?

我们在课上不会演示所有可能的情况,但别忘了,AI知道“所有”的情况,你知道该怎么问AI了吗?

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 用 OpenAI 兼容接口获取文本向量,这里用的是智谱的服务
import os
from openai import OpenAI
import numpy as np
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("ZHIPU_API_KEY"), base_url=os.getenv("ZHIPU_BASE_URL"))

def get_embeddings(texts, model="embedding-3"):
    """获取文本列表的 Embedding 向量"""
    response = client.embeddings.create(
        model=model,
        input=texts
    )
    return [item.embedding for item in response.data]

# 示例:获取两个句子的向量
texts = ["全球冲突升级", "global conflict", "足球"]
embeddings = get_embeddings(texts)
print(f"向量维度:{len(embeddings[0])}")
print(f"第一个向量的前5维:{embeddings[0][:5]}")
print(f"第二个向量的前5维:{embeddings[1][:5]}")
print(f"第三个向量的前5维:{embeddings[2][:5]}")

返回结果:

向量维度:2048

第一个向量的前5维:[0.01158471, 0.015066884, -0.022312963, 0.027812319, -0.033424366]

第二个向量的前5维:[0.0031163762, 0.0234473, -0.028435837, 0.025421685, -0.042478513]

第三个向量的前5维:[-0.0024149674, -0.024989344, -0.024284316, 0.028612407, -0.05283797]

❤️ 从上面的返回结果中能肉眼看出这几个文本向量之间的相似关系吗?

向量之间的相似度计算

两种主要的相似度计算方法:

余弦相似度(越大越相似,值域 [-1, 1],通常 [0, 1]):

$$\cos(\theta) = \frac{A \cdot B}{|A| \cdot |B|}$$

  • 直觉:把两个向量当成两条射线,射线方向越接近,相似度越高
  • 对向量长度不敏感,只关注方向

欧氏距离(越小越相似):

$$d(A, B) = \sqrt{\sum_{i=1}^{n}(A_i - B_i)^2}$$

  • 直觉:就是两点之间的直线距离
  • 对向量长度敏感

Plain Text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 先安装依赖包:pip install numpy
# 向量相似度计算实现
import numpy as np
from numpy.linalg import norm

def cos_sim(a, b):
    """余弦相似度 -- 越大越相似"""
    a, b = np.array(a), np.array(b)
    return np.dot(a, b) / (norm(a) * norm(b))

def euclidean_dist(a, b):
    """欧氏距离 -- 越小越相似"""
    a, b = np.array(a), np.array(b)
    return norm(a - b)

# 测试
v1 = [1.0, 2.0, 3.0]
v2 = [1.1, 2.1, 3.1]
v3 = [-1.0, -2.0, -3.0]
print(f"v1 vs v2 余弦相似度:{cos_sim(v1, v2):.4f}")  # 接近 1
print(f"v1 vs v3 余弦相似度:{cos_sim(v1, v3):.4f}")  # 接近 -1
print(f"v1 vs v2 欧氏距离:{euclidean_dist(v1, v2):.4f}")  # 接近 0

🎉 好,文本向量通过embedding模型生成了,向量之间的相似度计算方式也有了,我们再计算一下["全球冲突升级", "global conflict", "足球"]这几个向量的相似度吧!

Python
1
2
3
import vector_similar
print(f"第一个向量与第二个向量的相似度:{vector_similar.cos_sim(embeddings[0], embeddings[1])}")
print(f"第一个向量与第三个向量的相似度:{vector_similar.cos_sim(embeddings[0], embeddings[2])}")

输出:

第一个向量与第二个向量的相似度:0.8208282604267259

第一个向量与第三个向量的相似度:0.3927280212101791