用大模型时,几乎所有讨论都绕不开 token:上下文窗口是 20 万 token,输入 3 元每百万 token,回复超过 8000 token 会被截断。这篇讲清楚 token 到底是什么,以及它为什么决定了你的账单。
Token 是大模型读写文本的最小单位。模型不认识“字符”也不认识“单词”,它只认识 token。
一段文本进入模型前,会先被切成若干个 token;模型生成回复时,也是一个 token 一个 token 往外吐。上下文窗口的长度、API 的定价、生成的速度,全部按 token 计。
token 不是字,也不是词
一个常见误解是“token = 单词”,或“一个汉字一个 token”。实际都不是。
以 GPT 系列使用的 BPE(Byte Pair Encoding)为例,一段文本会被拆成“高频子串”。频繁出现的字符组合会合并成一个 token,罕见的组合则被拆碎。
看几个例子(用 GPT-4 的分词器):
| 原文 | token 数 | 拆分方式 |
|---|---|---|
hello |
1 | hello |
unbelievable |
3 | un / bel / ievable |
你好 |
2 | 你 / 好 |
你好世界 |
4 | 每个汉字一个 token |
🍥 |
3~4 | 一个 emoji 会占多个字节,拆成多个 token |
规律是:训练语料里越常见的片段,越容易独占一个 token;越冷门的字符,越会被切碎。因为主流分词器都以英语语料为主,中文、日文、代码里的罕见符号,token 数普遍多于英语。
为什么设计成这样
模型的词表大小是固定的,通常在 5 万到 20 万之间。如果按单词切,光是英语就远远超过这个规模;按字符切,模型要处理的序列又太长,学习效率低。
BPE 的做法是折中:先按字节切,然后统计哪些相邻字节最常一起出现,把它们合并成新的 token。这个过程反复迭代,直到词表满了为止。得到的词表里,the、ing、tion 这种高频组合独占一个 token,罕见的字符组合则保留细粒度。
结果就是一段英文文本平均下来每个 token 覆盖大约 4 个字符或 0.75 个单词,中文平均一个字占 1~2 个 token。
你可以自己数
OpenAI 提供了在线工具(platform.openai.com/tokenizer),也可以用官方库本地跑:
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4o")
text = "MCP 是一个开放协议"
tokens = enc.encode(text)
print(len(tokens), tokens)
# 11 [78241, 5745, 42648, 21043, 45114, 92795, 40792, 29102, 45383, 32574, 30298]高亮的那一行就是从字符串到 token id 列表的转换。每个 id 对应词表里的一个位置,模型看到的是这串数字,不是原文。
想反过来看每个 id 对应的字符片段:
for tid in tokens:
print(tid, repr(enc.decode([tid])))跑一下就能直观看到 BPE 是怎么把中文一个字拆成一两个字节 token 的。
Token 和账单
主流 API 全部按 token 计费,输入和输出通常价格不同(输出往往是输入的 3~5 倍)。一次调用的成本可以粗略估算:
成本 = 输入 token 数 × 输入单价 + 输出 token 数 × 输出单价一次看似普通的对话,token 消耗可能远超预期,因为:
- 每一轮都要重发历史。多轮对话里,前面所有 turn 都会作为输入再次传入。第 10 轮的输入 token 数是第 1 轮的十几倍。
- 系统提示词也算钱。system prompt 每次调用都要传,长 prompt 是持续开销。
- 工具定义也算钱。挂了 10 个工具,它们的 schema 每次调用都要放进上下文。
一个常见的坑是把日志、文档、代码全塞进 prompt。看着方便,账单会翻倍。
上下文窗口
模型能“看到”的 token 总数就是上下文窗口。2026 年主流模型的窗口大小:
| 模型 | 上下文窗口 |
|---|---|
| GPT-4o | 128k |
| Claude Sonnet 4.5 | 200k |
| Gemini 2.5 Pro | 1M~2M |
窗口不是越大越好。原因有几个:
- 中间部分容易被忽略。长上下文里,模型对开头和结尾的内容记得清楚,中间段落经常“读了但没记住”。这现象叫 Lost in the Middle。
- 成本线性上涨。100k token 的输入是 10k 的十倍钱,还没算生成。
- 延迟明显增加。输入越长,首 token 出来越慢。
真正需要长上下文时才用长上下文,其他情况该做 RAG 就做 RAG。
Token 决定了什么
除了账单和窗口,token 还悄悄影响了几件事:
- 流式响应的粒度。API 的 stream 返回是按 token 推的,一次通常一个 token。中文往往几个字符才凑出一个 token,所以中文流式看起来比英文“卡”一点。
- 模型的空间感知。让模型“每段 300 字”,它其实数的是 token 数(大致对应),不是精确字数。
- 生成速度。厂商公布的 “80 tokens/秒” 是 token 速度,中文实际字符速度会更低。
- 提示词的调整方向。同样意思用更少 token 的表达(比如英文关键词代替长中文短语)在极端场景下确实能省钱,但可读性下降,通常不划算。
一些工程经验
- 调用前先估 token。用官方分词器算一遍输入 token 数,可以避免 prompt 意外超长。
- 压缩历史。多轮对话到一定长度后,让模型自己写一段摘要替换掉旧 turn,能显著降本。
- 区分输入和输出定价。有些优化只降输入 token 没用,输出 token 才是大头。
- 别用字符数估算。中英混合、含代码的文本,字符数和 token 数比例波动很大。
- 系统提示词值得优化。它每次调用都要传,砍掉一句话就是每次都省钱。
写在最后
Token 不是一个 AI 使用者能绕开的抽象。上下文窗口、API 账单、生成速度、模型的“记忆力”,本质上都是 token 的表达。理解它怎么切、怎么算,比死背哪个模型多大窗口有用得多。
下次看到一个 200k token 的模型时,先算一下这够写多少中文、多少代码、能塞下多少文档,再决定值不值这个价。
