[控场AI]
· 6 分钟阅读· 3,222 字

粘贴前先算Token:LLM Token数学实用指南

粘贴前先算Token:LLM Token数学实用指南

Token是模型处理文本的基本单位,理解其计数、估算与成本机制可避免上下文超限和账单失控。

文章从长文档粘贴进大模型时的三类常见故障切入,指出它们都源于Token这一基本单位。分词器按固定词表把文本切块,英文常见词多为一个Token,罕见词、非拉丁文字、代码和URL的Token密度显著更高。文章给出英文散文的经验估算(1 Token≈4字符≈¾单词,100词≈130 Token),并演示了用js-tiktoken和Python tiktoken精确计数,以及通过Claude、Gemini的API计数端点获取数字。成本方面,输入与输出按每百万Token分别计价,聊天历史每轮重发、输出通常更贵,是两大易被忽视的开支来源。最后提供五种省Token策略和不写代码的浏览器计数工具。

把一份长文档粘贴进ChatGPT、Claude或Gemini时,常见三种翻车方式:回答忽略了结尾、触发了上下文上限、API账单比预期高出一截。这三个问题的根源指向同一个数字——Token。

Token数学实用指南

Token到底是什么

模型不直接读字符或单词。分词器(Tokenizer)按固定词表把文本切成块,模型看到的只是一串块ID。

  • 常见英文单词通常是一个Token:the、house、token
  • 更长或更罕见的词会被拆分:tokenization → token + ization
  • 空格和标点也算数,前导空格往往属于下一个Token
  • 数字、代码、URL和非拉丁文字,每字符消耗的Token更多

最后一点最容易被低估。同一句话翻译成印地语、日语或阿拉伯语,Token数可能是英文版的两三倍;压缩过的JSON或一段堆栈跟踪,密度远高于普通散文。理解这个差异,是估算成本的第一步。

分词器(Tokenizer)和模型是两套独立的东西。分词器是文本与模型之间的"翻译层",它的词表在模型训练之前就已固定,训练完成后不会再变。这意味着同一个词在不同模型家族中可能被切成完全不同的块——GPT-4o用的o200k_base词表约20万条,能更高效地表示多语言文本,而老模型用的cl100k_base只有约10万条,遇到罕见词时切得更碎。分词算法本身通常是BPE(字节对编码)或其变体:从单个字符出发,反复合并出现频率最高的相邻组合,直到词表填满。这个过程的统计来源是训练语料,所以英文占主导的语料会让英文词切得更"整",其他语言的文本则被切得更"碎"——这正是非英文Token密度高的根本原因,而不是模型"不擅长"某种语言。

心算就够了:经验法则

对于英文散文和OpenAI当前的分词器:

  • 1 Token ≈ 4个字符
  • 1 Token ≈ ¾个单词,即100词 ≈ 130 Token
  • 一页密集的A4文本 ≈ 600–800 Token

其他厂商也公布过自己的粗略比例,数值略有差异,因为每个模型家族的分词器不同。把这些当作估算值即可,涉及关键决策时还是得实际计数。

用代码精确计数

OpenAI的分词器是开源的。在JavaScript中,js-tiktoken可以在任何环境运行,包括浏览器:

import { Tiktoken } from "js-tiktoken/lite";
import o200k_base from "js-tiktoken/ranks/o200k_base";

const enc = new Tiktoken(o200k_base);
const text = "Count your tokens before you paste.";
console.log(enc.encode(text).length); // Token数量

o200k_base是GPT-4o及更新OpenAI模型使用的编码,较老的GPT-4和GPT-3.5则使用cl100k_base。Python里对应的是tiktoken包:

import tiktoken

enc = tiktoken.get_encoding("o200k_base")
print(len(enc.encode("Count your tokens before you paste.")))

Claude和Gemini的分词器没有公开,但两家API都提供了计数端点(Anthropic的count_tokens、Gemini的countTokens),需要在发送请求前拿到精确数字时可以用上。

需要注意encode返回的是Token ID数组,其长度即Token数量,但它并不等于模型实际处理的全部Token。多数API会在输入前后自动附加对话模板标记(如特殊的角色分隔符),这些"隐形成本"通常有几十个Token,短Prompt时可忽略,但在批量调用或极短请求中会累积成可观的偏差。此外,计数的结果依赖使用的词表:用cl100k_base去估算一个GPT-4o的请求,结果会系统性偏高。因此精确估价的正确做法是——先确认目标模型对应的编码名称,再计数,最后加上对话模板的固定开销。Claude和Gemini由于分词器未公开,只能依赖官方计数端点,本地无法复现其结果。

一个Prompt要花多少钱

所有API价目表都按每百万Token计价,输入和输出分开收费:

cost = input_tokens  / 1,000,000 × input_price
     + output_tokens / 1,000,000 × output_price

用一个虚构的整数价格走一遍:假设输入每百万Token收费2美元,输出8美元。一个3,000 Token的Prompt加500 Token的回答,成本为:

3,000 / 1,000,000 × $2 = $0.006
  500 / 1,000,000 × $8 = $0.004
                 total = $0.010 每次请求

一美分看起来微不足道,直到它每天运行50,000次。有两个常被忽略的点:

  1. 聊天历史每次都是输入。 长对话中每条新消息都会重发整个线程,输入Token随轮次不断增长。
  2. 输出通常是更贵的一侧。 要求"简短"回答或固定格式,往往比精简Prompt省得更多。

上下文窗口(Context Window)和计费是两件相关但不同的事。上下文窗口指一次请求中模型能"看到"的Token总数上限,包括系统提示、聊天历史、当前输入和即将生成的输出,各家模型从8K到200K不等。计费则按实际消耗的输入与输出Token分别计算。关键在于:聊天历史虽然可能早已"过时",但只要还在窗口内,每一轮都会作为输入重新计费。也就是说,一段20轮的对话,第20轮要为前19轮的全部内容付费。这也是为什么长会话的边际成本会随轮次上升,而非保持常数。当历史逼近窗口上限时,部分API会触发截断或报错,这就是开头提到的"忽略结尾"和"触发上限"两个翻车场景的共同机制。

不损质量的五种省Token方法

  1. 先剥离HTML和模板内容:粘贴网页前删掉导航、页脚和标签,这些纯属浪费。
  2. 压缩或裁剪JSON:只发送模型需要的字段,而不是整个API响应。
  3. 总结旧上下文:把长线程的前20条消息替换成五行摘要。
  4. 不要在每条消息里重复指令:放进系统提示词一次即可。
  5. 检查非英文和代码密集输入:这两类最容易让Token数超出预期。

不写代码的快速检查法

如果只想粘贴一段文本看看数量,作者提供了一个免费Token计数器,完全在浏览器内运行,粘贴的内容不会上传。它对OpenAI分词器给出精确计数,对Claude和Gemini标注为估算,并附带一个带日期、可编辑价格表的成本计算器。

你遇到过最大的Token意外是什么:超长的聊天历史、非英文文档,还是一个吃掉整个上下文窗口的JSON?

#Token计算#LLM Token#tiktoken#API成本优化#上下文窗口#Token计数器#Prompt成本#分词器
分享:

相关推荐