据 Anthropic 最新披露的数据,2026 年企业级 LLM API 月均支出已突破 50 万美元,其中 60%-80% 的成本来自 Token 消耗。更令人警醒的是,Hacker News 上近期一则「AI Agent 因扫描 DN42 网络导致运营者破产」的案例引发热议——Token 成本失控已不是理论问题,而是每个接入 LLM 的开发者都必须面对的现实挑战。如果你正在开发 AI 驱动的应用,Token 优化不是可选项,而是决定产品能否盈利的关键能力。
🔍 一、理解 Token 成本结构
1.1 输入 Token vs 输出 Token 的价格鸿沟
很多开发者只知道「Token 要花钱」,却不理解输入(Input)和输出(Output)Token 之间的巨大价差。以 2026 年主流模型的定价为例:
| 模型 | 输入价格 ($/1M tokens) | 输出价格 ($/1M tokens) | 输出/输入比 |
|---|---|---|---|
| GPT-4o | $2.50 | $10.00 | 4x |
| Claude Sonnet 4 | $3.00 | $15.00 | 5x |
| Gemini 2.5 Pro | $1.25 | $10.00 | 8x |
| DeepSeek V3 | $0.27 | $1.10 | 4x |
| Kimi K2.7-Code | $0.30 | $1.20 | 4x |
⚡ 关键结论: 输出 Token 的价格通常是输入的 4-8 倍。优化输出长度比优化输入长度的 ROI 高得多。
1.2 隐藏成本:上下文窗口的「隐性膨胀」
一个典型的 RAG(检索增强生成)应用中,实际 Token 消耗分布如下:
- 系统 Prompt(System Prompt):500-2000 tokens(固定成本,每次请求都消耗)
- 检索上下文(Retrieved Context):2000-8000 tokens(动态,随检索结果变化)
- 对话历史(Chat History):1000-10000 tokens(随对话轮次线性增长)
- 用户输入:50-500 tokens(通常占比最小)
- 模型输出:200-2000 tokens
一个 6 轮对话中,对话历史可能吃掉 60% 以上的输入 Token,而这部分信息密度往往最低。
// 计算一次请求的实际 Token 成本
// 假设使用 GPT-4o,输入 $2.50/1M,输出 $10.00/1M
const inputTokens = 8500; // system(1500) + context(5000) + history(1500) + user(500)
const outputTokens = 800; // 模型回复
const costPerInputToken = 2.50 / 1_000_000;
const costPerOutputToken = 10.00 / 1_000_000;
const totalCost = (inputTokens * costPerInputToken) + (outputTokens * costPerOutputToken);
console.log(`单次请求成本: $${totalCost.toFixed(4)}`);
// 单次请求成本: $0.0293
// 假设日均 10000 次请求
const dailyCost = totalCost * 10000;
console.log(`日均成本: $${dailyCost.toFixed(2)}`);
// 日均成本: $292.50
console.log(`月均成本: $${(dailyCost * 30).toFixed(2)}`);
// 月均成本: $8775.00
💡 提示: 在估算成本时,很多开发者只计算了用户输入和模型输出,忽略了 System Prompt 和检索上下文这两个「大头」,导致实际账单是预估的 3-5 倍。
🛠️ 二、六大核心优化策略
2.1 策略一:Prompt 压缩——用更少的 Token 说同样的事
Prompt 压缩是最直接的优化手段。核心原则是:去除冗余,保留语义。
❌ 冗余写法(消耗 ~180 tokens):
You are a highly experienced and professional senior software engineer
who has been working in the industry for over 15 years. You have deep
expertise in JavaScript, TypeScript, Python, and many other programming
languages. Your task is to help the user by reviewing their code and
providing detailed, comprehensive, and thorough feedback on code quality,
performance, security, and best practices. Please make sure your response
is well-structured and easy to understand.
✅ 压缩写法(消耗 ~60 tokens,效果相同):
Senior code reviewer. Expert in JS/TS/Python. Review code for quality,
performance, security. Be structured and concise.
一个实用的 Prompt 压缩函数:
// Prompt 压缩工具函数
function compressPrompt(prompt) {
const rules = [
// 移除填充词
[/\b(please|kindly|make sure to|ensure that|it is important to)\b/gi, ''],
// 合并同义重复
[/\bdetailed.*comprehensive.*thorough\b/gi, 'comprehensive'],
// 移除冗余修饰
[/\bhighly experienced and professional\b/gi, 'senior'],
[/\bdeep expertise in\b/gi, 'expert in'],
// 压缩空格
[/\s{2,}/g, ' '],
// 移除尾部空格
[/\s+\n/g, '\n'],
];
let compressed = prompt;
for (const [pattern, replacement] of rules) {
compressed = compressed.replace(pattern, replacement);
}
return compressed.trim();
}
// 使用示例
const original = `You are a highly experienced and professional senior software engineer
who has been working in the industry for over 15 years. You have deep
expertise in JavaScript, TypeScript, Python, and many other programming languages.
Please make sure your response is well-structured and easy to understand.`;
console.log(`原始: ~${estimateTokens(original)} tokens`);
console.log(`压缩后: ~${estimateTokens(compressPrompt(original))} tokens`);
// 原始: ~65 tokens → 压缩后: ~25 tokens(节省 62%)
📌 记住: Prompt 压缩的前提是不损失语义。过度压缩会导致模型理解偏差,反而需要更多轮对话才能达到目标,得不偿失。
2.2 策略二:上下文窗口管理——对话历史的智能裁剪
对话历史是 Token 消耗的「无底洞」。三种主流策略各有优劣:
// 三种对话历史管理策略
// 策略 1:滑动窗口(Sliding Window)—— 简单但粗暴
function slidingWindow(history, maxMessages = 10) {
// 保留最近 N 条消息
return history.slice(-maxMessages);
}
// 策略 2:Token 预算裁剪 —— 精确控制
function tokenBudgetTrim(history, maxTokens = 4000) {
const result = [];
let totalTokens = 0;
// 从最新消息向前遍历
for (let i = history.length - 1; i >= 0; i--) {
const msgTokens = estimateTokens(history[i].content);
if (totalTokens + msgTokens > maxTokens) break;
totalTokens += msgTokens;
result.unshift(history[i]);
}
return result;
}
// 策略 3:摘要压缩(最佳方案)—— 保留关键信息
async function summarizeAndTrim(history, client, maxTokens = 4000) {
if (estimateHistoryTokens(history) <= maxTokens) {
return history;
}
// 将旧对话压缩为摘要
const oldMessages = history.slice(0, -4); // 保留最近 4 条
const recentMessages = history.slice(-4);
const summary = await client.chat.completions.create({
model: 'gpt-4o-mini', // 用便宜模型做摘要
messages: [
{
role: 'system',
content: 'Summarize this conversation in under 200 words. Preserve key decisions, facts, and context.'
},
{ role: 'user', content: JSON.stringify(oldMessages) }
],
max_tokens: 300
});
// 用摘要替换旧对话
return [
{ role: 'system', content: `[Previous conversation summary]\n${summary.choices[0].message.content}` },
...recentMessages
];
}
| 策略 | Token 节省 | 信息保留率 | 实现复杂度 | 适用场景 |
|---|---|---|---|---|
| 滑动窗口 | 40-60% | 低(丢失早期上下文) | ⭐ 简单 | 短对话、客服机器人 |
| Token 预算裁剪 | 30-50% | 中(均匀丢失) | ⭐⭐ 中等 | 通用对话 |
| 摘要压缩 | 50-70% | 高(保留关键信息) | ⭐⭐⭐ 复杂 | 长对话、专业助手 |
⚡ 关键结论: 对于超过 20 轮的长对话,摘要压缩策略的综合效果最好。用 gpt-4o-mini($0.15/1M tokens)做摘要的成本远低于将全部历史发给主模型的成本。
2.3 策略三:语义缓存——相同问题不再重复付费
传统缓存(精确匹配)在 LLM 场景下几乎无用——用户问「北京天气如何」和「今天北京什么天气」语义相同但字符串不同。语义缓存(Semantic Cache)通过向量相似度匹配解决这个问题。
// 语义缓存实现(基于余弦相似度)
import OpenAI from 'openai';
const openai = new OpenAI();
class SemanticCache {
constructor(options = {}) {
this.cache = new Map();
this.similarityThreshold = options.threshold ?? 0.92;
this.ttl = options.ttl ?? 3600_000; // 1 hour
this.embeddingModel = options.embeddingModel ?? 'text-embedding-3-small';
}
// 获取文本的向量表示
async getEmbedding(text) {
const response = await openai.embeddings.create({
model: this.embeddingModel,
input: text,
});
return response.data[0].embedding;
}
// 计算余弦相似度
cosineSimilarity(a, b) {
let dotProduct = 0, normA = 0, normB = 0;
for (let i = 0; i < a.length; i++) {
dotProduct += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}
// 查询缓存
async get(query) {
const queryEmbedding = await this.getEmbedding(query);
let bestMatch = null;
let bestScore = 0;
for (const [key, entry] of this.cache) {
// 检查 TTL
if (Date.now() - entry.timestamp > this.ttl) {
this.cache.delete(key);
continue;
}
const score = this.cosineSimilarity(queryEmbedding, entry.embedding);
if (score > bestScore) {
bestScore = score;
bestMatch = entry;
}
}
if (bestScore >= this.similarityThreshold && bestMatch) {
return { hit: true, result: bestMatch.result, similarity: bestScore };
}
return { hit: false };
}
// 存入缓存
async set(query, result) {
const embedding = await this.getEmbedding(query);
this.cache.set(query, {
embedding,
result,
timestamp: Date.now(),
});
}
}
// 使用示例
const cache = new SemanticCache({ threshold: 0.90 });
async function askLLM(question) {
// 1. 先查语义缓存
const cached = await cache.get(question);
if (cached.hit) {
console.log(`缓存命中! 相似度: ${cached.similarity.toFixed(3)}`);
return cached.result; // 省掉一次 LLM 调用
}
// 2. 缓存未命中,调用 LLM
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: question }],
});
const result = response.choices[0].message.content;
// 3. 存入缓存
await cache.set(question, result);
return result;
}
// 这两个问题语义相近,第二次会命中缓存
await askLLM('北京今天天气怎么样?');
await askLLM('今天北京的天气如何?'); // 缓存命中,省 $0.003
语义缓存的成本效益分析:
- Embedding 调用成本:text-embedding-3-small 仅 $0.02/1M tokens
- 一次缓存命中的节省:$0.003 - $0.05(取决于模型和输入长度)
- 盈亏平衡点:约 100 次查询中有 5 次命中即可回本
💡 提示: 语义缓存最适合 Q&A 类应用(客服、知识库问答)。对于创意生成类任务,缓存命中率低且可能返回过时内容,不建议使用。
2.4 策略四:结构化输出——告别冗长的自然语言回复
强制模型返回结构化数据(JSON),而非自然语言,可以大幅减少输出 Token。
// 使用 OpenAI Structured Outputs 限制输出格式
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'system',
content: 'Analyze the code and return issues as JSON.'
},
{
role: 'user',
content: 'Review this function:\nfunction add(a,b){return a+b}'
}
],
response_format: {
type: 'json_schema',
json_schema: {
name: 'code_review',
strict: true,
schema: {
type: 'object',
properties: {
issues: {
type: 'array',
items: {
type: 'object',
properties: {
severity: { type: 'string', enum: ['low', 'medium', 'high'] },
message: { type: 'string' },
line: { type: 'integer' }
},
required: ['severity', 'message', 'line'],
additionalProperties: false
}
},
summary: { type: 'string' }
},
required: ['issues', 'summary'],
additionalProperties: false
}
}
}
});
对比效果:
- ❌ 自然语言回复:~350 tokens(「I’ve analyzed the code and found several issues…」)
- ✅ JSON 结构化回复:~80 tokens(
{"issues":[...],"summary":"..."}) - 节省 77% 的输出 Token
2.5 策略五:模型路由——不同任务用不同模型
不是所有请求都需要最贵的模型。建立智能路由层,根据任务复杂度分配模型:
// 智能模型路由
const MODEL_TIERS = {
// 简单任务:分类、提取、格式转换
low: { model: 'gpt-4o-mini', inputCost: 0.15, outputCost: 0.60 },
// 中等任务:摘要、翻译、代码解释
mid: { model: 'gpt-4o', inputCost: 2.50, outputCost: 10.00 },
// 复杂任务:推理、创作、架构设计
high: { model: 'o3', inputCost: 10.00, outputCost: 40.00 },
};
function classifyTask(userMessage) {
const lowPatterns = /^(classify|extract|convert|format|list|translate)/i;
const highPatterns = /(design|architect|reason|analyze deeply|compare.*trade.?off)/i;
if (lowPatterns.test(userMessage)) return 'low';
if (highPatterns.test(userMessage)) return 'high';
return 'mid';
}
async function routedChat(userMessage, history = []) {
const tier = classifyTask(userMessage);
const { model } = MODEL_TIERS[tier];
console.log(`路由到: ${model} (${tier} tier)`);
return openai.chat.completions.create({
model,
messages: [...history, { role: 'user', content: userMessage }],
});
}
实际项目中,60-70% 的请求可以路由到低成本模型,整体成本降低 50% 以上。
2.6 策略六:流式输出 + 提前终止——不为废话买单
设置合理的 max_tokens 并使用流式输出,在检测到完整回答后主动断开:
// 流式输出 + 提前终止
async function streamWithEarlyStop(messages, options = {}) {
const { maxTokens = 1000, stopPatterns = [] } = options;
const stream = await openai.chat.completions.create({
model: 'gpt-4o',
messages,
max_tokens: maxTokens,
stream: true,
});
let fullResponse = '';
let tokenCount = 0;
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content || '';
fullResponse += delta;
tokenCount++;
// 检测到完整回答模式,提前终止
if (stopPatterns.some(p => fullResponse.match(p))) {
console.log(`提前终止,节省了约 ${maxTokens - tokenCount} tokens`);
stream.controller.abort();
break;
}
}
return { content: fullResponse, tokensUsed: tokenCount };
}
// 使用:JSON 提取场景,检测到完整 JSON 后立即停止
await streamWithEarlyStop(
[{ role: 'user', content: 'Extract JSON from: ...' }],
{
maxTokens: 500,
stopPatterns: [/^\s*\{[\s\S]*\}\s*$/], // 完整 JSON 对象
}
);
📊 三、综合优化效果对比
以一个典型的 AI 客服应用(日均 5000 次对话)为例,对比优化前后的成本:
| 优化措施 | 优化前(月成本) | 优化后(月成本) | 节省比例 |
|---|---|---|---|
| 未优化基准 | $12,000 | — | — |
| + Prompt 压缩 | $12,000 | $9,600 | 20% |
| + 对话摘要压缩 | $9,600 | $6,720 | 30% |
| + 语义缓存 | $6,720 | $5,040 | 25% |
| + 结构化输出 | $5,040 | $4,032 | 20% |
| + 模型路由 | $4,032 | $2,822 | 30% |
| 累计优化 | $12,000 | $2,822 | 76.5% |
⚡ 关键结论: 六项策略叠加使用,可以将 LLM API 成本降低 70%-80%。但不要一开始就全部上——先从 Prompt 压缩和模型路由开始,这两项投入产出比最高。
⚠️ 四、避坑指南
坑 1:过度压缩导致质量问题
压缩 Prompt 时如果去掉了关键约束条件,模型输出质量会断崖式下降。建议先在测试集上对比压缩前后的输出质量(用 LLM-as-Judge 自动评估),再上线。
坑 2:语义缓存的相似度阈值设置
阈值设太高(>0.95)命中率极低,设太低(<0.85)会返回不相关的结果。建议从 0.92 开始,根据业务反馈逐步调整。
坑 3:摘要压缩丢失关键上下文
用便宜模型做摘要时,可能遗漏技术细节(如变量名、版本号)。对精确度要求高的场景(如代码助手),建议在摘要 Prompt 中加入「保留所有专有名词和技术细节」的约束。
坑 4:模型路由的分类准确性
基于正则的简单分类器准确率约 80%。误分类为低级模型的复杂请求会产生低质量回复。建议对分类结果做 A/B 测试,或者用一个小型分类模型(如 fine-tuned BERT)替代正则。
🎯 总结与建议
Token 优化是一项系统工程,不是改一句 Prompt 就能解决的。按优先级排序,建议的实施路径是:
- 第一步(立即可做):Prompt 压缩 + 设置合理的 max_tokens
- 第二步(1-2 周):模型路由 + 结构化输出
- 第三步(2-4 周):对话历史摘要压缩
- 第四步(按需):语义缓存(适合高重复率场景)
推荐的 Token 监控工具:
- LangSmith:全链路 Token 追踪和成本分析
- Helicone:实时 API 监控,支持按用户/模型/路由维度分析
- OpenAI Usage Dashboard:原生用量统计,适合纯 OpenAI 用户
最终目标不是把 Token 消耗降到最低,而是在成本和质量之间找到最优平衡点。一个好的优化方案,应该让用户感知不到任何质量下降,同时让账单减少 50% 以上。