
引言:Token 是新的电费
你的 LLM 月度账单是多少?
两年前,这个问题几乎没有工程师关心------用量小、单价高、成本被增长焦虑掩盖。现在不一样了。斯坦福 2025 年 AI Index 报告显示,主流推理模型的价格已从 2023 年的 20/百万 Token 降至 0.07/百万 Token,降幅超过 99%。但这个「好消息」的另一面是:中国日均 Token 调用量从 2024 年初的 1000 亿飙升至 2025 年底的 100 万亿。
价格下降,用量爆炸。多数团队的 LLM 支出不是在下降,而是在指数级上升。
我见过一个典型的团队:2025 年 Q3 月度 LLM 支出 800,Q4 推出了 Agent 产品后飙升至 4,200,2026 Q1 继续涨到 12,000。他们最贵的模型 gpt-4o 每百万输出 Token 10,而同一任务用 deepseek-chat 只需要 $0.14------71 倍的单价差异。他们根本不知道哪些请求用了哪种模型,也说不清楚哪笔支出在「浪费」。
这就是 LLM 推理成本工程的核心问题:你无法优化你没有计量的东西。
本文给出一套五层成本防御体系,从最简单的 Token 计量,到最复杂的智能路由与预算熔断。每一层都有可运行的代码,每一层都有实测数据。读完本文,你可以在两周内将 LLM 账单降低 40%~70%,同时不牺牲输出质量。
第一层:摸清底数------Token 成本建模
1.1 成本公式与计价结构
LLM 推理成本的核心公式极其简单:
日成本 = (输入Token数 × 输入单价 + 输出Token数 × 输出单价) × 日请求数
但其中三个变量都不是常量。
输入/输出 Token 比例因场景差异巨大:
- 代码补全:输入 200 tokens / 输出 50 tokens,比例 4:1
- 文档摘要:输入 4000 tokens / 输出 500 tokens,比例 8:1
- 深度推理(reasoning model):输入 1000 tokens / 输出 1500 tokens,比例 1:1.5
上下文长度对成本的影响是非线性的。OpenAI 与 Anthropic 的 Prompt Cache 机制可以降低重复前缀的成本,但当你的 System Prompt + 历史对话累积到 64K tokens 时,即使有缓存,单次请求的成本仍然是 8K 场景的 8 倍。introl.com 的测算表明,Context 从 8K 扩展到 64K,成本提升 64 倍------这是线性增长的 Token 量背后被忽略的常数因子(KV Cache 压力、内存占用、调度开销)。
输出 Token 的定价通常是输入的 2~4 倍。这意味着:让模型「简洁回答」比「压缩输入」更有成本效益。
1.2 主流模型定价对比(2026年6月)
| 模型 | 输入价格 ($/M tokens) | 输出价格 ($/M tokens) | 适用场景 |
|---|---|---|---|
| GPT-4o | $2.50 | $10.00 | 复杂推理 |
| GPT-4o-mini | $0.15 | $0.60 | 通用任务 |
| Claude Sonnet 4 | $3.00 | $15.00 | 代码/分析 |
| Claude Haiku 3.5 | $0.80 | $4.00 | 快速任务 |
| DeepSeek Chat | $0.14 | $0.28 | 高性价比 |
| DeepSeek Reasoner | $0.55 | $2.19 | 推理任务 |
| Gemini 2.5 Pro | $1.25 | $10.00 | 多模态 |
一个 4000 输入 + 800 输出的典型对话,各模型单次成本:
- GPT-4o:$0.018
- DeepSeek Chat:$0.000784
- 差距:23 倍
1.3 Token 计量中间件
第一步永远是「看清」。接入计量层不需要更换模型,不需要改动业务逻辑,只需要包装 API 调用:
python
import time
import json
from litellm import completion, cost_per_token
class TokenCostTracker:
def __init__(self, storage_path: str = "token_usage.jsonl"):
self.storage_path = storage_path
def tracked_completion(self, model: str, messages: list,
user_id: str = None, project: str = None,
**kwargs):
start = time.time()
resp = completion(model=model, messages=messages, **kwargs)
latency_ms = (time.time() - start) * 1000
usage = resp.usage
cost = cost_per_token(
model=model,
prompt_tokens=usage.prompt_tokens,
completion_tokens=usage.completion_tokens
)
record = {
"timestamp": time.time(),
"model": model,
"user_id": user_id,
"project": project,
"input_tokens": usage.prompt_tokens,
"output_tokens": usage.completion_tokens,
"total_cost_usd": cost,
"latency_ms": latency_ms,
}
with open(self.storage_path, "a") as f:
f.write(json.dumps(record) + "\n")
return resp
# 使用
tracker = TokenCostTracker()
response = tracker.tracked_completion(
model="openai/gpt-4o-mini",
messages=[{"role": "user", "content": "解释什么是 RAG"}],
user_id="u_12345",
project="customer-support"
)
运行一周后,你第一次拥有了真实的成本画像:
bash
# 统计每个项目的日均成本
cat token_usage.jsonl | jq -r '
select(.timestamp > now - 86400*7) |
[.project, .total_cost_usd] |
@tsv' | awk -F'\t' '{sum[$1]+=$2} END {for(k in sum) printf "%s: $%.2f\n", k, sum[k]/7}'
典型输出:
customer-support: $18.40/day
code-generation: $32.15/day
data-extraction: $7.20/day
agent-orchestration: $45.30/day ← 这是重点优化目标
没有这个数据,所有后续优化都是盲人摸象。
第二层:Prompt 压缩与 Prefix Cache
2.1 System Prompt 去冗余
这是成本最低、见效最快的优化手段,却也是最常被忽视的。
我审计过一个 Agent 产品的 System Prompt:3,842 tokens。其中:
- 角色描述(必要):120 tokens
- 任务指令(必要):380 tokens
- 示例对话(冗余):1,680 tokens
- 安全限制声明(重复):620 tokens
- 工具函数 Schema(臃肿):1,042 tokens
压缩后:980 tokens,节省 74%。每次对话都省,每人每天触发 N 次,年化节省显著。
Prompt 压缩的三板斧:
- 删除示例对话中的冗余解释,只保留输入/输出对
- 合并重复的安全指令(「不要回答 XX」「禁止输出 YY」通常可以用一句话概括)
- 使用 JSON Schema 代替自然语言描述工具函数,LLM 原生支持
python
# 压缩前:620 tokens
TOOL_DESC_BEFORE = """
你有以下工具可用:
1. search_database:搜索数据库。参数:query(搜索关键词,字符串类型,必填),
limit(返回条数,数字类型,默认10)。返回:结果列表。
使用方式:当你需要查找信息时使用此工具。
2. send_email:发送邮件。参数:to(收件人邮箱,字符串,必填),
subject(邮件主题,字符串,必填),body(邮件正文,字符串,必填)。
返回:发送状态。使用方式:当你需要发送邮件时使用此工具。
"""
# 压缩后:180 tokens(工具 schema JSON 格式)
TOOL_DESC_AFTER = """[{"name":"search_database","desc":"搜数据库",
"params":{"query":"string,required","limit":"int,default:10"}},
{"name":"send_email","desc":"发邮件",
"params":{"to":"string,required","subject":"string,required","body":"string,required"}}]"""
2.2 Prefix Cache 机制
Prefix Cache 是当前最有性价比的「被动优化」------不需要改代码,只需要理解它的触发条件。
工作原理:LLM 推理服务会缓存已计算的 KV 张量(Key-Value Cache)。当新请求的前缀与历史请求完全匹配时,直接复用缓存的 KV,跳过 prefill 计算。
各家实现差异:
| 提供商 | 机制名称 | 缓存粒度 | 最小缓存长度 | 价格折扣 |
|---|---|---|---|---|
| Anthropic | Prompt Caching | 字符级前缀 | 1024 tokens | 输入价格 -90% |
| OpenAI | Automatic Caching | Token 级前缀 | 1024 tokens | 输入价格 -50% |
| DeepSeek | Prefix Cache | Token 级前缀 | 64 tokens | 输入价格 -90% |
| Context Caching | 显式配置 | 32K tokens | 按时间计费 |
Anthropic 的实现最值得关注------它允许显式标记哪些部分应该被缓存:
python
import anthropic
client = anthropic.Anthropic()
# 固定部分标记 cache_control,实现 90% 成本节省
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=1024,
system=[
{
"type": "text",
"text": VERY_LONG_SYSTEM_PROMPT, # 你的 3000 token 系统提示词
"cache_control": {"type": "ephemermal"} # 触发 prefix cache
}
],
messages=[{"role": "user", "content": user_query}]
)
# 查看缓存效果
print(f"Cache read tokens: {response.usage.cache_read_input_tokens}")
print(f"Cache creation tokens: {response.usage.cache_creation_input_tokens}")
# 输出示例:
# Cache read tokens: 2847 ← 命中缓存,这部分成本降低 90%
# Cache creation tokens: 0 ← 已在上一次请求中创建
缓存命中率的工程判断:
- 重复率 > 30%(多用户问同一类问题)→ 开启 Prefix Cache,ROI > 1
- 重复率 < 10%(每次都是全新问题)→ Cache 写入反而增加成本,慎用
- 多轮对话(有固定 System Prompt)→ 几乎总是值得缓存 System 部分
实测数据(Mavik Labs, Jan 2026):
- Prompt Caching 平均降低 API 成本 45%~80%
- 同时 Time-to-First-Token(TTFT)提升 13%~31%(因为跳过了 prefill 计算)
第三层:语义缓存------相同问题不再重复计算
Prefix Cache 节省的是「重复前缀的计算」,但请求本身仍然会到达 LLM。语义缓存更进一步:如果用户的提问和历史某条查询「语义相似」,直接返回历史答案,完全跳过 LLM 推理。
3.1 工作原理
用户 Query → Embedding 模型 → 向量
↓
向量数据库(已缓存的向量)
↓
相似度匹配 → 命中(> 阈值)→ 返回缓存 Response
↓
未命中 → 调用 LLM → 存储 Query 向量 + Response
核心参数:
- 相似度阈值 :0.92 是工程实践的 sweet spot
- 过高(0.98):命中率低,优化效果差
- 过低(0.85):误命中,返回不相关的缓存答案
- TTL(生存时间):时效性内容设 30min,通用知识设 24h
- 缓存粒度:按 project/user 隔离,避免跨业务答案污染
3.2 实现方案:Redis LangCache
python
from redis_langcache import SemanticCache
from litellm import completion
from openai import OpenAI
# 初始化语义缓存
cache = SemanticCache(
redis_url="redis://localhost:6379",
embedding_model="text-embedding-3-small",
similarity_threshold=0.92,
ttl_seconds=3600 # 1小时过期
)
def cached_completion(prompt: str,
model: str = "openai/gpt-4o-mini",
project: str = "default") -> str:
"""
语义缓存包装器:命中缓存则直接返回,未命中则调用 LLM 并存储。
"""
cache_key_prefix = f"llm:{project}"
# 1. 尝试缓存命中
cached_response = cache.get(prompt, prefix=cache_key_prefix)
if cached_response:
return cached_response
# 2. 缓存未命中,调用 LLM
response = completion(
model=model,
messages=[{"role": "user", "content": prompt}]
)
answer = response.choices[0].message.content
# 3. 存入缓存
cache.set(prompt, answer, prefix=cache_key_prefix)
return answer
# 使用
answer = cached_completion(
"RAG 和 Fine-tuning 的区别是什么?",
model="openai/gpt-4o-mini",
project="docs-chatbot"
)
3.3 命中率监控
语义缓存的价值完全取决于命中率。建立监控是必须的:
python
import time
from dataclasses import dataclass, field
from typing import Dict
from collections import defaultdict
@dataclass
class CacheMetrics:
hits: int = 0
misses: int = 0
hit_savings_usd: float = 0.0
@property
def hit_rate(self) -> float:
total = self.hits + self.misses
return self.hits / total if total > 0 else 0.0
class CacheMonitor:
def __init__(self):
self._metrics: Dict[str, CacheMetrics] = defaultdict(CacheMetrics)
def record_hit(self, project: str, estimated_cost_saved: float):
m = self._metrics[project]
m.hits += 1
m.hit_savings_usd += estimated_cost_saved
def record_miss(self, project: str):
self._metrics[project].misses += 1
def report(self) -> dict:
return {
proj: {
"hit_rate": f"{m.hit_rate:.1%}",
"total_queries": m.hits + m.misses,
"savings_usd": f"${m.hit_savings_usd:.2f}"
}
for proj, m in self._metrics.items()
}
命中率的经验阈值:
- < 5%:说明查询高度个性化,语义缓存 ROI 为负(存储 + embedding 成本 > 节省)
- 15%~35%:正常水平,客服/文档问答类场景典型值
-
40%:高重复场景(FAQ、知识库问答),ROI 极高
Redis LangCache 实测数据(redis.io, Jun 2026):高重复工作负载下成本降低约 73%,缓存命中响应时间在毫秒级,对比 LLM 推理的秒级延迟。
第四层:智能模型路由------用对的模型处理对的任务
这是成本优化的核心杠杆。
4.1 为什么需要路由
同一个产品里,不同请求的「难度」差异可能是 100 倍:
- 「今天星期几?」→ 任意模型都能回答
- 「用 Python 写一个带重试机制的 Redis Sentinel 连接池」→ 需要中等模型
- 「分析这段 Rust 异步代码的生命周期错误并给出完整修复方案」→ 需要顶级模型
用 GPT-4o 回答「今天星期几」,成本是 DeepSeek Chat 的 18 倍,质量完全相同。
路由的本质:将请求发送到「刚好够用」的最便宜模型。
4.2 路由策略
基于规则的路由(最简单,最稳定):
python
from enum import Enum
class Complexity(Enum):
TRIVIAL = "trivial" # 简单:分类、格式化、简单问答
MEDIUM = "medium" # 中等:摘要、翻译、代码补全
COMPLEX = "complex" # 复杂:推理、长文生成、多步骤
MODEL_MAP = {
Complexity.TRIVIAL: "deepseek/deepseek-chat",
Complexity.MEDIUM: "openai/gpt-4o-mini",
Complexity.COMPLEX: "anthropic/claude-sonnet-4-5-20250514",
}
# 规则判断
def classify_complexity(prompt: str, context: dict) -> Complexity:
token_count = count_tokens(prompt)
has_code = "\`\`\`" in prompt
task_type = context.get("task_type", "general")
if token_count < 100 and not has_code:
return Complexity.TRIVIAL
elif task_type in ["summarize", "translate", "extract"]:
return Complexity.MEDIUM
elif has_code or token_count > 2000 or task_type == "reasoning":
return Complexity.COMPLEX
return Complexity.MEDIUM
基于模型的路由(更智能,需要训练分类器或使用 LLM 自身):
RouteLLM(Stanford 开源,7.9k stars)是一个专门的路由框架。它训练了一个轻量级分类器(< 100M 参数),在不调用大模型的情况下判断「这个问题有多难」:
python
import routellm
# 初始化 RouteLLM 控制器
controller = routellm.Controller(
routers=["mf"], # matrix factorization 路由器
strong_model="gpt-4o",
weak_model="gpt-4o-mini"
)
# 动态路由
response = controller.chat.completions.create(
model="router/mf-0.76", # 阈值 0.76:高于此用 strong model
messages=[{"role": "user", "content": user_prompt}]
)
# RouteLLM 会自动选择 strong/weak,并记录决策理由
4.3 生产级路由:LiteLLM Router
LiteLLM 是目前最成熟的 LLM 路由 + 负载均衡 + 预算管理框架:
python
from litellm import Router
router = Router(
model_list=[
{
"model_name": "cost-optimized",
"litellm_params": {
"model": "deepseek/deepseek-chat",
"api_key": "sk-deepseek-xxx",
"rpm": 1000 # 每分钟请求数限制
}
},
{
"model_name": "cost-optimized",
"litellm_params": {
"model": "openai/gpt-4o-mini",
"api_key": "sk-openai-xxx",
"rpm": 500
}
},
{
"model_name": "frontier",
"litellm_params": {
"model": "anthropic/claude-sonnet-4-5-20250514",
"api_key": "sk-ant-xxx",
"rpm": 200
}
},
],
routing_strategy="usage-based-routing-v2", # 基于延迟 + 成功率的自适应路由
fallbacks=[{"cost-optimized": ["deepseek/deepseek-chat", "openai/gpt-4o-mini"]}],
num_retries=2,
timeout=30,
)
# 使用:自动路由到负载最低、成功率最高的端点
response = router.completion(
model="cost-optimized",
messages=[{"role": "user", "content": prompt}],
max_tokens=1000
)
实测效果(meta-intelligence.tech, Feb 2026):正确的模型路由策略可以在不降低任务完成质量的前提下,将平均 Token 成本降低 40%~60%。
第五层:批处理与预算熔断
5.1 批处理的经济学
LLM 推理的主要成本来自 GPU 内存占用,而非计算本身。将多个请求打包成一个 batch 并行处理,内存占用几乎不变,但 GPU 利用率显著提升,服务商可以给出更低的单价。
各家批处理定价:
| 提供商 | 批处理折扣 | 延迟容忍 | 适用场景 |
|---|---|---|---|
| OpenAI Batch API | 输入 -50%,输出 -50% | 24 小时内完成 | 非实时任务 |
| DeepSeek Batch | -30% | 12 小时 | 批量标注 |
| Anthropic Message Batches | -50% | 24 小时 | 文档分析 |
典型场景:日报生成、用户反馈分类、文档批量摘要、数据标注。
python
import json
import openai
client = openai.OpenAI()
# 准备批量请求(JSONL 格式)
tasks = [
{"custom_id": f"task-{i}", "method": "POST", "url": "/v1/chat/completions",
"body": {"model": "gpt-4o-mini", "messages": [{"role": "user", "content": prompt}],
"max_tokens": 500}}
for i, prompt in enumerate(prompts)
]
with open("batch_input.jsonl", "w") as f:
for task in tasks:
f.write(json.dumps(task) + "\n")
# 上传并创建批量任务
file = client.files.create(file=open("batch_input.jsonl", "rb"), purpose="batch")
batch = client.batches.create(input_file_id=file.id, endpoint="/v1/chat/completions",
completion_window="24h")
print(f"Batch ID: {batch.id} --- 等待完成...")
# 节省:300 条 x 500 output tokens x $10/M = $1.50 → 批处理后 $0.75
Continuous Batching(自建推理服务场景):
如果使用 vLLM 或 TensorRT-LLM 自建推理服务,continuous batching 是默认开启的。它比 static batching 更高效:
- Static batching:等攒齐 N 个请求一起处理,延迟高,GPU 空转多
- Continuous batching:新请求随时插入正在运行的 batch,GPU 永远满载
introl.com(Jan 2026)的数据:Batching 32 个请求,per-token 成本降低 85%,延迟仅增加 20%。
5.2 预算熔断器(Budget Circuit Breaker)
这是一道安全阀。在所有优化之外,预算熔断器确保你的 LLM 支出永远不超出预算:
python
import time
import threading
from enum import Enum
class BreakerState(Enum):
CLOSED = "closed" # 正常:允许请求
OPEN = "open" # 熔断:拒绝所有请求
HALF_OPEN = "half_open" # 试探:允许少量请求测试恢复
class BudgetCircuitBreaker:
def __init__(self, daily_limit_usd: float,
warning_threshold: float = 0.8,
cooldown_seconds: int = 300):
self.daily_limit = daily_limit_usd
self.warning_threshold = warning_threshold
self.cooldown_seconds = cooldown_seconds
self.spent_today = 0.0
self.state = BreakerState.CLOSED
self.last_tripped = 0.0
self._lock = threading.Lock()
def check(self, estimated_cost: float) -> bool:
"""请求前检查:是否允许本次请求。"""
with self._lock:
if self.state == BreakerState.OPEN:
elapsed = time.time() - self.last_tripped
if elapsed > self.cooldown_seconds:
self.state = BreakerState.HALF_OPEN
else:
return False # 拒绝
if self.state == BreakerState.HALF_OPEN:
if self.spent_today + estimated_cost > self.daily_limit * 0.5:
return False # 半开状态下更保守
# 预算检查
projected = self.spent_today + estimated_cost
if projected > self.daily_limit:
self._trip()
return False
if projected > self.daily_limit * self.warning_threshold:
self._warn(projected)
return True
def record(self, actual_cost: float):
"""请求后记录实际支出。"""
with self._lock:
self.spent_today += actual_cost
if self.state == BreakerState.HALF_OPEN and actual_cost > 0:
self.state = BreakerState.CLOSED # 试探成功,恢复正常
def _trip(self):
self.state = BreakerState.OPEN
self.last_tripped = time.time()
print(f"🚨 BREAKER TRIPPED: ${self.spent_today:.2f} / ${self.daily_limit:.2f}")
def _warn(self, projected):
print(f"⚠️ WARNING: projected ${projected:.2f} / ${self.daily_limit:.2f}")
def reset_daily(self):
"""每日重置,通常由 cron 触发。"""
with self._lock:
self.spent_today = 0.0
self.state = BreakerState.CLOSED
# 使用
breaker = BudgetCircuitBreaker(daily_limit_usd=50.0)
def cost_aware_completion(prompt: str, model: str):
estimated = estimate_cost(prompt, model)
if not breaker.check(estimated):
return {"error": "budget_exceeded", "spent": breaker.spent_today}
response = completion(model=model, messages=[{"role": "user", "content": prompt}])
actual = calculate_actual_cost(response)
breaker.record(actual)
return response
综合架构:五层成本防御体系
以上五层不是互斥的,而是叠加的。一个生产级 LLM 应用的成本优化架构如下:
用户请求
↓
┌─────────────────────────────────────────────┐
│ 第5层 预算熔断器 │
│ └─ 超限直接拒绝,防止失控 │
├─────────────────────────────────────────────┤
│ 第4层 智能路由 │
│ └─ simple → DeepSeek Chat ($0.14/M) │
│ └─ medium → GPT-4o-mini ($0.15/M) │
│ └─ complex → Claude Sonnet ($3.00/M) │
├─────────────────────────────────────────────┤
│ 第3层 语义缓存 │
│ └─ 相似 query → 返回缓存,零推理成本 │
├─────────────────────────────────────────────┤
│ 第2层 Prefix Cache │
│ └─ System Prompt KV 缓存,输入成本 -90% │
├─────────────────────────────────────────────┤
│ 第1层 Token 计量 │
│ └─ 全量记录,实时成本画像 │
└─────────────────────────────────────────────┘
↓
LLM 推理(或缓存命中直接返回)
↓
记录实际成本 → 更新计量 → 触发预算检查
组合收益估算(以日均 $100 LLM 支出为基准):
| 优化层 | 假设条件 | 节省比例 | 节省金额/日 |
|---|---|---|---|
| Token 计量 | 可视化,不做优化 | 0% | $0(但看清了) |
| Prompt 压缩 | 压缩 50% 冗余 | 10% | $10 |
| Prefix Cache | 命中率 60% | 25% | $25 |
| 语义缓存 | 命中率 20% | 15% | $15 |
| 模型路由 | 60% 请求降级到便宜模型 | 35% | $35 |
| 批处理(非实时) | 20% 请求走批处理 | 8% | $8 |
| 总计 | 叠加(非简单相加) | ~55-70% | 55-70 |
开始优化的第一步:不要一上来就搭路由,先接入 Token 计量中间件(本文第一层),运行一周,看清你的真实成本画像。然后从命中率最高的那个优化层开始,逐层叠加。
结语:Token 经济学下的工程师思维
LLM 推理成本不是一个可以一劳永逸解决的问题。它是一个持续演进的工程系统------模型价格在下降,新模型在涌现,业务需求在变化。
但有一个不变的原则:先计量,再优化,再计量。
那些让 LLM 账单失控的团队,几乎都有一个共同特征:他们知道「用了什么模型」,但不知道「每个请求花了多少钱」。他们优化的依据是「感觉贵了」,而不是「数据说这里花了 $4000」。
Token 计量不是优化手段,而是工程纪律。
建立这个纪律,然后从五层防御体系里选你最有 ROI 的那一层开始,一个月后你会惊讶于同样的请求量,账单可以少一半。