Ein Semantic Cache beantwortet "wie setze ich mein Passwort zurück" mit der Antwort, die er bereits für "ich komme nicht mehr rein" generiert hat, weil beide dasselbe meinen. Statt die exakte Zeichenkette einer Anfrage abzugleichen, embeddet er die Anfrage und sucht nach einer gespeicherten Anfrage, deren Embedding nah genug liegt, und liefert dann diese gecachte Antwort, ohne das Modell aufzurufen. Wenn das funktioniert, spart man sich einen Modellaufruf komplett: keine Tokens, keine Latenz, keine Kosten. Wenn die Einschätzung von "nah genug" danebenliegt, liefert der Cache eine selbstbewusste Antwort auf eine Frage, die der Nutzer nicht gestellt hat.

Die zentrale Umdeutung: Ein normaler Cache schlüsselt nach Identität, ein Semantic Cache schlüsselt nach Ähnlichkeit, und Ähnlichkeit ist ein Schwellenwert, den man festlegt, keine Tatsache. Dieser Schwellenwert ist die gesamte Risikofläche. Zu locker eingestellt liefert man falsche Antworten, zu eng eingestellt cacht man fast nichts. Alles am guten Betrieb eines Semantic Cache läuft darauf hinaus, diesen Regler zu justieren.

Wie es funktioniert, minus die Magie

Der Mechanismus hat drei Schritte. Die eingehende Anfrage wird mit einem Embeddings-Modell wie Amazon Titan Text Embeddings oder Cohere auf Bedrock in einen Vektor umgewandelt. Ein Vector Store wird nach der nächstliegenden bereits gesehenen Anfrage durchsucht. Liegt die Cosine Similarity des nächsten Nachbarn über dem eigenen Schwellenwert, wird dessen gecachte Antwort zurückgegeben, andernfalls wird das Modell aufgerufen und anschließend das neue Anfrage-Embedding samt Antwort für das nächste Mal gespeichert.

vec = embed(request)
hit = vector_store.nearest(vec)
if hit and hit.similarity >= THRESHOLD:
    return hit.cached_response      # no model call
answer = model.invoke(request)
vector_store.put(vec, answer)
return answer

Der Vector Store kann alles sein, was man schon betreibt: OpenSearch, Aurora mit pgvector, oder ein In-Memory-Index für eine kleine, heiße Teilmenge. Der schwierige Teil ist nie die Speicherung. Es ist der Wert von THRESHOLD und was man überhaupt erst in den Cache lässt.

Das False-Hit-Risiko ist das ganze Spiel

Ein False Hit liegt vor, wenn zwei Anfragen im Embedding-Raum nah beieinander liegen, aber unterschiedliche Antworten verlangen. "Wie ist unsere Rückgabepolitik für EU-Kunden" und "wie ist unsere Rückgabepolitik für US-Kunden" können gefährlich nah beieinander im Vektorraum liegen, während sie unterschiedliche Antworten fordern. Ein loser Schwellenwert liefert die EU-Antwort an einen US-Nutzer, und tut das mit voller Zuversicht, weil das Modell nie konsultiert wurde.

Das ist schlimmer als ein normaler Cache-Miss, der einen nur einen Modellaufruf kostet. Ein False Hit kostet eine falsche Antwort, die richtig aussieht. Der Schwellenwert muss also gegen echten Traffic austariert werden, nicht geraten, und er sollte zur Enge tendieren: Ein Miss ist billig, ein False Hit kann ein Support-Ticket oder ein Compliance-Problem sein. Die False-Hit-Rate an einer gelabelten Stichprobe messen, bevor man dem Cache irgendetwas anvertraut, das wichtig ist.

Was man nicht cachen sollte

Semantic Caching passt zu stabilem, allgemeinem, geteiltem Wissen und zu sonst nichts. Die Antwort auf "wie exportiere ich meine Daten" cachen, die für alle gleich ist. Nichts cachen, das davon abhängt, wer fragt oder wann. Faustregeln, die es sich lohnt, im Code durchzusetzen:

  • Nie über Identitätsgrenzen hinweg cachen. Den Cache pro Mandant schlüsseln oder alles Personalisierte ausschließen. Ein geteilter Cache, der den Aufrufer ignoriert, liefert irgendwann die Antwort eines Kunden an einen anderen.
  • Nie zeitkritische Antworten cachen. Kontostände, Bestellstatus und Lagerbestand ändern sich unter der Hand. Ein veralteter Hit ist hier ein frischer Bug.
  • Das Retrieval-freie cachen, nicht das Retrieval-lastige. Hängt die Antwort von Dokumenten ab, die sich ändern, den Embedding-Lookup cachen, nicht die fertige Antwort.

Invalidierung ist der Teil, den alle überspringen

Der älteste Witz in der Informatik ist, dass Cache-Invalidierung eines der beiden schweren Probleme ist, und ein Semantic Cache bekommt keine Ausnahme. Ändert sich die zugrunde liegende Wahrheit, wird eine Policy aktualisiert, bewegt sich ein Preis, wird ein Dokument überarbeitet, ist jede gecachte Antwort, die sich auf die alte Wahrheit gestützt hat, jetzt falsch und wird weiter ausgeliefert, bis man sie entfernt.

Einträgen eine Time-to-Live geben, die kurz genug ist, dass veraltete Antworten von selbst altern, und einen expliziten Purge-Pfad an die Ereignisse binden, die die Grundwahrheit ändern: Das Veröffentlichen einer neuen Policy-Version sollte den Teil des Caches invalidieren, der auf der alten aufgebaut war. Ohne eine Invalidierungsstrategie spart ein Semantic Cache nicht nur Aufrufe, er nagelt das Produkt still auf die Fakten von gestern fest.

Fazit

Semantic Caching ist ein echter Gewinn bei Kosten und Latenz für Fragen, die dieselbe Frage in anderen Worten sind, und eine Falle für alles Personalisierte, Zeitkritische oder Änderliche. Der Mechanismus ist trivial: embedden, suchen, Schwellenwert. Die Ingenieursarbeit steckt vollständig im Schwellenwert, den Scope-Regeln und dem Invalidierungspfad. Den Schwellenwert gegen gelabelten Traffic austarieren, nur stabiles geteiltes Wissen cachen, und bei den Ereignissen invalidieren, die die Wahrheit bewegen. Diese drei Dinge tun, und der Cache zahlt sich selbst zurück. Sie überspringen, und er liefert falsche Antworten schneller, als das Modell richtige hätte liefern können.

Weiterlesen

Für die Plattformseite des Betriebs eines Vector Store und seiner Eviction unter Last gibt es die Cloud-Field-Notes auf ercan.cloud, und den Hub auf ercanermis.com.