我是怎么被Token坑了$8的
上个月用ChatGPT API写了一个客服机器人,心想就几百条对话,能花多少钱?结果月底看到账单直接傻眼——$8.47。
我回溯了一下日志,明明对话量很少,每条消息撑死100个词,怎么就烧了这么多?后来才搞明白,原来我用的那个Prompt模板长这样:
你是一个专业的电商客服。请根据以下产品信息回答用户问题。
产品名称:XXX智能手表
价格:1999元
功能:心率监测、睡眠追踪、GPS定位、防水50米...
(后面还有500字的产品详情)
用户问题是:{user_question}
请用专业、友好的语气回答,不要超过100字。
就这个Prompt,每次请求都要完整发送。我以为"1000 Token"是1000个英文单词,实际上一条Prompt就吃了800多Token。这才反应过来——Token根本不是按词算的,是按字符/子词切分的。
血泪教训
千万别用"词数"来估算Token消耗。中文尤其坑——一个短句可能就是几十个Token。
Token到底是什么鬼?
简单说,Token是大模型处理文本的最小单位。模型不认字符,而是把文本切成一串Token来理解。
中英文Token化差异巨大
这里有个关键规律:
- 英文:通常1 Token ≈ 0.75个单词,1000个Token约等于750个英文单词
- 中文:1个汉字 ≈ 1-2个Token,标点符号也算
- 代码:tokenizer对代码更友好,1 Token通常能覆盖更多字符
实测数据:
- "Hello, world!" → 6 Tokens
- "你好,世界!" → 7 Tokens(每个汉字约1.5-2 Token,标点另算)
- "AI大模型真厉害" → 9 Tokens
所以中文开发者尤其要注意:一个看似简短的Prompt,实际上Token消耗可能远超预期。
标点符号和空格也占Token
这点很多人忽视。在API眼里,,、。、\n都是独立的Token。格式化越复杂,Token越多。
# 高Token消耗的写法
"产品列表:\n\n1. 手机\n - 品牌:XXX\n - 价格:2999\n\n2. 电脑\n - 品牌:YYY\n - 价格:5999"
# 低Token消耗的写法
"产品: 手机(品牌XXX,价格2999) | 电脑(品牌YYY,价格5999)"
2026年主流模型最新定价表
我整理了目前最常用的几个模型的最新价格,数据来自各平台官网(截至2026年6月):
| 模型 | 输入 ($/1M Tokens) | 输出 ($/1M Tokens) | 特点 |
|---|---|---|---|
| GPT-4o | $2.50 | $10.00 | 全能型,多模态强 |
| GPT-4o mini | $0.15 | $0.60 | 性价比之选 |
| Claude 3.5 Sonnet | $3.00 | $15.00 | 长上下文,代码强 |
| Claude 3.5 Haiku | $0.80 | $4.00 | 速度快,便宜 |
| DeepSeek V3 | $0.27 | $1.10 | 国产性价比王 |
| Gemini 2.0 Flash | $0.10 | $0.40 | Google主力模型 |
成本换算小工具
100万Token约等于75万英文单词或50万汉字。写一篇2000字的中文文章,输入大概消耗4-8元。
多模态Token怎么算
如果你用GPT-4V或者Gemini处理图片、音频,那Token计算就更复杂了。
图片Token计算
OpenAI的图片Token计算公式是:
# 图片Token计算(简化版)
# 短边 resize 到 512,长边按比例缩放
# 然后切成 512x512 的块
# 每块 = 170 Tokens
# 最低消费 = 85 Tokens
def calc_image_tokens(width, height):
# 1. 短边缩放到 512
if width < height:
new_width = 512
new_height = int(height * 512 / width)
else:
new_height = 512
new_width = int(width * 512 / height)
# 2. 向上取整到 512 的倍数
tiles_x = (new_width + 511) // 512
tiles_y = (new_height + 511) // 512
# 3. 每块 170 Tokens,最低 85
total = tiles_x * tiles_y * 170
return max(total, 85)
# 例子:一手机照片 1080x1920
print(calc_image_tokens(1080, 1920)) # 输出约 850 Tokens
所以一张普通手机照片,传给GPT-4o Vision大约消耗800-1000 Token,比很多文字Prompt都贵。
音频Token计算
Whisper API的音频处理:
- 按分钟计费:$0.006/分钟
- 不会消耗输入Token配额,但会有单独的费用
- 建议上传前压缩到16kHz单声道,节省处理时间
视频帧Token估算
视频处理按帧计费,估算公式:
视频Token ≈ 帧数 × 单帧Token数 × 采样率系数
一般1秒钟视频(按1fps采样)≈ 100-200 Tokens。
Python Token计算工具
与其瞎猜,不如直接用代码算。下面是两个实用的Token计数方案:
方案1:tiktoken(英文为主)
pip install tiktoken openai
import tiktoken
def count_tokens_english(text: str, model: str = "gpt-4o") -> int:
"""使用tiktoken计算英文Token数"""
encoding = tiktoken.encoding_for_model(model)
tokens = encoding.encode(text)
return len(tokens)
# 测试
text = "Hello, world! How are you today?"
print(count_tokens_english(text)) # 输出: 9
方案2:中文Tokenizer(更准确)
# 安装中文分词器
pip install transformers
from transformers import AutoTokenizer
def count_tokens_chinese(text: str, model: str = "gpt-3.5-turbo") -> int:
"""
使用HuggingFace分词器计算中英文混合Token
支持大多数OpenAI兼容格式
"""
tokenizer = AutoTokenizer.from_pretrained(
"portkey-ai/gpt-3.5-turbo",
trust_remote_code=True
)
tokens = tokenizer.encode(text, add_special_tokens=True)
return len(tokens)
# 实际测试
test_cases = [
"你好世界",
"Hello world",
"AI大模型真的很厉害!",
"产品名称:智能手表\n价格:1999元\n功能:心率监测"
]
for text in test_cases:
tokens = count_tokens_chinese(text)
print(f"文本: {text[:30]}... → {tokens} Tokens")
方案3:直接用API返回的数据
最准确的方法是看API返回的usage字段:
import openai
client = openai.OpenAI(api_key="your-api-key")
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "你是一个有帮助的助手。"},
{"role": "user", "content": "解释一下量子计算的基本原理"}
]
)
# 从响应中提取详细用量
usage = response.usage
print(f"""
=== Token消耗明细 ===
Prompt Tokens (输入): {usage.prompt_tokens}
Completion Tokens (输出): {usage.completion_tokens}
Total Tokens (总计): {usage.total_tokens}
预估费用: ${(usage.prompt_tokens / 1_000_000) * 2.50 + (usage.completion_tokens / 1_000_000) * 10:.4f}
""")
重要字段说明:
prompt_tokens:你的输入(Prompt)消耗的Tokencompletion_tokens:模型的输出消耗的Tokentotal_tokens:两者之和
Cache命中:省钱的秘密武器
Claude和OpenAI都推出了上下文缓存功能,命中Cache可以大幅降低费用。
OpenAI Cache机制
# OpenAI的响应中会返回cache相关字段
print(f"""
=== Cache命中情况 ===
completion_tokens: {usage.completion_tokens}
completion_tokens_details: {usage.completion_tokens_details}
# 如果使用了cache,会看到:
# cached_read_tokens: 1234 (从缓存读取的Token)
""")
Claude的Cache字段
| 字段 | 说明 | 计费 |
|---|---|---|
| prompt_tokens | 正常输入Token | 全价 |
| cache_creation_input_tokens | 创建缓存的输入 | 全价(仅首次) |
| cache_read_input_tokens | 从缓存读取的输入 | 10%价格 |
简单说,如果你在Prompt前加一段固定上下文(如产品知识库),首次调用贵一些,后续调用因为Cache命中,实际费用只有原来的10%-50%。
Batch API:50%折扣的正确用法
OpenAI和Groq都有Batch API,价格更便宜,但有24小时延迟。
| 平台 | 折扣 | 延迟 | 适用场景 |
|---|---|---|---|
| OpenAI Batch | 50% | 最长24小时 | 批量翻译、批量总结、离线处理 |
| Groq Batch | 节省规则 | 实时或排队 | 大批量非实时任务 |
OpenAI Batch API调用示例
# 准备batch请求
batch_requests = [
{"custom_id": f"req_{i}", "method": "POST", "url": "/v1/chat/completions",
"body": {"model": "gpt-4o-mini", "messages": [{"role": "user", "content": f"任务{i}"}]}}
for i in range(100)
]
# 创建batch任务
batch_file = client.files.create(
file=io.StringIO(json.dumps(batch_requests)),
purpose="batch"
)
batch_job = client.batches.create(
input_file_id=batch_file.id,
endpoint="/v1/chat/completions",
completion_window="24h"
)
print(f"Batch ID: {batch_job.id}")
print("等待24小时内完成...")
不同场景Token消耗实测
我跑了几个常见场景的实测数据:
| 场景 | 输入Token | 输出Token | GPT-4o费用 | GPT-4o mini费用 |
|---|---|---|---|---|
| 简短问答(50字) | ~150 | ~50 | $0.0011 | $0.00007 |
| 中等长度对话(500字上下文) | ~800 | ~200 | $0.0055 | $0.0003 |
| 长文摘要(2000字文章) | ~3500 | ~150 | $0.012 | $0.0007 |
| 代码生成(100行) | ~500 | ~800 | $0.0135 | $0.0008 |
| 多模态(1张手机照片+问题) | ~1200 | ~100 | $0.006 | N/A |
优化建议
从实测数据看:
- 简单问答场景,用GPT-4o mini能省15倍费用
- 输出越长,输出Token费用占比越高
- 多模态输入比纯文字贵很多,能文字描述就别传图
精准成本监控方案
最后分享一个我用的成本监控方案,实时追踪每个请求的费用:
class TokenTracker:
"""Token消耗追踪器"""
PRICING = {
"gpt-4o": {"input": 2.50, "output": 10.00},
"gpt-4o-mini": {"input": 0.15, "output": 0.60},
"claude-3.5-sonnet": {"input": 3.00, "output": 15.00},
"deepseek-v3": {"input": 0.27, "output": 1.10},
}
def __init__(self):
self.total_cost = 0
self.total_tokens = 0
self.request_count = 0
def record(self, model: str, usage: dict):
price = self.PRICING.get(model, {})
input_cost = (usage['prompt_tokens'] / 1_000_000) * price.get('input', 0)
output_cost = (usage['completion_tokens'] / 1_000_000) * price.get('output', 0)
total = input_cost + output_cost
self.total_cost += total
self.total_tokens += usage['total_tokens']
self.request_count += 1
print(f"[请求#{self.request_count}] {model}")
print(f" Tokens: {usage['total_tokens']} (输入:{usage['prompt_tokens']}, 输出:{usage['completion_tokens']})")
print(f" 费用: ${total:.6f}")
print(f" 累计: ${self.total_cost:.4f} / {self.total_tokens} Tokens")
def report(self):
return f"总请求: {self.request_count}, 总Token: {self.total_tokens}, 总费用: ${self.total_cost:.4f}"
tracker = TokenTracker()
# 每次API调用后
tracker.record("gpt-4o-mini", {
"prompt_tokens": 150,
"completion_tokens": 50,
"total_tokens": 200
})
总结:控制Token成本的几个关键
- 用mini模型:简单任务别浪费在GPT-4o上,4o mini能省15倍
- 精简Prompt:删除重复的指令词,减少不必要的格式
- 善用Cache:固定上下文做缓存,后续调用打折
- 批量处理:非实时任务用Batch API,省50%
- 监控每一分:接入usage字段统计,别等账单吓一跳