Skip to content

分词 (Tokenization)

一句话定义:Tokenization(分词/词元化)是将连续的文本切分成离散的 Token(词元) 的过程。Token 是 LLM 处理文本的最小单位。

"Hello, world!" → ["Hello", ",", " world", "!"]
"你好世界" → ["你", "好", "世", "界"] 或 ["你好", "世界"]

Token ≠ 词。Token 可以是一个字符、一个词、甚至半个词(子词)。


想象你要用乐高搭建任何物体:

  • 字符级:只有 26 种基础小颗粒(字母),可以搭任何东西,但太慢
  • 词级:预制了”门”、“窗”、“轮子”等大块,搭建快但无法搭新东西
  • 子词级(BPE):预制了最常用的组合,既灵活又高效
"unhappiness" 的切分方式:
字符级: ["u", "n", "h", "a", "p", "p", "i", "n", "e", "s", "s"] → 11 个
词级: ["unhappiness"] → 1 个(但如果没见过这个词就无法处理)
子词级: ["un", "happiness"] → 2 个 ✅ 最佳平衡

// 你已经在做 "分词" 了!
// 1. 最简单的分词:按空格切分
const text = "Hello world";
const tokens = text.split(" "); // ["Hello", "world"]
// 2. URL 路由就是一种"分词"
const path = "/api/users/123";
const segments = path.split("/").filter(Boolean); // ["api", "users", "123"]
// 3. JSON 解析也需要"分词"(Lexer/Tokenizer)
// `{"name": "AI"}` → ["{", "name", ":", "AI", "}"]
// LLM 的 Tokenizer 做的是同样的事,只是更复杂


🔤 交互演示:分词器 (Interactive)

Section titled “🔤 交互演示:分词器 (Interactive)”

输入任意文本,观察它被分解成哪些 Token。

✂️ 分词器可视化

Hello[15496]
world[995]
![0]
Token ID 序列 (模型输入):
[15496, 995, 0]
字符数
12
Token 数
3
字符/Token
4.00
💡 关键发现:
  • 空格也是 token: " world" 和 "world" 是不同的 token
  • ChatGPT 被拆分: ["Chat", "G", "PT"] = 3 个 token
  • 中文效率低: 每个汉字约 1-2 个 token
  • 数字被切分: 每 3 位一组,所以 LLM 数学不好

💡 这是简化演示,实际 GPT-4 词汇表有 100,000+ token


# ❌ 不能直接输入文本
model("Hello, world!") # 报错!模型只接受数字
# ✅ 必须先分词 + 转索引
tokens = tokenizer.encode("Hello, world!") # [15496, 11, 995, 0]
output = model(tokens) # 现在可以了
文本 → [Tokenizer] → Token 序列 → [Embedding] → 向量序列 → [Model] → 输出
"猫很可爱"
↓ 分词
["猫", "很", "可爱"]
↓ 转索引
[1234, 567, 8901]
↓ 嵌入
[[0.2, 0.8, ...], [0.1, 0.5, ...], [0.3, 0.9, ...]]
↓ 模型处理
输出

text = "Hello"
tokens = list(text) # ['H', 'e', 'l', 'l', 'o']
优点缺点
词汇表小(仅 256 个字符)序列太长(每个字符一个 token)
不会有”未知词”难以学习长距离语义
text = "Hello world"
tokens = text.split() # ['Hello', 'world']
优点缺点
语义完整词汇表巨大(需 100k+)
序列短无法处理新词 (OOV)
text = "unhappiness"
tokens = ["un", "happi", "ness"] # BPE 切分
优点缺点
词汇表适中(32k~100k)算法较复杂
能处理任何新词同一词可能有多种切分
平衡语义和长度

GPT 系列使用。核心思想:反复合并最常见的字符对

初始词汇表: ['a', 'b', 'c', ..., 'z', ' ']
训练语料: "aaabdaaabac"
第 1 轮: 'aa' 出现最多 → 合并为 'Z' → "ZabdZabac"
第 2 轮: 'Za' 出现最多 → 合并为 'Y' → "YbdYbac"
第 3 轮: 'Yb' 出现最多 → 合并为 'X' → "XdXac"
...
最终词汇表: ['a', 'b', ..., 'z', 'aa', 'ab', 'aab', ...]

BERT 使用。与 BPE 类似,但选择合并对时使用似然最大化而非频率。

# WordPiece 的特点:子词以 ## 开头
"unbelievable"["un", "##believ", "##able"]

支持无空格语言(中文、日文)。直接在原始文本上训练,不依赖预分词。

"我爱北京天安门"["▁我", "", "北京", "天安门"]
# ▁ 表示词的开始(原本是空格的位置)

from transformers import AutoTokenizer
# 加载 GPT-2 的分词器
tokenizer = AutoTokenizer.from_pretrained("gpt2")
text = "Hello, world! This is AI."
# 1. 编码:文本 → Token ID
token_ids = tokenizer.encode(text)
print(token_ids) # [15496, 11, 995, 0, 1212, 318, 9552, 13]
# 2. 查看 Token 文本
tokens = tokenizer.tokenize(text)
print(tokens) # ['Hello', ',', 'Ġworld', '!', 'ĠThis', 'Ġis', 'ĠAI', '.']
# Ġ 表示前面有空格
# 3. 解码:Token ID → 文本
decoded = tokenizer.decode(token_ids)
print(decoded) # "Hello, world! This is AI."
# 4. 查看词汇表大小
print(f"词汇表大小: {tokenizer.vocab_size}") # 50257

模型词汇表大小Tokenizer1 Token ≈
GPT-250,257r50k_base4 个英文字符
GPT-3.5/4100,000cl100k_base4 个英文字符 / 1-2 个中文字
GPT-4o200,000o200k_base更高效,中文提升 2-3x
GPT-5 (2025.8)200,000+新版本多语言优化
Claude 3.5100,000自定义类似 GPT-4
Claude 4 (2025.5)100,000+优化版代码效率提升
LLaMA 2/332,000SentencePiece英文更优
Gemini 2.0 (2025)-自定义多模态优化
# 计费估算
text = "这是一段测试文本"
tokens = tokenizer.encode(text)
price_per_1k = 0.03 # 假设 $0.03/1k tokens
cost = len(tokens) / 1000 * price_per_1k
print(f"预估成本: ${cost:.4f}")