token 是怎么算的?中英文差在哪,账单为什么总对不上
token 不是字也不是词,是模型分词器切出来的片段;中文大致一个字一个 token 上下,英文平均三到四个字符一个 token。你自己估的数和账单对不上,九成不是算错了,而是漏算了 system prompt、工具定义和多轮历史——这些你没打出来的内容,每次请求都在照常计费。
这篇不讲 tokenizer 的算法原理,只讲一件事:怎么把「这个功能一个月烧多少钱」估到量级正确。想边看边算,可以直接开 token 计算器 把你真实的 prompt 粘进去。
先纠正一个直觉:token 不等于字数
很多人第一次接触计费时会默认「一千字大概就是一千 token」,这个直觉对中文勉强能用,对英文就完全不成立了。
分词器的工作方式是把文本切成常见片段。英文里高频词整体是一个 token,长单词会被拆成词根加后缀,平均下来三到四个字符才凑一个 token。中文因为字符本身信息密度高,多数常用汉字在中文友好的分词器里对应一个 token,但生僻字、特殊符号、emoji 经常被拆成两三个字节级 token。
这带来一个实际后果:同样意思的中英文文本,token 数可能差不少。所以把英文场景的成本经验直接套到中文项目上,或者反过来,都会估偏。
更麻烦的是各家分词器不一样。同一段中文,不同厂商切出来的 token 数可以差一两成。这就是为什么跨厂商只比单价会失真——单价低但分词更碎的模型,实际账单未必更便宜。真要较真,就拿同一段代表性文本分别调一次,读各自返回的 usage 字段对比,那才是厂商自己的计数。
你以为的输入,和实际发出去的输入
这是估算最容易翻车的地方。多数人算输入时只算用户打的那句话,而实际发给模型的一次请求通常包括:
- system prompt:角色设定、输出格式要求、禁止事项。成熟项目里这一段几百上千 token 很常见。
- 工具/函数定义:如果你开了 function calling 或 MCP 工具,每个工具的名称、描述、参数 schema 都要序列化进请求。工具一多,这块能顶得上一篇短文。
- few-shot 示例:为了让输出稳定给的那几个样例。
- 检索片段:RAG 场景下取回来的文档段落,往往是输入里最大的一块。
- 对话历史:见下一节,这是增长最快的一块。
- 最后才是用户输入。
真实项目里,用户那句话经常只占总输入的一小部分。所以估算时应该粘的是「完整拼装后的请求体」,而不是聊天框里那一行。
多轮对话的输入是累加的
单轮请求的成本好算,多轮就不是简单乘法了。因为模型没有记忆,第十轮请求必须把前九轮的问答一起重发过去,它才知道你们之前聊了什么。
于是一次十轮的会话,输入 token 不是十份单轮输入,而是接近平方级的增长。做长会话产品时如果不管这件事,成本曲线会翘得很难看:用户聊得越久越贵,而聊得久的恰恰是你最活跃的用户。
常见的两种处理办法:一是滑动窗口,只保留最近几轮完整对话;二是摘要压缩,把更早的部分用便宜的小模型压成一段摘要再带上。两者可以叠加,先摘要再滑窗。
输出比输入贵,而且贵得多
绝大多数厂商的输出单价都显著高于输入单价,倍数因家而异。这意味着成本大头常常在输出侧,而不是你精心优化的那个长 prompt 上。
由此推出两条很实用的规则:
第一,max_tokens 别乱设大。 你把上限设成很大,模型就真的可能一路写下去。给一个贴合场景的上限,是最省事的降本手段。
第二,选型要看输入输出比。 做摘要是长输入短输出,做生成是短输入长输出,两种场景下最划算的模型经常不是同一个。把两个数分别填进 月成本估算器,它会按你的真实用量结构排序,比肉眼比单价靠谱。
一个能用的估算流程
- 拿一个典型请求,把完整拼装后的内容粘进 token 计算器,得到单次输入 token 数。
- 输出侧粘不了(还没生成),就按平均回答长度估,或者干脆按 max_tokens 上限估一个天花板。
- 乘日请求数,再乘三十,得到月输入和月输出。
- 代进月成本估算器看各模型月成本。
- 数字不能接受时,先别急着换模型——按「砍输入、开缓存、分流小模型」的顺序优化一遍,通常不用换。
不同内容类型的 token 密度差很多
同样的字符数,换成不同类型的内容,token 数能差出一倍以上。做预算时按「平均值」估,遇到下面几类内容会明显偏低。
代码:符号密集,缩进、括号、驼峰命名都会被切碎。一段格式化良好的代码,token 数往往比同等字符数的散文多出不少。这也是为什么代码补全类产品的成本模型和聊天产品差别很大。
JSON 和结构化数据:引号、冒号、逗号、大括号全都占 token,而且字段名每出现一次就计一次。一份字段名冗长的 JSON,光是键名就能吃掉可观的比例。传结构化数据给模型时,把字段名缩短、去掉不必要的嵌套,是很直接的省法。
表格:Markdown 表格的分隔符、对齐符号密度很高,转成更紧凑的表示(比如 CSV 风格)通常能省一截。
emoji 和特殊符号:多数会被拆成多个字节级 token,一个看起来只占一个位置的表情,实际可能顶几个汉字。
空白与换行:连续空格、大量空行也计费。从文档里复制粘贴的内容常常带着一堆多余空白,清理一下是免费的收益。
别忘了工具定义和结构化输出
开了 function calling 或 MCP 工具之后,每个工具的名称、描述、参数 schema 都要序列化进请求,而且是每次请求都发。工具挂得多的 Agent,光工具定义就可能几千 token,比用户输入大一个数量级。
优化方向有两个:一是按场景动态挂载工具,不要把所有工具无差别地全挂上;二是精简工具描述——描述写得太啰嗦不但费钱,还会稀释模型的注意力。
结构化输出(JSON schema 约束)同样要占输入,但它换来的是格式稳定、重试变少。这笔账通常是划算的,因为一次格式错误导致的重跑,成本远高于 schema 本身。
几个高频问题速查
改了 prompt 之后成本涨了,正常吗? 正常,但要量化。改前改后各粘进计算器对比一次,心里有数再上线。
流式输出会更贵吗? 计费按 token 数算,流式与否不改变 token 数。但流式中断后如果整体重来,那次重来是全额计费的。
中英混排怎么估? 分段估再相加比整体估准:中文部分按字数近似,英文部分按字符数除以三到四。
system prompt 每轮都发,能不能只发一次? 协议上不能,模型没有跨请求的记忆。但可以让它命中提示缓存,那样虽然还是发了,但按折扣价计费。
为什么工具估的数和账单还是有差
因为本站的计算器用的是通用近似规则,不加载各家真实分词器,误差在正负一两成属于正常。它的定位是上线前判断量级,不是对账。
真正精确的数字只有两个来源:API 响应里的 usage 字段,以及厂商官方提供的 tokenizer 工具。做财务对账请以这两个为准。
如果你想进一步了解上下文长度怎么影响成本,可以接着看上下文长度计算器那一页;想按厂商看计费口径,国产大模型 API 价格对比拆得更细。