作者将 API 支出当作数据库查询成本来管理,通过模型路由表区分任务复杂度,并叠加缓存策略,实现月度成本大幅下降。
我是在一次惨痛的教训中学到这一课的。去年,我的团队在一个本该"简单"的 LLM 功能上三个月烧掉了 14,000 美元。事实上它确实很简单。我们只是没有注意自己发送了什么、发送给了哪个模型、以及发送的频率。一旦我开始把 API 开销当作数据库查询成本问题来对待(因为它本质上就是),数字就开始急剧下降了。
说一句,这篇文章不是关于寻找什么神奇的企业折扣。它讲的是对任何昂贵的外部依赖都适用的工程卫生习惯:分析它、绕过它、缓存能缓存的、不要发送不需要的字节。
以下是我们真正有效的做法。
这是最重要的一点。在我看来,最大的杠杆是选择与实际任务复杂度相匹配的模型。我见过的绝大多数"AI 功能"其实不需要前沿推理模型。它们需要的只是一个把文本转换成略微不同文本的东西。
我现在把路由表贴在显示器上了:
是的,这些百分比是真实的。不,我没有编造。2025/2026 年,前沿模型和小模型在通用任务上的差距是荒谬的。这就像租一辆半挂卡车去买菜。
最终我写了这个路由助手:
MODEL_ROUTER = {
"chat": "deepseek-v4-flash", # $0.25/M
"code": "deepseek-coder", # $0.25/M
"classification": "Qwen/Qwen3-8B", # $0.01/M
"reasoning": "deepseek-reasoner", # $2.50/M
"summarization": "Qwen/Qwen3-32B", # $0.28/M
"translation": "Qwen-MT-Turbo", # $0.30/M
}
def pick_model(task_type: str) -> str:
return MODEL_ROUTER.get(task_type, "deepseek-v4-flash")
# usage
resp = client.chat.completions.create(
model=pick_model(classify(user_input)),
messages=[{"role": "user", "content": user_input}],
)
如果你用 global-apis.com/v1 作为 OpenAI 兼容的 base URL,这个可以无缝接入不用改代码。说真的,这就是完整的集成故事。
基本的路由表搭好之后,我又往前走了一步。如果便宜模型能搞定,为什么还要发给贵模型?
这个模式完全是从缓存层次结构 playbook 里借鉴的:先试 L1,miss 了就升级到 L2,只有万不得已才打到 L3。同样的思路,不同的底层实现。
def tiered_generate(prompt: str, budget_usd: float = 0.50):
# Tier 1: 超便宜的分类/聊天层
resp = call_model("Qwen/Qwen3-8B", prompt) # ~$0.01/M
if confidence(resp) >= 0.8:
return resp # ~80% 的流量在这里终止
# Tier 2: 标准质量
resp = call_model("deepseek-v4-flash", prompt) # ~$0.25/M
if confidence(resp) >= 0.9:
return resp # ~15% 的流量
return call_model("deepseek-reasoner", prompt) # ~$2.50/M
来一段亲身经历:我做过的一个客服管道从每月 420 美元降到了 28 美元。第 85 百分位的查询是"我的订单到哪了",这种事完全不需要推理模型。大部分查询都不需要。
诚实地说,你还需要一个不是胡说八道的 confidence() 函数。对我们来说是这样:短小的、看起来确定性的响应、与检索上下文高度重叠的,给通过。任何开始像"我觉得可能也许……"这样含糊其辞的,就升级。你的情况可能不同,但原则是不变的。
坦白讲,我不敢相信自己交付的系统里居然没有这个。缓存相同或几乎相同的请求是如此显而易见。
import hashlib, json, time
_cache = {}
def cached_chat(model, messages, ttl=3600):
key = hashlib.md5(
json.dumps({"model": model, "messages": messages}, sort_keys=True).encode()
).hexdigest()
entry = _cache.get(key)
if entry and time.time() - entry["ts"] < ttl:
return entry["resp"] # 免费
resp = client.chat.completions.create(model=model, messages=messages)
_cache[key] = {"resp": resp, "ts": time.time()}
return resp
FAQ 类内容的命中率是 50-80%。如果你不信,就接入监控跑一周。你会对自己损失了多少钱感到恼火。
对于语义相似性(不仅仅是精确匹配),基于 embedding 的缓存也能用,但那是一个单独的工程项目。先从精确匹配缓存开始。它很无聊但很管用。
Token 就是字节。字节就是钱。用同样的方式对待它们。
诀窍是用一个便宜的模型来总结长上下文,然后再把摘要发给贵模型。你在压缩步骤上花的钱,总账算下来是赚的。
def compress_prompt(text: str, target_ratio: float = 0.5) -> str:
if len(text) < 500:
return text
target_chars = int(len(text) * target_ratio)
summary = call_model(
"Qwen/Qwen3-8B",
f"Summarize this in {target_chars} chars: {text}",
)
return summary
做个快速计算因为我总想看数字:2000 token 的系统 prompt 压缩到 400 token,在 DeepSeek V4 Flash 上每请求节省 0.024 美元。按每天 10,000 次请求算,那是 240 美元/天,即 87,600 美元/年。这还只是一个功能。一次压缩调用就搞定。
你不应该把整个代码库、每个 README、以及昨天所有的日志都作为每次请求的一部分发过去。在底层,让检索变得有用的同一套 RAG 技术也能让账单变小。
如果你有 N 个独立请求且没有实时要求,不要做 N 次往返。合并它们。
# 之前:N 次调用,N*输入 token 被计费
for q in questions:
client.chat.completions.create(
model="deepseek-v4-flash",
messages=[{"role": "user", "content": q}],
)
# 之后:1 次调用,单个共享系统 prompt
batch_prompt = "\n".join(f"{i+1}. {q}" for i, q in enumerate(questions))
resp = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[
{"role": "system", "content": "Answer each numbered question."},
{"role": "user", "content": batch_prompt},
],
)
answers = parse_numbered_responses(resp.choices[0].message.content, len(questions))
这也是大多数提供商(包括 Global API,顺便说一句)有额外折扣的显式批量端点的地方。如果你本来就是做异步处理,用它们。参考:这和 RFC 9221(优先级提示)是同一个思路——不要为普通货运付快递价格。
这里的节省:在你已经做到的基础上再加 10-20%。虽然不炫酷,但很值得。
一个不受欢迎的观点:不要相信自己能"盯着仪表盘"。把它自动化。
class BudgetGuard:
def __init__(self, monthly_budget_usd: float):
self.budget = monthly_budget_usd
self.spent = 0.0
self.month = time.strftime("%Y-%m")
def check(self, estimated_cost_usd: float) -> bool:
if time.strftime("%Y-%m") != self.month:
self.spent = 0.0
self.month = time.strftime("%Y-%m")
if self.spent + estimated_cost_usd > self.budget:
raise RuntimeError(f"over budget: ${self.spent:.2f}/${self.budget:.2f}")
return True
def record(self, actual_cost_usd: float):
self.spent += actual_cost_usd
guard = BudgetGuard(monthly_budget_usd=500.0)
# 每次调用前
estimated = estimate_cost(model, messages)
guard.check(estimated)
resp = client.chat.completions.create(model=model, messages=messages)
guard.record(usage_to_cost(resp.usage, model))
这个守卫第一次在生产环境触发的时候,你要么愤怒要么如释重负。对我来说是后者。
按团队的总数字会掩盖真相。你要的是按功能、按路由、按租户(如果能拿到的话)来追踪。做不到这一点,你就会优化错误的东西。
一个简单的带标签客户端就够了:
class TaggedClient:
def __init__(self, base_url: str, api_key: str):
self._client = OpenAI(base_url=base_url, api_key=api_key)
self._costs = defaultdict(float)
def chat(self, *, model, messages, tags: dict):
resp = self._client.chat.completions.create(
model=model, messages=messages
)
cost = usage_to_cost(resp.usage, model)
label = tags.get("feature", "unknown")
self._costs[label] += cost
# 同时推送到你的 metrics 后端
metrics.increment("llm.cost.usd", cost, tags=tags)
return resp
def report(self):
for k, v in sorted(self._costs.items(), key=lambda kv: -kv[1]):
print(f"{k:30s} ${v:8.2f}")
每周跑一次报告。我跑第一次的时候就立刻搞清楚了哪个功能是烧钱大户。我不会告诉你它是哪个,因为太丢人了。
优化前:大约每月 4,600 美元,而坦白说那只是相当一般的工作负载。
优化后,同等流量:
这是 97% 的削减。具有讽刺意味的是延迟也降了,因为便宜的模型通常更快。我唯一放弃的是在日志里看到"gpt-4o"的温暖感觉。
OpenAI 兼容客户端,指向 global-apis.com/v1
MODEL_ROUTER 里写 6 条路由规则
cached_chat() 默认 1 小时 TTL 作为入口
compress_prompt() 处理任何超过 1k token 的上下文
BudgetGuard 接上 Slack 告警
每周按功能标签跑成本报告
这是周末的工作量。很可能一年帮你节省五位数。这数学不会说谎,即使账单会。
供参考,这是文章开头表格里那些百分比的背后数字。贴在某个显眼的地方——每个 10 美元/M 的模型选择对比 0.25 美元/M 的模型选择,都是某人账单上真实的行项目。
如果你已经在 Global API 上跑东西了,定价方式是一样的,SDK 迁移基本上就是改个 base URL。如果你还没用过,去 global-apis.com/v1 看看——我迁移一个服务大约花了二十分钟,然后就再没回头看过。
这就是 playbook。没什么花哨的。就是工程。