欢迎拜访:雾里看山-CSDN博客
本篇主题:认识 Token:为什么大模型按 Token 计费
发布时间:2026.8.27
隶属专栏:AI进化之路

在这里插入图片描述

先算一笔账

打开任何一家大模型平台的计费页面,几乎都会看到一句话:

按 Token 计费。

刚开始学 AI 的人经常会问两个问题:

  1. Token 到底是个什么东西?为什么不是按"字"算钱?
  2. 我写的一句中文,到底被算成了多少个 Token?

这一篇就把这两个问题讲清楚,同时把"上下文长度限制"和"成本控制"一起带出来。

一句话理解 Token

可以这样记:

Token 是大模型在处理文本时使用的最小语义单元。它不是字,也不是词,而是模型自己定义的"切分粒度"。

对中文来说,常见的情况是:

  • 一个汉字 ≈ 1 ~ 2 个 Token。
  • 一个英文单词 ≈ 1 ~ 3 个 Token。
  • 一个标点、空格、换行也算 Token,但通常按"半个左右"计入。

不同模型的 Tokenizer(分词器)不同,但同一句话在不同模型上得到的 Token 数会有差异。

为什么大模型不直接按"字"处理

表面上看,按字处理最简单也最直观。但工程上不行,原因有三:

1. 词表大小爆炸

中文常用字有几万个。如果每个字都作为一个独立单元:

  • 词表会非常大,Embedding 层参数会爆。
  • 稀有字训练数据少,模型学不好。

2. 语义信息丢失

单字没有"词"的语义。比如"苹果公司"和"吃苹果",如果按字切分,模型很难直接学到"苹果"在不同语境下是不同含义。

3. 跨语言支持差

大模型要同时处理中、英、代码、公式等多语言。如果按字处理,跨语言一致性和对齐会非常麻烦。

所以最终主流大模型都选择了子词(Subword)切分方案,本质上是把"高频词"、“低频词”、"生僻字"统一拆成固定大小的基础单元。

三种主流分词方式

下面三种是学习大模型时绕不开的,理解它们的差异就够用了。

1. BPE(Byte Pair Encoding)

核心思路:从字符开始,不断合并出现频率最高的相邻字符对。

例如原始语料里有:

low low low newer newer newer wider wider wider
  • 第一轮:合并频率最高的 r + r → rr,得到 lowe r 这种组合。
  • 第二轮:合并 e r → er。
  • 反复迭代,直到词表大小达到设定值。

GPT 系列、LLaMA 系列基本都基于 BPE 或其变体。

2. WordPiece

和 BPE 类似,但合并的判断标准从"出现频率"换成"对语言模型概率提升的贡献"。BERT 系列就是用 WordPiece。

3. SentencePiece

可以理解为"语言无关版的 BPE"。它直接以原始字节流(Unicode 字符)为输入,不需要预分词。中文、日文等多语言模型大量采用 SentencePiece。

把三者放在一起对比:

方案训练粒度典型用户优点缺点
BPE子词GPT/LLaMA简单、易实现词表稳定性一般
WordPiece子词BERT概率驱动的合并训练稍慢
SentencePiece字节级Qwen/ChatGLM语言无关、无需预分词词表可能略大

动手看 Token 是怎么切的

光看概念太抽象。下面用一个最小的 Python 例子,把一段中文拆成 Token。

安装分词器

pip install transformers tiktoken

用 Hugging Face 的 tokenizer

from transformers import AutoTokenizer

# 这里以 Qwen 的分词器为例,中文表现稳定
tokenizer = AutoTokenizer.from_pretrained(
    "Qwen/Qwen2.5-0.5B-Instruct",
    trust_remote_code=True
)

text = "今天天气真不错,我想去爬个山。"
tokens = tokenizer.tokenize(text)
ids = tokenizer.encode(text)

print("原文:", text)
print("Token:", tokens)
print("Token 数:", len(tokens))
print("Token IDs:", ids)

一次典型输出可能类似:

原文: 今天天气真不错,我想去爬个山。
Token: ['今天', '天气', '真', '不错', ',', '我', '想', '去', '爬', '个', '山', '。']
Token 数:12
Token IDs: [107340, 116882, 5971, 98288, 3837, 108540, 7291, 5391, 40854, 104728, 130309, 37011]

可以看到:

  • 高频词(今天、天气)被合并成一个 Token。
  • 单字(真)单独成为一个 Token。
  • 标点(,、。)也算 Token。

用 OpenAI 的 tiktoken

如果想直接看 GPT 系列的切分方式:

import tiktoken

enc = tiktoken.encoding_for_model("gpt-4o-mini")
text = "今天天气真不错,我想去爬个山。"

tokens = enc.encode(text)
print("Token 数:", len(tokens))
print("Tokens:", tokens)

# 反向解码回文本
print("反解码:", enc.decode(tokens))

题外话:tiktoken 是 OpenAI 开源的纯 Python 实现,专门用来精确计算 Token 数,便于预算成本。

上下文长度到底在限制什么

很多同学把"上下文长度"理解成"最多能输入多少字"。更准确的说法是:

上下文长度限制的是一次请求中输入 Token + 输出 Token的总和。

常见上下文长度:

模型上下文长度(Token)适合场景
GPT-3.5 早期版本4K短对话
GPT-4o128K长文档总结
Claude 3.5 Sonnet200K长代码、长文档
Gemini 1.5 Pro1M ~ 2M整本书、视频
Qwen2.5-72B128K长文本
DeepSeek-V364K ~ 128K长文本

需要注意:

  • 上下文越长,推理延迟和成本都会显著上升,不是越长越好。
  • 上下文长到一定程度,模型对中间位置的信息会出现"中间遗忘"现象。

一次调用到底花多少钱

假设使用 GPT-4o-mini 这种常见的小尺寸旗舰模型,假设输入 0.15 美元 / 百万 Token,输出 0.6 美元 / 百万 Token(价格会变动,以官方为准)。来算一笔账:

输入:5000 Token
输出:2000 Token
总费用:
    输入费用 = 5000 / 1_000_000 * 0.15 = 0.00075 美元
    输出费用 = 2000 / 1_000_000 * 0.60 = 0.00120 美元
    合计     ≈ 0.00195 美元 ≈ 1.4 分钱

如果每天调用 1 万次:

每日费用 ≈ 1.4 分 * 10000 = 140 元
每月费用 ≈ 140 * 30 = 4200 元

这就是为什么在工程上必须做:

  1. 控制上下文长度:不必要的 Prompt 全部删掉。
  2. 控制输出长度:用 max_tokens 限制最大输出。
  3. 分级使用模型:简单任务用便宜模型,复杂任务才用旗舰模型。
  4. 缓存重复 Prompt:相同的系统提示可以缓存。

Token 相关的常见坑

坑 1:以为中文字符数和 Token 数是 1:1

实际上中文 1 个字 ≈ 1 ~ 2 个 Token。把 1 万字的小说塞进 Prompt,可能要预留 2 ~ 3 万 Token 的预算。

坑 2:以为 Token 数就是字数

英文里 1 Token 大约对应 4 个字符。中文里要按"字符 / 0.75"粗略估算。

坑 3:忽略"看不见的"Token

在聊天接口里,每次请求其实包含三类内容:

  • system(系统提示)
  • 之前几轮 user / assistant 对话
  • 当前 user 问题

所有这些全部计入 Token 总量。

坑 4:以为长上下文一定好

Gemini 1.5 Pro 这种 1M Token 模型不是"万能"。把 50 万字的废话塞进去,模型依然会抓不住重点。质量比长度更重要。

坑 5:不同模型的 Token 不能直接比较

Qwen 的 1000 个 Token 和 GPT-4o 的 1000 个 Token,背后的语义粒度并不完全一样。迁移模型时要重新测一遍。

实战:做一个简易成本计算器

下面是一段可以直接拷贝运行的最小 Python 代码,用来估算一次调用的大致成本:

import tiktoken

def estimate_cost(prompt: str,
                  output_tokens: int = 0,
                  model: str = "gpt-4o-mini"):
    enc = tiktoken.encoding_for_model(model)
    input_tokens = len(enc.encode(prompt))

    # 假设价格:单位是美元 / 1M Token,按官方最新价替换
    prices = {
        "gpt-4o-mini": {"input": 0.15, "output": 0.60},
        "gpt-4o":      {"input": 5.00, "output": 15.00},
    }

    p = prices[model]
    cost_in = input_tokens / 1_000_000 * p["input"]
    cost_out = output_tokens / 1_000_000 * p["output"]
    return {
        "input_tokens": input_tokens,
        "output_tokens": output_tokens,
        "cost_usd": cost_in + cost_out
    }


if __name__ == "__main__":
    prompt = "请帮我把下面这段话翻译成英文,并保持原意。"
    print(estimate_cost(prompt, output_tokens=200))

这段代码虽然简单,但已经是很多团队的"成本估算原型"。

这一篇到底要记住什么

  • Token 是大模型处理的最小语义单元,不是字也不是词。
  • 主流分词方式有 BPE、WordPiece、SentencePiece,理解思路即可。
  • 上下文长度限制的是"输入 + 输出 Token 总和"。
  • 中文 1 字 ≈ 1~2 个 Token,英文 1 Token ≈ 4 个字符。
  • 工程上必须做 Token 控制:精简 Prompt、限制 max_tokens、分级模型、缓存重复内容。

给后续几篇打个底

  • 第 05 篇会带大家真正调一次大模型 API,把这一篇的 Token 概念落到一段可运行的 curl / Python 示例上。
  • 第 06 篇开始走"本地化"路线:用 Ollama / LM Studio 在自己电脑上跑一个小模型,彻底绕开 Token 成本。

⚠️ 写在最后:以上内容是我整理 Token 概念时的一份学习笔记,本质上是把"为什么按 Token 收费"这件事从直觉层面拉到工程层面。如果你在实际项目里遇到"账单突然爆了"这种问题,可以从这一篇的四条控制手段逐条排查。

更多推荐