7. OptimizationIntermediate

Prompt Caching: The Trick That Cuts Your LLM Bill by 10x (Anthropic, OpenAI, Google)

August 2, 2026
22 min read
Ailog Team

Complete guide to prompt caching for reducing LLM costs: how prefix matching works, per-provider strategies (Anthropic, OpenAI, Google), savings calculations, and RAG-specific optimization.

Prompt Caching: The Trick That Cuts Your LLM Bill by 10x

Is your LLM bill spiraling out of control? Are you sending the same system instructions, the same few-shot examples, the same RAG context with every request? There's a solution that can cut your costs by 90% with Anthropic and 50% with OpenAI -- and most developers aren't using it yet.

Welcome to the world of prompt caching.

TL;DR

  • Prompt caching = the LLM provider caches the prefix of your prompt so it doesn't reprocess it every request
  • Anthropic: -90% on cached tokens (most aggressive), minimum 1,024 tokens, 5-minute TTL
  • OpenAI: -50% on cached tokens, fully automatic, minimum 1,024 tokens
  • Google: -75% on cached tokens, explicit context caching, minimum 32,768 tokens
  • For RAG: cache the system prompt + few-shot examples + static context, only vary the query
  • Typical savings: 40-80% reduction on monthly LLM bill

How Prompt Caching Works

The principle: prefix matching

On each LLM call, the provider compares the beginning of your prompt with recent prompts. If an identical prefix is found in cache, only the new portion is processed at full price.

Request 1:
┌──────────────────────────────────────────────────────────┐
│ System prompt (2000 tokens) │ Few-shots (1000) │ Query 1 │
│ ████████████████████████████ │ ████████████████ │ ████    │
│        Processed normally        │                │         │
└──────────────────────────────────────────────────────────┘
Cost: 3000 tokens × normal price = $0.045

Request 2 (same prefix):
┌──────────────────────────────────────────────────────────┐
│ System prompt (2000 tokens) │ Few-shots (1000) │ Query 2 │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░ │ ░░░░░░░░░░░░░░░ │ ████    │
│        CACHED (reduced rate)     │                │ Normal  │
└──────────────────────────────────────────────────────────┘
Cost: 3000 tokens × cached price + 50 tokens × normal price = much less

Conditions for cache hits

ConditionDescription
Identical prefixTokens must be exactly identical at the start
Same modelCache is per-model (GPT-4o ≠ GPT-4o mini)
Within TTLCache expires after a certain time (varies by provider)
Minimum sizeA minimum number of tokens required to trigger caching
Order mattersSystem → User → Assistant must be in the same order

Anthropic: The Caching Champion (-90%)

How it works

Anthropic offers the most aggressive reduction: 90% off cached tokens, with a slight 25% surcharge on the initial cache write.

ParameterValue
Cache read discount-90%
Cache write surcharge+25%
TTL5 minutes (renewed on each hit)
Minimum size1,024 tokens (Claude 3.5) / 2,048 tokens (Claude 3)
Cache blocksMultiple breakpoints supported

Detailed pricing: Claude 3.5 Sonnet

Token typePrice / 1M tokensvs Base
Input (base)$3.00-
Input (cache write)$3.75+25%
Input (cache read)$0.30-90%
Output$15.00-

Anthropic implementation

DEVELOPERpython
import anthropic client = anthropic.Anthropic() # The system prompt will be cached after the first call SYSTEM_PROMPT = """You are an expert assistant for {company_name}. You answer only from the provided documents. You always cite your sources with [Source: document_name]. You never hallucinate. If you don't know, say so. ## Formatting rules - Concise responses (3-5 sentences max) - Use bullet points for lists - Cite the source in brackets ## Expected response examples Q: What is the return policy? A: Our return policy allows returns within 30 days for any unused item [Source: return-policy.pdf]. Return shipping costs are the customer's responsibility except for defective products [Source: terms-2026.pdf]. Q: How do I configure SSO? A: To configure SSO, go to Settings > Security > SSO. Select your provider (Okta, Azure AD, Google) and paste the metadata URL [Source: admin-guide.pdf]. """ + context_documents # Add your RAG context here def query_with_caching(user_query: str, rag_context: str): """Query with Anthropic prompt caching.""" response = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=1024, system=[ { "type": "text", "text": SYSTEM_PROMPT, "cache_control": {"type": "ephemeral"} # Enable caching } ], messages=[ { "role": "user", "content": f"RAG Context:\n{rag_context}\n\nQuestion: {user_query}" } ], ) # Check cache hit usage = response.usage print(f"Cache read: {usage.cache_read_input_tokens} tokens") print(f"Cache write: {usage.cache_creation_input_tokens} tokens") print(f"Uncached input: {usage.input_tokens} tokens") return response.content[0].text

Multi-breakpoint strategy with Anthropic

DEVELOPERpython
def query_with_multi_cache(user_query: str, rag_context: str): """Multiple cache levels to maximize savings.""" response = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=1024, system=[ { "type": "text", "text": STATIC_SYSTEM_PROMPT, # Rarely changes "cache_control": {"type": "ephemeral"} }, { "type": "text", "text": FEW_SHOT_EXAMPLES, # Changes sometimes "cache_control": {"type": "ephemeral"} } ], messages=[ { "role": "user", "content": [ { "type": "text", "text": rag_context, # Changes often but shared "cache_control": {"type": "ephemeral"} }, { "type": "text", "text": user_query, # Always unique } ] } ], ) return response

OpenAI: Automatic Caching (-50%)

How it works

OpenAI launched automatic caching: no configuration needed, the system automatically detects and caches identical prefixes.

ParameterValue
Cache read discount-50%
Cache write surchargeNone (free)
TTL5-10 minutes (variable)
Minimum size1,024 tokens
ActivationAutomatic (no configuration)

Detailed pricing: GPT-4o

Token typePrice / 1M tokensvs Base
Input (base)$2.50-
Input (cached)$1.25-50%
Output$10.00-

OpenAI implementation

DEVELOPERpython
from openai import OpenAI client = OpenAI() # Caching is AUTOMATIC with OpenAI # Just structure the prompt with a stable prefix SYSTEM_PROMPT = """You are an expert assistant for {company_name}. ... (same long system prompt) ... """ def query_with_openai_caching(user_query: str, rag_context: str): """Caching is automatic - just keep the prefix identical.""" response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": SYSTEM_PROMPT}, # Tip: put stable RAG context as first user message {"role": "user", "content": f"Context:\n{rag_context}"}, {"role": "assistant", "content": "Context noted."}, {"role": "user", "content": user_query}, ], max_tokens=1024, ) # Check cached tokens in usage usage = response.usage cached = getattr(usage, 'prompt_tokens_details', {}) if cached: print(f"Cached tokens: {cached.get('cached_tokens', 0)}") return response.choices[0].message.content

Maximizing cache hit rate with OpenAI

DEVELOPERpython
# BAD: message order changes → no cache hit messages_v1 = [ {"role": "system", "content": SYSTEM}, {"role": "user", "content": f"Context: {context_A}\nQuery: {query_1}"}, ] messages_v2 = [ {"role": "system", "content": SYSTEM}, {"role": "user", "content": f"Context: {context_B}\nQuery: {query_2}"}, ] # context_A ≠ context_B → cache miss from 2nd message # GOOD: separate stable and variable context messages_v1 = [ {"role": "system", "content": SYSTEM}, # ← Always identical {"role": "user", "content": "Context: " + STATIC_CONTEXT}, # ← Identical {"role": "assistant", "content": "OK."}, {"role": "user", "content": query_1}, # ← Only variable element ] messages_v2 = [ {"role": "system", "content": SYSTEM}, # ← Cache hit! {"role": "user", "content": "Context: " + STATIC_CONTEXT}, # ← Cache hit! {"role": "assistant", "content": "OK."}, {"role": "user", "content": query_2}, # ← Only variable element ]

Google: Explicit Context Caching (-75%)

How it works

Google offers explicit context caching with configurable TTLs and a 75% discount.

ParameterValue
Cache read discount-75%
Cache storage cost$1.00 / 1M tokens / hour
TTLConfigurable (min 1 min, max 24h)
Minimum size32,768 tokens (highest threshold)
ActivationExplicit via API

Detailed pricing: Gemini 1.5 Pro

Token typePrice / 1M tokensvs Base
Input (base)$1.25-
Input (cached)$0.3125-75%
Output$5.00-
Cache storage$1.00/h/M tokens-

Google implementation

DEVELOPERpython
import google.generativeai as genai from google.generativeai import caching import datetime genai.configure(api_key="GOOGLE_API_KEY") # Create an explicit cache cache = caching.CachedContent.create( model="models/gemini-1.5-pro-002", display_name="rag-system-prompt", system_instruction=SYSTEM_PROMPT, contents=[ # Pre-load static RAG context (must be > 32K tokens) {"role": "user", "parts": [{"text": LARGE_RAG_CONTEXT}]}, {"role": "model", "parts": [{"text": "Context loaded."}]}, ], ttl=datetime.timedelta(hours=1), # Cache for 1 hour ) # Use the cache for queries model = genai.GenerativeModel.from_cached_content(cached_content=cache) def query_with_google_caching(user_query: str): """Query using Google context cache.""" response = model.generate_content(user_query) # Check cache usage print(f"Cached tokens: {response.usage_metadata.cached_content_token_count}") print(f"Total tokens: {response.usage_metadata.total_token_count}") return response.text # Delete the cache when no longer needed cache.delete()

Provider Comparison

Summary table

CriteriaAnthropicOpenAIGoogle
Cache discount-90%-50%-75%
Write surcharge+25%NoneStorage/h
Minimum size1,024 tokens1,024 tokens32,768 tokens
TTL5 min (renewable)5-10 minConfigurable (24h max)
ActivationManual (cache_control)AutomaticManual (API)
Multi-breakpointsYesNoNo
Best forLong system promptsAll usageVery large contexts

Cost simulator: 10,000 requests / day

Assumption: 3,000-token system prompt + 200-token query, GPT-4o / Claude 3.5 Sonnet / Gemini 1.5 Pro.

ScenarioWithout cacheWith cacheSavings
Anthropic$960/month$144/month-85%
OpenAI$750/month$412/month-45%
Google$480/month$168/month-65%

Note: Actual savings depend on cache hit rate. With a stable system prompt and steady traffic, hit rate exceeds 90%.

Which provider for caching?

Your situationRecommendation
System prompt > 2K tokens, continuous trafficAnthropic (max savings)
Don't want to change codeOpenAI (automatic)
RAG context > 32K tokens, long TTLGoogle (explicit cache)
Tight budget, small requestsOpenAI (no write surcharge)
Multi-tenant with different promptsAnthropic (multi-breakpoints)

RAG-Specific Caching Strategies

Optimal architecture for RAG

┌─────────────────────────────────────────────────────┐
│               RAG PROMPT STRUCTURE                    │
├─────────────────────────────────────────────────────┤
│                                                       │
│  ┌─────────────────────────────────┐ ← CACHED        │
│  │   System prompt (instructions)  │   (identical     │
│  │   + formatting rules            │    for all       │
│  │   + tone of voice               │    requests)     │
│  └─────────────────────────────────┘                  │
│                                                       │
│  ┌─────────────────────────────────┐ ← CACHED        │
│  │   Few-shot examples (3-5)       │   (rarely        │
│  │   + expected format             │    changes)      │
│  └─────────────────────────────────┘                  │
│                                                       │
│  ┌─────────────────────────────────┐ ← PARTIALLY     │
│  │   Dynamic RAG context           │   CACHED         │
│  │   (retrieved documents)         │   (if same docs) │
│  └─────────────────────────────────┘                  │
│                                                       │
│  ┌─────────────────────────────────┐ ← NOT CACHED    │
│  │   User query                    │   (always        │
│  │                                 │    unique)       │
│  └─────────────────────────────────┘                  │
└─────────────────────────────────────────────────────┘

Strategy 1: Cache system prompt + few-shots

The simplest and most effective strategy:

DEVELOPERpython
# System prompt and few-shots never change # → Cache hit rate close to 100% CACHED_PREFIX = f"""{SYSTEM_PROMPT} ## Examples {FEW_SHOT_EXAMPLES} """ # Only the RAG context and query change def build_prompt(rag_docs: list, query: str) -> str: return f"""{CACHED_PREFIX} ## Reference documents {format_documents(rag_docs)} ## Question {query} """

Strategy 2: Cache frequently accessed RAG context

For recurring questions that return the same documents:

DEVELOPERpython
from functools import lru_cache @lru_cache(maxsize=100) def get_top_documents(topic: str) -> str: """Local cache of most requested documents.""" docs = search_qdrant(topic, limit=5) return format_documents(docs) # If 2 users ask questions on the same topic # → same RAG context → cache hit on the prefix

Strategy 3: Grouping by tenant / category

DEVELOPERpython
# Multi-tenant: each tenant has its own cached system prompt TENANT_PROMPTS = { "tenant_A": "You are TechCorp's assistant...", "tenant_B": "You are RetailCo's assistant...", } # As long as requests from the same tenant arrive within the TTL window # → cache works perfectly

Savings Calculator

Calculation formula

Monthly savings =
  (num_requests × cached_tokens × normal_price × (1 - cache_discount))
  - (num_requests × cached_tokens × cache_price)
  - cache_write_cost

Concrete examples

ProfileRequests/monthCached tokens/reqWithout cacheWith cacheSavings
Startup50K2,000$300$75$225/mo
SMB300K3,000$2,700$540$2,160/mo
Enterprise2M5,000$30,000$4,500$25,500/mo
E-commerce1M2,500$7,500$1,500$6,000/mo

Pitfalls and Best Practices

Common mistakes

PitfallConsequenceSolution
Timestamp in promptSystematic cache missExclude from cached prefix
Variable message orderCache missStandardize the order
RAG context at the startPrevents cachingPut at the end of prompt
TTL too shortCache expires between requestsIncrease traffic or TTL
Too many variantsLow hit rateReduce prompt variants

Optimization checklist

  1. Structure the prompt: static at top, dynamic at bottom
  2. Minimize changes in the prefix
  3. Monitor cache hit rate
  4. Group requests by tenant/category
  5. Avoid dynamic elements (date, time) in the prefix
  6. Test with before/after metrics

FAQ

Is prompt caching compatible with streaming?

Yes, prompt caching is fully compatible with streaming across all 3 providers. Caching acts on input tokens, not on generation (output). You can cache your prompt and stream the response normally.

What happens if my system prompt changes?

A change to the system prompt invalidates the cache. The first request after the change pays full price (+ write surcharge with Anthropic). Subsequent requests benefit from the new cache. Tip: version your prompts and deploy changes during off-peak hours.

Does caching work in multi-tenant setups?

Yes, but each tenant will have its own cache (since system prompts differ). The trick: structure the prompt with a portion common to all tenants (cached) and a tenant-specific portion (uncached or with its own cache via Anthropic breakpoints).

How long does the cache stay active?

With Anthropic: 5 minutes, renewed on each hit. With OpenAI: 5-10 minutes, not guaranteed. With Google: configurable up to 24h. For continuous traffic (> 1 request / 5 min), the cache practically never expires with Anthropic.

Is prompt caching useful for low volumes?

Beyond ~100 requests per day with a stable prompt, prompt caching is worthwhile. Below that, the cache may expire between requests (especially with OpenAI's short TTL). For very low volumes, focus first on model selection optimization.


Ready to slash your LLM bill? Create your Ailog account and benefit from an optimized RAG pipeline with built-in prompt caching, hosted in France.

Tags

RAGprompt cachingoptimizationcostsLLMAnthropicOpenAIGoogle

Related Posts

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !