开始前
- 已经在跑 AI SaaS 或 PoC,有真实流量数据
- 月 API 成本 ≥ $50(低于这个数,优化 ROI 不如做产品)
- 能改代码(前后端都行)+ 能解读 token 用量日志
国内访问 LLM endpoint 不稳是变量之一,先把基础设施稳了:备一条 AI SaaS 出海可用的 API 中转,消除「网络抖动伪装成成本问题」的干扰。
杠杆 1:Prompt Caching(省 50-90%)
最高 ROI。Anthropic 与 OpenAI 都支持 prompt caching。
Anthropic 实现
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
system=[
{
"type": "text",
"text": "你是一个客服助手。规则:a) 礼貌 b) ...", # 长 system prompt
"cache_control": {"type": "ephemeral"},
}
],
messages=[{"role": "user", "content": user_query}],
)
cache_control: ephemeral 表示缓存 5 分钟。复用次数越多越赚:
| 复用次数 N | 标准成本 | 缓存成本 | 节省 |
|---|---|---|---|
| 1 | 1× | 1.25× | -25% |
| 3 | 3× | 1.45× | 52% |
| 10 | 10× | 2.15× | 79% |
| 100 | 100× | 11.15× | 89% |
何时开:system prompt + few-shot 重复使用,且单 prompt > 1024 tokens(缓存最低准备成本)。
适用场景
- 客服 chatbot 共用同一份业务知识 system prompt
- RAG 应用每次喂相同的指令模板
- Agent 框架的 system prompt + tool definitions
不适用场景
- 用户 prompt 每次都不一样且短
- 单次一问一答完事
杠杆 2:模型降级(省 30-70%)
不要每个请求都用 Opus。按任务复杂度分级:
| 任务类型 | 推荐模型 | 相对成本 |
|---|---|---|
| 关键词分类 | Haiku | 1× |
| 摘要 first pass | Haiku | 1× |
| 一般对话 | Sonnet | 3× |
| 长文档 RAG | Sonnet | 3× |
| 复杂代码生成 | Opus | 15× |
| 多步推理 | Opus | 15× |
实际策略:
def pick_model(task_type, prompt_complexity):
if task_type in {"classify", "tag", "summarize_short"}:
return "claude-3-5-haiku-20241022"
if task_type == "deep_reasoning" or prompt_complexity > 0.8:
return "claude-3-opus-20240229"
return "claude-3-5-sonnet-20241022" # default
怎么测降级安全
A/B:对照组 100% Sonnet,实验组 50% Haiku + 50% Sonnet。一周后看:
- 用户评分(点赞 / 点踩比例)
- 重试率(用户认为答案不够好重新问)
- 留存率(是否影响付费转化)
任一指标降幅 > 5% 回退原模型,否则保留降级。
杠杆 3:max_tokens 控制(省 10-30%)
很多人不设 max_tokens 或设过大(如 8192)。LLM 看到大空间倾向于「啰嗦」,输出比需要的长 30-50%。
设值原则:
- 短答案场景(分类、yes/no):100-200
- 单轮对话:800-1500
- 长内容生成(文章、报告):2000-4000
- Agent 多轮 tool use:1000(单轮)
实际效果:把 max_tokens 从 4096 降到 1500,输出 token 平均从 1800 降到 1100,省 ~40%。
杠杆 4:多模型路由(省 20-50%)
中文场景的杀手锏:DeepSeek V3 / GLM 4.7 / Kimi K2 价格是 Sonnet 的 1/3-1/5,中文质量接近。
def route_by_language(prompt):
if detect_language(prompt) == "zh":
return "deepseek-v3" # 中文优选
return "claude-3-5-sonnet-20241022"
或按用户 tier:
def route_by_tier(user):
if user.tier == "free":
return "claude-3-5-haiku-20241022" # 免费用户用便宜模型
if user.tier == "pro":
return "claude-3-5-sonnet-20241022"
if user.tier == "enterprise":
return "claude-3-opus-20240229"
杠杆 5:Streaming + 用户主动中断(省 5-15%)
用户读到一半发现「答案不是我想要的」,给个停止按钮立即终止 streaming,未生成 token 不计费。
const controller = new AbortController();
const response = await fetch("/api/chat", {
signal: controller.signal,
body: JSON.stringify({ message }),
});
// 用户点击「停止」按钮
stopBtn.onclick = () => controller.abort();
后端:
@app.post("/chat")
async def chat(req: Request, body: ChatBody):
async def gen():
async with client.messages.stream(...) as stream:
async for text in stream.text_stream:
if await req.is_disconnected():
break # 用户断了,立即停
yield text
return StreamingResponse(gen(), media_type="text/event-stream")
省钱比例不大但用户体验提升明显(响应感更强)。
优化后的成本量化
每次 API 调用记录字段:
{
"timestamp": ...,
"user_id": ...,
"feature": "chat" | "summarize" | ...,
"model": "claude-3-5-sonnet-20241022",
"input_tokens": 1500,
"output_tokens": 800,
"cache_read_tokens": 1200, # 缓存命中数
"cache_write_tokens": 0,
"cost_usd": 0.013,
}
每月 SQL aggregate:
SELECT feature, model,
SUM(input_tokens) as in_t,
SUM(output_tokens) as out_t,
SUM(cache_read_tokens) as cache_t,
SUM(cost_usd) as cost
FROM api_calls
WHERE created_at >= NOW() - INTERVAL '30 days'
GROUP BY feature, model
ORDER BY cost DESC;
对比优化前后曲线,每个杠杆量化省了多少。
跨地区使用
优化逻辑是后端代码,与地区无关。但 API 调用本身依赖网络,国内重度跑 AI SaaS 后端建议部署在境外服务器(Hetzner / Vultr / DigitalOcean),跳过国内出口的不稳定。