Claude 应用提速降本实战:从上下文压缩到流式输出源码示例
Claude 性能优化教程|附源码
在大模型应用开发中,Claude 以强大的长文本理解、代码生成、推理能力和较好的安全性受到很多开发者关注。但在真实业务场景里,仅仅“能调用 Claude API”远远不够。一个合格的 Claude 应用,还需要在响应速度、成本控制、上下文管理、稳定性、输出质量等方面进行系统优化。
本文将从工程实践角度,讲解 Claude 性能优化的核心思路,并提供一套可直接参考的源码示例,帮助你构建更快、更省、更稳定的 Claude 应用。
一、为什么要做 Claude 性能优化?
很多开发者在接入 Claude 后,常见的问题包括:
-
响应太慢
用户提问后等待十几秒甚至几十秒,交互体验较差。 -
Token 成本过高
每次请求都把大量历史对话、文档原文、系统提示词全部塞进去,导致输入 Token 暴涨。 -
上下文越来越长
多轮对话中,如果不做历史压缩,后续请求会越来越慢。 -
输出不稳定
同样的问题可能多次得到不同格式的结果,影响业务落地。 -
失败重试机制缺失
网络波动、限流、超时等问题会导致请求失败,影响用户体验。 -
并发能力不足
单用户测试没问题,但一旦用户量上来,服务端容易阻塞或超时。
因此,Claude 性能优化并不是单一技巧,而是一套完整的系统工程。
二、Claude 性能优化的核心方向
Claude 应用的优化可以从以下几个层面展开:
| 优化方向 | 目标 |
|---|---|
| Prompt 优化 | 降低输入 Token,提高输出稳定性 |
| 上下文压缩 | 减少历史消息长度,提高响应速度 |
| 流式输出 | 降低用户感知等待时间 |
| 缓存机制 | 避免重复请求,降低成本 |
| 模型选择 | 在质量、速度、成本之间平衡 |
| 并发控制 | 提升服务吞吐能力 |
| 错误重试 | 提高系统稳定性 |
| 输出约束 | 保证返回结构可解析、可落地 |
三、选择合适的 Claude 模型
Claude 系列模型通常会根据能力、速度和价格分为不同等级。实际开发中,不建议所有任务都使用最强模型,而应该根据任务复杂度动态选择。
例如:
- 简单分类、摘要、标签提取:使用更轻量、更快的模型;
- 复杂推理、代码生成、长文档分析:使用能力更强的模型;
- 用户实时聊天:优先考虑速度;
- 后台批处理任务:可以优先考虑成本。
一个典型的策略是:
简单任务 → Claude Haiku 类模型
中等任务 → Claude Sonnet 类模型
复杂任务 → Claude Opus 类模型
当然,具体模型名称会随着官方版本变化而更新,开发中建议将模型名称配置化,不要写死在业务逻辑中。
四、Prompt 优化:少即是多
Prompt 是影响 Claude 性能的第一因素。很多开发者习惯写很长的提示词,试图把所有规则一次性塞给模型。但过长的 Prompt 不仅会增加成本,还可能降低模型对重点任务的注意力。
1. 精简系统提示词
不推荐:
你是一个非常优秀、非常专业、非常厉害、经验丰富的人工智能助手,
你需要尽可能详细地回答用户问题,并且要非常认真,非常全面……
推荐:
你是一个专业的技术助手。
请用中文回答,内容准确、结构清晰、避免编造。
2. 明确输出格式
如果你的业务需要 JSON,就直接告诉模型返回 JSON,不要让它自由发挥。
示例:
请只返回 JSON,不要添加 Markdown,不要解释。
格式如下:
{
"title": "标题",
"summary": "摘要",
"tags": ["标签1", "标签2"]
}
3. 拆分复杂任务
一个复杂任务可以拆成多个小任务。例如“分析一篇长文并生成报告”,可以拆成:
- 提取核心观点;
- 识别关键数据;
- 总结风险;
- 生成最终报告。
这样做虽然请求次数可能增加,但每次请求更短、更稳定,也便于缓存中间结果。
五、上下文优化:不要无限追加历史消息
多轮对话是 Claude 的常见场景,但如果每轮都把完整历史传入,Token 会快速增长。正确做法是:
- 保留最近几轮对话;
- 对更早的历史进行摘要;
- 将摘要作为长期记忆传入;
- 对无关历史进行丢弃。
上下文管理策略
最终上下文 = 系统提示词 + 历史摘要 + 最近 N 轮对话 + 当前用户问题
例如:
系统提示词:
你是一个专业的技术助手。
历史摘要:
用户正在开发一个基于 Claude 的客服系统,关注流式输出、缓存和成本优化。
最近对话:
用户:如何减少 Token?
助手:可以压缩上下文、精简 Prompt、缓存重复请求。
当前问题:
请给出 Node.js 示例代码。
这种方式可以显著减少输入 Token,同时保持对话连续性。
六、流式输出:降低用户感知延迟
在用户界面中,最影响体验的往往不是完整响应耗时,而是“首字等待时间”。流式输出可以让用户尽早看到内容,从而感觉系统更快。
如果 Claude 接口支持 streaming,建议在聊天、写作、代码生成等场景中开启流式响应。
流式输出的优势:
- 用户不用等待完整结果;
- 长文本生成体验更自然;
- 可以边生成边渲染;
- 服务端可以更灵活地处理超时。
七、缓存优化:重复问题不要重复调用
很多 Claude 请求实际上是重复的,例如:
- 固定文档摘要;
- 常见问题回答;
- 商品描述生成;
- 代码解释;
- 同一 Prompt 多次提交。
对于这些请求,可以使用缓存机制。缓存 Key 通常由以下信息生成:
模型名称 + 系统提示词 + 用户输入 + 关键参数
然后进行哈希处理,得到唯一 Key。
需要注意的是,如果请求带有强随机性,例如 temperature 较高,则缓存命中意义较小。对于业务型输出,建议设置较低 temperature,以提升稳定性和缓存价值。
八、控制生成长度
很多人只关注输入 Token,却忽略输出 Token。输出越长,响应越慢,成本也越高。
优化方法包括:
- 设置
max_tokens; - 在 Prompt 中指定回答长度;
- 要求分点回答;
- 对摘要类任务限制字数;
- 避免“越详细越好”这种模糊指令。
例如:
请在 300 字以内回答,使用 3 个要点。
比下面这种写法更可控:
请详细回答。
九、参数优化建议
常见参数包括:
| 参数 | 作用 | 建议 |
|---|---|---|
temperature |
控制随机性 | 业务任务建议 0~0.3,创意任务可 0.7 以上 |
max_tokens |
控制最大输出长度 | 按业务场景设置,不要过大 |
model |
指定模型 | 按任务复杂度动态选择 |
system |
系统提示词 | 简短、稳定、明确 |
messages |
对话内容 | 控制长度,保留必要上下文 |
对于需要稳定 JSON 的任务,建议:
temperature = 0
max_tokens = 合理限制
Prompt 明确要求只返回 JSON
十、Node.js 源码示例:Claude 性能优化版客户端
下面是一套 Node.js 示例代码,包含:
- Claude API 调用;
- 流式输出;
- 简单缓存;
- 上下文截断;
- 自动重试;
- 模型配置化;
- Token 近似估算。
说明:以下代码以 Anthropic 官方 SDK 思路为例,实际使用时请根据你安装的 SDK 版本调整。
十一、项目结构
claude-optimizer-demo
├── package.json
├── .env
├── src
│ ├── config.js
│ ├── cache.js
│ ├── context.js
│ ├── claudeClient.js
│ └── index.js
十二、安装依赖
mkdir claude-optimizer-demo
cd claude-optimizer-demo
npm init -y
npm install @anthropic-ai/sdk dotenv
如果你的 Node.js 版本较旧,建议使用 Node.js 18 以上版本。
十三、配置环境变量
创建 .env 文件:
ANTHROPIC_API_KEY=你的_API_Key
CLAUDE_MODEL=claude-3-5-sonnet-latest
MAX_HISTORY_MESSAGES=8
MAX_OUTPUT_TOKENS=800
十四、配置文件:src/config.js
import dotenv from "dotenv";
dotenv.config();
export const config = {
apiKey: process.env.ANTHROPIC_API_KEY,
model: process.env.CLAUDE_MODEL || "claude-3-5-sonnet-latest",
maxHistoryMessages: Number(process.env.MAX_HISTORY_MESSAGES || 8),
maxOutputTokens: Number(process.env.MAX_OUTPUT_TOKENS || 800),
temperature: Number(process.env.CLAUDE_TEMPERATURE || 0.2),
retryTimes: Number(process.env.CLAUDE_RETRY_TIMES || 3),
};
十五、缓存模块:src/cache.js
这里使用内存缓存,适合演示或小型项目。生产环境建议使用 Redis。
import crypto from "crypto";
const memoryCache = new Map();
function createHash(input) {
return crypto.createHash("sha256").update(input).digest("hex");
}
export function createCacheKey({ model, system, messages, maxTokens, temperature }) {
const raw = JSON.stringify({
model,
system,
messages,
maxTokens,
temperature,
});
return createHash(raw);
}
export function getCache(key) {
const item = memoryCache.get(key);
if (!item) return null;
const now = Date.now();
if (item.expireAt && item.expireAt < now) {
memoryCache.delete(key);
return null;
}
return item.value;
}
export function setCache(key, value, ttlMs = 5 * 60 * 1000) {
memoryCache.set(key, {
value,
expireAt: Date.now() + ttlMs,
});
}
export function clearCache() {
memoryCache.clear();
}
缓存的关键点是:相同输入只请求一次。对于 FAQ、摘要、结构化提取等场景,缓存能明显降低成本。
十六、上下文管理:src/context.js
这个模块用于控制历史消息长度,避免无限追加对话。
import { config } from "./config.js";
export function trimMessages(messages) {
const max = config.maxHistoryMessages;
if (!Array.isArray(messages)) {
return [];
}
if (messages.length <= max) {
return messages;
}
return messages.slice(messages.length - max);
}
export function estimateTokens(text) {
if (!text) return 0;
// 粗略估算:
// 中文约 1 个字接近 1 token;
// 英文约 4 个字符接近 1 token。
const chineseChars = (text.match(/[\u4e00-\u9fa5]/g) || []).length;
const otherChars = text.length - chineseChars;
return chineseChars + Math.ceil(otherChars / 4);
}
export function estimateMessageTokens(messages) {
return messages.reduce((total, msg) => {
const content = typeof msg.content === "string"
? msg.content
: JSON.stringify(msg.content);
return total + estimateTokens(content);
}, 0);
}
这只是粗略估算,并不能完全等价于官方 Token 计算方式,但足以用于工程上的早期预警。
十七、Claude 客户端:src/claudeClient.js
import Anthropic from "@anthropic-ai/sdk";
import { config } from "./config.js";
import { createCacheKey, getCache, setCache } from "./cache.js";
import { trimMessages, estimateMessageTokens } from "./context.js";
const anthropic = new Anthropic({
apiKey: config.apiKey,
});
const DEFAULT_SYSTEM_PROMPT = `
你是一个专业的中文技术助手。
请回答准确、结构清晰、避免编造。
如果不确定,请明确说明不确定。
`;
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function withRetry(fn, retryTimes = config.retryTimes) {
let lastError;
for (let i = 0; i < retryTimes; i++) {
try {
return await fn();
} catch (error) {
lastError = error;
const waitMs = Math.min(1000 * 2 ** i, 8000);
console.warn(`Claude 请求失败,第 ${i + 1} 次重试,等待 ${waitMs}ms`);
await sleep(waitMs);
}
}
throw lastError;
}
export async function askClaude({
messages,
system = DEFAULT_SYSTEM_PROMPT,
model = config.model,
maxTokens = config.maxOutputTokens,
temperature = config.temperature,
useCache = true,
}) {
const finalMessages = trimMessages(messages);
const inputTokenEstimate = estimateMessageTokens(finalMessages);
console.log("估算输入 tokens:", inputTokenEstimate);
const cacheKey = createCacheKey({
model,
system,
messages: finalMessages,
maxTokens,
temperature,
});
if (useCache) {
const cached = getCache(cacheKey);
if (cached) {
console.log("命中缓存");
return cached;
}
}
const result = await withRetry(async () => {
const response = await anthropic.messages.create({
model,
system,
messages: finalMessages,
max_tokens: maxTokens,
temperature,
});
const text = response.content
.filter(item => item.type === "text")
.map(item => item.text)
.join("");
return {
text,
usage: response.usage,
model,
cached: false,
};
});
if (useCache) {
setCache(cacheKey, result);
}
return result;
}
这个客户端做了几件重要的事:
- 自动截断历史消息;
- 请求前估算 Token;
- 根据请求参数生成缓存 Key;
- 支持失败自动重试;
- 统一封装模型、温度、输出长度等参数。
十八、流式调用:src/claudeClient.js 增加方法
继续在 claudeClient.js 中添加流式输出方法:
export async function streamClaude({
messages,
system = DEFAULT_SYSTEM_PROMPT,
model = config.model,
maxTokens = config.maxOutputTokens,
temperature = config.temperature,
onText,
}) {
const finalMessages = trimMessages(messages);
await withRetry(async () => {
const stream = await anthropic.messages.stream({
model,
system,
messages: finalMessages,
max_tokens: maxTokens,
temperature,
});
for await (const event of stream) {
if (event.type === "content_block_delta") {
const text = event.delta?.text || "";
if (text && typeof onText === "function") {
onText(text);
}
}
}
});
}
流式输出一般不做完整缓存,因为内容是逐段返回的。但如果你希望缓存最终结果,可以在 onText 中拼接完整文本,结束后写入缓存。
十九、入口文件:src/index.js
import { askClaude, streamClaude } from "./claudeClient.js";
async function main() {
const messages = [
{
role: "user",
content: "请用 5 个要点解释 Claude 应用如何优化性能。",
},
];
console.log("===== 普通请求示例 =====");
const result = await askClaude({
messages,
useCache: true,
});
console.log(result.text);
console.log("usage:", result.usage);
console.log("\n===== 流式请求示例 =====");
await streamClaude({
messages: [
{
role: "user",
content: "请写一段关于 Claude 流式输出优势的说明,200 字以内。",
},
],
onText: text => {
process.stdout.write(text);
},
});
console.log("\n\n完成");
}
main().catch(error => {
console.error("程序执行失败:", error);
});
二十、修改 package.json
为了使用 ES Module,需要配置 type:
{
"name": "claude-optimizer-demo",
"version": "1.0.0",
"type": "module",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.30.0",
"dotenv": "^16.4.5"
}
}
运行:
npm run start
二十一、进一步优化:历史摘要机制
前面的 trimMessages 只是简单保留最近几轮消息。更高级的做法是:当历史消息过长时,自动调用 Claude 对旧消息进行摘要,然后保留摘要。
思路如下:
如果历史消息超过限制:
1. 取出较早的对话;
2. 调用 Claude 生成摘要;
3. 将摘要作为 system 或 user 上下文;
4. 保留最近几轮原始消息。
示例伪代码:
async function summarizeHistory(oldMessages) {
const content = oldMessages
.map(msg => `${msg.role}: ${msg.content}`)
.join("\n");
const result = await askClaude({
messages: [
{
role: "user",
content: `请总结以下历史对话,保留用户目标、关键偏好和已确认信息:\n${content}`,
},
],
maxTokens: 500,
temperature: 0,
useCache: true,
});
return result.text;
}
在客服、教育、代码助手等场景中,历史摘要非常有价值。它可以让 Claude 看起来“记得之前的对话”,但又不会付出完整上下文的成本。
二十二、结构化输出优化
如果你的系统需要解析 Claude 的输出,比如生成表单字段、分类结果、评分结果,就不要让模型自由输出自然语言,而应该强制结构化。
示例 Prompt:
请分析用户反馈情绪,只返回 JSON。
字段说明:
- sentiment: positive、neutral、negative 三选一
- reason: 判断理由,30 字以内
- score: 0 到 1 之间的小数
用户反馈:
{{feedback}}
期望输出:
{
"sentiment": "positive",
"reason": "用户表达了满意和认可",
"score": 0.92
}
工程上还应该加 JSON 解析和兜底逻辑:
export function safeParseJson(text) {
try {
return JSON.parse(text);
} catch {
const match = text.match(/\{[\s\S]*\}/);
if (!match) return null;
try {
return JSON.parse(match[0]);
} catch {
return null;
}
}
}
对于关键业务,不建议完全信任模型输出。可以增加 schema 校验,例如使用 zod 或 ajv。
二十三、并发优化与限流控制
当应用用户量增加时,不能无限并发请求 Claude API。否则容易出现:
- API 限流;
- 服务端内存升高;
- 请求堆积;
- 响应超时;
- 成本失控。
可以使用简单的并发队列限制同时请求数。
示例:
export function createLimiter(maxConcurrent = 5) {
let active = 0;
const queue = [];
async function run(fn) {
if (active >= maxConcurrent) {
await new Promise(resolve => queue.push(resolve));
}
active++;
try {
return await fn();
} finally {
active--;
const next = queue.shift();
if (next) next();
}
}
return { run };
}
使用方式:
const limiter = createLimiter(3);
const result = await limiter.run(() =>
askClaude({
messages: [
{
role: "user",
content: "请生成一段商品卖点文案。",
},
],
})
);
生产环境中可以使用更成熟的库,例如 p-limit、Bottleneck,并结合 Redis 做分布式限流。
二十四、超时控制
重试机制不能替代超时控制。一个请求如果长时间没有返回,应该及时中断,避免占用资源。
可以使用 Promise.race 实现:
export async function withTimeout(promise, timeoutMs = 30000) {
let timer;
const timeoutPromise = new Promise((_, reject) => {
timer = setTimeout(() => {
reject(new Error(`请求超时:${timeoutMs}ms`));
}, timeoutMs);
});
try {
return await Promise.race([promise, timeoutPromise]);
} finally {
clearTimeout(timer);
}
}
使用方式:
const result = await withTimeout(
askClaude({
messages: [
{
role: "user",
content: "请分析这篇长文的核心观点。",
},
],
}),
20000
);
二十五、成本监控:不要忽略 Usage
Claude API 通常会返回 usage 信息,包括输入和输出 Token。建议每次请求都记录:
- 用户 ID;
- 业务场景;
- 模型名称;
- 输入 Token;
- 输出 Token;
- 请求耗时;
- 是否命中缓存;
- 是否重试;
- 是否失败。
日志示例:
function logClaudeUsage({ userId, scene, result, durationMs }) {
console.log({
userId,
scene,
model: result.model,
inputTokens: result.usage?.input_tokens,
outputTokens: result.usage?.output_tokens,
cached: result.cached,
durationMs,
createdAt: new Date().toISOString(),
});
}
有了这些数据,才能判断到底是哪个业务模块最耗钱、哪个 Prompt 最低效、哪个模型被过度使用。
二十六、常见性能优化清单
下面是一份实用检查清单:
- [ ] 系统提示词是否足够简洁?
- [ ] 是否限制了
max_tokens? - [ ] 是否对长历史做了截断或摘要?
- [ ] 是否开启流式输出?
- [ ] 是否对重复任务做缓存?
- [ ] 是否根据任务复杂度选择模型?
- [ ] 是否设置较低 temperature 以提升稳定性?
- [ ] 是否有失败重试?
- [ ] 是否有超时控制?
- [ ] 是否记录 usage 和耗时?
- [ ] 是否对结构化输出做 JSON 校验?
- [ ] 是否做并发限制?
- [ ] 是否区分实时任务和后台任务?
二十七、推荐的工程实践架构
一个较成熟的 Claude 应用可以采用以下架构:
用户请求
↓
参数校验
↓
查询缓存
↓
上下文裁剪 / 摘要
↓
模型选择
↓
并发限流
↓
Claude API 调用
↓
流式返回 / 普通返回
↓
输出校验
↓
写入缓存
↓
记录日志与 usage
这种架构的好处是,每个模块职责清晰,后续可以单独替换。例如缓存从内存换成 Redis,日志从 console 换成数据库,限流从本地队列换成分布式队列。
二十八、总结
Claude 性能优化的本质,是在模型能力、响应速度、成本、稳定性之间找到平衡。
如果你只做一件事,建议先做上下文控制;如果你想提升用户体验,优先使用流式输出;如果你想降低成本,优先做缓存和模型分级;如果你要上线生产环境,必须补齐重试、超时、限流和日志监控。
本文提供的源码虽然是一个简化版本,但已经覆盖 Claude 应用开发中最常见、最实用的优化点。你可以在此基础上继续扩展 Redis 缓存、分布式限流、结构化输出校验、Prompt 模板管理和成本统计系统,最终构建一个真正可上线、可维护、可扩展的 Claude 应用。