第 2 章 · 04 Token 计数(token counting)


第 2 章 · 04 Token 计数(token counting)

本节摘要:Token 计数(token counting)让你在真正发推理请求之前,精确预估一段文本(或一份文件)会消耗多少 Claude token——从而预估成本、判断是否超长、决定要不要切更大上下文模型。本节讲清它的核心要点:用 count_tokens 端点(POST /v1/messages/count_tokens)拿精确计数;千万不要用 OpenAI 的 tiktoken,它在 Claude 文本上普遍少算 15~20%,代码与非英文内容偏差更大;计数是模型相关的,要传与推理时相同的模型 ID;端点无状态,跨版本对比靠分别计数再相减。读完本节,你能在发请求前算清成本,并理解不同模型 tokenizer 的差异。

内容来源:Anthropic 官方 Claude API 文档 shared/token-counting.md(随 Claude Code 分发,从泄露素材库提取),汉化并套用体系化模板。

学习目标

阅读完本节,你应当能够:

  1. 用 count_tokens 端点对一段文本或一份文件做精确的 Claude token 计数。
  2. 说清为什么不能用 tiktoken/gpt-tokenizer 这类 OpenAI tokenizer 估 Claude 的 token。
  3. 理解计数是模型相关的,知道不同模型 tokenizer 差异(Sonnet 5 比Sonnet 4.6 多约 30% token)。
  4. 用「分别计数再相减」实现文件跨版本(token)差异对比。

一、为什么要单独计数

LLM 按 token 计费、按 token 限长。在发推理请求前先预估 token 数,有三类典型用途:

  • 成本预估:一段 5 万 token 的文档跑 1000 次,按 Opus 4.8 输入价 $5/百万 token 算就是 $250——值不值得,先算清。
  • 长度判断:上下文窗口 200K(或 1M),一份文档加历史对话会不会超?超了就要切更大窗口模型或压缩。
  • 缓存规划:缓存最小可命中前缀与模型相关(Opus 4.8 需 4096 token、Sonnet 4.5 仅 1024),先数清才知道能不能缓存。

问题在于:Claude 的 tokenizer 不开源、不公开,本地无法精确模拟。唯一的精确办法是调 Anthropic 提供的 count_tokens 端点。

二、最简用法:计数一段文本或一份文件

count_tokens 端点的签名与 messages.create 类似——传 model 与 messages(可选 system、tools),返回 input_tokens:

from anthropic import Anthropic client = Anthropic() resp = client.messages.count_tokens( model="claude-opus-4-8", messages=[{"role": "user", "content": open("CLAUDE.md").read()}], ) print(resp.input_tokens) ​

TypeScript 写法对称:await client.messages.countTokens({model, messages}) 返回 .input_tokens。其它语言见各自 README,方法名一致。

💡 传与推理时完全相同的参数:要让计数准确,就把推理请求会带的 system、tools、messages 都传给 count_tokens——它们都计入输入 token。只传 messages 会漏算 system 与工具定义的开销。

CLI 形式

ant 命令行工具同样支持,配合 --transform 直接取出数字:

ant messages count-tokens --model claude-opus-4-8 \ --message '{role: user, content: "@./CLAUDE.md"}' \ --transform input_tokens -r ​

@./CLAUDE.md 是 ant 的文件内联语法,把文件内容读入消息。

三、绝对不要用 tiktoken

最常见的错误是用 OpenAI 的 tiktoken(或 gpt-tokenizer)来估 Claude 的 token 数。这是错的。

tiktoken 是 OpenAI 模型的 tokenizer。Claude 用的是 Anthropic 自家的 tokenizer,两者分词规则不同。在典型英文文本上,tiktoken 比 Claude 实际 token 少算约 15~20%;在代码、非英文(尤其是中文、日文)内容上偏差更大,可能少算 30~50%。

后果是直接的:你以为一份文档是 4 万 token、能塞进预算,实际跑起来是 5.5 万 token——成本超预算、长度超限、缓存策略失效。任何来自 tiktoken、gpt-tokenizer 或类似库的估算,对 Claude 都不可信。

⚠️ 唯一可信源:Claude token 的精确计数只能来自 count_tokens 端点(或同等 tokenizer)。如果你看到代码里用 tiktoken.encoding_for_model("claud...") 之类,那是错的——Claude 不在 tiktoken 的支持列表里。

四、计数是模型相关的

token 数随模型变化,因为不同模型用不同 tokenizer(或同族 tokenizer 的不同版本)。计数时务必传你推理时打算用的同一个模型 ID。

一个重要差异:Sonnet 5 用了新 tokenizer,同样的文本比 Sonnet 4.6 多约 30% token。这意味着从 Sonnet 4.6 迁到 Sonnet 5,即便提示一字不改,token 消耗也会上涨约三成——成本预估、缓存最小命中门槛、上下文窗口占用都要重算。Opus 4.8 与 Opus 4.7/4.6 用同一 tokenizer,token 数大致不变。

同一句中文/代码,不同模型 token 数差异(示意): Sonnet 4.6: 1000 tokens Sonnet 5: ~1300 tokens ← 新 tokenizer,多约30% Opus 4.8: ~1010 tokens ← 与 4.7/4.6 同 tokenizer ​

💡 工程启示:迁移模型后,第一件事是用 count_tokens 重新数一遍典型提示,重算成本与缓存策略。不要假设 token 数不变。

五、跨版本对比:分别计数再相减

count_tokens 是无状态的——它不记住任何上下文。所以要对比「同一文件的两个版本」(比如 CLAUDE.md 修改前后)各消耗多少 token,只能分别计数再相减:

from anthropic import Anthropic import subprocess client = Anthropic() def count(text: str) -> int: return client.messages.count_tokens( model="claude-opus-4-8", messages=[{"role": "user", "content": text}], ).input_tokens before = subprocess.check_output(["git", "show", "HEAD:CLAUDE.md"], text=True) after = open("CLAUDE.md").read() print(count(after) - count(before)) # 本次修改净增减的 token 数 ​

这种「两次计数相减」的模式在评估「精简 system prompt 省了多少 token」「加一段检索文档多了多少 token」时很有用。注意两次计数要用同一个模型 ID,否则差异里混入了 tokenizer 差异,无法归因。

六、计数与缓存、成本的联动

count_tokens 的返回值直接服务于第 2 章 03 节的缓存决策与成本预估:

count_resp = client.messages.count_tokens( model="claude-opus-4-8", messages=messages, system=system, ) estimated_input_cost = count_resp.input_tokens * 0.000005 # $5/百万 token print(f"Estimated input cost: ${estimated_input_cost:.4f}") ​

把计数、缓存、成本三者串起来,就是一个完整的「发请求前预算检查」流程:先数 token → 判断是否达到缓存最小门槛 → 估算命中缓存后的实际成本 → 决定是否值得发。

💡 注意输出 token 无法精确预估:count_tokens 只数输入。输出 token 数取决于模型生成长度,只能按 max_tokens 设上限、按历史经验估实际值。成本预估里,输入用 count_tokens 精确算,输出按经验比例估。

本节要点回顾

  1. 唯一精确源:count_tokens 端点(POST /v1/messages/count_tokens),传 model + messages(及 system/tools),返回 input_tokens。
  2. 禁用 tiktoken:tiktoken/gpt-tokenizer 是 OpenAI tokenizer,对 Claude 普遍少算 15~20%,代码与非英文偏差更大,任何此类估算都不可信。
  3. 模型相关:计数随模型变,要传与推理相同的模型 ID;Sonnet 5 比 Sonnet 4.6 多约 30% token,迁移后需重算。
  4. 无状态:跨版本/跨场景对比靠「分别计数再相减」,两次必须用同一模型 ID。
  5. 联动缓存与成本:计数服务于缓存门槛判断(最小可命中前缀模型相关)与成本预估;输出 token 只能按经验估。

下一节讲模型选择与迁移——Fable/Opus/Sonnet/Haiku 四档怎么选,以及从旧模型迁到新模型时要处理哪些破坏性变更(如 budget_tokens 改 adaptive thinking、采样参数被移除)。


作者与出处
原作者: 灏天文库
来源:asgeirtj
许可证:CC BY-NC-SA 1.0
整理: 灏天文库整理
由灏天文库结构化整理,提供目录导航、全文检索与在线阅读,便于系统化学习
发布者: 作者: 灏天文库 转发
评论区 (0)
U