領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多當應用程式重複傳送相同的提示內容時,大型語言模型 API 成本會迅速累積。一個典型場景:您正在構建一個文件分析器,每次請求都包含一個 3,000 令牌的文件。關於該文件的五個問題意味著以全價處理 15,000 令牌的相同內容。
Anthropic 的提示快取透過允許您重用以前處理過的提示段來解決此問題。Spring AI 透過策略性快取模式提供全面支援,這些模式會自動處理快取斷點放置和管理。
在這篇博文中,我們將解釋提示快取的工作原理、何時使用它,以及 Spring AI 如何簡化其實現。
提示快取允許您標記提示中的部分內容,以便在多個 API 請求中重複使用。啟用後,Anthropic 會快取指定內容,並在後續請求中對快取部分收取較低費用。
快取透過精確字首匹配進行操作。考慮以下序列
Request 1: [System Prompt] + [User: "Question 1"]
└─ Cached ──┘
Request 2: [System Prompt] + [User: "Question 2"]
└─ Cache Hit ─┘ (Only this part incurs full cost)
系統使用提示內容(直到指定的快取控制點)的加密雜湊生成快取鍵。只有內容完全相同的請求才能實現快取命中——即使是一個字元的更改也會建立一個新的快取條目。
Request 1: "You are a helpful assistant." → Cache created
Request 2: "You are a helpful assistant." → Cache hit
Request 3: "You are a helpful assistant " → Cache miss (extra space)
Request 4: "You are a Helpful assistant." → Cache miss (capitalization)
快取未命中時,系統會以標準費率處理內容並建立新的快取條目。這就是為什麼保持一致的提示模板對於有效快取很重要。
效能影響:除了節省成本外,Anthropic 報告稱,對於長提示,延遲可降低高達 85%。在他們的公告中,一個 100K 令牌的書籍示例顯示,啟用快取後,響應時間從 11.5 秒降至 2.4 秒。請注意,實際的延遲改進取決於您快取的內容量和快取命中率。
快取生命週期:條目在 TTL 視窗(預設 5 分鐘,可選 1 小時)內每次使用時都會重新整理。TTL 過期後,下一次請求會建立一個新的快取條目。
定價因模型層級而異
| 模型 | 基礎輸入 | 快取寫入 | 快取讀取 | 節省 |
|---|---|---|---|---|
| Claude Sonnet 4.5 | $3/MTok | $3.75/MTok (+25%) | $0.30/MTok | 90% |
| Claude Sonnet 4 | $3/MTok | $3.75/MTok (+25%) | $0.30/MTok | 90% |
| Claude Opus 4.1 | $15/MTok | $18.75/MTok (+25%) | $1.50/MTok | 90% |
| Claude Opus 4 | $15/MTok | $18.75/MTok (+25%) | $1.50/MTok | 90% |
| Claude Haiku 4.5 | $1/MTok | $1.25/MTok (+25%) | $0.10/MTok | 90% |
| Claude Haiku 3.5 | $0.80/MTok | $1/MTok (+25%) | $0.08/MTok | 90% |
| Claude Haiku 3 | $0.25/MTok | $0.30/MTok (+25%) | $0.03/MTok | 90% |
本部落格中的所有程式碼示例均使用 Claude Sonnet 4.5 定價,除非另有說明。
有關定價的更多資訊,請參閱 - Anthropic 提示快取定價
示例計算 (Claude 3.5 Sonnet, 5,000 令牌)
最小令牌閾值因模型而異
| 模型 | 最小可快取令牌 |
|---|---|
| Claude Sonnet 4.5、Claude Sonnet 4、Claude Opus 4.1、Claude Opus 4 | 1,024 |
| Claude Haiku 3.5、Claude Haiku 3 | 2,048 |
| Claude Haiku 4.5 | 4,096 |
低於這些閾值的提示無法快取,即使您使用快取控制指令標記它們也是如此。請注意,與其他模型相比,Claude Haiku 4.5 需要更多的令牌(4,096)。
有關這方面的更多資訊,請參閱 Anthropic 的可快取提示長度限制。
其他限制
Anthropic 以特定順序處理請求元件,此順序決定了快取失效的工作方式。
┌─────────────────────────────────────────┐
│ Request Processing Order: │
│ │
│ 1. Tools │
│ ↓ │
│ 2. System Message │
│ ↓ │
│ 3. Message History │
└─────────────────────────────────────────┘
更改透過此層次結構向下級聯
┌──────────────────────────────────────────────────────┐
│ Cascade Invalidation: │
│ │
│ Change Tools → Invalidates: Tools, System, Msgs │
│ Change System → Invalidates: System, Msgs │
│ Change Messages → Invalidates: Msgs only │
└──────────────────────────────────────────────────────┘
理解此行為對於選擇快取策略至關重要。層次結構中較高元件的更改會使所有下游快取失效,這直接影響您的快取命中率。
Spring AI 無需您手動放置快取斷點(這可能容易出錯且繁瑣),而是透過 AnthropicCacheStrategy 列舉提供了五種戰略模式。每種策略都會自動處理快取控制指令的放置,同時尊重 Anthropic 的 4 斷點限制。
| 策略 | 斷點 | 快取內容 | 典型用例 |
|---|---|---|---|
NONE |
0 | 無 | 一次性請求,測試 |
僅系統訊息 |
1 | 系統訊息 | 穩定的系統提示,少於 20 個工具 |
僅工具 |
1 | 工具定義 | 大型工具,動態系統提示 |
系統和工具 |
2 | 工具 + 系統 | 20 多個工具,兩者都穩定 |
會話歷史記錄 |
1-4 | 完整會話 | 多輪對話 |
讓我們透過實際示例來看看每種策略。
此策略快取系統訊息內容。由於工具在 Anthropic 的請求層次結構中出現在系統訊息之前(工具 → 系統 → 訊息),當您在系統訊息上放置快取斷點時,它們會自動成為快取字首的一部分。
重要:由於快取層次結構,更改任何工具定義都會使系統快取失效。
String systemPrompt = """
You are an expert software architect specializing in distributed systems.
You have deep knowledge of microservices, event-driven architecture, and cloud-native patterns.
When analyzing systems, consider scalability, resilience, and maintainability.
[... additional context ...]
""";
ChatResponse response = chatModel.call(
new Prompt(
List.of(
new SystemMessage(systemPrompt),
new UserMessage("What is microservices architecture?")
),
AnthropicChatOptions.builder()
.model(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET)
.cacheOptions(AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.SYSTEM_ONLY)
.build())
.maxTokens(500)
.build()
)
);
// Access cache metrics
AnthropicApi.Usage usage = (AnthropicApi.Usage) response.getMetadata()
.getUsage().getNativeUsage();
if (usage != null) {
System.out.println("Cache creation: " + usage.cacheCreationInputTokens());
System.out.println("Cache read: " + usage.cacheReadInputTokens());
}
在第一次請求時,cacheCreationInputTokens 將大於零,cacheReadInputTokens 將為零。後續使用相同系統提示的請求將顯示 cacheCreationInputTokens 為零,cacheReadInputTokens 為正值。這是您驗證快取是否在應用程式中按預期工作的方式。
當您的系統提示很大(達到最小令牌閾值)且穩定,但使用者問題各不相同時,請使用此策略。
此策略快取工具定義,同時在每個請求上重新處理系統訊息。在工具共享但系統提示需要定製的多租戶場景中,此用例變得清晰。
考慮一個服務多個組織的 SaaS 應用程式
@Service
public class MultiTenantAIService {
private final List<FunctionCallback> sharedTools = List.of(
weatherTool, // 500 tokens
calendarTool, // 800 tokens
emailTool, // 700 tokens
analyticsTool, // 600 tokens
reportingTool, // 900 tokens
// ... 15 more tools totaling 5,000+ tokens
);
public String handleRequest(String tenantId, String userQuery) {
TenantConfig config = tenantRepository.findById(tenantId);
// Each tenant requires a unique system prompt
String systemPrompt = """
You are %s's AI assistant.
Company values: [custom data]
Brand voice: [custom data]
Compliance requirements: [custom data]
""";
ChatResponse response = chatModel.call(
new Prompt(
List.of(
new SystemMessage(systemPrompt),
new UserMessage(userQuery)
),
AnthropicChatOptions.builder()
.model(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET)
.cacheOptions(AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.TOOLS_ONLY)
.build())
.toolCallbacks(sharedTools)
.maxTokens(800)
.build()
)
);
return response.getResult().getOutput().getText();
}
}
以下是發生的情況
所有租戶共享相同的快取工具定義,而每個租戶接收其定製的系統提示。對於 5,000 令牌工具集,這意味著建立快取只需支付一次 $0.01875,然後每次請求支付 $0.0015 用於快取讀取——無論哪個租戶發出請求。
此策略建立兩個獨立的快取斷點:一個用於工具(斷點 1),一個用於系統訊息(斷點 2)。當您擁有 20 多個工具或需要對這兩個元件進行確定性快取時,這種分離很重要。
關鍵優勢:更改系統訊息不會使工具快取失效。
ChatResponse response = chatModel.call(
new Prompt(
List.of(
new SystemMessage(systemPrompt),
new UserMessage(userQuery)
),
AnthropicChatOptions.builder()
.model(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET)
.cacheOptions(AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.SYSTEM_AND_TOOLS)
.build())
.toolCallbacks(toolCallbacks)
.maxTokens(500)
.build()
)
);
快取鍵的工作方式如下
hash(tools)hash(tools + system)級聯行為
這使得 SYSTEM_AND_TOOLS 在您的系統提示更改比工具更頻繁時成為理想選擇,從而實現工具快取的有效重用。
對於多輪對話,此策略會增量快取整個對話歷史記錄。Spring AI 在對話歷史記錄中的最後一條使用者訊息上放置一個快取斷點。這在構建對話式 AI 應用程式(例如聊天機器人、虛擬助手和客戶支援系統)時特別有用。
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultSystem("You are a personalized career counselor with 20 years of experience...")
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory)
.conversationId(conversationId)
.build())
.build();
String response = chatClient.prompt()
.user("What career advice would you give me based on our conversation?")
.options(AnthropicChatOptions.builder()
.model(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET)
.cacheOptions(AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY)
.build())
.maxTokens(500)
.build())
.call()
.content();
快取隨著對話的進行而增量增長
Turn 1: Cache [U1]
Turn 2: Reuse [U1], cache [U1 + A1 + U2]
Turn 3: Reuse [U1 + A1 + U2], cache [U1 + A1 + U2 + A2 + U3]
Turn 4: Reuse [U1 + A1 + U2 + A2 + U3], cache [full history + U4]
在對話的第 10 輪,您可能快取了 20,000 個令牌的歷史記錄,在每個後續輪次中,只需支付正常成本的 10% 即可獲得該上下文。
關鍵要求:工具和系統穩定性
使用 CONVERSATION_HISTORY 時,工具和系統提示在整個對話過程中必須保持穩定。對任何一個的更改都會使整個對話快取失效。
這是一個完整的示例,展示了多問題文件分析的快取效率
@Service
public class ContractAnalyzer {
private final AnthropicChatModel chatModel;
private final PdfExtractor pdfExtractor;
public AnalysisReport analyzeAgreement(String agreementPdf) {
// Extract text from PDF (typically 2,000-5,000 tokens)
String agreementText = pdfExtractor.extract(agreementPdf);
String systemPrompt = """
You are an expert business analyst specializing in partnership agreements.
Analyze the following partnership agreement and provide insights about
collaboration terms, value propositions, and strategic opportunities.
AGREEMENT:
%s
""".formatted(agreementText);
String[] questions = {
"What are the key collaboration opportunities outlined in this agreement?",
"Summarize the revenue sharing and financial arrangements.",
"What intellectual property rights and licensing terms are defined?",
"Identify the strategic value propositions for both parties.",
"What are the performance milestones and success metrics?"
};
AnalysisReport report = new AnalysisReport();
AnthropicChatOptions options = AnthropicChatOptions.builder()
.model(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET)
.cacheOptions(AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.SYSTEM_ONLY)
.messageTypeTtl(MessageType.SYSTEM, AnthropicCacheTtl.ONE_HOUR)
.build())
.maxTokens(1000)
.build();
for (int i = 0; i < questions.length; i++) {
ChatResponse response = chatModel.call(
new Prompt(
List.of(
new SystemMessage(systemPrompt),
new UserMessage(questions[i])
),
options
)
);
String answer = response.getResult().getOutput().getText();
report.addSection(questions[i], answer);
// Log cache performance
AnthropicApi.Usage usage = (AnthropicApi.Usage)
response.getMetadata().getUsage().getNativeUsage();
if (usage != null) {
if (i == 0) {
logger.info("First question - Cache created: {} tokens",
usage.cacheCreationInputTokens());
} else {
logger.info("Question {} - Cache read: {} tokens",
i + 1, usage.cacheReadInputTokens());
}
}
}
return report;
}
}
使用 Claude 3.5 Sonnet 的 3,500 令牌系統提示(協議 + 指令)
這表示快取系統提示部分成本降低了 68%。實際總節省會更低,因為您考慮了使用者問題令牌和輸出令牌(未快取),但隨著問題數量或文件大小的增加,節省會變得更顯著。
注意:Spring AI 1.1.0 及更高版本支援提示快取。請嘗試使用最新的 1.1.0-SNAPSHOT 版本。
將 Spring AI Anthropic Starter 新增到您的專案
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-anthropic-spring-boot-starter</artifactId>
</dependency>
在您的應用程式屬性中配置您的 API 金鑰
spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}
在您的應用程式中注入並使用
@Autowired
private AnthropicChatModel chatModel;
// Start using caching strategies immediately
預設快取 TTL 為 5 分鐘。對於請求不頻繁的場景,您可以配置 1 小時快取
AnthropicChatOptions options = AnthropicChatOptions.builder()
.model(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET)
.cacheOptions(AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.SYSTEM_ONLY)
.messageTypeTtl(MessageType.SYSTEM, AnthropicCacheTtl.ONE_HOUR)
.build())
.maxTokens(500)
.build();
當您配置 1 小時 TTL 時,Spring AI 會自動新增所需的 beta 標頭(anthropic-beta: extended-cache-ttl-2025-04-11)。
何時使用不同的 TTL
權衡:1 小時快取寫入成本是 5 分鐘寫入的兩倍(Claude 3.5 Sonnet 為 $6/M,而 5 分鐘為 $3.75/M)。評估您的應用程式的請求模式和穩定性要求,以確定哪種 TTL 有意義。
您可以為每種訊息型別設定最小內容長度,以最佳化斷點使用
AnthropicCacheOptions cache = AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY)
.messageTypeMinContentLength(MessageType.SYSTEM, 1024)
.messageTypeMinContentLength(MessageType.USER, 512)
.messageTypeMinContentLength(MessageType.ASSISTANT, 512)
.build();
為了精確的令牌計數,您可以提供一個自定義長度函式
AnthropicCacheOptions cache = AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY)
.contentLengthFunction(text -> customTokenCounter.count(text))
.build();
預設情況下,Spring AI 使用字串長度作為令牌計數的代理,但在生產場景中,您可能需要考慮注入適當的令牌計數器。
對於對內部機制感興趣的人,以下是 Spring AI 處理快取管理的方式
┌─────────────────────────────────────────────────────────┐
│ Request Flow: │
│ │
│ Application │
│ ↓ │
│ AnthropicChatModel │
│ ↓ │
│ CacheEligibilityResolver │
│ (created from strategy) │
│ ↓ │
│ For each component: │
│ - Check strategy eligibility │
│ - Verify minimum content length │
│ - Confirm breakpoint availability (<4) │
│ - Add cache_control if eligible │
│ ↓ │
│ Build request with cache markers │
│ ↓ │
│ Add beta headers if needed (1h TTL) │
│ ↓ │
│ Anthropic API │
│ ↓ │
│ Response with cache metrics │
└─────────────────────────────────────────────────────────┘
CacheEligibilityResolver 根據所選策略、訊息型別資格、內容長度要求和可用斷點來確定每條訊息或工具是否符合快取條件。CacheBreakpointTracker 透過每個請求的執行緒安全跟蹤來強制執行 Anthropic 的 4 斷點限制。
對於 CONVERSATION_HISTORY,Spring AI 使用聚合資格檢查——它在確定快取資格時會考慮最後約 20 個內容塊中所有訊息型別(使用者、助手、工具)的組合內容。這可以防止簡短的使用者問題(例如“告訴我更多”)在對話歷史記錄中有大量助手響應時阻止快取建立。
在以下情況下避免快取
避免這些常見錯誤
快取與流式傳輸和非流式傳輸響應無縫協作。使用流式傳輸時,快取指標會出現在最終響應塊中。兩種模式下的快取行為沒有區別。
Anthropic Claude 中的提示快取為具有可重用提示內容的應用程式提供了顯著的成本和延遲優勢。Spring AI 的戰略方法透過自動處理快取斷點放置、斷點限制和 TTL 配置來簡化實現。
五種快取策略涵蓋了常見的使用模式,從簡單的系統提示快取到複雜的多輪對話。對於大多數應用程式,根據內容穩定性模式選擇適當的策略就足夠了——Spring AI 處理實現細節。
有關更多資訊,請參閱 Spring AI Anthropic 文件和 Anthropic 的提示快取指南。