Microsofts eigene Policy-Dokumentation sagt, dass ein score threshold über 0.2 zu Cache-Mismatches führen kann, was die höfliche Formulierung dafür ist, dass das Gateway eine Frage beantwortet, die der Aufrufer nicht gestellt hat. Jeder andere Mechanismus dieser Serie ist laut gescheitert: eine 429, eine 503, ein abgelaufener Batch-Job. Ein semantischer Cache scheitert, indem er eine flüssige, wohlgeformte, selbstbewusste Antwort zurückgibt, die zum Prompt von jemand anderem gehört. Teil 5 hat Ausgaben zuordenbar gemacht. Dieser Teil macht sie kleiner und behandelt den Mechanismus, der das leistet, als Korrektheitsfläche statt als Kostenhebel.

Was der Cache wirklich braucht, bevor er funktioniert

Semantic caching in API Management hat eine Voraussetzungsliste, die eine Infrastrukturentscheidung festlegt, die sich später nicht revidieren lässt, weshalb sie vor die Policy gehört statt dahinter.

  • Ein zweites Modell-Deployment, für embeddings. Das Chat-Completion-Deployment bedient Consumer-Aufrufe; ein separates Embeddings-Deployment ist das, womit der Cache einen Prompt in einen Vektor verwandelt. Das ist eine zweite Kapazitätslinie, eine zweite Quota und ein zweites Ding, das überwacht werden will.
  • Authentifizierung per managed identity von API Management zu den Modell-APIs, die die Policy verlangt: embeddings-backend-auth muss auf system-assigned stehen. Eine Key-basierte Option gibt es hier nicht, was eine gute Einschränkung ist.
  • Azure Managed Redis mit aktiviertem RediSearch-Modul, konfiguriert als external cache auf der API-Management-Instanz.

Der letzte Punkt trägt die Falle. RediSearch lässt sich nur beim Erstellen des Cache aktivieren und kann einem bestehenden Cache nicht hinzugefügt werden. Eine Plattform, die bereits eine Redis-Instanz für Sessions oder rate-limit-State betreibt, kann semantic caching nicht einfach einschalten: Sie braucht einen neuen Cache, provisioniert mit dem Modul, und das Terraform in Teil 2 ist der Ort, an dem diese Entscheidung festgehalten wird. Sie mitten in einem Sprint zu entdecken, der für „Caching aktivieren“ einen Nachmittag budgetiert hat, ist der gewöhnliche Ausgang.

Das Policy-Paar

Lookup gehört in inbound, store in outbound, und jedes der beiden darf pro Policy-Section nur einmal auftauchen. Beide sind auf global, product, API und operation scope verfügbar, und auf classic-, v2-, consumption- und self-hosted-Gateways.

<inbound>
  <base />
  <llm-semantic-cache-lookup
      score-threshold="0.05"
      embeddings-backend-id="embeddings-backend"
      embeddings-backend-auth="system-assigned"
      ignore-system-messages="true"
      max-message-count="6">
    <vary-by>@(context.Subscription.Id)</vary-by>
  </llm-semantic-cache-lookup>
  <rate-limit calls="10" renewal-period="60" />
</inbound>
<outbound>
  <llm-semantic-cache-store duration="60" />
  <base />
</outbound>

Vier dieser Attribute sind Entscheidungen statt Boilerplate.

score-threshold definiert, wie eng ein eingehender Prompt einem gecachten entsprechen muss, auf einer Skala von 0.0 bis 1.0, wobei niedrigere Werte höhere semantische Ähnlichkeit verlangen. Das kehrt um, was die meisten beim ersten Lesen annehmen, und wer die Richtung falsch versteht, macht aus einem konservativen Cache einen promiskuitiven. Microsofts Empfehlung ist, niedrig zu starten, um 0.05, und in Richtung des gewünschten Hit-zu-Miss-Verhältnisses zu tunen, mit der expliziten Warnung, dass über 0.2 Mismatches wahrscheinlich werden und sensible Use Cases niedriger bleiben sollten.

ignore-system-messages="true" entfernt System-Messages, bevor die Ähnlichkeit bewertet wird, und ist empfohlen. Das wiegt schwerer, als es klingt: Zwei Anwendungen mit identischen Nutzerfragen und verschiedenen System-Prompts sähen für den Cache sonst verschieden aus, und eine einzelne Anwendung, deren System-Prompt editiert wird, würde ihren gesamten Cache ohne semantischen Grund invalidieren.

max-message-count überspringt das Caching, sobald ein Dialog mehr als die angegebene Zahl verbleibender Messages hat. Lange Konversationen sind genau der Ort, an dem einem semantischen Match am wenigsten zu trauen ist, weil die Bedeutung der letzten Message von Turns abhängt, die das Embedding nie gesehen hat.

vary-by ist die Isolationsgrenze, und der nächste Abschnitt handelt davon, warum sie ein Security-Control ist.

vary-by ist keine Partitionierungs-Feinheit

Ohne vary-by wird ein Cache über alle Aufrufer der API geteilt. Ein Prompt des Kundenservice-Assistenten mit den Daten eines Kunden kann aus einer gecachten Completion beantwortet werden, und ein semantisch ähnlicher Prompt eines anderen Tenants kann aus genau diesem Eintrag beantwortet werden. Die Dokumentation sagt es unverblümt: Cross-User-Zugriff auf Cache-Einträge kontrolliert man, indem man vary-by mit spezifischen User- oder User-Group-Identifiern setzt.

Für diese Plattform ist das Minimum die Subscription-ID, was die Cache-Grenze exakt an der Tenancy-Grenze ausrichtet, die Teil 5 gebaut hat. Wo eine Anwendung Endnutzer bedient, deren Daten sich nicht mischen dürfen, ist der korrekte Wert ein claim aus dem validierten Token statt irgendetwas, das der Aufrufer in einem Header setzen kann, und das ist der Grund, warum das validate-jwt aus Teil 5 sein Token in output-token-variable-name schreibt. Ein vary-by, das einen unvalidierten Header liest, ist ein Cross-Tenant-Datenleck mit einer Konfigurationsdatei als Root Cause.

Der Preis enger Partitionierung ist eine niedrigere Hit Rate, und dieser Trade ist real. Er ist trotzdem der richtige Default: Ein Cache, der nie leakt und 20 Prozent spart, schlägt einen, der 45 Prozent spart und irgendwann die Antwort des falschen Kunden zurückgibt.

Die Abhängigkeit, die gerade dazugekommen ist

Der Cache sitzt im Request-Pfad jedes Aufrufs, womit Redis jetzt auf dem kritischen Pfad des Gateways liegt. Microsofts Empfehlung ist spezifisch und es lohnt sich, ihr exakt zu folgen: eine rate-limit- oder rate-limit-by-key-Policy unmittelbar nach dem Cache-Lookup platzieren, damit das Backend nicht überrannt wird, falls der Cache nicht verfügbar ist.

Diesen Ausfall lohnt es durchzudenken. An einem normalen Tag erreicht ein nennenswerter Anteil des Traffics nie ein Modell. Wird Redis unverfügbar, wird jeder dieser Requests sofort zu einem echten Completion-Aufruf, gegen eine Quota, die für den gecachten Normalzustand dimensioniert wurde. Der Cache-Ausfall degradiert die Plattform nicht, er multipliziert ihre Last, und das rate-limit ist das, was daraus Throttling statt eines Ausfalls macht. Das ist dieselbe Lektion wie bei jedem Cache vor einer Datenbank, und sie ist hier leichter zu vergessen, weil der Cache als Kostenoptimierung eingeführt wurde statt als Kapazitätsabhängigkeit.

Das Embeddings-Deployment verdient denselben Gedanken. Jeder Lookup embedded den eingehenden Prompt, also braucht das Embeddings-Modell genug Kapazität und genug Kontextgröße für das Prompt-Volumen und die Prompt-Längen der Produktion. Ein Embeddings-Deployment, dimensioniert für einen Proof of Concept, wird zum Flaschenhals für allen Traffic, gecacht oder nicht, weil der Lookup passiert, bevor Hit oder Miss bekannt ist.

Was ein Cache Hit mit den Zahlen aus Teil 5 macht

Ein Hit ist nicht gratis, und er ist keine Completion. Er kostet einen Embeddings-Aufruf, etwas Redis-Zeit und keinerlei Completion-Tokens, was bedeutet, dass das Chargeback-Modell aus Teil 5 drei kleine Änderungen braucht statt eines Rewrites.

  • Embeddings-Ausgaben werden eine Plattform-Kostenzeile. Sie fallen bei jedem Request an, Misses eingeschlossen, und sie sind keiner Completion zuordenbar. Entweder werden sie den Tenants pro rata nach Request-Zahl berechnet, oder die Plattform absorbiert sie. Eines davon wählen und aufschreiben; nicht aus der Abstimmung weglassen.
  • Hit Rate ist eine legitime Metrik-Dimension. Sie hat niedrige Kardinalität und gehört auf das Dashboard neben die Ausgaben, denn eine fallende Hit Rate ist meistens eine Prompt-Template-Änderung, die niemand angekündigt hat.
  • Ersparnisse sollten als vermiedene Kosten berichtet werden, nicht als Ausgaben. Ein Tenant, dessen Rechnung durch das Caching um 30 Prozent fiel, wird die niedrigere Zahl für die neue Baseline halten. Vermiedene Tokens neben abgerechneten Tokens zu zeigen hält dieses Gespräch ehrlich, und es begründet die Redis-Instanz, die die Plattform bezahlt.

Wann man gar nicht cachen sollte

Semantic caching passt zu Prompts mit hohem Volumen, niedriger Varianz und ohne Personalisierung. Die Retail-Wissenssuche des Unternehmens über Produktdokumentation ist nah am Ideal. Die anderen Fälle sind es nicht, und die Policy sollte pro API gescoped werden statt global zu gelten, was genau der Grund ist, warum sie product und API scope unterstützt.

Auslassen, wo die Antwort von der aktuellen Zeit oder von Live-State abhängt, denn eine duration von 60 Sekunden ist ein Korrektheitsfenster, nicht nur eine Frische-Präferenz. Auslassen für Tool-Calling-Flows, wo der Output des Modells eine Handlungsanweisung ist statt Text zum Lesen, und eine veraltete Anweisung eine falsche Handlung ist. Auslassen für alles, was über das hinaus personalisiert ist, was vary-by partitionieren kann. Und lange Multi-Turn-Dialoge per max-message-count aus dem Scope nehmen, statt zu hoffen, dass der Similarity Score es bemerkt.

Fehlerbilder, die man im Blick behalten sollte

  • Der Threshold verkehrt herum gesetzt. Höher ist lockerer. Ein Team, das auf Hit Rate optimiert, hebt ihn auf 0.4, das Verhältnis verbessert sich, und die Mismatches bleiben unsichtbar, bis ein Nutzer eine Antwort meldet, die nichts mit seiner Frage zu tun hat.
  • Ein fehlendes vary-by. Kein Fehler, keine Warnung, und ein geteilter Cache über jeden Tenant der API.
  • RediSearch spät entdeckt. Das Modul lässt sich einem bestehenden Cache nicht hinzufügen, also ist die Antwort ein neuer Cache und eine Migration, mitten in der Arbeit, die von einer Config-Änderung ausging.
  • Redis down, Backend geflutet. Ohne das rate-limit direkt nach dem Lookup kommt ein Cache-Ausfall beim Modell als Traffic-Spike an.
  • Ein unterdimensioniertes Embeddings-Deployment. Es wird bei jedem Request aufgerufen, drosselt also Hits und Misses gleichermaßen, und das Symptom sieht aus, als machte der Cache alles langsamer.
  • Eine Prompt-Template-Änderung, die den Cache still leert. Es lohnt, auf die Hit Rate zu alerten, statt es auf der Rechnung zu entdecken.

Was Teil 7 erbt

Der Cache beantwortet Wiederholungen. Er tut nichts für den weit häufigeren Fall, dass das Modell Informationen braucht, auf die es nie trainiert wurde, also das Retrieval-Problem, und die Retail-Wissenssuche des Unternehmens wartet bereits darauf. Als Nächstes: Azure AI Search gegen eine dedizierte Vektordatenbank, verglichen auf den Kriterien, die es tatsächlich entscheiden.

Weiterlesen

Für die Infrastruktur- und Plattform-Seite, so etwas in diesem Maßstab zu betreiben, gibt es die Field Notes auf ercan.cloud, und der Hub liegt auf ercanermis.com.

Referenzen