Token、Embedding 与向量相似度
🔤 LLM 处理文本的第一步:将文字切成 Token,映射为高维向量,再用相似度度量语义距离。
Tokenization
为什么不直接用字符或单词?
- 字符级:序列太长,语义信息稀疏
- 单词级:词表过大,生僻词无法处理(OOV 问题)
- 子词级(BPE/WordPiece):平衡词表大小与序列长度
BPE(Byte Pair Encoding)
- 初始化:每个字符作为一个 token
- 统计相邻 token 对的频率
- 合并最高频的 token 对
- 重复直到词表达到目标大小
例:"tokenization" → ["token", "ization"]
实用要点
- GPT-4 词表约 10万,平均 1 token ≈ 0.75 个英文单词
- 中文通常 1 字 = 1-2 tokens
- 代码、数字的 token 效率较低
tiktoken可以本地统计 token 数
Embedding(嵌入向量)
什么是 Embedding?
将离散的 token ID 映射为连续的高维稠密向量,使语义相近的词在向量空间中距离更近。
Embedding 矩阵: [vocab_size × d_model]
输入 token_id → 查表 → d_model 维向量
嵌入的层次
| 层次 | 来源 | 特点 |
|---|---|---|
| Token Embedding | 词表映射 | 静态,不含上下文 |
| Contextual Embedding | Transformer 中间层 | 含上下文语义 |
| Sentence Embedding | 模型最终输出 | 用于检索、分类 |
向量相似度
余弦相似度(最常用)
cos(a, b) = (a · b) / (|a| × |b|)
- 范围:[-1, 1],越大越相似
- 不受向量模长影响,只看方向
其他度量方式
| 度量 | 公式 | 适用场景 | ||
|---|---|---|---|---|
| 余弦相似度 | cos(a,b) | 语义检索(最常用) | ||
| 点积 | a·b | 注意力分数计算 | ||
| 欧氏距离 | \ | a-b\ | 聚类、分类 | |
| 曼哈顿距离 | sum\ | ai-bi\ | 稀疏向量 |
向量数据库与 ANN 检索
近似最近邻(ANN)
精确 KNN 复杂度 O(n·d),n 百万级时太慢,用 ANN 换精度获速度:
- HNSW(Hierarchical Navigable Small World):分层图索引,速度快,recall 高
- IVF(倒排文件索引):先聚类,只在相关簇内搜索
- PQ(乘积量化):压缩向量,降低内存
主流向量数据库
| 数据库 | 特点 |
|---|---|
| Qdrant | Rust 实现,内存高效,支持 payload 过滤 |
| Weaviate | 内置 GraphQL,Schema 管理完善 |
| Pinecone | 全托管,易上手 |
| pgvector | PostgreSQL 插件,适合已有 PG 的场景 |
| Milvus | 开源,高并发,支持多种索引 |
Embedding 模型选型
| 模型 | 维度 | 特点 |
|---|---|---|
| text-embedding-3-small | 1536 | OpenAI,中英文均衡 |
| text-embedding-3-large | 3072 | OpenAI,更高质量 |
| BGE-M3 | 1024 | 开源,中文优秀,多语言 |
| Cohere embed-v3 | 1024 | 支持 int8 量化 |
常见误区
- Token 数 ≠ 字数,计费前先用
tiktoken估算 - 余弦相似度高不等于语义完全相同,需结合阈值调整
- Embedding 模型和生成模型要分开选,不能混用