一文搞懂 AI 大模型 API 的 Token 计费机制
你有没有遇到过这种情况:调了一个月大模型 API,账单出来吓一跳,却完全不知道钱花在哪里了?这篇文章带你把 Token 计费机制彻底搞清楚,顺带分享几个实用的省钱技巧。
什么是 Token?
Token 是大模型处理文本的最小单位。模型并不是逐字读取文字,而是把文本切分成一个个 token 再处理。
中英文的 token 密度差异很大:
| 语言 | 大致换算 |
|---|---|
| 英文 | ~0.75 token / 词(“hello world” ≈ 2 tokens) |
| 中文 | ~1.5–2 token / 字(“你好世界” ≈ 6–8 tokens) |
| 代码 | 介于两者之间,标点和缩进单独占 token |
举个具体例子:
"今天天气不错,适合出门走走。" → 大约 20-24 tokens(包括标点) "The weather is nice today, great for a walk." → 大约 10-11 tokens 所以中文应用的 token 消耗通常比同等英文内容高 2 倍左右,这在估算成本时非常重要。
Tokenizer 可视化工具
想直观感受 token 切分?可以用 TikToken 的在线工具,或者用代码自己跑:
# 安装:pip install tiktokenimport tiktoken enc = tiktoken.get_encoding("cl100k_base")# GPT 系列使用的编码 text ="今天天气不错,适合出门走走。" tokens = enc.encode(text)print(f"文本: {text}")print(f"Token 数: {len(tokens)}")print(f"Token IDs: {tokens}")注意:不同模型用不同的 tokenizer,上面这个是通用参考,各家模型的实际切分可能略有差异,但数量级差不多。
计费模型:input + output 分开算
大模型 API 的计费公式很简单:
费用 = input_tokens × 输入单价 + output_tokens × 输出单价 为什么 input 和 output 分开定价?因为两者的计算开销不同——生成 token(output)比处理 token(input)更耗算力,所以输出通常比输入贵。
国产主流模型定价对比(2025年参考)
价格以人民币每百万 tokens(元/M tokens)计,来源为各官方文档,实际以官网最新价格为准。
| 模型 | 输入价格(元/MT) | 输出价格(元/MT) | 上下文窗口 |
|---|---|---|---|
| DeepSeek-V3 | 0.27 | 1.10 | 64K |
| DeepSeek-R1 | 0.55 | 2.19 | 64K |
| Qwen-Max | 40 | 120 | 32K |
| Qwen-Plus | 4 | 12 | 131K |
| Qwen-Turbo | 0.3 | 0.6 | 1M |
| GLM-4-Flash | 0.1 | 0.1 | 128K |
| GLM-4 | 100 | 100 | 128K |
| Moonshot-v1-8k | 12 | 12 | 8K |
| Moonshot-v1-128k | 60 | 60 | 128K |
几个观察:
- DeepSeek-V3 性价比极高,效果媲美旗舰但价格接近零
- Qwen-Turbo 轻量任务首选,长上下文支持好
- GLM-4-Flash 超低价,适合高并发简单任务
- Moonshot 按上下文窗口分档计费,用多少上下文就选对应档位
推理模型的特殊计费:Thinking Tokens
DeepSeek-R1 这类推理模型在回答前会进行"思考",这个思考过程也会产生 tokens,计入计费。
import openai client = openai.OpenAI( api_key="your-api-key", base_url="https://api.deepseek.com") response = client.chat.completions.create( model="deepseek-reasoner", messages=[{"role":"user","content":"证明根号2是无理数"}]) usage = response.usage print(f"输入 tokens: {usage.prompt_tokens}")print(f"输出 tokens: {usage.completion_tokens}")# R1 的 usage 里有额外字段ifhasattr(usage,'completion_tokens_details'): details = usage.completion_tokens_details print(f" 其中思考 tokens: {details.reasoning_tokens}")print(f" 其中实际输出 tokens: {details.completion_tokens - details.reasoning_tokens}")实际影响:R1 解一道复杂数学题可能产生 2000–5000 个 thinking tokens,加上实际答案。如果你的场景不需要深度推理,用 V3 就够了,便宜 4 倍。
影响 Token 消耗的关键因素
1. System Prompt
很多人忽略 system prompt 的 token 开销。如果你的 system prompt 有 500 字,每次请求都要带上,日均 1 万次调用就是 500 × 1万 = 500万 input tokens/天。
2. Few-shot 示例
给模型提供几个例子(few-shot)确实能提升效果,但代价是输入 token 暴增。每加一个示例对,通常增加 100–500 tokens。权衡效果和成本再决定用几个。
3. 对话历史(多轮对话)
多轮对话每次都要把历史记录全部发送:
第1轮:100 tokens 第2轮:100 + 150 = 250 tokens(带上第1轮) 第3轮:100 + 150 + 200 = 450 tokens(带上前两轮) ... 第N轮:累积增长 长对话的 token 消耗呈二次方增长,是成本失控的常见原因。
4. 输出长度
max_tokens 设置决定了模型最多能输出多少,但不代表一定会用完。不过对于生成任务(写文章、写代码),输出 tokens 往往占大头。
成本估算实战
场景:一个智能客服应用,日均 1 万次对话
假设:
- System prompt:300 tokens
- 平均用户输入:80 tokens
- 平均对话 3 轮(历史累积后平均约 600 tokens 输入)
- 平均输出:200 tokens
- 选用模型:Qwen-Plus(输入 4元/MT,输出 12元/MT)
计算:
每次请求输入 tokens ≈ 300(system)+ 600(历史+当前输入)= 900 tokens 每次请求输出 tokens ≈ 200 tokens 日消耗: 输入:900 × 10,000 = 9,000,000 tokens = 9 MT 输出:200 × 10,000 = 2,000,000 tokens = 2 MT 日费用: 输入:9 × 4 = 36 元 输出:2 × 12 = 24 元 合计:60 元/天 月费用 ≈ 1,800 元 如果换 DeepSeek-V3(输入 0.27元/MT,输出 1.10元/MT):
日费用: 输入:9 × 0.27 = 2.43 元 输出:2 × 1.10 = 2.20 元 合计:4.63 元/天 月费用 ≈ 139 元 选对模型,成本差 13 倍。
省钱技巧
技巧1:精简 System Prompt
把 system prompt 做极简化处理,只保留真正影响输出的指令。把 500 字的 system prompt 压缩到 100 字,每月省 80% 的 system prompt 成本。
技巧2:设置合理的 max_tokens
response = client.chat.completions.create( model="deepseek-chat", messages=messages, max_tokens=500,# 根据实际需求设置上限,别让模型无限输出 temperature=0.7)技巧3:对话历史做截断
deftrim_history(history:list, max_tokens:int=2000)->list:"""保留最新的对话,总 token 不超过限制"""# 简单实现:按字数估算,1 token ≈ 1.5 中文字 total_chars =0 trimmed =[]for msg inreversed(history): chars =len(msg["content"])if total_chars + chars > max_tokens *1.5:break trimmed.insert(0, msg) total_chars += chars return trimmed 技巧4:按任务选模型
- 简单分类/抽取 → GLM-4-Flash(便宜 100 倍)
- 通用问答/摘要 → DeepSeek-V3 或 Qwen-Turbo
- 复杂推理/代码 → DeepSeek-R1 或 Qwen-Max
- 超长文档处理 → Qwen-Turbo(100万 token 上下文)
技巧5:缓存高频相同请求
如果你的应用有大量重复问题(FAQ 类),在应用层做语义缓存,命中缓存的请求零 token 消耗。
Python 实战:记录和统计 Token 消耗
在生产环境中,必须把每次请求的 token 使用情况记录下来,方便对账和优化。
import openai import json from datetime import datetime from dataclasses import dataclass, asdict from typing import Optional @dataclassclassTokenUsageRecord: timestamp:str model:str prompt_tokens:int completion_tokens:int total_tokens:int reasoning_tokens: Optional[int]# 推理模型专用 estimated_cost_cny:float# 估算费用(元)# 各模型单价配置(元/百万tokens) MODEL_PRICING ={"deepseek-chat":{"input":0.27,"output":1.10},"deepseek-reasoner":{"input":0.55,"output":2.19},"qwen-max":{"input":40.0,"output":120.0},"qwen-plus":{"input":4.0,"output":12.0},"qwen-turbo":{"input":0.3,"output":0.6},"glm-4-flash":{"input":0.1,"output":0.1},}defcalculate_cost(model:str, prompt_tokens:int, completion_tokens:int)->float: pricing = MODEL_PRICING.get(model,{"input":0,"output":0}) input_cost = prompt_tokens /1_000_000* pricing["input"] output_cost = completion_tokens /1_000_000* pricing["output"]returnround(input_cost + output_cost,6)defchat_with_tracking( client: openai.OpenAI, model:str, messages:list, usage_log:list,**kwargs )->str:"""发送请求并自动记录 token 使用""" response = client.chat.completions.create( model=model, messages=messages,**kwargs ) usage = response.usage reasoning_tokens =None# 提取推理模型的 thinking tokensifhasattr(usage,'completion_tokens_details')and usage.completion_tokens_details: reasoning_tokens =getattr(usage.completion_tokens_details,'reasoning_tokens',None) cost = calculate_cost(model, usage.prompt_tokens, usage.completion_tokens) record = TokenUsageRecord( timestamp=datetime.now().isoformat(), model=model, prompt_tokens=usage.prompt_tokens, completion_tokens=usage.completion_tokens, total_tokens=usage.total_tokens, reasoning_tokens=reasoning_tokens, estimated_cost_cny=cost ) usage_log.append(asdict(record))return response.choices[0].message.content defprint_usage_summary(usage_log:list):"""打印 token 消耗汇总"""ifnot usage_log:print("暂无记录")return total_prompt =sum(r["prompt_tokens"]for r in usage_log) total_completion =sum(r["completion_tokens"]for r in usage_log) total_cost =sum(r["estimated_cost_cny"]for r in usage_log)print(f"\n{'='*40}")print(f"请求次数: {len(usage_log)}")print(f"输入 tokens 合计: {total_prompt:,}")print(f"输出 tokens 合计: {total_completion:,}")print(f"估算总费用: ¥{total_cost:.4f}")print(f"平均每次费用: ¥{total_cost/len(usage_log):.6f}")print(f"{'='*40}\n")# 使用示例if __name__ =="__main__": client = openai.OpenAI( api_key="your-deepseek-api-key", base_url="https://api.deepseek.com") usage_log =[] questions =["用 Python 写一个快速排序","什么是 CAP 定理?","解释一下 Transformer 的注意力机制"]for q in questions: answer = chat_with_tracking( client=client, model="deepseek-chat", messages=[{"role":"user","content": q}], usage_log=usage_log, max_tokens=500)print(f"Q: {q[:20]}...")print(f"A: {answer[:100]}...\n") print_usage_summary(usage_log)# 保存详细日志withopen("token_usage.jsonl","a")as f:for record in usage_log: f.write(json.dumps(record, ensure_ascii=False)+"\n")运行后你会看到类似输出:
======================================== 请求次数: 3 输入 tokens 合计: 487 输出 tokens 合计: 1,243 估算总费用: ¥0.001503 平均每次费用: ¥0.000501 ======================================== 总结
Token 计费的核心逻辑很简单,但魔鬼在细节里:
- 中文比英文贵 2 倍,估算时别用英文标准
- 推理模型有 thinking tokens,复杂问题成本可能超出预期
- 多轮对话是隐形成本,历史 token 线性累积
- 选对模型是最大的省钱手段,相同任务成本差距可达百倍
- 必须做 token 监控,否则成本失控时你根本不知道问题在哪
把 token 使用记录接入你的 metrics 系统,设置费用告警,比什么技巧都管用。
笔者在 TheRouter 中内置了用量统计面板,每次请求的 token 消耗、模型分布、费用明细都会自动汇总,不需要自己搭日志管道,对多模型场景下的成本归因非常有帮助。
作者:TheRouter 开发者,专注 AI 模型路由网关。项目主页:therouter.ai