大模型 Token 科普:什么是 Token?为什么输出 Token 更贵?
大模型 Token 科普:什么是 Token?为什么输出 Token 更贵?
很多人第一次看大模型 API 账单,会有两个困惑:
- 同样是 Token,为什么“模型生成的输出”(completion)经常更贵?
- 明明提示词写得很“稳定”,为什么有时成本和延迟会突然飙升?
这篇文章用科普视角把 Token、分词器切分、以及“为什么输出 token 更贵”的计算原因讲清楚。
说明一下术语:很多厂商把“输入”叫 prompt(提示词/请求内容),把“模型生成的输出”叫 completion(对输入的续写/补全)。
说明:本文内容整理自笔记材料。
摘要(先看结论)
- Token 是大模型处理文本的最小计费/计算单位,本质是“分词器把字符串切成片段后映射到词表 id”的结果。
- 预填充(prefill,处理输入)可以在序列维度高度并行;解码(decode,生成输出)必须自回归逐 token 生成,GPU 利用率更难拉满,所以输出通常更贵。
- 预填充可以理解成“先把题目读完”:模型一次性处理整段输入的所有 token,并为每个位置做计算;因为输入 token 都已知,很多计算可以并行铺开做。
- 解码可以理解成“开始写答案”:模型每次只生成 1 个新 token,下一步要基于“刚生成的 token + 之前所有内容”继续生成,所以步骤之间有严格先后顺序,天然更串行。
- 结果就是:同样 1000 个 token,输入侧更像一块并行计算;输出侧更像 1000 次连续的小步计算,吞吐更难做高,价格往往更高。
- 一些平台会做“前缀缓存”(prompt prefix cache):当输入前缀完全一致时,可复用部分计算结果,主要影响延迟与成本结构的波动。
快速导航(按问题定位)
| 你看到的现象 | 优先看哪节 | 一句话解释 |
|---|---|---|
| 输出 token 比输入 token 贵 | 为什么输出更贵、Token 计费怎么来的 | 并行度不同导致成本结构不同 |
| 同样模板,偶尔突然变慢/变贵 | 前缀缓存命中机制 | 前缀变了就要重算,等同“冷启动” |
| 语义看起来一样,却没命中缓存 | Tokenizer 怎么切、前缀缓存命中机制 | 缓存看的是字节级一致,不看语义 |
| 账单主要被输出占据 | 为什么输出更贵、Token 计费怎么来的 | 长回答场景,成本大头常在输出段 |
Token 是什么:别把它当“字数”
大模型只能处理数字序列,不懂“文字”。所以需要一个翻译官:Tokenizer(分词器)。
一条典型流水线是:
文本 → Tokenizer 编码 → Token id 序列(数字) → 模型计算 → Token id → Tokenizer 解码 → 文本
用一张 ASCII 图把“谁在干什么”画清楚:
(字符串) (数字) (字符串)
┌───────────────┐ encode ┌────────────────────────┐ decode ┌───────────────┐
│ 输入文本(prompt)│ ─────────► │ token id 序列 [..,..] │ ─────────► │ 输出文本 text │
└───────────────┘ └────────────────────────┘ └───────────────┘
│ ▲ │ ▲
│ │ │ │
▼ │ ▼ │
┌─────────────┐ │ ┌─────────────┐ │
│ Tokenizer │ │ │ 大模型 │ │
└─────────────┘ │ └─────────────┘ │
│
└──(模型只“认识”数字序列)
这里有两个关键点:
- Token 不等于“字”也不等于“词”,可能是一个字、一个词、甚至一个子词片段(例如
debug可能被切成de+bug这样的子词)。 - 你在 API 里看到的输入/输出 token 计数,取决于“分词器如何切分”,不是你肉眼看到的字符数。
可以用一个很直觉的类比理解“子词 token”:有些单独拿出来你不认识,但把它放进一个常见词语里,你马上就认识了。
对应到 Token:
- 单个 token 可能只是“词的一部分”,单看不一定有意义
- 但多个 token 拼在一起,就组成了你熟悉的词语/句子
类比(直觉示意,不代表真实分词结果):
单独看: [醐] [俎] [阖] [缪] (单看不一定认识/不会读)
放进词语: 醍醐灌顶 越俎代庖 纵横捭阖 未雨绸缪 (放进词语里更容易“认出来”)
对应到 token:
token1 + token2 → 一个你“认识”的词
Tokenizer 怎么切:不懂语义,只做统计切分
分词器通常基于大规模语料训练,目标很朴素:
- 高频共现的片段更容易被合并成一个 token
- 低频、混杂符号、罕见组合更容易被拆成多个 token
理解上需要记住两件事:
- 对“整段输入字符串”,切分结果是稳定的:同一个模型/同一个 tokenizer、同一段字符串输入,切分结果一致。
- 但你在讨论“某个词/短语”时,它在不同上下文里左右邻接字符可能不同(空格、标点、换行、全角半角、Unicode 归一化等),导致它在整段文本中的切分边界看起来不一样。
举个中文例子(示意切分,用来帮助理解“边界来自上下文”,不代表任何具体 tokenizer 的真实输出):
句子 A:我喜欢人工智能
可能的 token:["我", "喜欢", "人工智能"]
句子 B:我喜欢 人工智能
可能的 token:["我", "喜欢", "␠人工", "智能"]
说明:
- 这里的 ␠ 表示“空格字符”。很多 tokenizer 会把“前导空格”一起并进 token 里。
- 所以你肉眼看到的“人工智能”看起来没变,但在不同上下文里,它周围的字符(有没有空格)变了,
token 的边界就可能变,token 数也可能变。
这也直接影响后面要讲的缓存命中:缓存通常按“前缀是否完全一致”判断,而不是按语义相似判断。
为什么输出更贵:并行 vs 串行
把推理过程粗略拆成两段会更好理解:
输入阶段:预填充(Prefill)
输入 token 在 Transformer 的注意力计算中,可以在序列长度维度高度并行(尽管仍然消耗显存与算力)。因此在同等 token 数下,吞吐更好,单位 token 成本更低。
输出阶段:解码(Decode)
输出 token 的生成是自回归的:
- 生成第 101 个 token 之前,必须先得到前 100 个 token 的结果
- 每一步都要做一次前向计算(并更新/读取缓存)
这导致:
- 计算链路更难并行,GPU 更容易“吃不满”
- 同样数量的 token,输出段更贵、更慢
用一张图直观看“并行”和“串行”的差别:
时间轴 ─────────────────────────────────────────────────────────────►
Prefill(处理输入:更容易并行)
输入 tokens: t1 t2 t3 ... tn
计算方式: [██████████████████████████████████████████████████████] (一大块并行算完)
Decode(生成输出:必须串行)
输出 tokens: y1 y2 y3 ... ym
计算方式: [██]→[██]→[██]→ ... →[██] (每一步都依赖上一步的结果)
Token 计费怎么来的:输入/输出分开计价
很多厂商按“输入 token + 输出 token”分别计费。以笔记中举的 DeepSeek 例子(仅作机制示意):
| 计费类型 | 定价逻辑 | 技术原因 | 典型价格(DeepSeek 示例) |
|---|---|---|---|
| 输入 Token | 价格较低 | 可并行处理,GPU 资源利用率高 | 2 元 / 百万 token |
| 输出 Token | 价格较高 | 串行生成,推理资源消耗更大 | 3 元 / 百万 token |
你可以用一个最简单的成本公式在心里做估算:
成本 ≈ 输入token数 × 输入单价 + 输出token数 × 输出单价
从这个计费结构可以得到两个直觉结论:
- “提示词很长但输出很短”的任务,成本更接近输入段
- “输出很长(写文章/长代码/长推理)”的任务,账单主要由输出段决定
前缀缓存命中机制:前缀一样就省钱,不一样就重算
这里的“缓存”,讨论的是很多厂商在服务端做的“前缀缓存命中”(也常被称为 prompt cache / prefix cache)。
先用一张图把“前缀缓存到底缓存哪一段”说清楚:
一次请求的输入(prompt)通常可以拆成两段:
┌─────────────────────────── 固定前缀(应尽量稳定) ───────────────────────────┐┌──────── 动态后缀(每次变化) ────────┐
│ system prompt / 角色设定 / 输出格式约束 / 工具描述 / 固定示例 / 长模板 ... ││ user question / 实时数据 / 变量 ... │
└──────────────────────────────────────────────────────────────────────────────┘└───────────────────────────────────────┘
缓存命中:固定前缀“字节级完全一致” → 复用这段的中间计算结果 → 省时/省钱(视平台而定)
缓存不命中:固定前缀有任何差异(空格/换行/标点) → 这段需要重新计算 → 变慢/变贵
命中是什么意思?
当你的输入文本存在一段“稳定不变的前缀”(典型就是系统提示词、固定指令模板、固定工具描述等),并且这段前缀与历史请求完全一致时:
- 服务端可以复用这段前缀对应的中间计算结果
- 减少重复计算,降低延迟
- 部分平台会对“已缓存 token”给出折扣计费或更低的计费档位
什么情况下会不命中?
只要前缀发生变化(哪怕只是一处标点/空格/换行不同),就需要重新计算整段前缀:
- 延迟上升
- 成本上升
- 在“固定前缀很长”的场景下,变化一次就可能带来明显的波动
笔记中的提醒很直白:缓存未命中可能导致价格“直接飙升”。把它理解成软件系统里的“冷启动”就好。
Token 量级怎么估:一个实用类比
笔记里给了一个很好用的类比:
- 100 万 token ≈ 3 本《三体》的文本量
你可以把它当作“容量单位”来做粗估:
- 如果一次对话要塞入很多长文档,先问自己:是不是已经接近“几本书”的量级?
- 如果每次都在系统提示词里塞一大段规范,缓存命中与否会对成本影响非常明显
常见误区(很容易踩)
-
误区 1:以为 Token 就是字数/字符数
实际由 tokenizer 决定,不同语言/符号密度差异很大。 -
误区 2:以为“语义一样就能缓存命中”
多数前缀缓存要求字节级一致;差一个空格也可能不命中。 -
误区 3:只盯着输入段
写长答案时输出段常是成本大头。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)