293 字
1 分钟
Embedding 与向量搜索原理
一、Embedding 概述
1.1 什么是 Embedding
flowchart LR
subgraph Input[" 输入文本"]
T["'人工智能改变世界'"]
end
subgraph Model[" Embedding 模型"]
direction TB
M1["Tokenizer 分词"]
M2["Transformer 编码"]
M3["Pooling 池化"]
M4["归一化"]
M1 --> M2 --> M3 --> M4
end
subgraph Output[" 向量输出"]
V["[0.12, -0.34, 0.56, ...]<br/>1536 维浮点数"]
end
subgraph Storage[" 向量存储"]
direction TB
S1["向量数据库"]
S2["相似度索引"]
S1 --> S2
end
T --> M1
M4 --> V
V --> S1
style Input fill:#e3f2fd
style Model fill:#fff8e1
style Output fill:#f3e5f5
style Storage fill:#e8f5e9
graph LR
A["文本"] --> B["模型"]
B --> C[1536 维向量]
C --> D[向量数据库]
D --> E[相似文本检索]
Embedding 是将离散数据(文本、图像)映射到连续向量空间的技术:
- 语义相似:语义相近的文本,向量距离更近
- 维度固定:模型输出的向量维度固定(如 1536 维)
- 可计算:余弦相似度、点积等度量
1.2 常见 Embedding 模型
| 模型 | 维度 | 特点 |
|---|---|---|
| text-embedding-ada-002 | 1536 | OpenAI 最新模型 |
| text-embedding-3-small | 1536 | 更小更快 |
| m3e | 1024 | 中文优化 |
| BGE | 1024 | 中英文优化 |
二、Embedding 模型原理
2.0 Embedding 创建流程详解
flowchart TB
subgraph Input[" 输入层"]
direction LR
T["原始文本:<br/>'机器学习很有趣'"]
end
subgraph Tokenize[" 分词层"]
direction TB
TK1["Tokenizer"]
TK2["Token IDs<br/>[102, 4523, 1234, 3892]"]
TK3["Attention Mask<br/>[1, 1, 1, 1]"]
TK1 --> TK2
TK1 --> TK3
end
subgraph Transformer[" Transformer 编码"]
direction TB
TR1["Token Embedding<br/>词嵌入层"]
TR2["Position Embedding<br/>位置编码"]
TR3["Multi-Head Attention<br/>多头注意力"]
TR4["Feed Forward<br/>前馈网络"]
TR1 --> TR2 --> TR3 --> TR4
end
subgraph Pooling[" 池化层"]
direction TB
P1["Mean Pooling<br/>平均池化"]
P2["或 CLS Pooling<br/>首 token 池化"]
end
subgraph Output[" 输出向量"]
direction LR
V["归一化向量<br/>[0.12, -0.34, ...]<br/>维度: 768/1536"]
end
T --> TK1
TK2 --> TR1
TK3 --> TR3
TR4 --> P1
TR4 --> P2
P1 --> V
P2 --> V
style Input fill:#e3f2fd
style Tokenize fill:#fff8e1
style Transformer fill:#f3e5f5
style Pooling fill:#e8f5e9
style Output fill:#fce4ec
2.1 Transformer 结构
# Transformer 简化的前向传播class TransformerEmbedding: def __init__(self, model_name): self.tokenizer = AutoTokenizer.from_pretrained(model_name) self.model = AutoModel.from_pretrained(model_name)
def encode(self, texts): # 1. Tokenize tokens = self.tokenizer( texts, padding=True, truncation=True, max_length=512 )
# 2. Forward outputs = self.model(**tokens)
# 3. Pooling embeddings = self.mean_pooling(outputs, tokens['attention_mask']) return F.normalize(embeddings, p=2)2.2 Pooling 策略
# Mean Poolingdef mean_pooling(output, attention_mask): # 掩盖 padding token input_mask_expanded = attention_mask.unsqueeze(-1).expand(output.size()).float() return torch.sum(output * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
# CLS Pooling(使用 [CLS] 向量)def cls_pooling(output): return output[:, 0] # 取第一个 token三、向量索引
3.1 暴力检索 vs 索引
# 暴力检索def brute_search(query_vector, vectors, top_k): scores = cosine_similarity(query_vector, vectors) return top_k_indices(scores, top_k)# 时间复杂度 O(n*d)
# IVF 索引def ivf_search(query_vector, vectors, top_k): # 1. 找到最近的聚类中心 center = find_nearest_center(query_vector)
# 2. 在中心内搜索 candidates = vectors[center_points[center]] scores = cosine_similarity(query_vector, candidates) return top_k(scores, top_k)# 时间复杂度 O(sqrt(n))3.2 HNSW 图索引
flowchart TB
subgraph L2[" Layer 2 - 快速跳转"]
direction LR
A2["Node A"] --- B2["Node B"]
B2 --- C2["Node C"]
end
subgraph L1[" Layer 1 - 中间层"]
direction LR
A1["Node A"] --- B1["Node D"]
B1 --- C1["Node E"]
C1 --- D1["Node F"]
end
subgraph L0[" Layer 0 - 精确搜索"]
direction LR
A0["Node A"] --- B0["Node G"]
B0 --- C0["Node H"]
C0 --- D0["Node I"]
D0 --- E0["Node J"]
E0 --- F0["Node K"]
end
L2 --> L1
L1 --> L0
style L2 fill:#e3f2fd,stroke:#1976d2
style L1 fill:#fff8e1,stroke:#f57c00
style L0 fill:#e8f5e9,stroke:#388e3c
flowchart LR
subgraph Search[" HNSW 搜索过程"]
direction TB
S1["入口点<br/>顶层开始"] --> S2["贪心搜索<br/>找最近邻"]
S2 --> S3["逐层下沉<br/>缩小范围"]
S3 --> S4["底层精确<br/>返回结果"]
end
style Search fill:#f3e5f5
graph TB
A["Layer 2"] --> B["稀疏连接"]
B --> C["Layer 1"]
C --> D["Layer 0"]
D --> E["密集连接"]
style A fill:#87CEEB
style E fill:#90EE90
# HNSW 参数class HNSWIndex: def __init__(self): self.ef_construction = 200 # 建图精度 self.M = 16 # 每个节点连接数 self.ef_search = 100 # 搜索精度四、向量数据库
4.1 Milvus 配置
# Milvus Collection 配置collection_schema: name: documents fields: - name: id type: int64 is_primary: true - name: embedding type: FLOAT32 dim: 1536 index: type: HNSW params: M: 16 efConstruction: 200 - name: text type: varchar max_length: 10004.2 Pinecone 操作
# Pinecone SDKimport pinecone
# 连接pinecone.init(api_key="...", environment="us-east1")index = pinecone.Index("documents")
# 插入index.upsert([ ("1", [0.1] * 1536, {"text": "文档1"}), ("2", [0.2] * 1536, {"text": "文档2"})])
# 检索results = index.query( vector=[0.1] * 1536, top_k=10, include_metadata=True)五、相似度计算
5.0 相似度搜索流程
flowchart TB
subgraph Query[" 查询向量"]
Q["Query: '深度学习教程'<br/>[0.15, 0.32, -0.08, ...]"]
end
subgraph Database[" 向量数据库"]
direction TB
D1["Doc 1: '机器学习入门'<br/>相似度: 0.72"]
D2["Doc 2: '神经网络教程'<br/>相似度: 0.89"]
D3["Doc 3: 'Python 编程'<br/>相似度: 0.45"]
D4["Doc 4: '深度学习指南'<br/>相似度: 0.95"]
D5["Doc 5: '数据结构'<br/>相似度: 0.31"]
end
subgraph Compute[" 相似度计算"]
direction TB
C1["余弦相似度<br/>Cosine Similarity"]
C2["点积<br/>Dot Product"]
C3["欧氏距离<br/>Euclidean Distance"]
end
subgraph Ranking[" 排序输出"]
R1["#1 Doc 4: 0.95 "]
R2["#2 Doc 2: 0.89 "]
R3["#3 Doc 1: 0.72 "]
end
Q --> Compute
Database --> Compute
Compute --> Ranking
style Query fill:#e3f2fd
style Database fill:#fff8e1
style Compute fill:#f3e5f5
style Ranking fill:#e8f5e9
graph TB
subgraph VectorSpace["向量空间可视化"]
direction TB
V1["(相似文本聚类)"]
V2["同义词 → 距离近"]
V3["无关词 → 距离远"]
end
A["'猫'"] ---|"距离近"| B["'小猫'"]
A ---|"距离近"| C["'宠物'"]
A ---|"距离远"| D["'汽车'"]
A ---|"距离远"| E["'编程'"]
style VectorSpace fill:#f5f5f5
5.1 余弦相似度
def cosine_similarity(a, b): """余弦相似度:-1 到 1,1 表示完全相同""" dot_product = sum(x * y for x, y in zip(a, b)) norm_a = sqrt(sum(x * x for x in a)) norm_b = sqrt(sum(x * x for x in b)) return dot_product / (norm_a * norm_b)5.2 点积
def dot_product(a, b): """点积:值域无限,需要归一化""" return sum(x * y for x, y in zip(a, b))
# 归一化后点积等价于余弦相似度normalized_a = a / norm(a)normalized_b = b / norm(b)dot(normalized_a, normalized_b) == cosine_similarity(a, b)5.3 距离度量
def euclidean_distance(a, b): """欧几里得距离:值域 0 到 +∞""" return sqrt(sum((x - y) ** 2 for x, y in zip(a, b)))
def manhattan_distance(a, b): """曼哈顿距离""" return sum(abs(x - y) for x, y in zip(a, b))六、工程实践
6.1 批量处理
class BatchEmbedding: def __init__(self, batch_size=32): self.batch_size = batch_size
def encode_batch(self, texts): results = [] for i in range(0, len(texts), self.batch_size): batch = texts[i:i+self.batch_size] embeddings = self.model.encode(batch) results.extend(embeddings) return results6.2 增量索引
# 增量添加到向量数据库def add_documents(new_docs): embeddings = model.encode(new_docs) index.upsert( zip(ids, embeddings, metadatas) )
# 异步增量索引async def add_async(new_docs): embeddings = await model.encode_async(new_docs) await index.upsert_async(embeddings)七、总结
mindmap
root((Embedding 系统))
模型
OpenAI ada-002
BGE/m3e 中文优化
维度选择
768/1024/1536
处理流程
Tokenize 分词
Transformer 编码
Pooling 池化
归一化
索引结构
HNSW 高效
IVF 聚类
PQ 压缩
相似度度量
余弦相似度
点积
欧氏距离
工程
批量处理
增量索引
缓存优化
| 组件 | 关键指标 |
|---|---|
| Embedding 模型 | 维度、语义理解能力 |
| 索引结构 | HNSW > IVF > 暴力 |
| 向量数据库 | QPS、延迟、召回率 |
| 相似度 | 余弦相似度、点积、欧氏距离 |
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
Embedding 与向量搜索原理
https://blog.souloss.com/posts/ai-engineering/embedding-vectors/ 部分信息可能已经过时
相关文章 智能推荐
1
RAG 检索增强生成原理
AI 深入解析 RAG 检索增强生成技术——架构原理、检索流程、Context 组装与工程实践。
2
让AI拥有知识:RAG检索增强生成详解
AI 让AI拥有知识——RAG检索增强生成详解
3
AI 工程化实践
AI AI 工程化全景导览——从提示词工程到多模态系统,梳理大模型落地的核心工程能力与知识体系
4
向量数据库深度解析
AI 深入解析主流向量数据库的架构原理、性能对比与选型指南,涵盖 Milvus、Qdrant、Pinecone、Chroma、Weaviate。
5
Agent 记忆系统:短期、长期与向量数据库
AI AI Agent 记忆机制详解——短期记忆、长期记忆、情景记忆的设计与实现,以及记忆的检索、压缩与遗忘策略。






