Skip to content

All lessons

Area 05 // AI System DesignLesson 83 / 14013 min read

Semantic caching

A semantic cache stores past answers and returns one when a new question means the same thing as a cached one (judged by embedding similarity), skipping the model call entirely, which saves cost and time as long as the similarity threshold is strict enough to avoid wrong answers.

Think of it like this

Analogy

A helpdesk worker keeps a notebook of answers to common questions. When someone asks "how do I get a new badge?", they recognise it's the same as yesterday's "I lost my ID card, what do I do?" and read out the saved answer instead of researching again. But a careful worker won't mix up "reset my password" with "reset my router", even though they sound alike.

The problem it solves

Many AI products get the same questions over and over, phrased differently: "How do I reset my password?", "forgot password help", "can't log in, password reset?". Each one costs a full model call (and RAG retrieval). An exact-match cache barely helps because wording varies. A cache that understands meaning can serve a large share of traffic instantly and for almost nothing.

How it works, step by step

  1. On each request, embed the question with an embedding model.
  2. Search the cache (a vector index of past questions) for the nearest neighbour, within the right scope (same tenant, same feature, same language).
  3. If similarity ≥ threshold, return the cached answer (a cache hit): no model call.
  4. Otherwise call the model, return the answer, and store (question embedding, answer, metadata, timestamp).
  5. Choose the threshold carefully: tune it on real pairs of questions labelled same/different; strict (e.g. 0.95+ cosine) is safer.
  6. Scope and protect: never return a cached answer generated for one user's data to another user; key caches by tenant and avoid caching personalised answers.
  7. Expire and invalidate: set a TTL and clear entries when the source data (policies, prices) changes.
  8. Measure: hit rate, cost saved, and false-hit rate (sample hits and check them).
A semantic cache in front of the model.

See it in code

Install
pip install numpy
Needs
Python 3.10+. Embeddings are hand-made here; an embedding model produces them in practice.

A semantic cache with a strict threshold, and why a loose one would be dangerous.

semantic_cache.py
import numpy as np
 
# Pretend embeddings (an embedding model makes these in real life).
EMB = {
    "How do I reset my password?":          [0.90, 0.10, 0.00],
    "how can i reset my password":          [0.88, 0.12, 0.02],
    "I forgot my password, how to reset?":  [0.85, 0.15, 0.05],
    "How do I reset my router?":            [0.70, 0.10, 0.60],
    "What are your opening hours?":         [0.00, 0.95, 0.10],
}
def cos(a, b):
    a, b = np.array(a), np.array(b)
    return float(a @ b / (np.linalg.norm(a) * np.linalg.norm(b)))
 
class SemanticCache:
    def __init__(self, threshold):
        self.threshold, self.entries = threshold, []          # (embedding, answer)
    def get(self, q):
        best = max(self.entries, key=lambda e: cos(EMB[q], e[0]), default=None)
        if best and cos(EMB[q], best[0]) >= self.threshold:
            return best[1]
        return None
    def put(self, q, answer):
        self.entries.append((EMB[q], answer))
 
cache = SemanticCache(threshold=0.95)
cache.put("How do I reset my password?", "Go to Settings > Security > Reset password.")
for q in ["how can i reset my password", "I forgot my password, how to reset?",
          "How do I reset my router?", "What are your opening hours?"]:
    hit = cache.get(q)
    print(f"{q:38} -> {'HIT: ' + hit if hit else 'miss (call the model)'}")
print("router similarity:", round(cos(EMB['How do I reset my router?'], EMB['How do I reset my password?']), 2),
      "<- with a 0.75 threshold this would wrongly get the password answer")
Output
how can i reset my password            -> HIT: Go to Settings > Security > Reset password.
I forgot my password, how to reset?    -> HIT: Go to Settings > Security > Reset password.
How do I reset my router?              -> miss (call the model)
What are your opening hours?           -> miss (call the model)
router similarity: 0.76 <- with a 0.75 threshold this would wrongly get the password answer

Production semantic caches store embeddings in a vector database or Redis with vector search, keyed by tenant and feature, with TTLs. Gateways such as LiteLLM and several cloud AI gateways offer semantic caching built in.

A real example

Example

A telecom FAQ bot saves a third of its calls

A telecom's support bot answered about 400,000 questions a day; analysis showed the top 200 intents covered over half of them. The team added a semantic cache for general (non-account) questions only, with a 0.95 threshold tuned on 2,000 labelled question pairs, a 24-hour TTL, and automatic invalidation when help articles changed.

Hit rate settled at 34%, those answers returned in 40 ms instead of 2.5 s, and model spend fell by about a third. Sampled hits were checked weekly; the false-hit rate stayed under 0.5%. Account-specific questions ("why is my bill high?") always bypassed the cache.

The easy way

Start here

Start with an exact-match cache on normalised text (lower-case, trimmed) for general questions; it's safe and often surprisingly effective. Add a semantic layer only with a strict threshold tested on real question pairs, and only for answers that don't depend on the user.

When you grow: the production setup

Production setups scope caches per tenant and feature, cache only safe categories, store prompt and model versions with entries (and invalidate on changes), use TTLs and event-based invalidation, monitor hit and false-hit rates, and combine semantic caching with provider prompt caching, which saves on cache misses too.

Trade-offs

What you gain

  • Big cost and latency savings for repetitive traffic.
  • Consistent answers to common questions.
  • Reduces load on providers and rate limits.

What it costs you

  • False hits return wrong answers with full confidence.
  • Stale answers if invalidation is missed.
  • Privacy risk if personalised answers are shared.

When not to use it

  • Answers depend on the user's data, time-sensitive facts, or tool results.
  • Traffic is mostly unique (creative writing, analysis): the hit rate won't justify it.

Common mistakes

  • A loose threshold chosen by gut feeling.
  • One global cache shared across tenants and users.
  • Caching answers that included account data.
  • No invalidation when source documents or prompts change.
  • Measuring hit rate but never checking false hits.

Interview questions

Try answering out loud first, then open the model answer.

How does a semantic cache work and what are its risks?

Model answer

Each query is embedded and compared with embeddings of previously answered queries in the same scope; if the nearest one exceeds a similarity threshold, its stored answer is returned without calling the model; otherwise the model answers and the pair is stored. Risks: false hits returning answers to subtly different questions, stale answers after data changes, and data leakage if personalised answers are shared across users. Mitigate with strict tuned thresholds, scoping, safe-category caching, TTLs and invalidation, and monitoring false hits.

Semantic caching vs prompt caching?

Model answer

Semantic caching skips the model call entirely when a similar question was already answered, returning the stored answer; it's an application-level cache with correctness risk. Prompt caching (provider or prefix caching) still runs the model but reuses the computed prefix of identical prompts, lowering cost and latency with no correctness risk. They complement each other.

How would you choose the similarity threshold?

Model answer

Collect real query pairs from logs, label whether each pair should share an answer, compute similarities with your embedding model, and choose the threshold that keeps false hits below an acceptable rate (e.g. under 1%) while maximising hits; validate on a held-out set and monitor in production with sampled reviews.

Quiz

Pick an answer to see whether it’s right and why.

  1. 01How is a semantic cache different from an exact cache?
  2. 02What's the main risk of a low similarity threshold?
  3. 03When must you NOT share cached answers between users?
  4. 04The refund policy changes. What should happen to the semantic cache?
  5. 05Where do semantic caches help most?

0 of 5 answered

Key terms

Semantic cache
A cache that returns a stored answer when a new question is close in meaning (by embedding similarity) to one already answered, skipping the model call.
Embedding
A vector of numbers that represents the meaning of a piece of text (or an image), so that similar meanings get similar vectors.
Cosine similarity
A score from -1 to 1 for how closely two vectors point in the same direction, ignoring their length. The standard way to compare embeddings.
Cache hit
A request that finds what it needs already stored in a cache, so the expensive work is skipped.
TTL (time to live)
How long a cached entry stays valid before it expires and must be fetched or computed again.

Before and after

Progress is saved in this browser only.