Prompt Caching 完全指南:从入门到精通,掌握 LLM 缓存成本优化
一、什么是 Prompt Caching?
1.1 一句话定义
Prompt Caching(提示缓存)是 AI API 提供商推出的一项成本与延迟优化功能。当你多次发送包含相同前缀内容的请求时,系统会缓存已处理过的 token 计算结果,后续请求只需支付极低的缓存读取费用,从而避免对相同内容的重复计算。
Prompt Caching 的核心逻辑是 "缓存不变前缀,仅处理动态内容" 。通过设置缓存断点,服务器会将断点之前的所有内容(如系统提示词、工具定义、长文档)缓存起来。下次请求时,只要前缀完全一致,就直接读取缓存,无需重新处理,仅对新增的动态内容计费。
1.2 它解决什么问题
| 痛点 | 现状 | Prompt Caching 的解法 |
|---|---|---|
| 重复计费 | 每次请求都重新发送相同的系统提示词和工具定义,每次都全额付费 | 缓存固定前缀,后续请求仅支付缓存读取费用(低至 10%) |
| 响应缓慢 | 长提示词的首次 Token 延迟(TTFT)居高不下 | 缓存命中时无需重新解析固定内容,TTFT 可降低 80% |
| 成本失控 | 高频调用场景下,固定内容的 Token 消耗占比极高 | 缓存读取费用仅为标准输入价格的 0.1 倍,节省高达 90% |
| 长上下文昂贵 | RAG 场景中反复传递长文档,成本极高 | 文档缓存后,反复查询仅需支付极低的读取费用 |
一个直观的成本对比:若系统提示词为 5000 Token,每天调用 1000 次------
- 无缓存 :5000 Token × 1000 次 × 3/百万 Token = **15/天**
- 有缓存 :1 次写入(0.01875)+ 999 次读取(约 1.50)≈ $1.52/天
- 每天节省 13.48,每月节省超过 400
1.3 核心原理:前缀匹配
Prompt Caching 的工作方式是前缀匹配(prefix matching) 。API 会从请求开头开始缓存,一直缓存到每个缓存断点为止。缓存命中要求字节级完全一致的前缀匹配------哪怕多一个空格或大小写不同,都会导致缓存未命中。
请求 1: [系统提示词] + [用户: "问题 1"]
└── 已缓存 ──┘
请求 2: [系统提示词] + [用户: "问题 2"]
└── 缓存命中 ──┘(仅此部分全额计费)
系统使用提示词内容的加密哈希生成缓存键。只有内容完全相同的请求才能实现缓存命中。
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
二、各平台缓存支持对比
| 平台 | 缓存类型 | 缓存折扣 | 最小缓存量 | 缓存时效 | 缓存写入费用 |
|---|---|---|---|---|---|
| Anthropic (Claude) | 显式缓存(需手动标记) | 90% 折扣 | 1,024 tokens | 5 分钟 / 1 小时 | 1.25x(5分钟)/ 2x(1小时) |
| OpenAI (GPT) | 自动缓存(无需设置) | 50% 折扣 | 1,024 tokens | 5-60 分钟 | 无额外费用(GPT-5.6 前) |
| Google (Gemini) | Context Caching | 75% 折扣 | 32,768 tokens | 自定义 | 按存储时间计费 |
| AWS Bedrock | 显式缓存 | 90% 折扣 | 1,024 tokens | 5 分钟 / 1 小时 | 1.25x / 2x |
| Azure OpenAI | 自动 + 显式 | 折扣费率 | 1,024 tokens | 30 分钟 | 标准部署无写入费 |
关键差异:
- Anthropic/Claude :需要显式使用
cache_control标记缓存断点,最多支持 4 个缓存断点 ,缓存读取享受 90% 折扣(即支付 0.1 倍价格) - OpenAI :自动缓存,无需代码改动,对所有 ≥1024 tokens 的请求生效,缓存读取享受 50% 折扣
- Azure OpenAI:GPT-5.6 系列之前无缓存写入费用,GPT-5.6 及以后版本可能产生缓存写入费用
三、Spring AI 中的 Prompt Caching 配置
3.1 环境要求
| 组件 | 要求 |
|---|---|
| Spring AI | 1.1.0+(Anthropic 缓存支持) |
| Java | 17+ |
| Spring Boot | 3.2+ |
| 模型 | Anthropic Claude(通过 Anthropic API 或 AWS Bedrock) |
3.2 Anthropic Claude 缓存策略
Spring AI 提供了 5 种预置缓存策略 (AnthropicCacheStrategy 枚举),自动处理缓存断点的放置,尊重 Anthropic 的 4 断点限制:
| 策略 | 缓存内容 | 断点数 | 适用场景 |
|---|---|---|---|
SYSTEM_ONLY |
仅系统提示词 | 1 | 系统提示词较长且固定 |
TOOLS_ONLY |
仅工具定义 | 1 | 工具定义复杂且固定 |
SYSTEM_AND_TOOLS |
系统提示词 + 工具定义 | 2 | 两者都长且固定(推荐) |
CONVERSATION_HISTORY |
对话历史 | 1-4 | 多轮对话场景 |
NONE |
不缓存 | 0 | 一次性请求 |
3.3 Spring AI 配置示例
java
@Service
public class CachedChatService {
private final ChatClient chatClient;
public CachedChatService(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String askWithCache(String question) {
// 配置 Anthropic 缓存策略
AnthropicChatOptions options = AnthropicChatOptions.builder()
.model("claude-sonnet-4-5-20250929")
.strategy(AnthropicCacheStrategy.SYSTEM_AND_TOOLS) // 同时缓存系统提示词和工具定义
.cacheTtl(AnthropicCacheTtl.FIVE_MINUTES) // 5 分钟 TTL(默认)
.build();
return chatClient.prompt()
.system("你是一个专业的法律文档分析师...(约 5000 字的系统提示词)")
.user(question)
.options(options)
.call()
.content();
}
}
核心配置项说明:
| 配置项 | 说明 | 默认值 |
|---|---|---|
strategy(AnthropicCacheStrategy) |
缓存策略 | CONVERSATION_HISTORY |
cacheTtl(AnthropicCacheTtl) |
缓存有效期 | FIVE_MINUTES(5 分钟) |
multiBlockSystemCaching(true) |
多块系统缓存支持 | false |
3.4 AWS Bedrock 缓存配置
java
@Service
public class BedrockCachedService {
private final ChatClient chatClient;
public String askWithCache(String question) {
BedrockCacheOptions cacheOptions = BedrockCacheOptions.builder()
.strategy(BedrockCacheStrategy.SYSTEM_ONLY)
.ttl(BedrockCacheTtl.ONE_HOUR) // 1 小时 TTL
.build();
return chatClient.prompt()
.system("长系统提示词...")
.user(question)
.options(BedrockChatOptions.builder()
.model("anthropic.claude-sonnet-4-5-20250929-v1:0")
.cacheOptions(cacheOptions)
.build())
.call()
.content();
}
}
3.5 缓存使用量追踪
Spring AI 提供了缓存使用量的追踪字段,每次响应中都会返回:
java
ChatResponse response = chatClient.prompt(...).call().chatResponse();
// 获取缓存使用情况
Usage usage = response.getMetadata().getUsage();
// cache_creation_input_tokens:缓存写入的 token 数
// cache_read_input_tokens:缓存读取的 token 数
// 计算缓存命中率
double hitRate = (double) usage.getCacheReadInputTokens() /
(usage.getCacheReadInputTokens() + usage.getCacheCreationInputTokens());
四、LangChain4j 中的 Prompt Caching 配置
4.1 依赖要求
LangChain4j 从 1.11.0 开始原生支持 Prompt Caching,1.21.0 版本进一步增强了 OpenAI 缓存支持。
xml
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bedrock</artifactId>
<version>1.11.0+</version>
</dependency>
4.2 配置示例
java
// AWS Bedrock 缓存配置
BedrockChatRequestParameters params = BedrockChatRequestParameters.builder()
.promptCaching(BedrockCachePointPlacement.AFTER_SYSTEM) // 在系统消息后放置缓存点
.build();
ChatModel model = BedrockChatModel.builder()
.modelId("anthropic.claude-sonnet-4-5-20250929-v1:0")
.defaultRequestParameters(params)
.build();
支持的缓存点位置 :AFTER_SYSTEM(系统消息后)、AFTER_USER_MESSAGE(用户消息后)、AFTER_TOOLS(工具定义后)。
五、提升缓存命中率的实战技巧
5.1 核心原则:固化核心 System Prompt
Prompt Caching 的核心逻辑是把重复使用的 System Prompt 和常用上下文标记为缓存,后续相同请求命中缓存后,这部分 Token 按折扣价计费。缓存策略优化的三个关键是:固化核心 System Prompt、动态内容后置、分层设计 Prompt。把跨请求不变的核心指令放在 Prompt 最前面并保持绝对不变,把时间戳、会话 ID 等动态变量移到 User Message 中。
5.2 使用 prompt_cache_key 提升命中率
在 GPT-5.6 及后续模型家族中,设置 prompt_cache_key 参数并重复使用相同的键,可以改善共享长提示前缀的请求的缓存匹配。
json
{
"model": "your-model",
"prompt_cache_key": "conv-6900xxxx",
"messages": [
{"role": "system", "content": "长系统提示词..."},
{"role": "user", "content": "用户问题"}
]
}
关键实践 :不同对话使用不同的 prompt_cache_key,避免缓存污染。同一个会话中始终使用相同的键。
5.3 监控缓存命中率
像监控 uptime 一样监控缓存命中率。 对 cache break 做告警,并把它当成事故来处理------哪怕只是几个百分点的 miss rate。
java
@Component
public class CacheMetrics {
private final MeterRegistry registry;
public void recordCacheUsage(String model, int cachedTokens, int totalTokens) {
double hitRate = (double) cachedTokens / totalTokens;
registry.gauge("prompt.cache.hit_rate",
Tags.of("model", model), hitRate);
if (hitRate < 0.8) {
log.warn("缓存命中率低于 80%:{},model={}", hitRate, model);
}
}
}
5.4 避免常见陷阱
| 陷阱 | 后果 | 正确做法 |
|---|---|---|
| 每次请求修改系统提示词 | 缓存永远无法命中 | 将动态内容移至 User Message |
| 中途切换工具或模型 | 缓存失效 | 用工具表达状态变化,不修改系统提示词 |
| 前缀中存在时间戳/会话 ID | 每次请求前缀不同 | 将动态变量放在缓存断点之后 |
| 缓存前缀小于 1024 tokens | 不满足最小缓存条件 | 确保缓存内容 ≥1024 tokens |
| 频繁写入缓存 | 写入成本(1.25x)超过节省 | 提高缓存读取频率,而非频繁写入 |
六、成本节省计算实战
6.1 计算公式
首次请求成本 = (tokens × base_rate × 1.25) // 缓存写入(25% 溢价)
后续请求成本 = (new_tokens × base_rate) + (cached_tokens × base_rate × 0.1)
节省金额 = 原始成本 - 缓存后成本
6.2 完整计算示例
场景:法律文档分析系统,系统提示词 10,000 Token,每天处理 500 次查询。
java
public class CacheCostCalculator {
public static void main(String[] args) {
double baseRate = 3.0; // $3/百万 Token
int systemTokens = 10_000; // 系统提示词 Token 数
int dailyQueries = 500; // 每日查询次数
int avgUserTokens = 200; // 平均用户问题 Token 数
// 无缓存成本
double noCacheCost = (systemTokens + avgUserTokens) / 1_000_000.0
* baseRate * dailyQueries;
// 有缓存成本
double writeCost = systemTokens / 1_000_000.0 * baseRate * 1.25; // 首次写入
double readCost = (dailyQueries - 1) * systemTokens / 1_000_000.0
* baseRate * 0.1; // 后续读取
double userCost = dailyQueries * avgUserTokens / 1_000_000.0 * baseRate;
double cachedCost = writeCost + readCost + userCost;
System.out.printf("无缓存日成本: $%.2f%n", noCacheCost);
System.out.printf("有缓存日成本: $%.2f%n", cachedCost);
System.out.printf("日节省: $%.2f (%.1f%%)%n",
noCacheCost - cachedCost,
(noCacheCost - cachedCost) / noCacheCost * 100);
System.out.printf("月节省: $%.2f%n", (noCacheCost - cachedCost) * 30);
}
}
输出结果:
无缓存日成本: $15.30
有缓存日成本: $0.94
日节省: $14.36 (93.9%)
月节省: $430.80
七、实战示例:长上下文 RAG 缓存优化
7.1 场景描述
企业 RAG 管道处理大量法律文档或代码库,每次查询都需传递同一份长文档。通过 Prompt Caching,文档只需缓存一次,后续查询仅支付极低的读取费用。
7.2 完整实现
java
@Service
public class CachedRagService {
private final ChatClient chatClient;
private final JtokkitTokenCounter tokenCounter;
public CachedRagService(ChatClient.Builder builder) {
this.chatClient = builder.build();
this.tokenCounter = new JtokkitTokenCounter();
}
public String queryWithCachedDocument(String document, String question) {
int docTokens = tokenCounter.countTokens(document);
// 确保文档满足最小缓存要求(1024 tokens)
if (docTokens < 1024) {
return chatClient.prompt()
.system("基于以下文档回答问题:\n" + document)
.user(question)
.call().content();
}
// 使用 Anthropic 缓存策略,将文档作为系统提示词缓存
AnthropicChatOptions options = AnthropicChatOptions.builder()
.strategy(AnthropicCacheStrategy.SYSTEM_ONLY)
.cacheTtl(AnthropicCacheTtl.ONE_HOUR) // 长文档使用 1 小时 TTL
.build();
return chatClient.prompt()
.system("基于以下文档回答问题:\n\n" + document)
.user(question)
.options(options)
.call()
.content();
}
}
7.3 与 Promptfoo 集成进行缓存效果评估
在 CI/CD 中,可以用 Promptfoo 测试缓存前后的成本与效果差异:
yaml
# promptfooconfig.yaml
prompts:
- file://prompts/cached-rag-v1.txt
providers:
- id: anthropic:claude-sonnet-4-5
config:
cache:
enabled: true
strategy: SYSTEM_ONLY
tests:
- vars:
document: file://docs/long-legal-doc.txt
question: "这份合同的违约责任条款是什么?"
assert:
- type: llm-rubric
value: "回答应准确引用合同中的违约责任条款"
八、最佳实践总结
| 实践 | 说明 | 预期收益 |
|---|---|---|
| 固化 System Prompt | 跨请求不变的核心指令放在最前面并保持绝对不变 | 缓存命中率 > 90% |
| 动态内容后置 | 时间戳、会话 ID 等动态变量移至 User Message | 避免缓存失效 |
| 缓存内容 ≥1024 tokens | 满足最小缓存条件 | 确保缓存生效 |
| 使用 prompt_cache_key | 为共享前缀的请求使用相同键 | 提升缓存匹配率 |
| 监控命中率 | 记录 cache_read / cache_creation 比例 | 及时发现命中率下降 |
| 发版前预热 | 少量模拟请求提前构建缓存 | 避免突增流量导致 miss |
| 分层设计 Prompt | 固定层(缓存)+ 可变层(不缓存) | 最大化缓存收益 |
| 选择合适 TTL | 5 分钟(默认)vs 1 小时(长任务) | 平衡写入成本与读取收益 |
九、常见问题
Q1:Prompt Caching 会自动生效吗?
A:OpenAI 的缓存是自动的,无需代码改动。Anthropic 的缓存需要显式使用 cache_control 标记(Spring AI 通过 AnthropicCacheStrategy 自动处理)。
Q2:缓存的最小 Token 数是多少?
A:Anthropic 和 OpenAI 都是 1,024 tokens ,Gemini 是 32,768 tokens。小于最小值的提示词不会被缓存。
Q3:缓存命中要求完全一致吗?
A:是的,需要字节级完全一致的前缀匹配------哪怕多一个空格或大小写不同,都会导致缓存未命中。
Q4:Spring AI 中如何知道缓存是否命中?
A:通过 Usage 对象中的 cache_creation_input_tokens 和 cache_read_input_tokens 字段。如果 cache_read_input_tokens > 0,说明有缓存命中。
Q5:缓存 TTL 过了怎么办?
A:TTL 过期后,下一次请求会创建新的缓存条目,按缓存写入费率计费。频繁读取的缓存会在每次读取时刷新 TTL,保持活跃。
Q6:Java 团队如何快速验证缓存效果?
A:用 Promptfoo 在 CI 中运行缓存前后的对比测试,或直接在 Java 代码中记录 cache_read_input_tokens 并计算命中率。
十、总结
| 维度 | 内容 |
|---|---|
| 核心原理 | 前缀匹配,缓存不变内容,仅处理动态部分 |
| 最大收益 | 成本节省 90% ,TTFT 降低 80% |
| 最小缓存量 | 1,024 tokens(Anthropic/OpenAI) |
| Spring AI 支持 | AnthropicCacheStrategy + BedrockCacheOptions |
| LangChain4j 支持 | 1.11.0+ 原生支持 |
| 关键实践 | 固化 System Prompt、动态内容后置、监控命中率 |
| 入门门槛 | 低------Spring AI 一行配置即可启用 |
核心价值:Prompt Caching 是将 LLM 应用从"能用"推向"经济高效"的关键优化技术。它让长上下文 RAG、多轮对话、Agent 工作流等场景的成本从"难以承受"变为"可持续运营"。对于 Java 团队,Spring AI 和 LangChain4j 都已提供了开箱即用的缓存支持,只需几行配置即可享受最高 90% 的成本节省。