Token(词元):LLM 文本处理的最小单元与通用货币
摘要: Token(词元)是 LLM 处理文本的最小语义单元,也是贯穿模型效率、API 计费与上下文容量管理的核心概念。本文从 Token 的基本定义与分词的必要性出发,系统对比了 BPE、WordPiece、SentencePiece 和 Unigram 四种主流子词分词算法——重点解剖了使用最广泛的 BPE 算法的逐级合并过程——进而分析了词表大小在 Embedding 参数量、中文编码效率与 API 调用成本之间的三重权衡。最后,本文建立了 Token 与上下文窗口之间的换算关系,阐明在选型时同时评估窗口大小和 tokenizer 词表效率的必要性。全文为理解 LLM 的文本处理流水线提供了从 Token 视角出发的完整认知地图。
1. Token 的定义
Token(词元) 是 LLM 处理文本的最小单位。模型不直接"阅读"人类文字,而是先将文本切分成一段段 token,每个 token 对应词表中的一个整数 ID。
为什么叫"词元"而不是"词"?因为一个 token 不总是一个完整的词。以 GPT-4 的标准 tokenizer 为例:
中文句子: "人工智能改变世界"
→ tokens: ["人工", "智能", "改变", "世界"] (1 个中文汉字 ≈ 1-2 tokens)
英文句子: "Artificial intelligence changes the world"
→ tokens: ["Art", "ificial", " intelligence", " changes", " the", " world"]
混合: "Transformer 是一种神经网络架构"
→ tokens: ["Transformer", " 是一种", "神经网络", "架构"]为什么需要 tokenization?
因为 GPU 只能做数值运算,Tokenizer 将文字序列转化为整数向量 [10449, 43290, 33490, ...],然后 Embedding 层再将整数映射为 GPU 能计算的浮点向量。Tokenizer 是整个 LLM 流水线中的"翻译官"——它架起了人类语言与数学世界之间的桥梁。
2. Tokenization 分词算法
将文字拆成 token 并非简单按空格或字符切分。现代 LLM 使用子词分词算法(Subword Tokenization),在"词"和"字符"之间寻找平衡点:既能用少量 token 表示常见词,又能用字符拼接表示生僻词。
全词分词的问题: "running" 和 "runner" 是两个完全不同的 token,
模型学不到它们共享 "run" 词根 → 词表膨胀,泛化性差
字符分词的问题: "transformer" → t-r-a-n-s-f-o-r-m-e-r(13 个字符 token)
序列过长,语义被割裂,训练和推理效率都低
子词分词(最优): "transformer" → ["trans", "former"](2 个子词 token)
"running" → ["runn", "ing"]
保留词根共性能,同时词表可控四种主流子词算法对比:
| 算法 | 代表 Tokenizer | 切分方向 | 核心思想 |
|---|---|---|---|
| BPE(Byte Pair Encoding) | GPT 全系列、Llama | 自底向上(合并) | 从字符出发,反复合并高频相邻对 |
| WordPiece | BERT | 自底向上 | 类似 BPE,但用概率增益而非频率选择合并 |
| SentencePiece | T5、LLaMA 2 | 自底向上 | BPE 或 Unigram,直接处理原始文本(不依赖空格预分割) |
| Unigram | XLNet、ALBERT | 自顶向下(剪枝) | 先假设一个巨大词表,逐步删除"贡献小"的子词 |
BPE 分词过程图解(最广泛使用的算法):
常见词保持完整
生僻词与新词,可自动拆为子词组合(如 "unalienable" → ["un", "alien", "able"])
示例: "lower low"
Step 1: 字符级初始化
["l", "o", "w", "e", "r", " ", "l", "o", "w"]
Step 2~4: 反复合并最高频相邻对
高频对 "l" + "o" → "lo"
高频对 "lo" + "w" → "low"
高频对 "e" + "r" → "er"
最终: ["low", "er", " ", "low"]
↑ 两个 "low" 共享子词,一个 "er" 服务于 lower/wider/deeper 等
BPE 的巧妙之处:常见词保持完整(如 "the" → 1 token),
生僻词/新词自动拆为子词组合(如 "unalienable" → ["un", "alien", "able"])3. Tokenizer 与词表大小
每个 LLM 都有一个固定大小的词表(Vocabulary),其中每个 token 对应一个唯一的整数 ID。词表大小直接影响模型效率:
| 模型 | 词表大小 | 说明 |
|---|---|---|
| GPT-2/3/4 | 50,257 ~ 100,000 | 英文为主,中文效率偏低 |
| Llama 2/3 | 32,000 | 相对小,clean 文本 |
| Qwen 2.5 | 152,064 | 多语言大词表,中文 1 汉字约 1 token |
| DeepSeek-V3 | 129,280 | 大词表,兼顾中英文效率 |
| Gemma 2 | 256,128 | 超大词表,多语言覆盖最广 |
词表大小是一把双刃剑:
一个好的 tokenizer 应该:常见词 1 token、生僻词 2-3 tokens、支持多语言时各语言 token 效率均衡。
词表太大的代价:
Embedding 矩阵 = vocab_size × d_model → 词表每增大 1 万,参数多出数千万
如 DeepSeek-V3: 129280 × 7168 ≈ 9.27 亿参数仅用于 Embedding
词表太小的代价:
中文文本被过度切碎 → 同样语义需要更多 token → 上下文窗口被快速占满
例如:GPT-3 tokenizer 下,100 字中文 ≈ 200+ tokens,llama-3 约 150 tokens
而在 Qwen tokenizer 下,100 字中文 ≈ 100-120 tokens4. Token 与计费的关系
所有 LLM API 的计费都基于 token。 我们没调用一次模型对话接口,API 提供商会同时计算 input tokens(你的提示)和 output tokens(模型的回复),分别按不同费率收费。一次典型 API 调用的 token 账单(以某模型定价为例):
Input: 用户的 System Prompt(200 tokens)
+ 对话历史(800 tokens)
+ 用户最新消息(100 tokens)
──────────────────────────────
= 1,100 input tokens × ¥0.008/1K = ¥0.0088
Output: 模型回复(400 tokens)
= 400 output tokens × ¥0.016/1K = ¥0.0064
总计:约 ¥0.015(1.5 分钱)/ 次对话为什么 output 比 input 贵?
输出 token 是在推理时逐个生成的(自回归),无法像 input token 那样批量并行计算。
此外,每生成一个 output token 都需要计算它之前所有 token 的注意力——生成第 500 个 token 时,需要计算 500×500 的注意力矩阵,计算量随输出长度增长。
实务建议:控制 System Prompt 长度、适时裁剪对话历史、用大词表模型处理中文(降低 token 数),都是有效降本手段。
5. Token 与上下文窗口的关系
上下文窗口(Context Window)的容量是用 token 数来衡量的。例如 "128K 上下文窗口" 意味着模型一次最多能处理 128,000 个 token。
一个直观的换算:
| 内容类型 | 换算关系 | 128K 窗口能容纳 |
|---|---|---|
| 英文 | 0.75 词 ≈ 1 token | 约 96,000 词,相当于一本 150 页的书 |
| 中文(大词表) | 0.8-1.2 汉字 ≈ 1 token | 约 10-15 万汉字 |
| 中文(小词表) | 1.5-2.5 汉字/1 token | 约 5-8 万汉字(效率大幅下降) |
| 代码 | 约 0.5-1 字符/token | 约 6.5-13 万字符 |
因此,选模型时不仅要看窗口大小(128K vs 256K),还要关心 tokenizer 的词表大小——同样的中文内容,在 Qwen 的 tokenizer 下占 10K token,在 GPT-3 的 tokenizer 下可能占 20K token,这意味着前者的有效上下文容量是后者的 2 倍。