Token:AI 世界的基本粒子——不是"字",是统计上最优的"字符组合"

LLM 基础系列 · 第 3 篇

你问 AI 问题,账单上写的是"消耗 Token 数"。AI 的参数规模------GPT-4 是"约 1.8 万亿参数,上下文 128K Token"。

Token 是 AI 世界的基本计量单位------就像物理学里的原子。这篇文章告诉你:Token 是怎么切出来的?为什么同一个词在中英文里 Token 数不一样?以及为什么你调 API 的时候,价格跟"问题长度"不是比例关系。


Token 不是"字",也不是"单词"

给出一句话:

"今天天气真好"

GPT-4 的 Tokenizer 把它切成:

复制代码
今 / 天 / 天 / 气 / 真 / 好

6 个字 → 6 个 Token。但英文 "The weather is really nice today":

bash 复制代码
The / weather / is / really / nice / today

6 个词 → 6 个 Token。到这里似乎 Token = 单词------但继续看:

"unbelievably"

复制代码
un / belie / vably

一个单词 → 3 个 Token。

"ChatGPT is amazing"

csharp 复制代码
Chat / G / PT / is / amazing

"ChatGPT"被拆成了三块:"Chat" 是一个 Token、"G" 是一个、 "PT" 是一个。一个单词 → 3 个 Token。

所以 Token 不是字、不是词、而是子词(Subword) ------比字母大、比单词小。而子词不是人工定义的------是 BPE(Byte Pair Encoding)算法从海量文本里自动学出来的。


BPE 是怎么"长"出词典的

BPE 是纯统计驱动的------它不"理解"语言,只是一直合并出现频率最高的字符对。

从零开始的推演:

erlang 复制代码
初始状态:每个字符是一个独立的 Token
训练文本(极简版):
  "low"  → l, o, w
  "lower" → l, o, w, e, r
  "lowest" → l, o, w, e, s, t

统计所有字符对的频率:
  l+o: 3 次  ← 最高频 → 合并为 "lo"
  o+w: 3 次  ← 合并为 "ow"
  w+e: 2 次  ← 合并为 "we"
  ...

合并后:
  "low" → lo, w    (两个 Token)
  "lower" → lo, we, r  (三个 Token)
  "lowest" → lo, we, s, t  (四个 Token)

继续合并 lo+w → "low"
  "low" → low    (一个 Token!)
  "lower" → low, er  (两个 Token)
  "lowest" → low, est  (两个 Token)

继续合并 e+r → "er", e+s+t → "est"
  "lower" → low, er    (前缀 + 比较级后缀)
  "lowest" → low, est  (前缀 + 最高级后缀)

这就是 BPE 在微观层面的作用------通过反复合并高频对,最终词典里汇聚了大量有意义的语言单元:"low" 是一个 Token(高频词根)、"er" 和 "est" 各是一个 Token(高频后缀)。

训练完成后------这个词典大小通常是 50000 个 Token(GPT-3)或 100000 个 Token(GPT-4)。


每个模型切 Token 的方式不一样

BPE 的训练数据决定了哪些字符对是"高频"的。GPT-4 用的是 OpenAI 自己的训练数据。Claude 用的是 Anthropic 的训练数据。同一个句子,两个模型切出的 Token 数量可能不同------因为它们各自的频率统计来源不同。

后果:你不能简单比较"GPT-4 消耗 1000 Token"和"Claude 消耗 1200 Token"------可能是两个模型切的 Token 数量客观上不同,而不是"谁更省"。你只能用各自的 Token 计数器做预算。


为什么中文的 Token 效率低

同样的信息量,中文通常比英文消耗更多 Token。根本原因是:

  1. 中文没有空格分界。BPE 依赖"统计共现频率"------没有空格,Tokenizer 很难确定"哪里是词边界"。英文有空格天然标识出词之间的间隔,BPE 只需要在词内部合并。中文的一串汉字连在一起------BPE 需要额外"猜测"哪些字应该合并------这天然更困难。

  2. 中文字是多字节 UTF-8。BPE 的输入是字节流,不是字符。一个英文字母 = 1 字节(UTF-8),一个中文字 = 3 字节(UTF-8)。Tokenizer 看到的是一串字节------中文要比英文多处理 3 倍的"输入单元"才能找到相同的 Token 边界。

  3. 常用中文字符数远多于英文字母。英文 26 个字母的组合空间很小------高频组合(如 "ing", "tion")非常密集------BPE 迅速将它们合并成有意义的子词。中文常用字有 3500 个------组合空间比英文大两个数量级------相同训练迭代下------BPE 较难学到最优的切分边界。

具体代价:一篇 1000 字的中文文章,GPT-4 消耗约 3500-4000 个 Token。同样内容的英文,消耗 1800-2200 个 Token。同等信息量------中文 Token 成本约是英文的 1.7-2 倍。


Token 限制上下文窗口------128K 够不够?

GPT-4 的上下文是 128K Token。这里的"128K"不是字数------是 Token 数。

复制代码
128K Token ≈
  ├── 30 万英文字 (约 500 页 PDF)
  ├── 5-8 万中文字 (约 100-150 页 PDF)
  └── 或者 50 轮你 + AI 的来回对话

你的对话越长、发的文件越多------窗口被塞得越满。满了之后------AI 需要"压缩"或"丢弃"最早的对话------这就是你问了很多问题之后 AI 突然"不听话"的原因。

而且有一个容易被忽略的点:位置在中间的细节最容易被 AI 忽略 ------这叫"Lost in the Middle"效应。AI 对长文本的开头和结尾有较强的注意力,中间部分容易被"稀释"。所以如果你要让 AI 遵循某个重要规则------把规则写在 Prompt 的开头结尾------不要藏在中间。


一句话总结

Token 是 AI 的"原子"------BPE 算法从海量文本里统计高频字符对、一层一层合并------最终形成一个大小约 5 万到 10 万的词典。你的问题在进入 AI 之前被切成了一串 Token------每个 Token 对应一个向量------然后送入 Transformer。中文的 Token 效率天然低于英文------这是 UTF-8 编码和分词难度决定的,不是厂商的差别对待。

下一篇:Context Window(上下文窗口)------为什么 128K Token 不是"越大越好"?滑动窗口、RoPE、以及你怎么组织 Prompt 能最大化利用窗口的"有效范围"。

相关推荐
DigitalOcean2 小时前
AI 应用成本怎么算?从推理费用到完整 TCO 拆解
llm·agent
古法安卓2 小时前
Android-DeviceStorageMonitorService 流程分析
java·面试·android studio
预知同行2 小时前
从 MCP 到 CLI:AI Agent 工具链的架构演进与实战抉择
前端·面试
黄敬峰2 小时前
从零搞懂React受控与非受控组件——一个Demo串起表单处理全流程
面试
Java内核笔记2 小时前
Spring Boot 4 拥抱 Jackson 3:包名迁移、配置改名与自动配置源码剖析
java·后端
liulilittle3 小时前
MOE路由:路由(logits: top-k/8)
c++·人工智能·算法·机器学习·llm
Hamm3 小时前
前端转Java+AI全栈?那我推荐几个实战开源项目给你
前端·后端·全栈
凤山老林3 小时前
Spring Boot 定时任务进阶:动态 Cron 与集群防重实战
java·spring boot·后端·定时任务·集群定时任务
站大爷IP4 小时前
被 `asyncio.gather` 和 `wait` 坑惨了:异常处理的天壤之别
后端