In production AI applications, latency and API costs are two of the biggest obstacles to scaling. Adding a caching layer is therefore often one of the first optimizations developers make. As discussed in the guide to caching LLM responses, a smart cache can cut response time from several seconds to a few milliseconds while saving the large language model's (LLM) tokens entirely.
Traditional key-value caches fall short with natural language, however. Questions such as "How do I change my password?" and "Changing my password, where do I do that?" have exactly the same intent but produce completely different hashes. This is where a semantic cache comes in. But while storing answers on the basis of meaning is relatively straightforward, managing the lifecycle of that data — specifically expiry (eviction) and invalidation — brings complex challenges with it.
In this article we dive deep into the strategies for expiring semantic cache entries in time and invalidating them explicitly. We cover the delicate balance of similarity thresholds, the difference between space management and correctness management, namespacing against data leaks, and how to measure your cache quality.
To understand why invalidation is so challenging in a semantic cache, we first have to look at the fundamental difference with a traditional exact-key cache.
In a exact-key cache (Redis or Memcached based on a SHA-256 hash, for instance) the relationship between key and value is 1-to-1 and fully deterministic. Request exactly the same string and you get a hit. Change a single punctuation mark or space and it is a miss. Invalidation is trivial here: when a source changes, you delete the specific key cache:user_123:profile from memory.
In a semantic cache we convert the incoming prompt into a vector — a multidimensional series of numbers — using an embedding model. We then search a vector index for existing prompts with a high cosine similarity or a low Euclidean distance. For the basics of vector search, see the explanation of semantic search.
| Property | Exact-key cache (hash-based) | Semantic cache (vector-based) |
|---|---|---|
| Linkage | Exact string match (1-to-1) | Similarity of meaning in vector space (1-to-n region) |
| Lookup time | O(1) — constant time | O(log N) to O(N) — approximate nearest neighbor (ANN) |
| Invalidation impact | Targeted: delete exactly one known key | Regional: an entire cloud of related vectors expires |
| Risk of errors | Zero (provided the hash is unique) | False positives (wrong hit at a low threshold) |
The crucial difference for invalidation is that a change at the source does not simply invalidate one key but a region in vector space. If the returns policy changes from "14 days" to "30 days", hundreds of variations of questions about returns are suddenly out of date, regardless of the exact wording in which they were once stored.
The heart of a semantic cache is the similarity threshold, usually measured in cosine similarity (a scale of 0.0 to 1.0). The choice of threshold determines the balance between hit rate and the precision of the answer.
Suppose you set the threshold too low in order to save as many LLM calls as possible. The cache sees the question "How can I cancel my subscription?" and compares it with the cached question "Can I pause my subscription temporarily?". At too low a threshold, the vector index matches these questions because both concern "stopping or changing a subscription". The user who wants to cancel now gets the instructions for pausing. That is a critical false positive hit.
Set the threshold extremely high to avoid errors and you lose the power of semantics. Subtle synonyms or typos (such as "reset password" versus "restore password") fall just short of the threshold. The cache generates constant misses, so you still have to call the expensive LLM for every variant.
A practical rule for thresholds: Which threshold is optimal depends heavily on the embedding model you choose. Consult the analysis of embedding models compared for the distance characteristics of each model. Always test thresholds against a representative dataset of your own domain questions.
In practice the terms eviction (clearing out) and invalidation (marking as invalid) are often used interchangeably. A robust architecture requires them to be kept strictly apart.
Because vector indexes load index structures (such as HNSW graphs) on top of RAM, smart eviction is essential:
Real invalidation is triggered by events in the application landscape. A semantic cache has to listen for the following five specific triggers:
In retrieval-augmented generation (RAG) systems, the LLM's answer leans on external documents or databases. When a source document is updated or deleted, all related cached answers are potentially invalid. To solve this, link the vectors in the cache to the source IDs of the RAG documents. For handling index changes, see also the article on vector index maintenance.
When developers adjust the system prompt — to change the tone, add formatting requirements or tighten safety instructions — old cached answers no longer meet the new specification. How to organize this version control is covered in version control for prompts in code.
An upgrade from gpt-4o-2024-05-13 to a newer snapshot, or an adjustment to parameters such as temperature or top_p, changes the expected output of the pipeline. A change in model configuration means old answers must no longer be served.
When a user is promoted from a "standard" to an "admin" role, they may be entitled to more extensive answers. Cache entries generated under limited permissions must not simply be returned to a user with higher (or lower) authorization.
Questions containing time-dependent words (such as "today", "current quarterly figures", "who is the current CEO") carry a built-in expiry date. If the prompt is time-sensitive, the cache entry must be given a very short TTL or be filtered out explicitly by an entity recognizer before storage.
To avoid having to wipe the entire vector database by hand on every prompt or parameter change, apply hybrid cache keys . Here you combine deterministic metadata with the semantic vector.
A robust semantic cache entry consists of two parts:
Before the semantic similarity (cosine similarity) is computed, the vector database first performs exact metadata filtering. If there is no match on the metadata, the item is skipped, however close the vectors may be.
// Voorbeeld van een hybride cache-lookup structuur
{
"vector": [0.012, -0.045, 0.389, ...], // Embedding van de gebruikersvraag
"filter": {
"tenant_id": "org_9871",
"prompt_hash": "a1b2c3d4e5", // SHA256 van system prompt + sjabloon
"model_name": "gpt-4o",
"temperature": 0.0,
"user_role": "finance_manager"
}
}
The advantage: Adjust the system prompt and the prompt_hashchanges. On the very next lookup, the metadata filter no longer matches. The old cache entries are thereby de facto invalidated immediately, without any expensive write or delete operation in the vector index. Old entries then expire by themselves through the regular LRU eviction process.
A semantic cache that is not strictly isolated per tenant or user context can lead to serious security and privacy incidents (GDPR). If user A (company X) asks "What are the terms of the contract?" and the answer is cached, user B (company Y) asking a similar question "What arrangements are in the contract?" could receive company X's confidential data as a cache hit.
When implementing a semantic cache in environments with multiple users or organizations, the following rules must be applied without exception:
tenant_id = X) that the backend code enforces inescapably. For architectural patterns, see the article on multi-tenant LLM applications.An often overlooked pitfall in semantic caching is updating the embedding model itself (switching from OpenAI's text-embedding-ada-002 to text-embedding-3-large or an open-source BGE model, for instance).
Embedding vectors from different models live in entirely different mathematical spaces. A vector computed with model A cannot be compared with a vector computed with model B. Even if both models happen to share the same dimensionality (1536, say), the distances between them are meaningless.
When you move to a new embedding model, you have two options:
You can only manage a semantic cache effectively once you measure its performance quantitatively. A high hit rate looks positive, but if the share of wrong hits rises, user satisfaction drops sharply. For detailed cost calculations, see the guide to monitoring LLM costs.
Steer your semantic cache on the following four core KPIs:
Hit Rate = (Aantal Cache Hits / Totaal Aantal Vragen) * 100%
Designing an invalidation strategy for semantic caches, we see the same mistakes recur in practice:
A semantic cache is a powerful instrument for speeding up LLM applications and cutting infrastructure costs sharply. Its success stands or falls, however, with how the data lifecycle is managed.
By drawing a sharp line between spatial eviction (LRU/LFU/cost) and substantive invalidation (events, metadata filters and version hashes), you prevent users from receiving outdated or incorrect information. Keep tenants strictly separated to rule out data leaks, and measure the false positive rate continuously to safeguard the balance between speed and precision.