ai /
Tokenizer 定义与实现
2026 年 9 月 11 日发布
基本概念
Tokenizer 是连接原始文本与LLM 数值输入的编码系统,其基本任务是:
文本
→ Token 序列
→ Token ID 序列
→ LLM例如:
"unbelievable"
→ ["un", "believ", "able"]
→ [412, 8271, 539]一个完整的 Tokenizer 通常包含:
- Vocabulary:
Token ↔ ID的映射; - Tokenization Rules:文本如何被切分为 Token;
- Normalization:Unicode、空格等文本规范化规则;
- Special Tokens:如
<BOS>、<EOS>、<PAD>; - Decoder:Token 序列如何恢复为文本。
因此,Tokenizer 并不只是一个映射表。tokenizer.json 只是将这些规则和数据序列化保存下来。
为什么需要 Tokenizer
LLM 不能直接处理字符串,只能处理数值向量,因此首先需要把文本转换为离散 ID。
最直接的两种粒度都有明显问题。
字符 / Byte 级
例如:
unbelievable
→ u n b e l i e v a b l e优点:
- 词表很小;
- 可以表示任意文本;
- 几乎不存在 OOV(未知词)问题。
缺点:
- 序列很长;
- LLM 需要进行更多次计算。
Word 级
例如:
unbelievable
→ [unbelievable]优点:
- 序列较短。
缺点:
- 词表会非常大;
unbelievable、unbelievably等需要分别存储;- 无法良好处理新词、代码和多语言文本。
因此现代 LLM 通常采用 Subword:
unbelievable
→ un + believ + ableTokenizer 本质上是在:
小词表 + 长序列
↕
大词表 + 短序列之间寻找合适的计算折中。
Tokenizer 如何产生
所谓“训练 Tokenizer”,通常不是神经网络意义上的梯度训练,而是:
准备代表性语料
↓
确定预处理规则
↓
选择 Tokenizer 算法
↓
统计 / 优化语料
↓
Vocabulary + Rules
↓
保存 Tokenizer例如选择:
algorithm = BPE
vocab_size = 32000算法会根据训练语料自动学习哪些文本片段值得成为独立 Token。
因此可以将 Tokenizer 训练类比为:
LLM:
数据 + 网络结构 + 优化算法
→ Model Weights
Tokenizer:
语料 + Tokenizer 算法 + 超参数
→ Vocabulary + RulesTokenizer 一般在 LLM 正式训练前确定,并在训练和推理期间保持一致。
Tokenizer 基本算法
BPE(Byte Pair Encoding)
BPE 的核心思想是:
> 不断合并语料中最常共同出现的相邻片段。
例如训练语料:
low
lower
lowest初始拆分:
l o w
l o w e r
l o w e s t统计相邻组合:
(l, o) → 3
(o, w) → 3
(w, e) → 2
...于是执行:
l + o → lo得到:
lo w
lo w e r
lo w e s t继续统计:
lo + w → low最终可能得到:
Vocabulary:
l
o
w
lo
low
er
est
...
Merge Rules:
l o → lo
lo w → low
e r → er
...简化后的 BPE 训练算法:
vocab = initial_units(corpus)
while len(vocab) < target_vocab_size:
pairs = count_adjacent_pairs(corpus)
a, b = most_frequent(pairs)
new_token = a + b
corpus = merge(corpus, a, b)
vocab.add(new_token)因此 BPE 可以理解为一种根据语料自动学习压缩字典的方法。
常见片段:
the
ing
tion
人工
智能
return
function更容易成为独立 Token。
Unigram
Unigram 的思路与 BPE 相反。
BPE 从很小的词表开始:
字符 / Byte
→ 不断添加 TokenUnigram 通常从一个较大的候选词表开始:
大量候选 Token
→ 不断删除价值较低的 Token每个 Token 都带有一个概率:
Token Probability
un 0.08
believe 0.03
able 0.05
...对于:
unbelievable可能存在多种切分:
un + believable
un + believe + able
u + n + believe + ableUnigram 根据整条 Token 序列的概率选择较优方案:
训练过程中逐渐删除贡献较小的 Token,直到词表达到目标大小。
其特点是:
- 不依赖固定的 BPE Merge 顺序;
- 同一字符串可以存在多个候选切分;
- 可以通过概率模型选择更合适的 Token 序列。
WordPiece
WordPiece 与 BPE 类似,也通过 Subword 构建词表。
区别主要在于 Token 的选择标准不同:
- BPE 主要根据相邻片段出现频率;
- WordPiece 更关注加入某个 Token 后对语言建模能力的改善。
BERT 是典型的 WordPiece 使用者。
例如:
playing
→ play + ##ing其中 ## 表示该 Token 出现在单词内部。
Tokenizer 的设计
设计 Tokenizer 时主要需要决定以下内容:
训练语料
↓
基础单位:Byte / Character
↓
Normalization
↓
Pre-tokenization
↓
BPE / Unigram / WordPiece
↓
Vocabulary Size
↓
Special Tokens其中最重要的几个因素是:
训练语料
Tokenizer 会直接反映训练数据分布。
如果大量数据是代码,可能学习:
return
const
def
::
==如果大量数据是中文,则可能学习:
中国
人工智能
模型
系统因此 Tokenizer 本身也是一种针对数据分布的编码设计。
Vocabulary Size
词表越大:
文本
→ 更少 Token但 Embedding 和输出层参数更多。
对于隐藏维度 :
其中 为词表大小。
因此:
Vocabulary ↑
Sequence Length ↓
Embedding Parameters ↑不存在无限增大词表的收益。
评价指标
Tokenizer 不应只看“能否编码文本”,还应关注:
- 平均 Token 数;
bytes / token;- 中文、英文等不同语言的编码效率;
- Code Tokenization 效率;
- Vocabulary Size;
- 对未知字符和异常输入的鲁棒性。
Tokenizer 的局限
传统 Tokenizer 有一个根本特点:
> Token 的划分规则在 LLM 训练之前就已经固定。
例如 BPE 可能始终将某个字符串编码为:
un + believable而不会根据上下文动态改变计算粒度。
它本身并不知道:
- 当前 Token 的语义;
- 当前任务是否困难;
- 哪些区域值得更多计算;
- 哪些区域可以被高度压缩。
因此 Tokenizer 实际上人为规定了 LLM 的基础计算粒度。
未来研究方向
Learnable Tokenizer
一种直接思路是:
> 让一个神经网络决定文本应该如何分块。
例如:
Bytes
↓
Small Neural Network
↓
Dynamic Chunks
↓
Large Language Model与固定 BPE 不同,Chunk 可以根据上下文动态变化。
简单区域可以使用较大的 Chunk:
[The cat is sitting]复杂区域则使用更细粒度:
[x] [9] [Q] [@] [7]此时 Tokenization 不再是独立的数据预处理,而成为模型的一部分。
无固定 Tokenizer
进一步可以完全取消传统 Vocabulary:
UTF-8 Bytes
↓
Local Encoder
↓
Latent Patches
↓
Global Model其中:
- Local Model 处理字符、拼写等局部结构;
- Global Model 处理语义、知识与推理。
核心思想从:
如何设计一个更好的 Tokenizer?变成:
模型应该如何自动决定自己的计算粒度?这类方法的优势包括:
- 不依赖人工固定词表;
- 无 OOV;
- 对多语言更加自然;
- 可以动态分配计算资源;
- Global Model 可以在更短的序列上工作。
主要问题则集中在输出侧。
层次化计算
传统 LLM 基本在单一 Token 粒度上进行计算:
token
token
token
token
↓
Large Transformer但语言本身具有天然层次:
Byte
↓
Character
↓
Subword
↓
Word
↓
Phrase
↓
Sentence
↓
Concept因此一种可能的未来架构是:
Bytes
↓
Tiny Local Model
↓
Lexical Chunks
↓
Small Model
↓
Semantic Chunks
↓
Large Global Model低层模型负责:
字符
拼写
局部语法高层模型负责:
语义
知识
推理
规划其目的不是单纯“去掉 Tokenizer”,而是避免让昂贵的大模型对所有低层信息进行同等级计算。
输出与 Diffusion
无 Tokenizer 或 Latent 模型的一个核心困难是输出。
传统自回归模型:
token_1
→ token_2
→ token_3
→ ...优点是质量高、因果关系明确,但必须逐步生成。
Diffusion 可以同时更新多个位置:
[MASK] [MASK] [MASK] [MASK]
↓
[word] [MASK] [word] [MASK]
↓
[word] [word] [word] [word]因此它有机会提高并行生成能力。
但 Diffusion 也存在:
- 需要多次 Denoising;
- 每一步可能重新计算整段序列;
- 输出长度处理更困难;
- 更少 Denoising Step 通常意味着质量下降。
因此目前的核心问题仍是:
Generation Speed
↕
Generation Quality一种值得关注的结构是:
Global Model
↓
Semantic Latent
↓
Local Diffusion Model
↓
Token / Byte SequenceGlobal Model 负责低频、高层的推理;
Local Decoder 负责高速展开具体语言。
从 Tokenizer 到 Latent Thought
更进一步,可以质疑另一个假设:
> 推理本身是否必须以语言 Token 的形式进行?
传统 Chain-of-Thought:
内部表示
→ 语言 Token
→ 内部表示
→ 语言 Token
→ ...模型每进行一步推理,都必须把内部状态转换成人类语言。
但人的思考体验往往并不完全表现为逐词生成:
问题
↓
模糊的概念 / 联想 / 候选方案
↓
形成表达意图
↓
组织语言
↓
逐字、逐词说出因此可以考虑:
Input
↓
Encoder
↓
Continuous Latent Thought
↓
Reasoning / Planning
↓
Communicative Intent
↓
Language Decoder
↓
Text此时语言只是智能系统的一种输入输出形式,而不是推理本身。
这种架构可能允许连续表示同时保留多个候选方案,而不必像 Token Generation 一样过早做离散选择。
最终问题也从:
如何设计 Tokenizer?逐渐演化为:
模型应该使用什么内部表示进行思考?
不同计算粒度之间应该如何组织?
语言是否只是内部认知状态的一种表达形式?这已经从 Tokenizer 问题进一步扩展为 LLM 表示与推理架构问题。