token 是什么?和字数怎么换算——开发者必知的基础
调用大模型 API 之前,你必须搞清楚一件事:你付费的单位不是”字”,不是”词”,而是 token。一旦理解 token,你就能在写 prompt 前估算成本、在超额之前主动控制用量。
token 到底是什么
Token 是大模型处理文本的最小单位,由 Tokenizer(分词器) 在输入文本进入模型之前切割生成。它既不等于一个字,也不等于一个单词,而是介于两者之间的”子词”片段。
同一段文字,不同模型使用的 Tokenizer 不同,切出的 token 数量也会有差异。主流实现包括 BPE(Byte Pair Encoding)、WordPiece 等算法,其核心逻辑都是:高频出现的字符组合合并为一个 token,低频组合则拆散处理。
这里多说一句”为什么”,很多人只记结论不知道原理,后面遇到怪异计费就没法自己排查。BPE 的合并表不是凭空定的,而是在训练语料上统计出来的:先把文本按字节/字符拆到最细,然后反复统计”哪两个相邻单元一起出现的次数最多”,把它们合并成一个新 token,重复几万次,就得到了一张几万到十几万条目的词表。这意味着词表是语料喂出来的,语料里什么语言占比高,那门语言就切得更”粗”(token 更少),切得不划算的语言自然就更”细”(token 更多)。GPT 系列的分词器早期训练语料里英文占绝对多数,“the”、“tion”、“ing”这类高频英文子串很快就被合并成了单个 token;而中文没有空格天然分词,字与字的组合方式又比英文灵活得多,很多汉字组合出现频率不够高,合并不到一起,只能拆成更细的片段。这就是为什么同样表达一个意思,中文调用经常比英文”贵”——不是模型故意针对谁,是词表统计规律决定的。反过来,像 Qwen、DeepSeek 这类国产模型在预训练时特意把中文语料占比拉高,词表里中文合并规则更充分,同一段中文切出来的 token 数就明显更少,这也是国产模型在中文场景下单价看着一样、实际花费却更省的重要原因之一。
中英文 token 换算规则
以下为实际工程中广泛使用的近似规则:
| 语言 / 内容类型 | 近似换算 | 说明 |
|---|---|---|
| 英文普通文本 | 4 个字符 ≈ 1 token | ”hello world” ≈ 2 token |
| 中文汉字 | 1 个汉字 ≈ 1–1.5 token | GPT 系列约 1.5,部分国产模型约 1 |
| 中文标点 / 空格 | 1 个符号 ≈ 0.5–1 token | 影响不大但不可忽略 |
| 代码(变量名) | 密度接近英文 | 注释和字符串更贵 |
| 特殊符号 / emoji | 1 个 ≈ 1–3 token | 视编码而定 |
快速心算口诀:
- 纯英文文章:字符数 ÷ 4
- 纯中文文章:汉字数 × 1.2(取中间值)
- 混合内容:分段估算再相加
精确计算建议使用 token 计算器 实测,因为不同模型的 Tokenizer 存在差异。
一段文字的实际拆分示例
以 “大模型接入层” 为例(7 个汉字):
- GPT-4o Tokenizer 拆分结果:约 9–11 token
- Qwen Tokenizer 拆分结果:约 7–8 token
- 国内针对中文优化的模型通常更接近「1字≈1token」
以 “large language model” 为例(19 个字符):
- 拆分为:
large/language/model→ 3 token
从这两个例子能看出一个规律:英文按”词根/词缀”合并,一个常见单词往往就是 1 个 token;中文按”高频字组”合并,一个词组也可能被硬生生切成两三段。这也解释了为什么”大模型”这种你觉得很短的词,token 数反而比看起来更长的英文短语还多——你数的是”字数”,模型数的是”合并规则命中次数”,两者根本不是一回事。
动手实测:用 tiktoken 精确算出真实 token 数
心算口诀能应付日常估算,但只要涉及三种场景——预算对账、限流告警、prompt 逼近上限——就必须用精确工具,误差 10%–20% 在这些场景里可能就是”多扣一次费”或”直接超限报错”的区别。OpenAI 系列模型可以直接用官方的 tiktoken 库本地计算,不需要联网调用 API:
import tiktoken
# cl100k_base 是 GPT-3.5/GPT-4 系列使用的编码
encoding = tiktoken.get_encoding("cl100k_base")
text = "大模型接入层的成本控制,核心是把 token 当成一等公民来管理。"
tokens = encoding.encode(text)
print(f"文本长度(字符):{len(text)}")
print(f"token 数:{len(tokens)}")
print(f"前 5 个 token 对应的原始片段:{[encoding.decode([t]) for t in tokens[:5]]}")
跑起来你应该看到类似这样的输出(具体数字会因版本略有差异,不用纠结个位数):
文本长度(字符):30
token 数:约 38-45
前 5 个 token 对应的原始片段:['大', '模', '型', '接', '入']
注意最后一行——你会发现常用汉字往往是一个字对应一个 token,但一遇到不那么高频的词组或标点组合,token 数就会跳涨,这就是前面说的”合并规则没覆盖到”的直观体现。如果你调用的不是 OpenAI 系列模型(比如 Qwen、GLM、文心一言这类国产模型),tiktoken 的编码规则不适用,得用对应厂商 SDK 里自带的分词方法,或者直接看 API 返回里的 usage 字段——这是最权威的口径,没有之一,任何本地估算工具都只是”贴近”,不是”等于”。
token 数量如何影响成本
API 按 token 计费,你为输入 token + 输出 token 各自付费,且输出单价通常更高。每次 API 调用消耗的 token 包括:
- System prompt(系统提示)
- 历史对话(所有轮次)
- 用户当前输入
- 模型生成的输出
理解这个结构之后,“成本优化”就变成了可量化的工程问题。详细的输入/输出计费差异见 输入价与输出价为什么不同。
三个真实踩过的坑,和对应的修法
坑一:用字符数估算长文档,结果直接超出 context 上限。
真实报错长这样:
Error: This model's maximum context length is 128000 tokens.
However, your messages resulted in 132456 tokens.
Please reduce the length of the messages.
根因往往不是文档真的很长,而是估算方法错了。有人拿到一份 10 万字符的中文长文档,按”字符数 ÷ 4”的英文口诀去估算,以为只有 2.5 万 token,结果实际中文按 1–1.5 倍换算,真实 token 数直接翻了 5 倍还多,超限报错来得莫名其妙。修法很简单:长文档输入前,先用上面的 tiktoken 脚本(或对应模型的分词工具)跑一遍精确计数,不要用心算口诀去卡边界,尤其是文档里混了代码块、表格这类”密度不均匀”的内容时,心算误差会被进一步放大。
坑二:正文里塞了大量装饰性符号和 emoji,token 悄悄涨了一截。
中文里常见的全角标点、破折号”——“、书名号《》,以及各种 emoji,很多都不是词表里的高频合并对象,一个符号可能被拆成 2–3 个 token。如果你的 prompt 模板里有大段格式化的分隔符(比如用一长串 emoji 做视觉分割,或者用很多”※""▶“这类符号做小标题),实测下来这部分”装饰”能占到整个输入 token 的 5%–10%,日调用量大的时候这笔隐性成本并不小。修法:正文精简符号,分隔符尽量用简单的 - # 这类 ASCII 字符,视觉效果交给前端渲染去做,不要指望靠塞符号让模型”读起来更清楚”。
坑三:多轮对话不裁剪历史,token 消耗随轮次线性爆炸。
大模型 API 本身是无状态的——每一次请求,你都要把 system prompt、历史对话、当前输入完整地重新传一遍,模型不会”记得”你上一轮说了什么。如果聊到第 10 轮还带着第 1 轮的全部内容,输入 token 会随对话轮次近似线性增长,很多团队上线一段时间后发现同一个会话越聊越贵,就是栽在这里。修法:做滑动窗口(只保留最近 N 轮原文)+摘要压缩(更早的历史用一段简短摘要代替),把历史部分的 token 占比死死摁住,不要让它跟着轮次无限往上堆。
什么场景该心算估算,什么场景必须精确计数
| 场景 | 心算估算(汉字数 ×1.2) | 精确工具(tiktoken / usage 字段) |
|---|---|---|
| 写文档、做预算规划心里有个数 | 够用,图快 | 没必要 |
| 生产环境计费对账、给用户出账单 | 不够用,误差会变成真金白银的纠纷 | 必须用,以 API 返回的 usage 为准 |
| prompt 长度逼近模型 context 上限 | 危险,容易超限报错 | 必须用,提前留出安全余量 |
| 做限流 / 熔断策略(按 token 预算控速) | 可以做粗粒度预判 | 精细限流仍要接实测数据 |
| 日常调试单条 prompt 效果 | 够用 | 没必要,除非怀疑计费异常 |
简单说:只要涉及”钱”和”硬上限”这两件事,就别偷懒用心算,跑一次精确计数只要几毫秒,比线上报错或者账单对不上省心得多。
进阶:流式输出和失败重试里的隐藏成本
流式(SSE)返回时不要用”屏幕上蹦出了多少字”去估算 token——流式是按增量文本块(chunk)陆续推送的,中间任何一个时间点看到的字数都不是最终的 token 统计口径。真正准确的数字,要看流结束时厂商返回的用量信息:OpenAI 需要显式在请求里开启 stream_options: {"include_usage": true} 才会在最后一个 chunk 里带上 usage 字段,不开的话你拿不到;其他厂商字段名和触发方式也不完全一致,具体以官方文档为准,接入前务必确认清楚,否则你的计费系统会一直拿不到准数据。
另一个容易被忽略的隐性成本是失败重试。网络超时、429 限流触发的自动重试,如果客户端逻辑是”整个请求原样重发”,那么这次输入 token(尤其是很长的 system prompt 和历史对话)就被重复计费了一次——重试三次,输入部分的钱就多付了三倍。工程上至少做两件事:一是重试要配合指数退避和最大重试次数上限,别无脑重试;二是如果你调用的模型支持 prompt caching(部分厂商对重复出现的 system prompt 前缀给缓存折扣甚至免费),把固定不变的大段 system prompt 放在请求最前面、内容保持字节级一致,能不能吃到缓存折扣直接影响长期账单,这块建议对照具体厂商文档逐条核实,不要想当然。
常见问题
token 和词向量、embedding 有关系吗?
有,但不同概念。token 是原始文本的切分单位;embedding 是 token 经过模型映射后的高维向量表示。计费阶段只关心 token 数量,embedding 是模型内部细节。
中文”的地得”这种虚词也算 token 吗?
算。所有字符都会被 Tokenizer 处理,虚词、标点、空格都占 token,只是数量通常较少。
用 token 估算成本准确吗?
近似估算误差在 10%–20% 以内,足够做预算规划。精确场景下建议跑几次实测并记录日志中返回的 usage 字段。
延伸阅读:
- 计费原理总览:大模型 token 计费完全指南
- 深入理解分词:Tokenizer 原理:中英文 token 差异
- 成本横向比较:各家计费规则与计费单位
- 在线估算用量:Token 计算器
- 实时价格对比:价格对比表
- 更多成本话题:token 成本专题