LLM 应用的 Token 成本工程:缓存、路由与网关的 5 个实战模式
把 LLM 应用从'能跑'带到'能盈利'的成本优化手册——围绕 Prompt Caching、模型路由、语义缓存、API Gateway、Token Budgeting 5 个模式,给出可落地的代码片段与账单算术。
约 24 分钟阅读7,147 字34 次阅读博主

把 LLM 应用从'能跑'带到'能盈利'的成本优化手册——围绕 Prompt Caching、模型路由、语义缓存、API Gateway、Token Budgeting 5 个模式,给出可落地的代码片段与账单算术。

一篇写给「把 LLM 接进生产环境」的工程师的成本优化手册。
2025-2026 年,AI 应用的落地速度远超预期。几乎所有 SaaS 都在塞一个 Chat 框,几乎所有 Agent 都在跑多轮 LLM 调用。但一个更现实的问题也开始浮现:当你的日活从 1k 涨到 100k 时,你的 API 账单可能从 1k 美元涨到 100k 美元——而且在多数团队里,这条曲线不是线性的,是"指数级 + 抖动"的。
我在和几个 LLM 应用团队聊的时候发现一个共同现象:大家花了 80% 的精力优化 prompt 和模型选型,但只花了 20%(甚至更少)做"成本工程"。结果是,明明 prompt 已经很精炼了,月度账单还是失控。
这篇文章要解决的是另一半问题:当你已经用上最好的 prompt 和模型之后,怎么把每一美元 Token 的边际效用榨到最高。我会围绕 5 个实战模式展开:
每节会给出可落地的代码或配置片段,并在最后一节给出"5 个模式的组合使用"。
数据基准(用于本文中的所有成本估算):
- Anthropic Claude 3.5 Sonnet:Input 15 / MTok(截至 2026-06 公开定价)
- Anthropic Claude 3 Haiku:Input 1.25 / MTok
- Anthropic Prompt Caching:Cache write 0.03 / MTok**(即相比 base input 价格 1/10)
- OpenAI GPT-4o / GPT-4o-mini 与 Anthropic 价差类似,核心结论通用
- 以上数据来自 Anthropic 官方 2024-12 公告与 2026-06 pricing 页面
- LiteLLM 50,104★、LangChain 139,087★、MLflow 26,451★(GitHub 2026-06-12 实时拉取)
几乎所有 LLM 应用的 prompt 都有这种结构:
[system prompt + few-shot examples + 工具定义] ← 几乎不变
[用户问题 + 检索到的上下文] ← 每次都变
[历史对话] ← 累加
后两段会变,但第一段——也就是"长前缀"——在 80% 的请求里是几乎一字不差的。Prompt Caching 的核心思想就是:把"前缀"标记成 cache,让 API 厂商在前缀不变时按 1/10 价格计费。
Anthropic 2024-12-17 上线 Prompt Caching 时给出的官方数据是 "成本降低 90%、长 prompt 延迟降低 85%"(来源:anthropic.com/news/prompt-caching)。对 Haiku 来说,cache_read 价格是 0.25 / MTok——8.3 倍的差价。
OpenAI 紧随其后在 2024-10 给 GPT-4o 加了类似机制(来源:openai.com/index/api-prompt-caching),按命中自动打 50% 折扣,不需要手动标注。两家路线略有差异,下面会展开。
cache_control 断点Anthropic 要求你显式在内容块上加 cache_control 标记,指定"从哪个 token 开始是 cache 区域"。
import anthropic
client = anthropic.Anthropic()
LONG_SYSTEM = "...(5000 token 的工具定义 + few-shot)" * 1 # 稳定的前缀
resp = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
system=[
{
"type": "text",
"text": LONG_SYSTEM,
"cache_control": {"type": "ephemeral"} # ← 关键
}
],
messages=[{"role": "user", "content": user_input}]
)
print(resp.usage) # cache_creation_input_tokens / cache_read_input_tokens
关键参数:
ephemeral cache 默认 TTL 5 分钟,可以配到 1 小时OpenAI 走的是另一个方向——不显式标记,由服务端自动检测前缀匹配:
这种"零配置"路线对小团队很友好,但控制粒度差——你没法精确控制"哪一段应该 cache",而 Anthropic 路线可以。
假设一个客服 Agent 应用:
| 指标 | 数值 |
|---|---|
| 日活对话 | 50,000 |
| 平均每轮 system + tool 长度 | 6,000 token |
| 平均每轮 user + history | 1,500 token |
| 平均 output | 500 token |
| Sonnet 价格 | 15 / MTok out |
不用 cache(只用 Sonnet):
用 cache(假设 70% 命中):
省下 42%,**0.30/MTok 远低于 base $3/MTok),不是"完全免费"。
current_time 这种每次都变的值,否则永远命中不了cache_read_input_tokens / (cache_creation_input_tokens + cache_read_input_tokens) 是核心 KPI,目标 > 60%很多团队有一个"用最好模型"的执念。但如果你看真实 LLM 应用的请求分布:
用 Sonnet 一把梭的账单 vs 三档路由的账单,差 5-8 倍。
| 维度 | 例子 | 适用 |
|---|---|---|
| 关键词/规则 | "如果用户问天气、订外卖、查快递 → Haiku" | 简单业务分流 |
| 意图分类器 | 用一个小模型先分类,再分发 | 业务复杂但模式固定 |
| 成本约束 | "这个会话已花 $0.50 → 下次用更便宜模型" | 长对话 |
| 质量/置信度 | "主模型 confidence < 0.6 → escalate" | 严谨任务(代码、SQL、合同) |
LiteLLM(GitHub 50,104★,2026-06-12 实时数据)是当前最流行的多模型代理库之一。它支持声明式 routing 配置:
# litellm_config.yaml
model_list:
- model_name: gpt-4o
litellm_params: { model: openai/gpt-4o, api_key: os.environ/OPENAI_API_KEY }
- model_name: gpt-4o-mini
litellm_params: { model: openai/gpt-4o-mini, api_key: os.environ/OPENAI_API_KEY }
- model_name: claude-haiku
litellm_params: { model: anthropic/claude-3-haiku-20240307, api_key: os.environ/ANTHROPIC_API_KEY }
router_settings:
routing_strategy: usage-based-routing-v2
num_retries: 2
timeout: 30
redis_host: os.environ/REDIS_HOST
redis_port: 6379
cache: true
cache_params:
type: redis
ttl: 3600
from litellm import Router
router = Router(config_file="litellm_config.yaml")
# 自动按 cost / latency / 失败率路由
resp = router.completion(
model="gpt-4o-mini", # 指定"任务档位"
messages=[{"role": "user", "content": user_input}]
)
LiteLLM 内置 7 种 routing strategy:simple-shuffle、usage-based、latency-based、cost-based、usage-based-routing-v2 等。生产里最常用的是 usage-based-routing-v2——按 RPM/TPM 限额自动切到次选模型。
| 任务 | 推荐档位 | 备注 |
|---|---|---|
| 闲聊 / 问候 / FAQ | Haiku / GPT-4o-mini | $0.25 / MTok |
| 简单摘要 / 改写 | Haiku / GPT-4o-mini | 同上 |
| 中等推理 / RAG 回答 | Sonnet / GPT-4o | $3 / MTok |
| 长文分析 / 复杂规划 | Opus / o3 | $15 / MTok |
| 代码生成 / 重构 | Sonnet (claude-sonnet-4-x) | 性价比最佳 |
| 复杂数学 / 多步推理 | o-series / Claude Opus 4 | 别省 |
注意:以上价格为 2026-06 公开定价快照;Anthropic / OpenAI 都会频繁调价,生产环境必须以你 dashboard 上的实际数字为准。
if-else——业务一改你就改 50 个地方;用配置驱动Prompt Caching 只对"字节级完全相同的前缀"有效。但实际上,用户问的问题往往是近似但不完全相同:
这 4 句话语义相同,但用 prompt cache 一点都命中不了。这时候就需要语义缓存(Semantic Cache)。
用户问题 → embedding → 向量库查 top-1 相似度
│
┌───────────────┴───────────────┐
│ sim > threshold (e.g. 0.92) │
↓ ↓
直接复用上一次的回答 走正常 LLM 流程
关键参数:
text-embedding-3-small ($0.02/MTok) 或开源 bge-large两个现成方案:
from gptcache import cache
from gptcache.adapter.api import init_similar_cache
from langchain.chat_models import ChatOpenAI
from langchain.globals import set_llm_cache
set_llm_cache(init_similar_cache(cache.init()))
# 之后的 LangChain 调用就自动带语义缓存
llm = ChatOpenAI(model="gpt-4o-mini")
llm.predict("怎么重置密码?")
llm.predict("忘记密码怎么办?") # 命中 cache,不再调用 LLM
Cloudflare AI Gateway 把"caching"和"rate limiting"作为 core feature 免费提供(来源:developers.cloudflare.com/ai-gateway/pricing),不需要自己架 Redis:
curl https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/openai/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "cf-cache-ttl: 3600" \
-H "cf-similarity-threshold: 0.85" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"怎么重置密码?"}]}'
关键卖点:Cloudflare AI Gateway "inference pricing from providers is passed through with no markup"(同上来源)——只收缓存/日志基础设施的钱,token 走的是原始 API 价格。这一条对中小团队来说非常关键:你可以白嫖一层基础设施而不会因此多付 token 钱。
text-embedding-3-large 来算 cache key,省出来的 token 不够付 embedding 的当你的 LLM 应用超过 3-5 个下游模型/路由/重试/限流/日志规则时,在应用代码里维护它们就是一个灾难。典型痛点:
.py 文件里API Gateway 的核心价值:把"调用 LLM 之前/之后"的横切关注点(cross-cutting concerns)从应用代码里抽出去。
| 层级 | 代表 | 形态 | 适合 |
|---|---|---|---|
| 客户端库层 | LiteLLM、LangChain | import 一次就生效 | 快速接入多模型 |
| 自托管代理层 | LiteLLM Proxy、Portkey、MLflow | 独立服务,统一 URL | 多团队、多应用 |
| 托管服务层 | Cloudflare AI Gateway、Portkey Cloud | 不用自己运维 | 中小团队、想 focus 业务 |
# 安装
pip install 'litellm[proxy]' prometheus_client
# config.yaml (前面路由一节里的)
# 启动
litellm --config /path/to/litellm_config.yaml --port 4000
应用代码接入:
import openai
client = openai.OpenAI(
base_url="http://litellm.internal:4000", # 所有请求走这里
api_key="anything" # 真实 key 在 proxy 里
)
resp = client.chat.completions.create(
model="claude-haiku", # proxy 自动路由到 Anthropic
messages=[...]
)
这一行 base_url 切换就把:
全部接住了。强烈建议 5 个以上 LLM 调用点的团队就上 proxy。
如果不想自己运维代理,Cloudflare AI Gateway 几乎是零成本方案(来源:同上 pricing 页面,caching & rate limiting 是 free core feature):
import openai
client = openai.OpenAI(
base_url="https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/openai",
api_key=os.environ["OPENAI_API_KEY"],
default_headers={"cf-aig-metadata": json.dumps({"user_id": user_id})}
)
一行 base_url 切换 + 一个 metadata header,就有:
对成本敏感但又不想自己搭基础设施的团队,托管 Gateway 是最优解。
如果你把一个 LLM 应用的 token 消耗画成直方图,80% 的 token 用在了 20% 的请求上——通常是:
前端不控制,缓存和路由都救不回来。
def retrieve(query: str, k: int = 5, max_tokens: int = 4000):
docs = vector_db.search(query, k=k*2) # 多取
out, total = [], 0
for d in docs:
t = count_tokens(d.text)
if total + t > max_tokens:
break
out.append(d)
total += t
return out
核心理念:不要用 "k=5" 硬编码,要用"max_tokens=N"硬上限。同一个 query 检索 5 个 500 token 的 doc 和 5 个 1500 token 的 doc,成本差 3 倍。
def compress_history(messages, max_tokens=8000):
if count_tokens(messages) <= max_tokens:
return messages
# 策略 A:保留 system + 最近 5 轮 + summary(老的)
# 策略 B:让 LLM 先把老 history 总结成 200 token
old = messages[:-5]
summary = client.messages.create(
model="claude-haiku-4-5",
max_tokens=200,
messages=[{"role": "user", "content": f"Summarize in 200 tokens: {old}"}]
).content[0].text
return [
messages[0], # system
{"role": "assistant", "content": f"[Earlier summary]: {summary}"},
*messages[-5:]
]
注意:summary 这步本身也要花钱,但 haiku 4.5 比 sonnet 便宜 12 倍,省钱+省 token 双重收益。
def few_shot_prompt(query, examples_pool, k=3):
# 不用"全 30 个 example",用 query 相似度选 top-3
sims = embed(query) @ embed_matrix(examples_pool).T
top_k = np.argsort(-sims)[:k]
return [examples_pool[i] for i in top_k]
这个套路能从 30k token 砍到 3k,直接省 90% input cost——而且很多 benchmark 显示质量几乎不掉。
把上面三条和 Anthropic 提出的 Context Engineering(参考 Anthropic 2024-09 文章)结合起来,核心是"动态决定哪些上下文值得放进去",而不是"放进所有能想到的东西"。
LLM 应用的每个环节都该有 token budget:
| 环节 | 建议 budget(示例) |
|---|---|
| system prompt | 1-2k |
| 工具定义 | 1-2k |
| few-shot examples | 1-3k |
| RAG 检索 | 2-5k |
| 对话历史 | 2-8k |
| 用户问题 | 0.5-1k |
| 总计 input | 8-20k |
| output | 0.5-2k |
经验值:一个健康的 LLM 应用,平均 input 应该在 5-15k token 之间。超过 30k 的几乎一定有优化空间。
最后把 5 个模式拼成一张架构图:
图表加载中…
5 个模式的协同:
真实账单对比(50k QPS、Sonnet 一把梭 vs 5 模式组合):
把全文浓缩成 5 条工程守则:
不要做的事:
LLM 应用的"成本工程"和传统软件的性能优化逻辑完全一致:
把这 5 个模式的成本节省加在一起,75-80% 是完全现实的。对一个一年烧 750k——这钱够再雇 5 个工程师。
但最重要的是:成本优化不能等到账单失控才开始。等老板问你"为什么这个月多了 $50k"时再回头看,已经晚了。
下一步行动(如果你刚开始):
- 先在 dashboard 上看上个月的真实账单,按 model 拆解
- 给最贵的 1-2 个调用点加 prompt caching(5 行代码)
- 给"闲聊"和"重排序"这种场景换 Haiku
- 上一个 LiteLLM Proxy 或 Cloudflare AI Gateway,1 小时内能看到全量调用分布
- 重复
本文 GitHub Star 数与定价数据均为 2026-06-12 实时拉取快照。模型定价、API 政策、缓存 TTL 等关键参数会随厂商更新而变化,生产环境实施前请以官方文档为准。
Conversation
0 条