Design the cache key for an embedding cache that survives vendor model upgrades
Same topic, related formats. Practice these next.
Same topic, related formats. Practice these next.
You're building an embedding cache to avoid re-embedding the same content twice. Design the cache key. Explain why a naive content-hash key is wrong, and what additional fields you need to include for correctness across model versions and fine-tunes.
Cache key must be (content_hash, model_id, model_version, normalization_state) at minimum. Content alone collides across models and silent version bumps leak stale vectors.
Imagine a library where every book gets photocopied, but a different machine sits in each room. Each machine produces slightly different copies. If you label your photocopies only by the book title, you cannot tell which machine made which copy. The day someone asks for the photocopy of Moby Dick, you might hand them a version that does not match the one currently in use. A saved lookup table for these text fingerprints works the same way. The same paragraph turns into different numbers depending on which fingerprinting machine produced it, so the label needs to record both the text and the machine. Otherwise, the day someone upgrades the machines, every saved answer becomes silently wrong, with no error, just bad search results.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
9 minutes: cross-model collision, the full key shape, silent-bump detection, Matryoshka and normalization wrinkles, and invalidation policy.
import hashlib
from dataclasses import dataclass
@dataclass(frozen=True)
class EmbeddingCacheKey:
content_hash: str # sha256 over normalized input text
model_id: str # 'text-embedding-3-large'
model_version: str # snapshot date or model-card hash
embedding_dim: int # 1536, 3072, etc. (Matryoshka-aware)
normalized: bool # True if unit-norm, False if raw
instruction_hash: str # hash of instruction prefix; '' if none
def to_str(self) -> str:
parts = (
self.content_hash,
self.model_id,
self.model_version,
str(self.embedding_dim),
str(int(self.normalized)),
self.instruction_hash,
)
return "|".join(parts)
def make_key(text: str, model_id: str, model_version: str,
dim: int, normalized: bool, instruction: str = "") -> EmbeddingCacheKey:
content = hashlib.sha256(text.strip().encode("utf-8")).hexdigest()
instr = hashlib.sha256(instruction.encode("utf-8")).hexdigest() if instruction else ""
return EmbeddingCacheKey(content, model_id, model_version, dim, normalized, instr)Real products, models, and research that use this idea.
What an interviewer would ask next. Try answering before peeking at the approach.
Red flags and common mistakes that signal junior thinking. Click to expand.
Keying the cache only by content hash, then switching models and serving mixed-vintage vectors that break cosine similarity and tank retrieval quality.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.