前言
LLM 应用上线 3 个月后,90% 的团队都会撞上一堵墙——账单。某中型 SaaS 团队的实例:
- 月初:月 5M token / 月,账单 $200
- 3 个月后:100M token / 月,账单 $4000
- 6 个月后:1B token / 月,账单 $40000
增长来自 3 个方向:用户量 × 调用频次 × 单次 token 数。任何一个失控,成本都会爆炸。
但比成本更可怕的是延迟——LLM 调用从 500ms 到 5s 不等,用户体验断崖式下降。
这一篇覆盖 5 大优化手段,按 ROI 排序:
- Prompt Cache(最高 90% token 节省,最容易)
- Streaming(首字延迟降到 200ms)
- Semantic Cache(重复 query 走缓存)
- 模型路由(按 query 难度分层)
- 降级与限流(失控时的兜底)
一、Prompt Cache:90% token 节省
[Mermaid] 视觉化:
OpenAI / Anthropic 原生 Prompt Cache
OpenAI 自动缓存**>= 1024 tokens** 的 prompt 前缀(gpt-4o 是 1024,gpt-4o-mini 是 2048),命中部分便宜 50%(cache write 不额外收费,cache read 是基础价 50%)。Anthropic 提供 5 分钟 TTL 的 prompt cache,支持 4 个 breakpoints(Sonnet 4 / Opus 4 / Haiku 4 / Claude 3.5 Sonnet 均支持)。
// OpenAI / Anthropic 自动处理,无需代码
// 只需要把"稳定不变的部分"放在 prompt 前面
const result = await generateText({
model: openai('gpt-4o'),
system: [
'你是 ACME 公司的客服助手。', // ← 稳定,命中缓存
'当前日期:2026-07-07。', // ← 稳定,命中缓存
'公司政策:30 天无理由退款。', // ← 稳定,命中缓存
// ...(总计 2000 tokens 稳定内容)
'\n\n以下是用户对话历史:\n' + history, // ← 动态,未命中
].join('\n'),
prompt: userQuery, // ← 动态,未命中
});
实战经验:
| 缓存命中率 | token 节省 |
|---|---|
| 30% | 30% × (2000/2500) ≈ 24% 总节省 |
| 60% | 60% × (2000/2500) ≈ 48% 总节省 |
| 90% | 90% × (2000/2500) ≈ 72% 总节省 |
关键:稳定内容(system prompt + few-shot examples + 长期上下文)放最前面,至少凑够 cache 阈值——gpt-4o 是 1024 tokens,gpt-4o-mini 是 2048 tokens。
二、Streaming:首字延迟 < 200ms
LLM 生成 500 tokens 通常需要 3-5s。流式输出让用户感知延迟从 5s 降到 0.2s:
[Mermaid] 视觉化:
Vercel AI SDK 流式实现
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { anthropic } from '@ai-sdk/anthropic';
// 服务端:流式返回
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4o'),
messages,
});
// AI SDK v4: 用 toUIMessageStreamResponse()(toDataStreamResponse 已弃用)
return result.toUIMessageStreamResponse();
}
// 客户端:消费流
const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ messages }),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
// 追加到 UI
appendToUI(chunk);
}
首字延迟(TTFT)通常 200-500ms,用户感知几乎是”瞬时”。
流式 + Tool Calling
Agent 调用工具时也可以流式:
const result = streamText({
model: openai('gpt-4o'),
tools: { searchWeb, queryDB },
prompt: userQuery,
// 工具调用和文本默认都流式(无需 experimental 开关)
});
for await (const chunk of result.textStream) {
// 文本部分
process.stdout.write(chunk);
}
// 工具调用在 result.toolCalls 中
三、Semantic Cache:重复 query 走缓存
prompt cache 只能缓存完全相同的前缀**。但用户问的问题常常是语义重复:
Q1: "Transformer 的核心创新是什么?"
Q2: "Transformer 有什么重大创新?"
两个 query 字面不同但语义相同,理想情况应该返回同一个答案。Semantic Cache 用 embedding 找相似 query:
GPTCache 实战
GPTCache 是开源 semantic cache:
from gptcache import Cache
from gptcache.adapter.api import init_similar_cache
# 配置:embedding + 相似度阈值 + 向量库
init_similar_cache(
cache_obj=Cache(),
embedding_func=onnx_embedding(), # 用 ONNX 跑 embedding,省钱
data_manager=milvus_data_manager(), # 向量库存 query embeddings
similarity_threshold=0.85, # 相似度阈值
)
# 用法:和 OpenAI client 一样
response = openai.ChatCompletion.create(...)
# GPTCache 自动拦截:相似 query 命中缓存
Vercel AI SDK + 自建 semantic cache
import { embed, generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
async function cachedGenerate(userQuery: string) {
// 1. embed query
const { embedding } = await embed({
model: openai.embedding('text-embedding-3-small'),
value: userQuery,
});
// 2. 查缓存
const { rows } = await pool.query(
`SELECT response FROM cache
WHERE embedding <=> $1 < 0.05 -- 相似度阈值
ORDER BY created_at DESC
LIMIT 1`,
[JSON.stringify(embedding)]
);
if (rows.length > 0) {
return { response: rows[0].response, cached: true };
}
// 3. 未命中,调用 LLM
const { text } = await generateText({
model: openai('gpt-4o'),
prompt: userQuery,
});
// 4. 存缓存
await pool.query(
`INSERT INTO cache (embedding, response, created_at)
VALUES ($1, $2, NOW())`,
[JSON.stringify(embedding), text]
);
return { response: text, cached: false };
}
实战经验:
| QPS | 缓存命中率 | 节省 |
|---|---|---|
| 100 | 30% | $0.5/千次 |
| 1000 | 50% | $5/千次 |
| 10000 | 70% | $50/千次 |
注意:semantic cache 适合FAQ 类、客服类场景;不适合创意 / 个性化生成。
四、模型路由:按 query 难度分层
不是所有 query 都需要 GPT-4。80% 的简单 query 用 GPT-4o-mini 就够了:
实现
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { anthropic } from '@ai-sdk/anthropic';
async function routedGenerate(userQuery: string) {
// 1. 用小模型先分类
const classification = await generateText({
model: openai('gpt-4o-mini'),
prompt: `判断 query 复杂度:simple / medium / hard / dangerous
Query: ${userQuery}
只输出一个词。`,
});
const tier = classification.text.trim();
// 2. 根据 tier 路由(Vercel AI SDK 要求 model 必须是 provider 实例,不是字符串)
const modelMap = {
simple: openai('gpt-4o-mini'),
medium: openai('gpt-4o'),
hard: anthropic('claude-opus-4-5'),
dangerous: null, // 拒绝
};
if (modelMap[tier] === null) {
return { response: '抱歉,这个问题我无法回答' };
}
const { text } = await generateText({
model: modelMap[tier],
prompt: userQuery,
});
return { response: text };
}
实战经验:
- 分类 LLM 自身开销:~5% 总体成本
- Tier 错配风险:分错类导致质量问题,需要评估集验证分类器准确率
- 降级兜底:tier 不可用时自动降级到下一个 tier
Cascade 模式
更进一步:先小模型,信心不够再升级:
let answer = await gpt4oMini(query);
let confidence = await evaluateConfidence(answer);
if (confidence < 0.7) {
answer = await gpt4o(query); // 升级
}
最坏情况才用最强模型,平均成本可控。
五、降级与限流:失控时的兜底
5 个兜底机制:
1. 限流(Rate Limit)
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(100, '1 m'), // 每分钟 100 次
});
// 应用层
const { success } = await ratelimit.limit(userId);
if (!success) return new Response('Too many requests', { status: 429 });
2. Token 限流
按 token 消耗限流比按请求数更合理:
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.tokenBucket(100000, '1 h', 10000), // 1 小时 100K tokens
});
const { success, remaining } = await ratelimit.limit(userId, 5000); // 本次 5K tokens
3. 超时降级
const result = await Promise.race([
generateText({ model: openai('gpt-4o'), prompt }),
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 5000)),
]).catch(() =>
generateText({ model: openai('gpt-4o-mini'), prompt }) // 降级到小模型
);
4. Fallback 链
async function robustGenerate(prompt: string) {
const models = [
openai('gpt-4o'),
anthropic('claude-sonnet-4-5'),
openai('gpt-4o-mini'),
];
for (const model of models) {
try {
return await generateText({ model, prompt });
} catch (e) {
// 失败继续尝试下一个
continue;
}
}
throw new Error('All models failed');
}
5. 熔断(Circuit Breaker)
const breaker = new CircuitBreaker({
failureThreshold: 5, // 5 次失败后熔断
resetTimeout: 30000, // 30s 后尝试半开
});
const result = await breaker.fire(() => callProvider(prompt));
熔断期间所有请求快速失败(不再阻塞),保护下游。
六、生产优化 checklist
5 件事必做:
- ✅ Prompt Cache 优化:稳定内容放最前面,gpt-4o ≥ 1024 tokens / gpt-4o-mini ≥ 2048 tokens
- ✅ 全链路流式:TTFT < 500ms
- ✅ Semantic Cache:FAQ 类场景命中率 50%+
- ✅ 模型路由:80% 简单 query 用 mini 模型
- ✅ Fallback + 熔断:超时降级 + 多供应商兜底
踩坑提醒
- 不要忽视 prompt cache 命中率。命中率 < 30% 说明 prompt 结构有问题(稳定内容分散),重新设计 prompt 顺序。
- 不要让 streaming 把整个上下文塞进第一 chunk。首字延迟可能飙到 1s+,用户体验比非流式还差。
- 不要在 semantic cache 里存 PII 数据。缓存命中可能让其他用户看到敏感信息,必须 user 隔离 + 脱敏。
- 不要无脑用最强模型。80% 的 query 用 mini 模型就够,路由能省 50-70%。
- 不要只依赖单一供应商。OpenAI / Anthropic 都可能宕机,至少 2 家供应商 + fallback 链。
总结
5 个 takeaway:
- Prompt Cache 节省 token 成本:稳定内容放最前面,凑够模型 cache 阈值(gpt-4o 1024 / gpt-4o-mini 2048)。
- Streaming 是必做:TTFT 从 5s 降到 200ms,用户体验质变。
- Semantic Cache 50-80% 命中:FAQ / 客服场景收益最大。
- 模型路由省 50-70%:80% query 用 mini 模型,复杂 query 才升级。
- Fallback + 限流 + 熔断:失控时的兜底,生产必备。
下一篇:LLM 应用的 Guardrails:Prompt Injection 与输出安全 — 安全是 LLM 应用第一防线。
参考资料
- GPTCache (Zilliz, GitHub) — 开源 semantic cache,10x 成本 / 100x 速度
- Vercel AI SDK — Streaming Text Generation — streamText 流式实现,SSE 协议
// 相关文章
Agent 架构:ReAct、Plan-and-Execute 与多 Agent 协作
从单步工具调用到完整 agent 思考循环——ReAct / Plan-and-Execute / Multi-Agent 三大主流架构与生产权衡
AI 时代的新 UI:当下与近未来的界面应该长什么样
Generative UI、Agent 优先、对话即操作——AI 时代 UI 设计的范式转移、实战模式与近未来趋势
Function Calling 与 Tool Use:从协议到工程实现
LLM 怎么调用你的代码——JSON schema 设计、tool 选择、错误处理、Zod 强校验、生产工程陷阱