Token彻底讲透:大模型“读“不了一个字,但能理解整个世界是怎么做到的?
如果你用过任何大语言模型——ChatGPT、Claude、文心一言、通义千问——你大概率在某个角落见过这个词:Token。API 按 Token 计费、模型有 Token 上限、"你的上下文太长,请缩短"……Token 像是 LLM 世界的"最小货币单位"。
但你有没有想过一个问题:大模型到底是怎么"看到"文字的?
答案可能会让你意外:大模型根本不认识字。 它连一个汉字、一个字母都不认识。它只认数字——准确地说,是一长串整数 ID。把文字变成数字的过程,就叫 Tokenization(分词/标记化),而这个数字,就是 Token。
这篇文章会带你从最底层理解 Token,搞清楚这层抽象到底是怎么运作的、为什么它如此重要、以及你在日常使用中应该注意什么。我们会深入到 BPE 算法的原理,也会手把手给你看代码。读完你会明白:Token 不止是计费单位,它决定了 LLM 能记住多少东西、能不能读懂代码、以及你到底要花多少钱。
一、Token 到底是什么?——从一个简单的实验开始
先做一个直觉实验。打开 OpenAI 的 Tokenizer 工具,输入这句话:
你好,世界!
GPT-4 的 tokenizer 会把它拆成这样:
你 (1 token) 好 (1 token) , (1 token) 世界 (1 token) ! (1 token)
5 个 Token。 为什么?因为 GPT-4 用的 tokenizer 不认识"你好"是个固定搭配——它把每个汉字当成一个 Token 来存。
再试试这句话:
Hello, world!
GPT-4 的 tokenizer 这次怎么拆?
Hello (1 token) , (1 token) world (1 token) ! (1 token)
也是 4 个 Token。看起来中文和英文差别不大?那你试试这句:
Transformer架构彻底改变了自然语言处理
GPT-4 tokenizer 拆出来是:
Transformer (1 token) 架构 (1 token) 彻底 (1 token) 改变 (1 token) 了 (1 token) 自然 (1 token) 语言 (1 token) 处理 (1 token)
8 个 Token。 而英文的 "Transformer architecture completely changed natural language processing" 是:
Transformer (1) architecture (1) completely (1) changed (1) natural (1) language (1) processing (1)
7 个 Token。 似乎差不多。
但如果你输入的是一个 Python 代码块呢?
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
GPT-4 tokenizer 会把它拆成:
def (1) fib (1) on (1) acc (1) i (1) ( (1) n (1) ) (1) : (1)
(LINEBREAK) (1) if (1) n (1) <= (1) 1 (1) : (1)
(LINEBREAK) (1) return (1) n (1)
(LINEBREAK) (1) return (1) fib (1) on (1) acc (1) i (1) ( (1) n (1) - (1) 1 (1) ) (1) + (1) fib (1) on (1) acc (1) i (1) ( (1) n (1) - (1) 2 (1) ) (1)
67 个 Token! 注意看——fibonacci 被拆成了 fib + on + acc + i,不是一整个单词。为什么?因为 fibonacci 不是一个常见的前缀/词根组合,tokenizer 不认识,只能拆到更细的粒度。
这就是 Token 的第一个核心认知:Token ≠ 单词。Token ≠ 字符。Token 是 tokenizer 认为"值得作为一个整体记忆"的最小语义单元。
二、为什么需要 Token?——一个极其朴素的问题
有人可能会问:为什么不直接把每个字符当成一个 Token?这样多简单?"你好世界"就 4 个字符,4 个 Token。何必搞那么复杂的 tokenization?
答案是:效率。
一个 GPT-4 级别的 Transformer 模型在计算 self-attention 时,计算复杂度是 O(n²),n 是 Token 数量。如果"你好世界"拆成 4 个字符处理,那还好。但如果是一篇 5000 字的文章呢?按字符拆,可能是 5000 个 Token;按 tokenization 拆,可能是 3500 个 Token。单层 attention 的计算量差就是 25,000,000 vs 12,250,000——差了一倍。
而且,把常见词组变成单个 Token,意味着模型只需要学习一个 embedding 向量就能理解这个概念。如果是按字符拆,"transformer" 要拆成 11 个字符,模型需要通过 attention 机制把 11 个字符的 embedding 组合起来才能理解——这需要更深层的学习、更多参数、更多数据。
Tokenization 本质上是一项压缩技术。 它把常见模式"打包"成一个 Token,让模型更高效。
三、Tokenization 怎么做?——三大主流算法的底层原理
现在我们来点硬核的。LLM 的 tokenizer 通常使用 子词(subword) 级别的分词——不是单词级别,也不是字符级别,而是在两者之间找一个最优平衡点。主流算法有三种。
3.1 BPE(Byte Pair Encoding)——GPT 系列的选择
BPE 是 OpenAI GPT 系列(GPT-2、GPT-3、GPT-4)使用的核心分词算法,也是最广泛使用的一种。
核心思想特别简单:从字符级开始,反复合并最常见的相邻字符对,直到达到预设的词汇表大小。
举个例子。假设我们有一个非常小的语料库,只包含三个词:
low lower lowest
BPE 的步骤是:
Step 1:初始化。 把每个词拆成字符,每个字符后加一个 </w>(词尾标记):
l o w </w>
l o w e r </w>
l o w e s t </w>
Step 2:统计字符对频率。 在这个语料库中:
(l, o)出现了 3 次(o, w)出现了 3 次(w, e)出现了 2 次(e, r)出现了 1 次(e, s)出现了 1 次(s, t)出现了 1 次(w, </w>)出现了 1 次(r, </w>)出现了 1 次(t, </w>)出现了 1 次
Step 3:合并最高频对。 (l, o) 和 (o, w) 都是 3 次,选第一个 (l, o) 合并成 lo。此时词汇表新增了 lo:
lo w </w>
lo w e r </w>
lo w e s t </w>
Step 4:重复。 继续统计并合并。下一步最高频的是 (lo, w)(3 次),合并成 low:
low </w>
low e r </w>
low e s t </w>
继续。最高频的是 (low, e)(2 次),合并成 lowe:
low </w>
lowe r </w>
lowe s t </w>
继续……
最终,经过多轮合并,词汇表里会出现 low、er、est、ing 等常见组合。当词汇表达到预设大小(比如 GPT-4 的 100,000),算法就停止了。
那遇到词汇表里没有的新词怎么办? BPE 会把新词拆成已知的子词。比如 unhappily:
- 词汇表里有 un、happi(通过 happy → happi + ly 学到)、ly
- 那 unhappily → un + happi + ly
这就是 BPE 的精髓:从未见过的词,也能用已知的子词组合"拼"出来。 这也是为什么 "architecture" 被拆成 arch + itecture 或 arch + it + ecture——取决于训练数据中这些子词的频率。
3.2 WordPiece——BERT 的选择
Google 的 BERT 使用 WordPiece 算法。和 BPE 很像,但合并策略不同。
BPE 合并「出现频率最高」的字符对;WordPiece 合并「组合在一起时"值得"成为一个 Token」的字符对。 衡量标准是:
score = count(pair) / (count(first) × count(second))
这个分数的含义是:这对字符实际一起出现的频率,与它们"偶然碰在一起"的概率之比。 如果这个值很高,说明它们是真正的组合,不是巧合。
举个例子:如果语料库中 un 出现了 100 次,而 u 出现了 1000 次,n 出现了 2000 次:
- "偶然碰在一起"的概率 ≈ (1000 × 2000) / N²
- 实际 = 100 / N
- score = 100N / (2,000,000)
如果 N 够大,这个值可能很大。
而如果 uq 出现了 10 次,u 出现了 1000 次,q 只出现了 5 次(因为 q 总是跟在 u 后面):
- "偶然碰在一起"的概率 ≈ (1000 × 5) / N²
- 实际 = 10 / N
- score = 10N / 5000
这个值可能比上面的还要大——因为 q 几乎总是和 u 一起出现。
WordPiece 的优势在于:它不容易被"高频但不重要的组合"误导。比如 "the" + 空格在英语中频率极高,但这不是有意义的组合,WordPiece 不会优先合并它们。
3.3 Unigram & SentencePiece——LLaMA 等现代模型的选择
Google 的 T5 和多语言模型使用 SentencePiece(基于 Unigram 算法)。和 BPE/WordPiece 不同,Unigram 是"自上而下"的:
- 从一个大词汇表开始(比如所有可能的子词组合)
- 计算每个子词的"损失"(如果去掉它,模型的困惑度会增加多少)
- 删除损失最小的子词(不太重要的)
- 重复直到词汇表缩小到目标大小
SentencePiece 最大的特点是:它把空格也当普通字符处理,用特殊符号 ▁(U+2581)表示词边界。这意味着它能优雅地处理任何语言——中文、日文、韩文、阿拉伯文——不需要语言特定的预处理。
Meta 的 LLaMA 系列使用的 tokenizer 就基于 SentencePiece。同一个算法既管英文也管中文,这也是为什么 LLaMA 处理中文的能力也在不断提升。
四、Token 经济——为什么每个 Token 都在烧钱?
现在你知道了 Token 怎么来的。我们聊聊更现实的:Token 与钱的关系。
所有主流 LLM API 都是按 Token 计费的。以 GPT-4o 为例(2026 年价格):
| 操作 | 价格 |
|---|---|
| 输入(prompt) | $2.50 / 1M tokens |
| 输出(completion) | $10.00 / 1M tokens |
| 缓存输入(命中) | $1.25 / 1M tokens |
看起来不贵?那我们来算一笔账。
一只"AI 助手"每天要烧多少 Token?
假设你的 AI Coding 助手(比如 Cursor、CodeBuddy、GitHub Copilot)每天帮你写代码,典型场景:
- 每次对话:1500 tokens 上下文(你问的问题 + 相关代码)+ 2000 tokens 系统提示词 = 3500 tokens 输入
- 每次生成:800 tokens 输出(生成的代码)
- 每天对话次数:50 次(真实的——你在调试时可能一小时就十几轮)
每天 Token 消耗:
- 输入:3500 × 50 = 175,000 tokens ≈ $0.44
- 输出:800 × 50 = 40,000 tokens ≈ $0.40
- 单日成本:约 $0.84
看起来还好。但如果你用的是 Claude Opus 4.8($15/$75 每 1M tokens):
- 输入:175,000 tokens × $15/1M = $2.63
- 输出:40,000 tokens × $75/1M = $3.00
- 单日成本:约 $5.63
- 一个月:约 $169
这就是为什么大家在关心"用哪个模型最划算"——Token 经济是真金白银。
Token 定价的隐性成本
还有一个更容易被忽视的成本:system prompt + 上下文窗口的"浪费"。
大多数 AI Coding 工具每次对话都带着一个很长的 system prompt(可能 2000-5000 tokens),即使在多轮对话中每轮都被重复计费。再加上对话历史不断增长——第 10 轮对话的输入可能已经膨胀到 8000 tokens。
实战建议:在 long-running coding session 中,适时开启新对话,重置上下文。这是减少 Token 浪费最直接的方法。
五、Token 与上下文窗口——为什么 Claude 能"记住"200K,而 GPT-3.5 只有 4K?
上下文窗口(Context Window)的单位就是 Token。 一个模型的上下文窗口有多大,决定了它一次性能"看到"和"记住"多少内容。
| 模型 | 上下文窗口 | 约等于 |
|---|---|---|
| GPT-3.5 | 4,096 tokens | ~3,000 个汉字 |
| GPT-4-Turbo | 128K tokens | ~96,000 个汉字 |
| Claude 3.5 Sonnet | 200K tokens | ~150,000 个汉字 |
| Gemini 2.5 Pro | 1M tokens | ~750,000 个汉字 |
| Qwen3.7 Max | 256K tokens | ~192,000 个汉字 |
但这里有一个关键陷阱:上下文窗口大 ≠ 模型能"有效利用"全部内容。这涉及到 LLM 的注意力衰减问题——在长上下文中,模型对开头的注意力会逐渐减弱,导致"遗忘"早期的信息。
业界有一套叫做"大海捞针"(Needle in a Haystack)的测试来评估这个能力。简单说就是把一个关键信息藏在超长文本的不同位置,看模型能不能找到。2026 年的主流模型在 128K 范围内表现都不错,但超出这个范围后准确性会显著下降。
对 AI Coding 的实际影响:如果你把整个项目的代码(可能十几万行)一次性喂给模型,它虽然"能读到",但大概率会遗漏很多细节。更好的做法是配合 RAG(检索增强生成,这个我们上篇文章刚聊过)做精准检索,只把相关代码段送进上下文。
六、Tokenization 的坑——那些让你 Debug 到崩溃的"隐形问题"
6.1 中文的 Token 效率问题
回到开头的实验。相同意思的一句话:
- 中文:"大语言模型正在改变世界" → 8 tokens
- 英文:"Large language models are changing the world" → 7 tokens
看起来差不多。但如果内容长了:
- 一篇 3000 汉字的中文文章 ≈ 4500-6000 tokens
- 一篇 3000 单词的英文文章 ≈ 3500-4000 tokens
中文的 Token 效率天然比英文低约 30%-50%。 这意味着在同样的上下文窗口下,中文用户能喂给模型的内容更少。这也是为什么很多中文 AI 应用对上下文窗口更敏感。
如果你在做中英混合的 prompt 工程,考虑核心指令用英文写(更省 Token),但领域知识用中文(因为模型对英文 Token 的语义压缩更好)。
6.2 数学和数字——Token 的绝对黑洞
这是一件很多人不知道的事:大模型处理数字的能力很差,Tokenization 是主要罪魁祸首。
试试用 tokenizer 处理 1234567890:它可能被拆成 123 456 789 0 四个 Token。而模型需要理解这不是四个独立的数字,而是一个整体。
如果 GPT-4 的 tokenizer 把 1234567890 拆成了 123、456、789、0 四个 Token,模型在计算 1234567890 + 9876543210 时,必须先通过 attention 机制把四个 Token 的语义"组装"成一个数字——而这正是 LLM 的弱点。这就是为什么大模型做数学经常翻车——不是因为"不会算",而是因为数字在 tokenization 阶段就被"打散"了。
这也是为什么你需要 MCP 的 Server 端工具——把数学计算交给 Python 或 Calculator MCP Server,而不是让 LLM 自己算。MCP 那篇文章里我们详细聊过这个。
6.3 特殊字符和代码——Tokenization 对程序员的特殊关照
代码里的符号在 tokenization 中通常被当作独立 Token:
x = arr[i] + 1
# → x, =, arr, [, i, ], +, 1
# → 8 tokens
但同一行代码在不同模型的 tokenizer 下可能差别很大:
- GPT-4:
arr[i]→arr+[+i+]= 4 tokens - CodeGemma(Google 代码专用模型):
arr[i]→ 可能只有 1 token(专门为这类模式训练了 tokenizer)
这就是为什么不同模型处理代码的效率天差地别。代码专用模型(如 CodeGemma、DeepSeek Coder、StarCoder)的 tokenizer 通常对编程语言的常见模式做了优化,让 for i in range 这样的高频代码模式被压缩成更少的 Token。
七、实战:用 Python 亲手操作 Tokenizer
光说不练假把式。我们直接用 Python 把 tokenization 跑一遍。
7.1 安装和基础操作
# 安装 tiktoken(OpenAI 的 tokenizer)
# pip install tiktoken
import tiktoken
# 加载 GPT-4o 的 tokenizer
enc = tiktoken.encoding_for_model("gpt-4o")
# 编码:文字 → Token ID 列表
text = "AI Coding is changing the way we build software."
tokens = enc.encode(text)
print(f"原始文字: {text}")
print(f"Token IDs: {tokens}")
print(f"Token 数量: {len(tokens)}")
# 输出: Token 数量: 12
# 解码:Token ID 列表 → 文字
decoded = enc.decode(tokens)
print(f"解码结果: {decoded}")
# 输出: AI Coding is changing the way we build software.
# 逐个看每个 Token 对应什么
for token_id in tokens:
token_bytes = enc.decode_single_token_bytes(token_id)
print(f"ID {token_id:>6} → {token_bytes}")
输出大概是:
ID 2582 → b'AI'
ID 16565 → b' Cod'
ID 318 → b'ing'
ID 374 → b' is'
ID 5079 → b' changing'
ID 290 → b' the'
ID 1638 → b' way'
ID 584 → b' we'
ID 4761 → b' build'
ID 6543 → b' soft'
ID 1193 → b'ware'
ID 13 → b'.'
注意看!"Coding" 被拆成了 Cod + ing,"software" 被拆成了 soft + ware。这就是 BPE 在起作用。
7.2 批量统计不同语言的 Token 效率
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4o")
# 中英文对比
cn_text = "人工智能正在彻底改变软件开发的方式,从代码生成到自动化测试,AI Coder正在成为每个工程师的标配工具。"
en_text = "Artificial intelligence is fundamentally changing the way software is developed, from code generation to automated testing, AI Coders are becoming a standard tool for every engineer."
cn_tokens = len(enc.encode(cn_text))
en_tokens = len(enc.encode(en_text))
print(f"中文: {len(cn_text)} 字符 → {cn_tokens} tokens (效率 {cn_tokens/len(cn_text):.2f})")
print(f"英文: {len(en_text)} 字符 → {en_tokens} tokens (效率 {en_tokens/len(en_text):.2f})")
# 典型结果:
# 中文: 52 字符 → ~85 tokens (效率 ~1.63)
# 英文: 190 字符 → ~45 tokens (效率 ~0.24)
注意看这个颠倒的结果:英文字符数更多但 Token 更少。 因为每个英文字母平均不到半个 Token,而每个汉字通常就是 1 个 Token。
7.3 估算 API 费用
def estimate_cost(prompt: str, model: str = "gpt-4o"):
"""估算单次 API 调用的费用"""
enc = tiktoken.encoding_for_model(model)
input_tokens = len(enc.encode(prompt))
# GPT-4o 预估输出长度(实践经验,通常在输入的 0.3-1.5 倍之间)
estimated_output = int(input_tokens * 0.5)
# GPT-4o 2026 年定价
input_price = 2.50 / 1_000_000 # $2.50 per 1M input tokens
output_price = 10.00 / 1_000_000 # $10.00 per 1M output tokens
cost = input_tokens * input_price + estimated_output * output_price
print(f"输入 Token: {input_tokens}")
print(f"预估输出 Token: {estimated_output}")
print(f"预估费用: ${cost:.6f}")
print(f"如果每天调用 100 次: ${cost * 100:.4f}/天, ${cost * 100 * 30:.2f}/月")
return cost
# 示例:一篇 2000 字的技术文章作为 prompt
long_prompt = "请分析以下代码的性能瓶颈并给出优化建议...\n\n" + "x = 1\n" * 500
estimate_cost(long_prompt)
7.4 上下文窗口检查器
import tiktoken
def check_context_limit(text: str, model: str = "gpt-4o", context_limit: int = 128000):
"""检查文本是否超出模型的上下文窗口"""
enc = tiktoken.encoding_for_model(model)
token_count = len(enc.encode(text))
percentage = (token_count / context_limit) * 100
print(f"模型: {model}")
print(f"上下文窗口: {context_limit:,} tokens")
print(f"文本 Token 数: {token_count:,}")
print(f"使用率: {percentage:.1f}%")
if token_count > context_limit:
print(f"⚠️ 超出限制 {token_count - context_limit:,} tokens!请精简内容。")
elif percentage > 80:
print(f"⚠️ 接近上限({percentage:.0f}%),建议缩减或开启新对话。")
else:
print(f"✅ 空间充足,还有 {context_limit - token_count:,} tokens 可用。")
return token_count
# 可以检查你的 system prompt + 对话历史的长度
conversation = "System: You are an expert coding assistant...\nUser: ...\nAssistant: ..."
check_context_limit(conversation)
八、Token 在 AI Coding 中的实战优化
8.1 Prompt 设计中的 Token 优化
很多人写 prompt 很随意,充满了"请"、"麻烦"、"能不能"这些礼貌用语。每个礼貌用语都是 1-2 个 Token。在单次对话中无所谓,但如果你的 prompt 是一个每天被调用 10 万次的 API 调用,每个 prompt 省 3 个 Token 就是每天省 30 万个 Token——按 GPT-4o 价格是 $0.75/天,一个月 $22.5。
优化前:
请帮我分析一下下面这段代码中可能存在的性能问题,并对每个问题给出详细的优化建议。非常感谢!
优化后:
分析以下代码的性能问题并给出优化建议:
第一个版本 ~35 tokens,第二个版本 ~18 tokens。内容几乎一样,Token 省了一半。如果你做一个面向海量用户的 AI Coding 产品,这种优化非常关键。
8.2 代码注释的 Token 权衡
很多 AI Coding 工具在生成代码时会附带详细注释。但你有没有想过——注释也是 Token,也占用上下文窗口。
对于 prompt 里喂给模型的参考代码,注释很有用(它是"few-shot 示例"的一部分)。但对于模型输出的代码,冗长的注释可能是浪费——尤其是那种 // i 自增 1 级别的无效注释。
更好的策略:在 system prompt 中指示"只对关键逻辑写注释",让模型输出时自动控制注释密度。
8.3 选择合适的模型 Tokenizer
同样的中文文章,不同模型的 Token 数量差异可能很大:
| 模型 | Tokenizer | 1000 汉字的 Token 数(约) |
|---|---|---|
| GPT-4o | tiktoken (o200k_base) | ~1600 |
| Claude 3.5 | 自定义 BPE | ~1400 |
| DeepSeek V3 | 自定义(多语言优化) | ~1200 |
| Qwen 2.5 | 自定义(中文优先) | ~900 |
Qwen 因为是中文优先的模型,处理中文的 Token 效率显著高于 GPT 和 Claude。 如果你的应用场景主要是中文,选择 Qwen 或 DeepSeek 不仅能获得更好的中文理解能力,还能省不少 Token 费用。
九、常见误区与真相
误区 1:"Token = 单词"
真相:Token ≠ 单词。一个单词可能是一个 Token(如 "hello"),也可能是多个 Token(如 "unhappiness" → "un" + "happiness"),也可能多个单词合并成一个 Token(如 "the " → 1 token 包含了 "the" 和后面的空格)。中文里,一个 Token 通常是一个汉字或常见词组。
误区 2:"上下文窗口大小就是字数"
真相:上下文窗口的单位是 Token,不是字数。128K tokens ≠ 128,000 个汉字。根据语言不同,128K tokens 约等于 80,000-100,000 个汉字,或约 90,000-110,000 个英文单词。
误区 3:"Token 越多,模型理解越好"
真相:Token 是手段,语义是目的。如果把 "the" 拆成 "t-h-e" 三个 Token,模型需要多花注意力来"粘合"它们,反而降低理解效率。好的 tokenizer 是把"有意义的单元"压缩成一个 Token,而不是让 Token 越多越好。
误区 4:"只要上下文窗口够大,就能无限塞内容"
真相:即使不超出窗口,超长的上下文也会导致注意力衰减——模型对文本中间和结尾部分的关注度不均匀。而且,长上下文的推理速度会显著变慢(O(n²) 的 self-attention),费用也会急剧上升。
十、总结:Token 是 LLM 世界的"最小作用量"
如果把 LLM 比作物理学,Token 就是作用量量子 h——它是一切计算的最小不可分割单元。你写的每一行 prompt、每一段代码、每一个字,最终都会落到 Token 这个层面被模型处理。
理解 Token 能帮你:
- 省钱:优化 prompt 设计,选择合适的模型 tokenizer,控制上下文长度
- 提效:在有限的上下文窗口内塞进更多有效信息
- Debug:当模型出现"不能理解数字"、"漏掉关键信息"等问题时,知道可能是 Tokenization 的锅
- 选模型:根据你的语言需求,选择 Token 效率更高的模型(中文选 Qwen/DeepSeek,代码选 StarCoder/DeepSeek Coder)
Tokenization 这个"翻译层"看似简单,却深刻影响了大模型的一切行为。搞懂了它,你就掌握了 LLM 世界的底层密码。
更多推荐

所有评论(0)