Token 计费与上下文长度:被忽视的成本杀手
Token 是 LLM 收费的基本单位,但大多数人只关注模型能力,忽略了成本优化。一个128K 上下文的模型跑满和不跑满,成本差 10 倍。本文从计费原理出发,详解跨境电商场景的成本控制实战技巧。
Token 是怎么计费的
LLM API 的收费逻辑很简单:按 token 计费,输入和输出分开算。模型厂商有一个公开的定价表(price per 1M tokens),你的实际成本 = (输入 tokens + 输出 tokens) × 单价。
GPT-4o 的定价约 $2.5/1M 输入 tokens,$10/1M 输出 tokens。Claude Sonnet 4 是 $3/1M 输入,$15/1M 输出。看起来单价不贵,但当你的日均调用量达到百万级别时,成本就开始显著了。
#主流模型定价对比(单位:USD per 1M tokens)
models = {
"GPT-4o (2024-05)": {"input": 2.5, "output": 10.0},
"GPT-4o-mini": {"input": 0.15, "output": 0.60},
"Claude Sonnet 4": {"input": 3.0, "output": 15.0},
"Claude Haiku 3.5": {"input": 0.8, "output": 4.0},
"Qwen2.5-72B (API)": {"input": 0.5, "output": 1.5},
"DeepSeek V3": {"input": 0.27, "output": 1.1},
}
def calc_cost(model, input_tokens, output_tokens):
return (input_tokens * models[model]["input"] + output_tokens * models[model]["output"]) / 1e6
print("单次调用成本估算(100 input + 500 output tokens):")
for model, prices in models.items():
cost = calc_cost(model, 100, 500)
print(f" {model:<25}: ${cost:.4f}")
print("\n日均 10000 次调用的月成本:")
for model, prices in models.items():
daily = calc_cost(model, 100_000, 5_000_000)
monthly = daily * 30
print(f" {model:<25}: ${monthly:.2f} / 月")上下文窗口:标称值 vs 实际可用
每个模型都有一个上下文窗口上限(如 GPT-4o 128K,Claude 3.5 200K),但"标称"和"实际可用"是两回事:
显存限制:KV Cache 需要把每个 token 的 Key 和 Value 矩阵存到显存里。13B 模型单 token 的 KV Cache 约 1MB,128K 上下文需要 128GB 显存——单卡放不下,需要 Tensor Parallelism,增加延迟。
计算成本 O(n2):Attention 的计算复杂度是序列长度的平方。128K token 的计算量是 32K 的 16 倍,延迟和费用都急剧上升。
质量稀释:超过一定长度后,模型对上下文中部信息的关注度下降("lost in the middle"问题)。实验表明,在 128K 上下文中,只有开头和结尾 10-20% 的信息能被可靠召回。
import numpy as np
def effective_context_ratio(actual_tokens, max_tokens):
usage_ratio = actual_tokens / max_tokens
if usage_ratio < 0.3:
return 0.95
elif usage_ratio < 0.5:
return 0.85
else:
middle_loss = (usage_ratio - 0.5) * 0.4
return max(0.7, 0.85 - middle_loss)
print("有效上下文比例估算:")
for max_ctx in [32, 128, 200]:
print(f"\n {max_ctx}K 上下文窗口:")
for actual in [8, 32, 64, 128]:
if actual > max_ctx:
continue
ratio = effective_context_ratio(actual, max_ctx)
print(f" {actual}K实际使用:有效率约 {ratio*100:.0f}% (利用率 {actual/max_ctx*100:.0f}%)")
print("\n结论: 128K 窗口用到 64K 时,中间信息质量已显著下降")中文用户的实际痛点:中文 tokenization 效率低于英文(一个字通常 1-2 tokens),同样的 128K token 窗口,中文承载的有效信息量约等于英文的 60-70%。这意味着中文用户应该把"有效上下文"按60-70% 折算,实际可用量比标称值短得多。
Token 计数的原理
理解 tokenization 才能优化 token 用量。不同模型用不同的分词器:
GPT 系列(Tiktoken):用 BPE(字节对编码),英文效率高。一个常见英语单词 = 1 个 token,标点 = 1 个 token。
中文模型(Qwen、GLM):用 SentencePiece/Unigram,中文效率较低。中文一个字通常 1-2 个 token。
# 使用 tiktoken 计算 token 数(GPT 同款分词器)
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
texts = [
"Running shoes for men breathable lightweight",
"男士轻便透气跑步运动鞋",
"Nike Air Max 270, the best-selling sneaker with Air Max cushioning",
"Nike Air Max 270 超轻缓震跑步鞋男款黑武士透气网面",
"USD 299.99",
"$299.99",
]
print("Token 数对比(Tiktoken cl100k_base):")
for text in texts:
tokens = enc.encode(text)
print(f" {len(tokens):>3} tokens | {text[:50]}")
# 关键观察:
# - 英文品牌名 "Nike" = 1 token
# - 中文字符串 token 数普遍较高
# - 数字+货币符号两种写法 token 数相近数字的特殊性:数字在 LLM 中是按 digit 逐个 token 化的。"299.99" 会被分解成 "2"、"9"、"9"、"."、"9"、"9" = 6 个 tokens,而 "$" 是另一个 token。如果你的场景涉及大量价格,数字本身的 token 消耗不可忽视。
成本控制的5 个实战技巧
技巧一:模型分流(大模型干重活,小模型干轻活)
不同的任务用不同的模型:简单分类、标签提取用小模型(GPT-4o-mini / Claude Haiku),复杂分析、翻译用大模型(GPT-4o / Claude Sonnet)。研究表明,80% 的电商 LLM 调用是简单任务,完全可以用小模型处理。
def route_task(task, model_pool):
if task["complexity"] == "low":
return min(model_pool, key=lambda m: m["cost_factor"])
elif task["complexity"] == "medium":
return sorted(model_pool, key=lambda m: m["cost_factor"])[1]
else:
return max(model_pool, key=lambda m: m["capability"])
model_pool = [
{"name": "GPT-4o-mini", "capability": 0.6, "cost_factor": 0.1},
{"name": "Claude Haiku", "capability": 0.65, "cost_factor": 0.12},
{"name": "GPT-4o", "capability": 0.95, "cost_factor": 1.0},
{"name": "Claude Sonnet 4", "capability": 1.0, "cost_factor": 1.2},
]
tasks = [
{"task": "产品标题分类", "complexity": "low"},
{"task": "竞品分析报告生成", "complexity": "high"},
{"task": "多语言翻译", "complexity": "medium"},
]
for task in tasks:
best = route_task(task, model_pool)
print(f" {task['task']} ({task['complexity']}) -> {best['name']}")技巧二:System Prompt 精简
System Prompt 每次调用都计入 input tokens。如果你的 System Prompt 长达 2000 tokens,每次调用光系统提示就消耗 $0.005(GPT-4o)。日均 1 万次调用,光 System Prompt 的月成本就是 $1500。
# 精简 System Prompt 的前后对比
original_system = """
你是一个专业的跨境电商产品经理助手。
你的专长:
- 分析亚马逊、Temu、SHEIN 等平台的产品标题和描述
- 提炼产品的核心卖点、目标人群、适用场景
- 识别标题中的关键属性(品牌、型号、颜色、尺码、材质)
- 提供多语言产品本地化建议(英语、西班牙语、德语、法语)
输出格式要求:
- 输出必须严格遵循用户指定的格式,不额外发挥
- 如果信息不足,明确说"信息不足,无法判断"
- 涉及价格、销量等数据时,标注"未提供"而不是编造
语言风格:专业、简洁、直接,关键结论放在最前面
"""
精简_system = """你是跨境电商产品分析助手。
专长:产品卖点提炼、属性识别、多语言本地化。
规则:严格按指定格式输出;信息不足说"未提供";不编造数据。
风格:专业简洁,结论先行。"""
def estimate_tokens(text):
return len(text.split()) * 1.3
orig_tokens = estimate_tokens(original_system)
mini_tokens = estimate_tokens(精简_system)
saving_pct = (orig_tokens - mini_tokens) / orig_tokens * 100
print(f"原始 System Prompt: ~{orig_tokens:.0f} tokens")
print(f"精简后: ~{mini_tokens:.0f} tokens")
print(f"节省: {saving_pct:.0f}% tokens")
print(f"月均万次调用节省: ${(orig_tokens - mini_tokens) * 10000 * 2.5 / 1e6:.0f}")技巧三:RAG 检索优化,减少输入 token
如果你用 RAG,但每次检索出来的 chunks 塞满了大量不相关信息,就是在浪费 token。优化检索精度(提高 reranker 质量、控制 chunk 长度)直接降低 input token 消耗。
def rag_cost(num_chunks, chunk_avg_tokens, model="GPT-4o"):
input_tokens = 50
retrieved_tokens = num_chunks * chunk_avg_tokens
system_tokens = 200
total_input = input_tokens + retrieved_tokens + system_tokens
output_tokens = 300
return (total_input * 2.5 + output_tokens * 10) / 1e6
print("RAG 成本对比(GPT-4o):")
configs = [
(1, 500, "只召回 top-1,chunk 长"),
(3, 300, "top-3 中等 chunk"),
(5, 200, "top-5 短 chunk"),
(10, 100, "top-10 极短 chunk"),
]
for num, avg, desc in configs:
cost = rag_cost(num, avg)
print(f" {desc}: ${cost:.4f}/次 = ${cost*10000:.2f}/万次")技巧四:缓存(Cache)
OpenAI 有 Cache(gpt-4o-cache)、Claude 有 Cache,都是对 input tokens 的成本减免(通常 50-90% off)。原理是你在短时间内重复发送相同的 System Prompt 或相同的文档内容,模型厂商缓存重复部分,只对变化的部分计费。
跨境电商的固定场景(产品分析模板、物流政策查询模板)天然适合缓存。设计 prompt 时,把固定部分放在开头,变化部分放在末尾,可以最大化缓存命中率。
技巧五:批量处理
把多条任务合并成一次 API 调用(在模型支持的情况下)。例如同时分析 10 个产品标题而不是10 次调用,每次调用共享相同的 System Prompt tokens。成本从 10 × (200+50) = 2500 input tokens 降低到 (200 + 10×50) = 700 input tokens,节省 72%。
def batch_cost(num_items, system_tokens=200, per_item_tokens=50, output_per_item=100):
single_total = num_items * (system_tokens + per_item_tokens + output_per_item)
batch_total = system_tokens + num_items * (per_item_tokens + output_per_item)
return single_total, batch_total
for n in [5, 10, 20, 50]:
single, batch = batch_cost(n)
saving = (single - batch) / single * 100
print(f" {n} 条任务: 逐条 {single} tokens -> 批量 {batch} tokens, 节省 {saving:.0f}%")成本优化的优先级:第一优先级是模型选型(换小模型省 80-90%),第二是 prompt 精简(省 20-30%),第三是 RAG 检索优化(省 30-50%),第四是缓存(省 50-90%),第五是批量处理(省 50-70%)。前两项不需要改代码,只需要选型和 prompt 重写,立竿见影。
关键结论
· Token 计数是成本的根本:理解 tokenization 才能优化。中文 token效率低,实际上下文比标称短30-40%
· 模型分流是成本控制的第一杠杆:80% 的简单任务用小模型处理,成本差 10-20 倍
· System Prompt 每次都计费:精简到必要内容,2000 tokens vs 200 tokens 的月成本差 10 倍
· RAG 检索优化直接降成本:控制 chunk 数和长度,成本可差 5 倍
· 缓存和批量处理是进阶技巧:固定场景天然适合缓存,批量处理适合离线场景