大模型在开口说话之前,先得把文字切成它能处理的小块,干这件事的部件叫分词器,而它手里那份切字依据的清单,就是词表。很多人以为词表是工程师手工编纂的字典,实际上它几乎完全是从训练语料里自动统计出来的。这一篇把词表的诞生过程一步步拆开看,看完你就能判断生词生字的锅该甩给谁。
先有语料,后有词表
训练团队先收集海量文本:网页、书籍、代码、对话,语料的构成直接决定词表的口味。中文语料多,中文字词在词表里占得就多;代码语料多,缩进、括号、常见关键字就会被收成独立词条。所以看到一个模型代码写得好、生僻字却切得稀碎,原因多半在语料配比这个环节。词表训练开始前,文本会被还原成最原始的字符序列,比如按字节或按单字,此时清单上只有最小单元,还没有任何多字词条。
合并循环:高频搭配一步步长成词条
主流方法 BPE 的核心是一个反复执行的循环:统计当前语料里哪两个相邻单元搭在一起出现得最频繁,就把这对组合收进词表当一个新词条,再把语料里所有出现该组合的位置替换成这个新单元,然后继续统计、继续合并。可以把它想成滚雪球:先有单字,高频双字组合滚成词条,接着高频的"词条加字"继续滚成更长的词条。类比里真实生效的是"高频优先合并"这条规则;雪球只是帮你记住过程是渐进的,语料里并没有真的球在滚。循环持续到词表达到预定容量为止,具体数字各家不同,以官方技术报告为准。像 DeepSeek、Kimi 这些模型的词表大小各不相同,同一段中文在不同模型里切出的 token 数有差异,根源常在这里,账单字数对不上的疑问也可以先查这里。
这轮循环里每一步的动作和后果,拆成四行看更清楚。
| 步骤 | 做什么 | 影响什么 |
|---|---|---|
| 统计 | 数出当前语料里哪两个相邻单元搭在一起出现得最频繁 | 决定下一个被收进词表的组合 |
| 合并 | 把这对组合收进词表,当成一个新词条 | 词表容量加一,多字词条开始出现 |
| 替换 | 把语料里所有出现该组合的位置换成这个新单元 | 后续统计的粒度变粗,能滚出更长的词条 |
| 停止 | 循环到词表达到预定容量为止 | 词表大小定稿,各家取值不同 |
词表装不下的字:字节兜底
无论词表多大,总会有没见过的字符:新造的网络用语、罕见 emoji、生僻汉字。要是分词器碰到不认识的单元就报错,模型就没法用了。通用做法是把文本退回字节层面:任何字符最终都能拆成若干字节,而基础字节单元一定在词表里。这就是为什么你在对话框里贴一个奇怪符号,模型照样能读——它可能被拆成一串字节词条,切得碎、花的 token 多,但至少不会卡死。所以生僻字占比高的文本 token 数偏高,机制上完全说得通,别急着怪模型读不懂。
词表多大才算合适
词表越大,平均每个词条越长,同样的文本切出的 token 越少,推理步数跟着变少;代价是嵌入层参数变大,低频词条还学不充分。词表太小则反过来,中文容易被切成单字甚至字节,序列变长,计算和显存开销跟着上涨。这是一笔平衡账,没有统一答案。词表定稿后通常随模型一起发布、长期固定,因为换词表等于换了一套文字度量衡,模型得重训。想接着看模型内部的后续环节,可以读量化是怎么取整的、RoPE 位置编码是怎么工作的,以及采样是怎么从概率里挑字的。
词表训练速查表
- 原料:训练语料,配比决定词表口味
- 核心动作:高频相邻单元反复合并,滚成多字词条
- 停止条件:达到预定词表容量
- 兜底机制:没见过的字符退回字节层面处理
- 定稿之后:随模型固定,轻易不更换
一句话带走:词表是统计出来的产物,生词怪不到模型笨,先看它进没进词表。
分词器快问快答三则
- 为什么同一段文字在不同模型里切的块数不一样?:各家词表是从各自语料统计出来的,收录词条不同,切分结果自然不同。
- 词表能中途扩充吗?:技术上可行但代价大,新增词条对应的向量要从头学,通常伴随继续训练,不能随手加。
- 数字和英文为什么切得比较整?:它们在语料里高频出现,合并循环早早把常见组合收进了词表。


