Ai Engineering Core / LLM Ecosystem & Integrations

Prompt Caching

๐Ÿง  What is Prompt Caching?

When you send a large input context (e.g. a long document, system prompt, or reference text) to an LLM, the provider processes all those tokens every time โ€” which costs money and takes time.

Prompt caching lets providers reuse the processed version of that input if they see it again soon, so you pay less and get faster responses.

๐Ÿ’ก Think of it like a browser cache โ€” instead of re-downloading the same page, it serves it from memory.


๐Ÿ”ฌ LiteLLM Demo โ€” Seeing Caching in Action

( Level2 โ†’ part1.ipynb )

Import LiteLLM in Case you havenโ€™t

โ–ถ๏ธ Create a new code cell and run it:

from litellm import completion

Load the context (Hamlet.txt)

download from below link:

https://github.com/codevedadev/ai-engineering-core/blob/main/level2/hamlet.txt

โ–ถ๏ธ Create a new code cell and run it:

with open("hamlet.txt", "r", encoding="utf-8") as f:
    hamlet = f.read()

loc = hamlet.find("Speak, man")
print(hamlet[loc:loc+100])  
# sanity check a snippet

Ask without context (hallucination test)

โ–ถ๏ธ Create a new code cell and run it:

question = [{"role": "user", "content": "In Hamlet, when Laertes asks 'Where is my father?' what is the reply?"}]

response = completion(model="gemini/gemini-2.5-flash-lite", messages=question)
display(Markdown(response.choices[0].message.content))
  • โŒ Model hallucinated a confident but wrong answer

  • Because no context attached = no accuracy

โ–ถ๏ธ Create a new code cell and run it:

print(f"Input tokens:  {response.usage.prompt_tokens}")
print(f"Output tokens: {response.usage.completion_tokens}")
print(f"Total tokens:  {response.usage.total_tokens}")
print(f"Total cost:    {response._hidden_params['response_cost']*100:.4f} cents")

Inject full Hamlet as context

โ–ถ๏ธ Create a new code cell and run it:

question[0]["content"] += "\n\nFor context, here is the entire text of Hamlet:\n\n" + hamlet

First call WITH context

โ–ถ๏ธ Create a new code cell and run it:

response = completion(model="gemini/gemini-2.5-flash-lite", messages=question)
display(Markdown(response.choices[0].message.content))

โœ… Correct answer because context attached: "Dead."

โ–ถ๏ธ Create a new code cell and run it:

print(f"Input tokens:  {response.usage.prompt_tokens}")
print(f"Output tokens: {response.usage.completion_tokens}")
print(f"Cached tokens: {response.usage.prompt_tokens_details.cached_tokens}")
print(f"Total cost:    {response._hidden_params['response_cost']*100:.4f} cents")

Second identical call (cache kicks in)

โ–ถ๏ธ Create a new code cell and run it:

response = completion(model="gemini/gemini-2.5-flash-lite", messages=question)

โ–ถ๏ธ Create a new code cell and run it:

print(f"Input tokens:  {response.usage.prompt_tokens}")
print(f"Output tokens: {response.usage.completion_tokens}")
print(f"Cached tokens: {response.usage.prompt_tokens_details.cached_tokens}")
print(f"Total cost:    {response._hidden_params['response_cost']*100:.4f} cents")
  • ๐Ÿ’ฐ ~5ร— cheaper on the second call โ€” automatically, no code changes needed


๐Ÿ“Š Token Cost Summary

Call

Input Tokens

Cached Tokens

Cost

No context

~19

0

~0.004ยข

With context (1st)

~53K

0

~0.5ยข

With context (2nd)

~53K

~44K

~0.1ยข


๐Ÿ”‘ The Golden Rule of Prompt Caching

โš ๏ธ Static content first, dynamic content last.

For caching to work, the beginning of your prompt must match between calls. As soon as the prefix differs, there's a cache miss.

โœ… CORRECT:  [Full Hamlet text]  โ†’  [Question about Hamlet]
โŒ WRONG:    [Question]          โ†’  [Full Hamlet text]

If you put today's date or the user's question at the top, every call will be a cache miss because the prefix changes every time.


๐Ÿ”ต OpenAI Prompt Caching

๐Ÿ“Ž Docs | Pricing

  • โœ… Fully automatic โ€” no code changes needed

  • ๐Ÿ” Only works on exact prefix matches โ€” the beginning of the prompt must be identical

  • ๐Ÿ’ฐ Cached input tokens cost 4ร— less

  • ๐Ÿ–ผ๏ธ Applies to images and tools too โ€” they must also be identical between requests


๐ŸŸ  Anthropic Prompt Caching

๐Ÿ“Ž Docs | Pricing

  • โš™๏ธ Manual โ€” you must explicitly tell Anthropic what to cache ("priming")

  • ๐Ÿ’ธ Priming the cache costs 25% more upfront

  • ๐Ÿ’ฐ But reusing from cache costs 10ร— less โ€” a much bigger saving than OpenAI

  • ๐Ÿงฎ Best for large, stable system prompts or documents used repeatedly

Trade-off summary:

OpenAI

Anthropic

Setup

Automatic

Manual (explicit)

Cache prime cost

None

+25%

Cache hit saving

4ร— cheaper

10ร— cheaper


๐ŸŸข Gemini Prompt Caching โ€” Implicit vs Explicit

๐Ÿ“Ž Docs

Gemini supports both modes:

๐Ÿ”‡ Implicit Caching (automatic)

  • Works like OpenAI โ€” Gemini detects repeated prefixes and caches them automatically

  • No code changes required

  • What happened in the demo above โ€” Gemini cached Hamlet on the second call without any setup

๐Ÿ”Š Explicit Caching (manual)

  • You proactively create a named cache object with the content you want stored

  • Gives you more control โ€” you can set a TTL (time-to-live), reuse across many sessions, and confirm it's cached before paying for calls

  • Similar philosophy to Anthropic's approach but with Gemini's API

When to use which:

Implicit

Explicit

Setup effort

None

Requires extra API calls

Best for

Short sessions, quick experiments

Long-running apps, production systems

Control

Low

High