Wie „zero data retention" (keine Datenspeicherung), oder ZDR, auf dieses Feature angewendet wird, erfährst du unter API und Datenspeicherung.
Prompt-Caching reduziert Latenz und Kosten erheblich, aber nur, wenn der Anfang deines Prompts Byte für Byte identisch mit einer kürzlichen Anfrage ist. Ein umsortiertes Tool, ein in deinen System-Prompt interpolierter Zeitstempel oder eine Bearbeitung einer früheren Nachricht kann den Cache stillschweigend 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 Grundursache 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 Google Cloud nicht unterstützt.
Wenn der Beta-Header vorhanden ist, speichert die API einen leichtgewichtigen Fingerprint jeder Anfrage, indiziert über die id der Antwort. Bei deiner nächsten Anfrage gibst du diese id als diagnostics.previous_message_id an. Die API erstellt den Fingerprint für die neue Anfrage neu, vergleicht ihn mit dem gespeicherten und hängt ein diagnostics-Objekt an die Antwort an, 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.
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
# Runde 1: Opt-in mit previous_message_id=None
r1 = client.beta.messages.create(
model="claude-opus-5",
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"],
)
# Runde 2: Referenziere die vorherige Response-ID
r2 = client.beta.messages.create(
model="claude-opus-5",
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}")Bei Streaming-Antworten erscheint diagnostics im message_start-Event.
# Runde 2: Streaming mit Verweis auf die vorherige Response-ID
with client.beta.messages.stream(
model="claude-opus-5",
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}")Das message_start-Event enthält das vollständige diagnostics-Feld; siehe Antwortformat für die möglichen Werte.
In einer Konversation mit mehreren Turns führst du die id der neuesten Antwort 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.
Dieser Workflow lässt sich nicht gut in einen einmaligen Shell-Befehl übersetzen. Siehe die SDK-Tabs für das Schleifenmuster; die HTTP-Anfrage pro Turn ist identisch mit Grundlegende Verwendung.
Das diagnostics-Feld auf der Message-Antwort hat vier mögliche Zustände:
| Wert | Bedeutung |
|---|---|
| Feld nicht vorhanden | Die Anfrage enthielt kein diagnostics, oder der Beta-Header fehlte. |
null | Entweder war previous_message_id null (erster Turn, nichts zu vergleichen), oder ein Vergleich wurde durchgeführt und es wurde keine Abweichung gefunden. |
{"cache_miss_reason": null} | Der Vergleich lief noch, als die Antwort serialisiert wurde. Dies kann passieren, wenn die Antwort sehr schnell beginnt. 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, ein A/B-Test oder ein Fallback ein anderes Modell ausgewählt). Der Cache ist pro Modell. | Halte das Modell innerhalb einer gecachten Konversation konstant. |
system_changed | Der system-Parameter unterscheidet sich. Typischerweise wurde ein Zeitstempel, eine Anfrage-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 sortierte Schlüssel). |
messages_changed | Modell, System und Tools stimmen alle überein, aber ein früherer Eintrag in messages wurde geändert, umsortiert oder entfernt, anstatt 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 Beweis 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 es ist zu viel Zeit seit dem Senden vergangen. | Sende den Beta-Header bei jedem Turn und halte aufeinanderfolgende Turns zeitlich nah beieinander. |
unavailable | Für diese Anfrage waren keine Diagnoseinformationen 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 Lebensdauer einer gecachten Konversation konstant. Falls das Problem bestehen bleibt, wende die manuellen Prüfungen unter Fehlerbehebung bei häufigen Problemen auf der Prompt-Caching-Seite an. |
Die vier *_changed-Typen enthalten außerdem eine Ganzzahl cache_missed_input_tokens: eine Schätzung, wie viele Input-Token nach dem Abweichungspunkt lagen, was dir ein Gefühl dafür gibt, wie viel cachebares Präfix verloren gegangen ist. Sie wird aus Byte-Längen vor der Tokenisierung abgeleitet, behandle sie also als Größenordnungsindikator und nicht als Abrechnungszahl. Sie kann von usage.input_tokens abweichen (und diese gelegentlich überschreiten).
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 Fehlerbehebung erforderlich. Die Matrix gilt auch nicht, wenn cache_miss_reason null ist (der Vergleich steht noch aus; prüfe den nächsten Turn) oder wenn dessen type previous_message_not_found oder unavailable ist (kein Vergleich wurde erstellt).
| Diagnoseergebnis | Cache-Read-Token | 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 eng beieinanderliegenden Anfragen durch.unavailable statt einer präzisen 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, indiziert über die id der Antwort und beschränkt auf deine Organisation und deinen Workspace. Fingerprints laufen nach kurzer Zeit ab und werden für keinen anderen Zweck verwendet.
Für die ZDR-Berechtigung über alle Funktionen hinweg siehe API und Datenaufbewahrung.
Was this page helpful?