Was this page helpful?
Diese Funktion qualifiziert sich für Zero Data Retention (ZDR) mit begrenzter technischer Speicherung. Siehe den Abschnitt Datenspeicherung für Details darüber, was gespeichert wird und warum.
Prompt-Caching reduziert Latenz und Kosten erheblich, aber nur, wenn der Anfang deines Prompts Byte für Byte identisch mit einer kürzlich gesendeten Anfrage ist. Ein umsortiertes Tool, ein in deinen System-Prompt interpolierter Zeitstempel oder eine Änderung an einer früheren Nachricht kann den Cache unbemerkt ungültig machen. Ohne Cache-Diagnose ist das einzige Signal, dass usage.cache_read_input_tokens auf null fällt, ohne Hinweis darauf, was sich geändert hat.
Die Cache-Diagnose schließt diese Lücke. Übergib die id deiner vorherigen Antwort, und die API vergleicht die beiden Anfragen und teilt dir mit, wo sie abgewichen sind (das Modell, der System-Prompt, die Tools oder der Nachrichtenverlauf), damit du die eigentliche Ursache beheben kannst, anstatt zu raten.
Die Cache-Diagnose befindet sich in der Beta-Phase. Füge den Beta-Header cache-diagnosis-2026-04-07 in deine API-Anfragen ein, um diese Funktion zu nutzen.
Die Cache-Diagnose ist derzeit nur über die Claude API verfügbar. Sie wird auf Amazon Bedrock oder Vertex AI nicht unterstützt.
Wenn der Beta-Header vorhanden ist, speichert die API einen leichtgewichtigen „fingerprint" (Fingerabdruck) jeder Anfrage, der über die Antwort-id referenziert wird. Bei deiner nächsten Anfrage fügst du diese id als diagnostics.previous_message_id ein. Die API erstellt den Fingerprint für die neue Anfrage neu, vergleicht ihn mit dem gespeicherten und fügt der Antwort ein diagnostics-Objekt hinzu, das den ersten Abweichungspunkt beschreibt.
Der Vergleich bezieht sich auf die Anfragestruktur, unabhängig davon, ob der Cache tatsächlich getroffen wurde. Siehe Diagnose zusammen mit Usage lesen, um zu erfahren, wie du das diagnostics-Ergebnis mit usage.cache_read_input_tokens kombinierst.
Fingerprints enthalten nur Hashes und Token-Anzahl-Schätzungen (niemals rohen Prompt-Inhalt), werden für eine begrenzte Zeit aufbewahrt, sind auf deine Organisation und deinen Workspace beschränkt und werden für keinen anderen Zweck verwendet.
Sende den Beta-Header bei jedem Turn. Beim ersten Turn übergibst du "previous_message_id": null, um dich anzumelden, ohne eine vorherige Nachricht zum Vergleich zu haben. Bei nachfolgenden Turns übergibst du die id aus der vorherigen Antwort.
Bei Streaming-Antworten erscheint diagnostics im message_start-Event.
Das message_start-Event enthält das vollständige diagnostics-Feld; siehe Antwortformat für die möglichen Werte.
In einer mehrstufigen Konversation übergibst du die neueste Antwort-id bei jedem Turn als previous_message_id weiter. Die erste Iteration übergibt null, um sich anzumelden; jede nachfolgende Iteration übergibt die id aus der vorherigen Antwort.
Das diagnostics-Feld in der Antwort-Message hat vier mögliche Zustände:
| Wert | Bedeutung |
|---|---|
| Feld fehlt | Die Anfrage enthielt kein diagnostics, oder der Beta-Header fehlte. |
null | Entweder war previous_message_id null (erster Turn, nichts zum Vergleichen), oder ein Vergleich wurde durchgeführt und keine Abweichung gefunden. |
{"cache_miss_reason": null} | Der Vergleich lief noch, als die Antwort serialisiert wurde. Dies kann passieren, wenn die Antwort sehr schnell startet. Behandle es als nicht aussagekräftig und prüfe den nächsten Turn. |
{"cache_miss_reason": {...}} | Ein cache_miss_reason ist angehängt. Bei *_changed-Typen identifiziert dies den ersten Abweichungspunkt; previous_message_not_found und unavailable sind Fälle, in denen kein Vergleich erstellt wurde. |
Wenn cache_miss_reason nicht null ist, sieht es so aus:
{
"id": "msg_01Xyz...",
"type": "message",
"role": "assistant",
"content": [{ "type": "text", "text": "..." }],
"usage": {
"input_tokens": 42,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 41850,
"output_tokens": 210
},
"diagnostics": {
"cache_miss_reason": {
"type": "system_changed",
"cache_missed_input_tokens": 41850
}
}
}cache_miss_reason ist eine diskriminierte Union über type. Die Antwort meldet nur die früheste Abweichung, also behebe diese zuerst; spätere können dahinter verborgen sein.
| Typ | Was es bedeutet | Was zu ändern ist |
|---|---|---|
model_changed | Das model unterscheidet sich von der vorherigen Anfrage (zum Beispiel hat ein Router, A/B-Test oder Fallback ein anderes Modell ausgewählt). Der Cache ist modellspezifisch. | Halte das Modell innerhalb einer gecachten Konversation konstant. |
system_changed | Der system-Parameter unterscheidet sich. Typischerweise wurde ein Zeitstempel, eine Request-ID oder ein anderer anfragespezifischer Wert in den System-Prompt interpoliert. | Mache den System-Prompt zu einer byte-stabilen Konstante und verschiebe dynamische Daten in die erste user-Nachricht nach deinem Cache-Breakpoint. |
tools_changed | Das tools-Array unterscheidet sich: Tools wurden zwischen Turns hinzugefügt, entfernt oder umsortiert, oder das input_schema-JSON der Tools wurde nicht-deterministisch serialisiert. | Sende bei jedem Turn dieselbe Tool-Liste in einer festen Reihenfolge mit deterministisch serialisierten Schemas (zum Beispiel mit sortierten Keys). |
Die vier *_changed-Typen enthalten außerdem einen cache_missed_input_tokens-Integer: eine Schätzung, wie viele Input-Tokens nach dem Abweichungspunkt lagen, was dir ein Gefühl dafür gibt, wie viel cachebares Präfix verloren ging. Er wird aus Byte-Längen vor der Tokenisierung abgeleitet, also behandle ihn als Größenordnungsindikator und nicht als Abrechnungszahl. Er kann von usage.input_tokens abweichen (und diesen gelegentlich übersteigen).
diagnostics beantwortet die Frage „Hat sich meine Anfrage geändert?", während usage.cache_read_input_tokens die Frage „Hat der Cache getroffen?" beantwortet. Die Kombination beider sagt dir, wo du suchen musst.
Diese Matrix gilt für Turns, bei denen du eine echte previous_message_id übergeben hast. Beim ersten Turn (previous_message_id: null) ist diagnostics immer null und cache_read_input_tokens ist normalerweise null, weil der Cache geschrieben und nicht gelesen wird; keine Fehlersuche nötig. Die Matrix gilt auch nicht, wenn cache_miss_reason null ist (der Vergleich läuft noch; prüfe den nächsten Turn) oder wenn sein type previous_message_not_found oder unavailable ist (es wurde kein Vergleich erstellt).
| Diagnose-Ergebnis | Cache-Read-Tokens | Interpretation |
|---|---|---|
null | hoch | Funktioniert wie erwartet. Dein Präfix ist stabil und der Cache hat getroffen. |
null | niedrig oder null | Deine Anfragen stimmen überein, aber der Cache-Eintrag war nicht mehr verfügbar. Erwäge, die Abstände zwischen Turns zu verkürzen oder die 1-Stunden-Cache-TTL zu verwenden. |
cache_miss_reason ist ein *_changed-Typ | niedrig oder null | Dein Bug. Die Anfrage hat sich geändert; behebe die durch type angegebene Ursache. |
cache_miss_reason ist ein *_changed-Typ | hoch | Selten. Eine Änderung trat spät im Prompt auf, aber ein früherer cache_control-Breakpoint hat trotzdem getroffen. Lohnt sich zu beheben, aber geringe Auswirkung. |
previous_message_id-Suche laufen nach kurzer Zeit ab. Führe Diagnosevergleiche zwischen zeitlich nah beieinanderliegenden Anfragen durch.unavailable statt einer genauen Position sein.unavailable zurück, oder cache_miss_reason: null, wenn der Vergleich noch lief.Die Cache-Diagnose ist ZDR-berechtigt (qualifiziert). Anthropic speichert für diese Funktion nicht den Rohtext deiner Prompts oder der Ausgaben von Claude.
Der für jede Anfrage gespeicherte Fingerprint besteht nur aus kryptografischen Hashes und Token-Anzahl-Schätzungen, ist über die Antwort-id referenziert und auf deine Organisation und deinen Workspace beschränkt. Fingerprints laufen nach kurzer Zeit ab und werden für keinen anderen Zweck verwendet.
Zur ZDR-Berechtigung über alle Funktionen hinweg siehe API und Datenaufbewahrung.
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
# Zug 1: Opt-in mit previous_message_id=None
r1 = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[{"role": "user", "content": "Summarize section 1."}],
diagnostics={"previous_message_id": None},
betas=["cache-diagnosis-2026-04-07"],
)
# Zug 2: Referenziere die vorherige Response-ID
r2 = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[
{"role": "user", "content": "Summarize section 1."},
{"role": "assistant", "content": r1.content},
{"role": "user", "content": "Now summarize section 2."},
],
diagnostics={"previous_message_id": r1.id},
betas=["cache-diagnosis-2026-04-07"],
)
diagnostics = r2.diagnostics
if diagnostics is None:
print("No divergence detected.")
elif diagnostics.cache_miss_reason is None:
print("Comparison still pending.")
else:
print(f"cache_miss_reason: {diagnostics.cache_miss_reason.type}")# Zug 2: Streaming, mit Verweis auf die vorherige Response-ID
with client.beta.messages.stream(
model="claude-opus-4-8",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[
{"role": "user", "content": "Summarize section 1."},
{"role": "assistant", "content": r1.content},
{"role": "user", "content": "Now summarize section 2."},
],
diagnostics={"previous_message_id": r1.id},
betas=["cache-diagnosis-2026-04-07"],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()
r2 = stream.get_final_message()
diagnostics = r2.diagnostics
if diagnostics is None:
print("No divergence detected.")
elif diagnostics.cache_miss_reason is None:
print("Comparison still pending.")
else:
print(f"cache_miss_reason: {diagnostics.cache_miss_reason.type}")messages_changed | Modell, System und Tools stimmen alle überein, aber ein früherer Eintrag in messages wurde geändert, umsortiert oder entfernt, anstatt nur angehängt zu werden. Typischerweise wurde der Konversationsverlauf gekürzt oder bearbeitet, oder Assistant-Turns und tool_result-Blöcke wurden beim erneuten Senden anders serialisiert. | Behandle den Verlauf als append-only; gib Assistant-content und Tool-Ergebnisse wortwörtlich zurück. |
previous_message_not_found | Für die angegebene previous_message_id existiert kein gespeicherter Fingerprint. Dies ist kein Beleg dafür, dass sich deine Anfrage geändert hat. Typischerweise enthielt die vorherige Anfrage nicht den Beta-Header, sie kam aus einem anderen Workspace, oder seit dem Senden ist zu viel Zeit vergangen. | Sende den Beta-Header bei jedem Turn und halte aufeinanderfolgende Turns zeitlich nah beieinander. |
unavailable | Diagnoseinformationen waren für diese Anfrage nicht verfügbar. Dies umfasst den Fall, dass model, system und tools übereinstimmen, aber ein anderer prompt-beeinflussender Anfrageparameter (tool_choice, thinking, context_management, output_config, output_format oder die Menge der aktiven anthropic-beta-Header) abweicht, sowie sehr lange Konversationen, bei denen die Abweichung jenseits des Vergleichshorizonts liegt. Deine Anfrage wurde normal verarbeitet. | Halte die prompt-beeinflussenden Anfrageparameter für die Dauer einer gecachten Konversation konstant. Falls das Problem weiterhin besteht, wende die manuellen Prüfungen unter Fehlerbehebung bei häufigen Problemen auf der Prompt-Caching-Seite an. |