2、向量化技术基础:Embedding模型简介、文本向量化、图像向量化、向量维度与精度权衡
好,我们正式开始聊向量化的底层逻辑。
很多人一上来就问我:「选哪个向量数据库好?」
我的回答通常是——你先搞清楚你的数据怎么变成向量。数据库再快,喂进去的向量是垃圾,查出来也是垃圾。这个道理,我在好几个项目里都吃过亏。
2.1 Embedding模型:到底在做什么?
说白了,Embedding 就是把「猫」、「狗」、「苹果」、「手机」这些人类能理解的概念,映射到一组浮点数上。比如「猫」可能变成 [0.23, -0.45, 0.67, ...],一共几百上千个数字。
这些数字不是乱给的。模型训练出来后,语义相近的词,它们的向量在空间里也靠得近。「猫」和「狗」的距离,肯定比「猫」和「汽车」近。这就是向量化的核心价值——把非结构化数据变成可计算的距离。
我个人习惯把 Embedding 模型理解成一个「翻译器」。它把人类语言翻译成机器能算的数学语言。你想想看,没有这个翻译器,数据库怎么知道「苹果手机」和「iPhone 15」是同一个东西?
2.2 文本向量化: vs 开源模型
文本向量化是最常见的场景。目前主流方案分两派:闭源 API 和开源模型。
2.2.1 Embedding API
的 text-embedding-3-small 和 text-embedding-3-large 是目前工业界用得最多的。我去年做一个知识库项目,直接调 API,效果确实稳。
import
response = .embeddings.create(
model="text-embedding-3-small",
input="向量数据库选型指南"
)
embedding = response.data[0].embedding
print(len(embedding)) # 输出: 1536
输出 1536 维。什么意思?就是每个文本被表示成 1536 个浮点数。维度越高,信息越丰富,但存储和计算成本也越高。这个后面会细说。
2.2.2 开源模型:BGE / Instructor / Sentence-BERT
如果你对数据隐私有要求,或者不想付 API 费,开源模型是唯一选择。
我比较推荐 BGE(BAAI General Embedding)系列。它在 MTEB 榜单上表现不错,而且中文支持好。用起来也不复杂:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
embeddings = model.encode("向量数据库选型指南")
print(embeddings.shape) # 输出: (1024,)
1024 维。比 小,但中文场景下效果不差。我在一个金融文档检索项目里做过对比,BGE 的召回率只比 低 2-3 个百分点,但成本几乎为零。
| 模型 | 维度 | 中文支持 | 成本 | 适用场景 |
|---|---|---|---|---|
| text-embedding-3-small | 1536 | 好 | 按 收费 | 通用、快速验证 |
| text-embedding-3-large | 3072 | 好 | 高 | 高精度需求 |
| BGE-large-zh-v1.5 | 1024 | 优秀 | 免费 | 中文场景、私有部署 |
| Instructor-XL | 768 | 一般 | 免费 | 多任务指令嵌入 |
| Sentence-BERT (all-MiniLM) | 384 | 差 | 免费 | 轻量、英文场景 |
2.3 图像向量化:不只是「看图说话」
图像向量化和文本不太一样。文本有天然的分词结构,图像是一堆像素。怎么把一张图变成向量?
主流做法是用预训练的 CNN 或 Vision Transformer(ViT)模型,把图像通过模型的全连接层之前的那一层特征提取出来。这一层输出的向量,就是图像的 Embedding。
from transformers import CLIPProcessor, CLIPModel
from PIL import Image
model = CLIPModel.from_pretrained("/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("/clip-vit-base-patch32")
image = Image.open("product_photo.jpg")
inputs = processor(images=image, return_tensors="pt")
image_features = model.get_image_features(**inputs)
print(image_features.shape) # 输出: torch.Size([1, 512])
CLIP 模型有个好处——它同时支持文本和图像,能把两者映射到同一个向量空间。这意味着你可以用文字搜图片,或者用图片搜图片。我在一个电商项目里就用 CLIP 做「以图搜图」,效果相当好。
2.4 向量维度与精度权衡:没有免费的午餐
这是本章最核心的部分。我见过太多人一上来就选 3072 维,觉得维度越高越好。其实不是。
维度越高,带来的问题越明显:
- 存储成本: 1536 维 float32 向量,每个占 6KB。1000 万条就是 60GB。3072 维直接翻倍。
- 计算成本: 高维向量的距离计算更慢。暴力搜索时,维度每翻一倍,耗时也翻倍。
- 维度诅咒: 维度太高时,所有向量之间的距离都趋于相等,区分度反而下降。这是数学上的问题,不是模型能解决的。
那怎么选?我一般按这个原则:
- 先看数据量: 百万级以下,1536 维随便用。千万级以上,考虑降维到 768 或 512。
- 再看精度要求: 搜索场景(Top-K 召回),768 维通常够用。分类或聚类场景,可能需要更高维度。
- 最后看硬件: GPU 显存有限的话,优先降维。我有个项目用 384 维的 MiniLM,在 CPU 上跑得飞快,精度损失不到 5%。
嗯,这里还要提一下精度格式。大部分模型输出 float32,但你可以转成 float16 甚至 int8。float16 精度损失几乎不可感知,但存储减半。int8 损失稍大,但适合大规模场景。
import numpy as np
# float32 -> float16
embedding_f32 = np.array([0.123456, -0.789012, ...], dtype=np.float32)
embedding_f16 = embedding_f32.astype(np.float16)
# 量化到 int8
scale = np.max(np.abs(embedding_f32))
embedding_i8 = (embedding_f32 / scale * 127).astype(np.int8)
2.5 本章知识体系总览
下面这张图把本章的核心逻辑串起来了。从原始数据到向量,再到维度权衡,每一步都有取舍。
总结一下:向量化不是越「大」越好。选模型、选维度、选精度,都是在做 trade-off。我个人的习惯是:先用小维度快速验证,再根据效果逐步调整。别一上来就追求完美,先跑通再说。