一个中文字占几个 token,你算过吗?

2026-02-25 15:22   6   0  
面试官问:"一个中文字占几个 token,你算过吗?"



"2 年大模型开发经验,熟悉 GPT、Claude、Qwen 等主流模型 API 调用与应用开发"

看到这份简历,我问了个简单的问题:一个中文字在 GPT-4 里占几个 token?

候选人愣了几秒,说"应该是 1 个吧"。

错了。而且不只是数字错了,是对整个分词机制没有概念。Tokenizer 是大模型的第一道工序——文本进来先过分词器,切成 token,才能送进模型。分词切得好不好,直接影响模型理解能力、推理速度和 API 成本。

很多人天天调 API,却从没想过模型是怎么"看"文字的。今天这场面试,就把 Tokenizer 的核心问题讲透。



Round 1:BPE 分词是怎么工作的?



面试官:"大模型用的分词算法叫 BPE,你能讲讲它的原理吗?"

候选人:"BPE...就是把文本切成子词吧?按词频合并?大概就是这样。"

正解

BPE 不需要任何语言学规则,纯靠统计频率就能学会怎么切词——这是它最反直觉的地方。

BPE(Byte Pair Encoding)最早是 1994 年 Philip Gage 提出的数据压缩算法,2016 年被 Sennrich 等人引入 NLP,现在 GPT、Llama、Claude 等主流模型全在用。

核心思路只有一句话:找到语料里出现频率最高的相邻 token 对,合并成一个新 token,不断重复。

具体流程:

Step 1:初始化词表。 把所有文本拆到最小单位。以 Byte-level BPE 为例,基础词表就是 256 个字节值。任何文字——中文、emoji、特殊符号——都能用字节表示,不会出现 OOV(未登录词)。

Step 2:统计频率。 遍历语料,数所有相邻 token 对出现了多少次。假设 "l" 和 "o" 紧挨着出现了 5000 次,是最高频的一对。

Step 3:合并。 把 "l" + "o" 合并成新 token "lo",加入词表。语料里所有 "l""o" 相邻的位置都替换成 "lo"。

Step 4:重复。 重新统计频率,继续合并。下一轮可能发现 "lo" 和 "w" 频率最高,合并成 "low"。BPE 就是这样层层叠加,从字节逐步构建出子词、词根、甚至完整单词。

合并持续到词表大小达到预设值为止。 GPT-2 的词表是 50,257,GPT-4 约 100,000,Llama 3 是 128,256。

推理时怎么切词? 不再看频率,而是按训练时学到的合并规则,按顺序依次执行。给定一段新文本,先拆成字节,然后按合并规则一步步合并,最终得到 token 序列。

一个直观的例子:BPE 训练时从来没见过 "lowest" 这个词,但它学到了 "low" 和 "est" 两个 token——分别是词根和后缀。所以 "lowest" 会被切成 ["low", "est"],模型依然能理解。这就是 BPE 处理未知词的方式,不需要整词匹配,靠子词组合就能覆盖。

要点速记
- BPE 核心:统计最高频的相邻 token 对 → 合并 → 重复
- 基础词表 256 个字节,不会出现 OOV
- 推理时按训练好的合并规则顺序执行,不看频率
- 主流词表大小:GPT-4 约 100K,Llama 3 为 128K




Round 2:词表从 32K 涨到 128K,为什么?



面试官:"Llama 2 的词表是 32K,Llama 3 直接扩到 128K,Gemini 更是到了 256K。词表越大越好吗?"

候选人:"词表大了,能表示的词就多了,应该效果更好吧?"

正解

词表大小不是越大越好,而是和模型参数量存在幂律关系——模型越大,最优词表也越大。

NeurIPS 2024 有篇重要论文 Scaling Laws with Vocabulary(来源:Sea AI Lab & HKU),专门研究了这个问题。核心结论:大多数 LLM 的词表都太小了。以 Llama 2-70B 为例,最优词表应该是 216K 以上,但实际只有 32K——差了 7 倍。

词表大小影响什么?

  • 压缩效率。

     词表越大,同样的文本切成的 token 数越少。Llama 2 用 32K 词表编码同一段文本,比 Llama 3 的 128K 词表多 30-40% 的 token。token 少意味着序列短,推理更快,能塞进上下文的信息更多。

  • Embedding 层参数量。

     词表扩大,Embedding 矩阵也跟着膨胀。vocab_size × hidden_dim,Llama 3-8B 的 128K × 4096 = 5.24 亿参数,光 Embedding 就占了模型总参数的 6.5%。对小模型来说这个比例很高,所以数据不够或模型不够大时,词表反而要小一些。

  • 多语言支持。

     这是 Llama 3 扩词表的主要动机之一。32K 词表里中文 token 太少,很多中文字被拆成 2-3 个字节级 token,效率极低。128K 词表能给中文、日文、韩文分配更多专属 token,大幅提升非英语文本的编码效率。

经验法则:

模型规模
推荐词表大小
代表模型
< 1B
32K
Phi 系列
1B - 13B
32K - 64K
Mistral 7B(32K)
13B - 70B
64K - 128K
Llama 3(128K)
 70B
128K - 256K
Gemini(256K)

实验数据佐证: 同样的计算预算(2.3e21 FLOPs),把词表从 32K 扩到 43K,ARC-Challenge 准确率从 29.1 提升到 32.0,差了近 3 个百分点(来源:Scaling Laws with Vocabulary 论文)。

词表太大的代价: 超过 100K 之后边际收益递减。从 8K 到 32K 的 perplexity 下降很明显,从 100K 到 200K 改善就很小了,但 Embedding 层参数和内存占用却在线性增长。

前沿进展: SuperBPE(COLM 2025,来自华盛顿大学 + NVIDIA + AI2)提出两阶段 BPE——先学子词,再学跨词边界的超级词(如 "by accident"、"of course" 这样的固定搭配)。同样 200K 词表,SuperBPE 比标准 BPE 少 33% 的 token,在 30 个 benchmark 上平均提升 4.0%,MMLU 提升 8.2%。Moondream AI 已经在产品中采用了 SuperBPE,序列长度平均缩短 21%。

要点速记
- 词表大小和模型参数量呈幂律关系,大模型配大词表
- Llama 2 的 32K 词表对 70B 模型来说太小,最优值约 216K
- 词表扩大 → token 更少 → 推理更快,但 Embedding 层参数也增加
- SuperBPE(2025)同词表大小下减少 33% token,MMLU +8.2%




Round 3:一个中文字占几个 token?为什么中文调 API 比英文贵 3 倍?



面试官:"同样的内容,中文调 GPT-4 的 API 费用是英文的好几倍,你知道为什么吗?"

候选人:"可能是...中文比较复杂?字数多?"

(面试官内心 OS):天天在调 API,连钱怎么花出去的都没想过...

正解

不是中文复杂,而是 GPT-4 的分词器对中文不友好——同样的语义信息,中文被切成了更多的 token。

BPE 分词的合并规则是从训练语料里学来的。GPT-4 的训练数据以英文为主,英文字母组合频率高,能学到大量高效的合并规则("tion"、"ing"、"the" 都是单个 token)。中文在训练数据中占比低,汉字之间的组合频率不够高,很多常见词没法合并成单独 token。

具体数据对比:

文本
GPT-4 token 数
Qwen token 数
Claude token 数
"machine learning"
2
3
2
"机器学习"
4
2
3
1000 字英文
~1,300 tokens
~1,400 tokens
~1,300 tokens
1000 字中文
~1,800 tokens
~900 tokens
~1,500 tokens

同样 1000 字的内容,中文在 GPT-4 上比英文多出约 40% 的 token。换算成 API 费用,同一段文本的中文版本比英文版贵 30-50%。有人实测:同样一段文本,中文调 GPT API 花 30 美分,翻译成英文只要 10 美分。

跨语言不公平问题:

这不是某一个模型的问题,而是英文主导的 BPE 分词器的通病。一篇 2023 年的研究发现(来源:arxiv 2305.15425),同一段文本翻译成不同语言后,token 数量最多能差 15 倍。低资源语言(泰语、阿拉伯语等)被过度碎片化,序列变长,不仅推理慢、API 贵,还会因为上下文窗口被浪费而影响模型表现。

中文分词还有一个更隐蔽的坑:语义切割错误。

MIT Press 2025 年发表的研究发现,GPT-4、GPT-4o 和 Llama 3 在处理中文时,会被 token 边界误导。两个毫不相关的汉字,如果碰巧被切成了相同的开头 token,模型会错误地认为它们语义相似。LLaMA 系列还会错误合并不存在的词——把"的事"当成一个词,而正确的切分应该是"事物"。这类问题在日常聊天里不明显,但在情感分析、法律文本等需要精确语义理解的场景里,影响很大。

省钱的工程策略:

  • 中文业务优先选中文优化模型。

     Qwen 和 DeepSeek 的分词器针对中文做了专门优化,词表中包含大量中文高频字词。同样的中文文本,Qwen 比 GPT-4 少 40-50% 的 token。
  • 混合语言策略。

     系统 prompt 用英文写(消耗更少 token),用户输入保持原语言。
  • 推理语言切换。

     DeepSeek R1 和 Qwen 3 在非英语语言下推理,token 消耗比英文少 20-40%,且准确率基本不受影响。Qwen 3 用韩语推理甚至能省 73% 的 token(来源:多语言推理基准测试)。

要点速记
- GPT-4 中"机器学习"占 4 个 token,Qwen 里只占 2 个
- 同样内容中文比英文多 40% token,API 费用差 30-50%
- 中文业务优先用 Qwen/DeepSeek,token 效率提升 40-50%
- 隐蔽坑:token 边界会影响模型对中文语义的理解

 



Round 4:tiktoken 和 SentencePiece 怎么选?



面试官:"你知道 tiktoken 和 SentencePiece 的区别吗?什么时候用哪个?"

候选人:"tiktoken 是 OpenAI 的,SentencePiece 是 Google 的...其他区别不太清楚。"

正解

两者都实现了 BPE,但实现方式不同,适用场景也不同。选错了不影响能不能跑,但影响效率和多语言效果。

核心区别在于处理顺序:

tiktoken 的流程:文本 → 正则预分词(按空格、标点切开)→ UTF-8 编码成字节 → 在字节上做 BPE 合并。它先用正则把文本切成粗粒度的块,然后在每个块内部做字节级 BPE,合并不能跨越块的边界。

SentencePiece 的流程:文本 → 直接在 Unicode 码点上做 BPE 合并,不需要预分词。空格被当成普通字符(用 ▁ 符号表示),和文字一视同仁地参与合并。

这个区别带来的实际影响:

  • 多语言处理。

     SentencePiece 不依赖空格分词,对中文、日文、泰语等没有空格分隔的语言更友好。tiktoken 依赖正则表达式做预分词,规则是面向英文设计的。
  • BPE 合并结果不同。

     tiktoken 的预分词会限制合并不能跨越块边界,SentencePiece 没有这个限制。同样的训练数据和词表大小,两者学到的词表可能不一样。有研究指出 tiktoken 的预分词优化实际上违反了标准 BPE 规则,某些情况下导致次优的合并结果(来源:HuggingFace Xenova 分析)。
  • 速度。

     tiktoken 用 Rust 实现,推理速度极快。基准测试显示 tiktoken 比 HuggingFace Transformers 的分词器快约 8.76 倍,比 SentencePiece 快 3-6 倍(来源:llm-calculator.com 2025 基准)。

tiktoken 有一个关键限制:只支持推理,不支持训练。 想训练自己的分词器,得用 SentencePiece 或 HuggingFace Tokenizers 库。

各模型的选择:

分词器
使用模型
tiktoken
GPT-3.5/4/4o、Llama 3(从 SentencePiece 切换过来)
SentencePiece
Llama 2、T5、Qwen、多数多语言模型
Mistral Tekken
Mistral Nemo(基于 tiktoken,131K 词表)
HuggingFace Tokenizers
自训练分词器首选工具

Llama 3 从 SentencePiece 切换到 tiktoken 是个标志性事件。Meta 同时把词表从 32K 扩到 128K,编码效率和推理速度都有提升。

训练自己分词器的注意事项:

训练分词器不需要海量数据——几百万 token 就够了,因为分词器只需要学 token 出现频率,不需要理解语义。关键配置:

  • 用 SentencePiece 训练时必须设 byte_fallback=True,否则遇到罕见字符会报 unknown token
  • 词表大小:小模型用 32K,大模型用 64K-128K
  • 训练数据要和模型训练数据分布一致,否则会出现 Glitch Token(下一个 Round 会讲)

要点速记
- tiktoken:字节级 BPE,快(3-6 倍),但只能推理不能训练
- SentencePiece:码点级 BPE,多语言友好,支持训练 + 推理
- Llama 3 从 SentencePiece 换成 tiktoken,词表同时扩到 128K
- 自训练分词器:几百万 token 即可,必须设 byte_fallback=True




Round 5:Glitch Token、数字切分、Token Healing——生产环境的三个坑



面试官:"在生产环境里,分词器有哪些容易被忽略的坑?"

候选人:"嗯...可能是特殊字符处理?Unicode 编码问题?"

正解

分词器的坑比想象中多,很多问题表现出来像模型的 bug,实际上是分词器的锅。

坑一:Glitch Token——词表里有但模型没学过的"幽灵 token"

2023 年有人发现,让 ChatGPT 复述 "SolidGoldMagikarp" 这个词,它回复的却是 "distribute"。这不是模型幻觉,而是 Glitch Token。

原因:SolidGoldMagikarp 是一个 Reddit 用户名,在分词器的训练语料(网页文本)里出现频率够高,被 BPE 合并成了单独的 token。但在模型的训练数据里,这个 token 几乎没出现过,Embedding 向量基本是随机值。模型遇到这个 token 就"懵"了。

Glitch Token 的典型症状(来源:ACM 2024 论文):

  • 幻觉:让模型复述一个词,输出完全不同的词
  • 拼写突变:Llama 2 被要求复述 "wurden",输出 "werden"
  • 随机字符:Mistral 7B 被要求复述 "}}^",输出 "^^^^"
  • 拒绝回复或反复重复问题

排查和防御:

  • GlitchHunter(ACM 2024):基于 embedding 空间聚类检测异常 token,在 7 个主流 LLM 上测试了 182,517 个 token
  • GlitchMiner:基于梯度的检测方法,用熵损失函数量化预测不确定性,precision 高于 GlitchHunter
  • LiteToken(2026 年 2 月):发现约 10% 的词表 token 是 BPE 合并过程的中间残留——训练时频繁出现,但最终几乎不被使用。删掉这些 token 能减少碎片化,提升对噪声输入的鲁棒性,不需要重新训练模型(在 Qwen3-8B、Llama-3.1-8B 上验证通过,来源:arxiv 2602.04706)

坑二:数字切分导致算术错误

让 GPT-4 算 1234 + 5678,有时会算错。问题不在 Transformer 的计算能力,在分词。

"480" 可能是一个 token,"481" 却被切成 "4" + "81"。数字的 token 切分是不规则的,模型无法稳定地对齐数位,自然算不准。GPT-4 的词表里甚至有 "693" 这样的三位数 token,但 "694" 可能就要拆成两个。

Llama 系列的做法是把所有数字逐位拆分——"1234" 切成 "1" "2" "3" "4",只需要 0-9 十个 token。这种方式让模型的算术能力明显提升,但代价是数字序列变长。DeepSeek V2 也采用了同样的策略。

工程建议:

  • 对算术精度要求高的场景,用代码执行(Code Interpreter)而非让模型直接算
  • 格式化数字输入,避免千分位分隔符干扰("1,234" 和 "1234" 的 token 切分完全不同)
  • 了解你用的模型的数字分词策略:Llama 系列是逐位切分,GPT 系列是混合切分

坑三:Token Healing——Prompt 边界偏差

这个坑更隐蔽。你写了一个 prompt 以 http: 结尾,期望模型补全 //www.example.com。但模型输出的是一个空格开头的奇怪 URL。

原因:训练时 :// 是一个完整的 token(GPT-2 里是 token 1358)。但 prompt 在 : 处截断了,模型看到的是单独的 : token(token 27),这和训练时的分布不一致,生成就跑偏了。

约 70% 的常见 token 都存在这个问题——它们是更长 token 的前缀,当 prompt 恰好在这里截断时,就会产生 token 边界偏差(来源:Guidance 文档)。

解决方案:Token Healing,由微软 Guidance 库(20K+ GitHub Stars)提出。核心思路:生成时回退一个 token,把 prompt 的最后一个 token 作为前缀约束,让生成的第一个 token 自然接上。



python

# Guidance 库示例
import guidance
model = guidance.models.Transformers("meta-llama/Llama-3-8B")
# Token healing 自动处理边界问题
result = model + "http:" + guidance.gen(max_tokens=20)



Token Healing 目前主要在本地推理时有效(Guidance 支持 LlamaCpp 和 Transformers 后端),调 API 时无法直接控制。规避方式:prompt 尾部不要截断在单词或符号的中间,保持完整的 token 边界。

要点速记
- Glitch Token:词表里有但模型没训练过的 token,约 10% 词表是残留 token
- 数字切分不规则导致算术错误,Llama 用逐位切分方案缓解
- 70% 的常见 token 存在边界偏差风险,Guidance 的 Token Healing 可修复
- API 调用时注意 prompt 尾部不要截断在 token 中间




面试官点评



这场面试暴露了一个典型问题:很多人天天用大模型 API,对 token 这个概念的理解却停留在"计费单位"。

Token 不只是计费单位,它是模型看世界的最小粒度。分词器怎么切,决定了模型能不能理解你的输入、能不能准确生成、以及你要为此付多少钱。

建议:

  • 用 OpenAI 的 Tokenizer 工具(tiktoken 在线版)实际看看中英文的 token 切分差异,比读十篇文章更直
  • 跑一个简单的 BPE 训练(Sebastian Raschka 有个从零实现的 notebook),理解合并规则是怎么生成的
  • 生产环境遇到奇怪的模型行为,先检查分词——很多时候不是模型的问题,是 token 切得不对

---

分词器是大模型最被低估的组件。做应用的人忽略它,做训练的人也经常直接用现成的。但从 SuperBPE 到 LiteToken,学术界一直在挖掘这个方向的潜力——同样的模型参数,换个更好的分词器就能提升 4-8% 的 benchmark 成绩。

面试时能把分词器讲清楚的候选人不多,但讲得清楚的,通常对模型的理解也不会差。

博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。