Skip to main content
Inference Economics

Caching for LLM applications

Five different mechanisms get called caching in a language-model system. One of them almost always pays and costs nothing to get right. One of them is how teams ship confident wrong answers at scale. Telling them apart is most of the work.

Five caches, one word

When somebody says "we should cache the model calls", they could mean any of five things with wildly different risk profiles. Two are close to free and safe. One is a large win that most teams get partly right by accident and could get fully right with an hour of prompt reordering. One is safe but small. And one — semantic caching — is a mechanism for returning an answer to a question the user did not ask, which is a category of bug your monitoring will not catch because a served response looks like a success.

CacheWhat it storesWhat it savesRisk if wrong
Prefix / prompt cacheProvider-side attention state for a repeated prompt prefixInput token cost and a large share of time to first tokenLow — a miss is only slower
Exact-match responseThe full response for an identical requestThe whole callModerate — staleness, and cross-user leakage if the key is wrong
Semantic / similarityResponses keyed by embedding proximityThe whole call, more oftenHigh — serves a wrong answer that looks right
Embedding cacheVectors for text you have already embeddedRe-embedding cost at corpus scaleLow — deterministic per model version
Pipeline stage cacheParsed documents, retrieval results, tool responsesLatency and third-party call costDepends entirely on the freshness of the underlying source

This article is about the specific behavior of each. The general discipline — staleness budgets, invalidation, stampede control, the honest way to measure — is in caching strategies that do not lie, and everything there still applies.

You are probably here because

  • The input token bill is most of the model bill and you suspect it should not be
  • Somebody proposed a semantic cache and you are uneasy about it
  • You shipped a prompt fix and the old behavior kept appearing for hours
  • A user saw an answer that belonged to a different account

The prefix section covers the first, the similarity section the second, the versioning section the third, and the key section the fourth — which is the one that ends projects.

The prefix cache is a prompt-ordering problem

Providers cache the computed state of a prompt prefix so that a later request beginning with the identical bytes can skip recomputing it. The saving is real on both axes: a substantial discount on the cached input tokens, and a large cut in time to first token, because prefill is the phase that scales with input length.

The catch is that it is a prefix match. Everything before the first differing byte is reusable; everything after it is not. Which means the single most effective thing you can do is reorder your prompt so the stable parts come first.

The order that works, from most to least stable: system instructions, tool definitions, few-shot examples, any long document or corpus the whole conversation refers to, then conversation history, then the current user turn. The order we routinely find in real code puts a timestamp, a request ID, a personalized greeting or a randomized example ordering somewhere near the top — and a single moved byte in position forty invalidates a four-thousand-token prefix on every request. That is not a small tuning issue; it is the difference between paying a discount rate on most of your input tokens and paying full rate on all of them.

A timestamp at the top of a system prompt can cost more than any model choice you will make this quarter. It looks like nothing in a code review.

Four operational details decide whether the win holds. Cache lifetime is short — typically minutes rather than hours — so a low-traffic endpoint may never hit it, and a warming request on a schedule can be worth more than it costs. There is usually a minimum prefix length, below which nothing is cached at all, so short prompts get no benefit and the optimization is wasted effort there. Only input is discounted; output tokens cost the same, so a workload dominated by long generations will see less than the headline number. And the cache is per model and per provider, so any traffic split fragments it — the interaction with multi-model routing is the term most often missing from a routing business case.

Exact-match response caching: safe, small, and mostly about the key

Storing the full response for a byte-identical request is the easiest cache to reason about and the hardest to get a good hit rate from. In open-ended consumer traffic, exact repeats are rare — low single digits is a normal hit rate, and anything above twenty percent usually means a head of common questions worth handling deliberately. In internal tooling with templated inputs, the same mechanism can hit most of the time, because the inputs really are identical.

Everything here rides on the key. A cache key that omits an input is not a cache; it is a mechanism for serving one user's answer to another. The key must contain, at minimum:

  • The full prompt bundle — system text, tools, few-shots, output schema, not just the user message
  • The model identifier including the snapshot, not a moving alias
  • Decoding parameters — temperature, top-p, max tokens, stop sequences
  • The prompt bundle version or content hash, so a prompt change cannot serve old behavior
  • The retrieval corpus version if documents are in the prompt
  • The tenant, and the requesting user’s permission set
  • Locale, formatting mode, and anything else the output visibly depends on

The permission entry is the one that ends projects. If two users of the same tenant can see different documents, and your retrieval-backed answer is keyed on the question alone, then the cache is a channel for showing one of them the other's data. It will not look like a breach in any log; it will look like a cache hit. Hash the effective permission set into the key, or partition the cache by it, and test the negative case explicitly with two accounts that should see different things.

Semantic caching: where the wrong answers come from

The pitch is appealing. Embed the incoming question, find a previously answered question within some cosine distance, return the stored answer. The hit rate is much better than exact match. The mechanism is also, in its naive form, a bet that vector similarity implies answer equivalence, and it does not.

Consider pairs that sit very close in embedding space and have opposite correct answers. "Can I cancel after thirty days" and "can I cancel before thirty days". "Is the fee waived for annual plans" and "is the fee waived for monthly plans". "What did revenue do in Q2" and "what did revenue do in Q3". Negation, quantity, entity, and time are exactly the dimensions general-purpose embeddings compress hardest, because for retrieval purposes those documents really are about the same topic. Topical similarity is what the embedding was trained to capture. Answer equivalence is a different relation and nobody trained for it.

So the failure is not random noise around the threshold. It is systematic, concentrated on the questions where being wrong matters most, and invisible in your metrics because a served cache hit records as a success. If you measure only hit rate, a semantic cache always looks like it is working.

If you build one anyway — and there are places it is genuinely right — constrain it hard:

  • Restrict it to a curated intent set with known-stable answers, rather than open traffic
  • Exclude anything containing a number, a date, a negation or a named entity from cache lookup
  • Set the threshold from a labeled set of paraphrase and near-miss pairs you built yourself, never from a default
  • Verify the hit with a cheap check that the stored answer addresses this question, and treat the verification cost as part of the saving
  • Measure the wrong-answer rate by sampling hits and grading them, and publish that number next to the hit rate
  • Never cache across tenants, and never cache anything a user could have personalized

Our honest position: for most products, a well-keyed exact-match cache over a curated head of common questions delivers most of the benefit with none of the exposure, and the engineering time that would have gone into tuning a similarity threshold is better spent on the prefix cache.

Return on effort, as we rank it for a typical retrieval-backed product

Reordering the prompt for prefix reuse
94
Caching embeddings for the corpus
85
Caching document parsing and chunking
78
Exact-match cache on a curated head of questions
66
Caching third-party tool calls
55
Open-traffic semantic cache
22

Benefit weighed against effort and risk. Our judgment from review work, not a benchmark. The ordering is the useful part.

Cache the deterministic stages, not the model

The best-return caching in a language-model pipeline is usually not on the model call at all. It is on the expensive deterministic work around it, where a hit is exactly equal to a miss and there is no correctness question to argue about.

Embeddings. For a fixed model version, embedding is deterministic. Key on a hash of the text plus the model identifier and you never pay twice. At corpus scale this is the difference between a re-index costing hours of compute and costing minutes, and it makes experimenting with chunk sizes affordable.

Document parsing. Optical character recognition, table extraction and layout analysis over a PDF are slow and expensive and the input never changes. Key on the file's content hash, not its name or path, because the same document arrives repeatedly under different names.

Retrieval results. For a fixed query, index version and filter set, the retrieved passage list is reproducible. Caching it saves the search and often the reranker, which is frequently the largest latency line in the pipeline. Include the index version in the key so a rebuild invalidates cleanly.

Tool calls. This one is per tool and requires judgment. A currency rate is cacheable for minutes, a filed document for effectively forever, an inventory count for seconds if at all. Write the freshness requirement per tool as a number in the code next to the call, not in a document. A tool cache with one global time-to-live is a bug waiting for the one tool whose data moves fastest.

Every cache extends your rollback window

This is the interaction teams discover during an incident. You ship a prompt fix at ten in the morning. The bad behavior keeps appearing until two in the afternoon, and no deploy explains it. The cache is serving pre-fix answers for its whole time-to-live, and it will keep doing so for every key that was warm.

There are two ways to handle it and one of them is clearly better. You can purge on every prompt or model change, which is a coordination problem, tends to be forgotten, and produces a cold-cache latency spike at the worst moment. Or you can put the prompt bundle hash and the model snapshot into the key, in which case a change is instantly a full miss on the new version, a rollback is instantly a full hit on the old one, and nothing needs purging or remembering. The second costs you a cold period after each release and buys correctness by construction. Take it. The bundle-hash concept and what belongs inside it is covered in prompt versioning and rollback.

Design Note

A cache is a copy of data, and copies have obligations

If a customer asks you to delete their data, the deletion must reach the cache. If a document's access rules change, cached answers derived from it are now potentially over-permissioned. If you told a customer their inputs are retained for thirty days, a cache holding responses for ninety has made that statement false. Enumerate every cache in the system, write down what it holds, for how long, and who can cause a read of it. That inventory takes an afternoon and it is the document you will want the first time someone asks.

Send us your prompt assembly and we will tell you what it is costing.

The code that builds the prompt, plus your input-versus-output token split for a typical month. Email contact@precisionfederal.com. You get back what to reorder for prefix reuse, an estimate of the discount you are currently leaving on the table, and anything we spot in the cache keys. One business day, no charge, no meeting.

contact@precisionfederal.com

Measuring a cache honestly

Hit rate is a vanity metric on its own, because a cache with a ninety percent hit rate serving stale or mismatched answers is worse than no cache. Report five numbers together:

  • Hit rate per cache, separately — prefix, exact, semantic, stage — never aggregated into one figure
  • Dollars saved per month, computed from real token prices, not a percentage
  • Latency delta at p50 and p95 between hits and misses, so the latency case stands on its own
  • Age distribution of served hits, which is your actual staleness rather than your configured time-to-live
  • Wrong-answer rate on any similarity-based cache, from graded samples, published beside the hit rate

Then add one operational habit: run evaluations with the cache bypassed. An eval suite that hits a warm cache is measuring your cache, not your system, and it will report that a regression did not happen because it never called the model. Provide an explicit bypass flag and default your eval harness to it. This is the same discipline as evaluation infrastructure for production models and it is broken more often than any other part of a harness.

The stampede case is worse here than elsewhere

When a popular cache entry expires and a hundred requests miss it simultaneously, an ordinary service issues a hundred database queries and recovers. An inference stack issues a hundred generations, each taking seconds, against a fixed pool of accelerators that is already sized for steady state. The queue backs up, latency climbs across every unrelated request sharing the pool, and the recovery is slow because in-flight generations cannot be cancelled cheaply.

The mitigations are standard and they matter more here: take a lock so one request regenerates and the rest wait for it, add jitter to expiry times so keys do not expire together, and serve stale content while revalidating in the background where the staleness budget permits. Refreshing shortly before expiry rather than after is worth the extra work on a small number of hot keys.

The mistakes we are called in to fix

  • A timestamp or request ID at the top of the system prompt, destroying prefix reuse on every call
  • A cache key without the model snapshot, so a provider model change served answers from the old one
  • A cache key without the permission set, so one user saw another user’s document summary
  • A semantic threshold copied from a tutorial, never validated against negation or numeric pairs
  • Hit rate reported with no wrong-answer rate, making a similarity cache look free
  • Evaluations running against a warm cache, reporting a regression that had not been tested
  • One global time-to-live across every tool, so the fastest-moving data was the stalest
  • No prompt version in the key, so a fix took the full time-to-live to take effect

A one-week caching pass

Caching Pass

1
Split the bill into input and output tokens. If input dominates, the prefix cache is the whole project
Day 1
2
Reorder the prompt: stable content first, volatile last. Measure the reported cached-token share
Day 2
3
Inventory every existing cache. Write down what is in each key and what is missing
Day 3
4
Add model snapshot, prompt hash, tenant and permission set to every key. Test with two accounts
Day 4
5
Cache the deterministic stages — embeddings, parsing, retrieval — keyed on content hashes
Day 5
6
Add the bypass flag, point the eval harness at it, and put the five metrics on a dashboard
Days 6–7

Day one usually settles the priorities on its own. A pipeline that sends a large stable context on every call is spending most of its bill on input tokens, in which case reordering the prompt is worth more than everything else on the list combined. A chat product generating long answers is spending it on output, where caching helps much less and the honest advice is to look at output length and model choice instead.

Common objections

Our provider handles prompt caching automatically. Is there anything to do?

Automatic caching still requires an exact prefix match, so the work is on your side: order the prompt so stable content comes first and nothing volatile sits above it. Check the cached-token count the provider reports on each response — if it is near zero on a long stable prompt, something near the top of your prompt is changing per request and you can usually find it in ten minutes.

Can we cache when temperature is above zero?

Yes, and be explicit that you are choosing to. Caching a sampled response means every hit returns the same one of many possible answers, which is often fine for a factual summary and wrong for anything where variety is the point, such as suggested replies or brainstorming. Decide per feature and record the decision, because the next engineer will assume the sampling still applies.

Is a vector database the right store for a semantic cache?

Technically it works, and it lets the cache inherit the operational weight of a second datastore — index freshness, recall tuning, capacity. Before taking that on, be sure a similarity cache is what you want at all rather than an exact-match cache over your most common questions, which needs a key-value store and an afternoon.

How long should responses be cached?

Derive it from how fast the underlying truth moves, not from a round number. If the answer depends on a document corpus that is reindexed nightly, the ceiling is the reindex interval. If it depends on a price that moves hourly, the ceiling is well under an hour. Then check the served-age distribution against that ceiling, because eviction and warming will make the real ages differ from the configured one.

Bottom line

Get the prefix cache right first: it is nearly free, it improves cost and time to first token together, and it is usually a matter of moving three lines of prompt assembly. Cache the deterministic stages next, because a hit and a miss are identical and there is nothing to argue about. Use exact-match response caching where the key can be made complete, and be honest that the hit rate will be modest. Approach semantic caching as a correctness decision rather than a cost decision, restrict it hard if you use it at all, and publish its wrong-answer rate beside its hit rate. And put the prompt bundle hash and model snapshot in every key, so the day you need to roll something back, the cache rolls back with it.

Frequently asked questions

How much does prompt prefix caching actually save?

It applies to input tokens only, so the saving depends on your input-to-output ratio. A pipeline that sends a large stable context and generates a short answer can see most of its input cost discounted and a substantial cut in time to first token. A chat product with short prompts and long answers sees much less. Split your bill by input and output before estimating.

Is semantic caching safe to use?

Only under constraints. Embedding similarity captures topical closeness, not answer equivalence, and it compresses exactly the dimensions that flip an answer — negation, quantity, entity and date. Restrict it to a curated intent set, exclude requests containing numbers or entities, validate the threshold on your own labeled pairs, and measure the wrong-answer rate rather than only the hit rate.

What has to be in an LLM cache key?

The full prompt bundle, the model snapshot rather than a moving alias, the decoding parameters, the prompt version hash, the retrieval index version, the tenant, and the requesting user's effective permission set. The last one is the one that causes incidents: if two users can see different documents, keying on the question alone lets the cache show one of them the other's data.

Why did our prompt fix take hours to take effect?

A response cache was serving pre-change answers for its whole time-to-live. Purging on every release works and is easy to forget; putting the prompt bundle hash and model snapshot in the key is better, because a change becomes an instant miss and a rollback becomes an instant hit with no coordination at all.

Should evaluations run against the cache?

No. An eval that hits a warm cache is measuring the cache and will happily report that a regression did not occur because the model was never called. Give the harness an explicit bypass and make it the default, then run one deliberate pass with caching on to measure what the cache itself contributes.

1 business day response

Want to know what your prompt assembly is costing you?

Send the code that builds your prompt and your input-versus-output token split. We will say what to reorder, what your cache keys are missing, and whether a similarity cache is a good idea for your traffic or a bad one. Email contact@precisionfederal.com.

Email an engineerCapabilitiesMore insights →
CachingInference CostRetrieval SystemsPlatform Engineering