El almacenamiento en caché de prompts ("prompt caching") reduce significativamente la latencia y el costo, pero solo cuando el inicio de tu prompt es idéntico byte por byte a una solicitud reciente. Una herramienta reordenada, una marca de tiempo interpolada en tu indicación del sistema o una edición de un mensaje anterior pueden invalidar la caché silenciosamente. Sin el diagnóstico de caché, la única señal es que usage.cache_read_input_tokens cae a cero, sin ninguna indicación de qué cambió.
El diagnóstico de caché cierra esa brecha. Pasa el id de tu respuesta anterior, y la API compara las dos solicitudes y te dice dónde divergieron (el modelo, la indicación del sistema, las herramientas o el historial de mensajes) para que puedas corregir la causa raíz en lugar de adivinar.
Cuando el encabezado beta está presente, la API almacena una "fingerprint" (huella digital) ligera de cada solicitud, indexada por el id de la respuesta. En tu siguiente solicitud, incluye ese id como diagnostics.previous_message_id. La API reconstruye la huella digital de la nueva solicitud, la compara con la almacenada y adjunta un objeto diagnostics a la respuesta que describe el primer punto de divergencia.
La comparación se refiere a la estructura de la solicitud, independientemente de si la caché realmente acertó. Consulta Leer el diagnóstico junto con el uso para saber cómo combinar el resultado de diagnostics con usage.cache_read_input_tokens.
Las huellas digitales contienen únicamente hashes y estimaciones de conteo de tokens (nunca el contenido sin procesar del prompt), se conservan durante un tiempo limitado, están restringidas a tu organización y espacio de trabajo, y no se utilizan para ningún otro propósito.
Envía el encabezado beta en cada turno. En el primer turno, pasa "previous_message_id": null para activar la función sin un mensaje previo con el que comparar. En los turnos siguientes, pasa el id de la respuesta anterior.
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
# Turno 1: actívalo con 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"],
)
# Turno 2: referencia el id de la respuesta anterior
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}")En las respuestas con streaming, diagnostics aparece en el evento message_start.
# Turno 2: usa streaming, haciendo referencia al id de la respuesta anterior
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}")El evento message_start lleva el campo diagnostics completo; consulta Formato de respuesta para ver los valores posibles.
En una conversación de varios turnos, lleva el id de la respuesta más reciente hacia adelante como previous_message_id en cada turno. La primera iteración pasa null para activar la función; cada iteración posterior pasa el id de la respuesta anterior.
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
messages = []
prev_id = None
for i, user_message in enumerate(
["Summarize section 1.", "Now section 2.", "Now section 3."]
):
messages.append({"role": "user", "content": user_message})
r = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=messages,
diagnostics={"previous_message_id": prev_id},
betas=["cache-diagnosis-2026-04-07"],
)
if r.diagnostics is not None and r.diagnostics.cache_miss_reason is not None:
print(f"Turn {i + 1} cache_miss_reason: {r.diagnostics.cache_miss_reason.type}")
messages.append({"role": "assistant", "content": r.content})
prev_id = r.idEl campo diagnostics en el Message de la respuesta tiene cuatro estados posibles:
| Valor | Significado |
|---|---|
| campo ausente | La solicitud no incluyó diagnostics, o faltaba el encabezado beta. |
null | O bien previous_message_id era null (primer turno, nada que comparar), o bien se ejecutó una comparación y no se encontró ninguna divergencia. |
{"cache_miss_reason": null} | La comparación aún se estaba ejecutando cuando se serializó la respuesta. Esto puede ocurrir cuando la respuesta comienza muy rápido. Trátalo como no concluyente y revisa el siguiente turno. |
{"cache_miss_reason": {...}} | Se adjunta un cache_miss_reason. Para los tipos *_changed, esto identifica el primer punto de divergencia; previous_message_not_found y unavailable son casos en los que no se produjo ninguna comparación. |
Cuando cache_miss_reason no es nulo, tiene este aspecto:
{
"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 es una unión discriminada por type. La respuesta informa únicamente la divergencia más temprana, así que corrígela primero; las posteriores pueden estar ocultas detrás de ella.
| Tipo | Qué significa | Qué cambiar |
|---|---|---|
model_changed | El model difiere del de la solicitud anterior (por ejemplo, un enrutador, una prueba A/B o un mecanismo de respaldo seleccionó un modelo diferente). La caché es por modelo. | Mantén el modelo constante dentro de una conversación en caché. |
system_changed | El parámetro system difiere. Normalmente se interpoló una marca de tiempo, un ID de solicitud u otro valor por solicitud en la indicación del sistema. | Haz que la indicación del sistema sea una constante estable a nivel de bytes y mueve los datos dinámicos al primer mensaje user después de tu punto de interrupción de caché. |
tools_changed | El arreglo tools difiere: se agregaron, eliminaron o reordenaron herramientas entre turnos, o el JSON de input_schema de las herramientas se serializó de forma no determinista. | Envía la misma lista de herramientas en cada turno en un orden fijo con esquemas serializados de forma determinista (por ejemplo, ordena las claves). |
messages_changed | El modelo, el sistema y las herramientas coinciden, pero una entrada anterior en messages fue alterada, reordenada o eliminada en lugar de que se le agregara contenido al final. Normalmente el historial de la conversación fue truncado o editado, o los turnos del asistente y los bloques tool_result se volvieron a serializar de forma diferente al reenviarlos. | Trata el historial como de solo anexado; devuelve el content del asistente y los resultados de herramientas textualmente. |
previous_message_not_found | No existe ninguna huella digital almacenada para el previous_message_id proporcionado. Esto no es evidencia de que tu solicitud haya cambiado. Normalmente la solicitud anterior no llevaba el encabezado beta, provenía de un espacio de trabajo diferente o ha pasado demasiado tiempo desde que se envió. | Envía el encabezado beta en cada turno y mantén los turnos consecutivos cercanos en el tiempo. |
unavailable | La información de diagnóstico no estaba disponible para esta solicitud. Esto incluye el caso en que model, system y tools coinciden pero otro parámetro de la solicitud que afecta al prompt (tool_choice, thinking, context_management, output_config, output_format o el conjunto de encabezados anthropic-beta activos) difiere, y las conversaciones muy largas en las que la divergencia está más allá del horizonte de comparación. Tu solicitud se procesó normalmente. | Mantén constantes los parámetros de la solicitud que afectan al prompt durante toda la vida de una conversación en caché. Si persiste, aplica las verificaciones manuales de Solución de problemas comunes en la página de almacenamiento en caché de prompts. |
diagnostics responde a "¿cambió mi solicitud?", mientras que usage.cache_read_input_tokens responde a "¿acertó la caché?". Combinarlos te indica dónde buscar.
Esta matriz se aplica a los turnos en los que pasaste un previous_message_id real. En el primer turno (previous_message_id: null), diagnostics siempre es null y cache_read_input_tokens normalmente es cero porque la caché se está escribiendo, no leyendo; no se necesita ninguna solución de problemas. La matriz tampoco se aplica cuando cache_miss_reason es null (la comparación aún está pendiente; revisa el siguiente turno) ni cuando su type es previous_message_not_found o unavailable (no se produjo ninguna comparación).
| Resultado del diagnóstico | Tokens leídos de caché | Interpretación |
|---|---|---|
null | alto | Funciona como se espera. Tu prefijo es estable y la caché acertó. |
null | bajo o cero | Tus solicitudes coinciden, pero la entrada de caché ya no estaba disponible. Considera acortar los intervalos entre turnos o usar el TTL de caché de 1 hora. |
cache_miss_reason es un tipo *_changed | bajo o cero | Es tu error. La solicitud cambió; corrige la causa indicada por type. |
cache_miss_reason es un tipo *_changed | alto | Poco frecuente. Ocurrió un cambio tarde en el prompt, pero un punto de interrupción cache_control anterior aún acertó. Vale la pena corregirlo, pero el impacto es bajo. |
previous_message_id expiran después de un período corto. Ejecuta las comparaciones de diagnóstico entre solicitudes cercanas en el tiempo.anthropic-workspace-id en las dos respuestas.unavailable en lugar de una ubicación precisa.unavailable, o cache_miss_reason: null cuando la comparación aún se estaba ejecutando.El diagnóstico de caché es elegible para ZDR (con condiciones). Anthropic no almacena el texto sin procesar de tus prompts ni las salidas de Claude para esta función.
La huella digital almacenada para cada solicitud consiste únicamente en hashes criptográficos y estimaciones de conteo de tokens, indexada por el id de la respuesta y restringida a tu organización y espacio de trabajo. Las huellas digitales expiran después de un período corto y no se utilizan para ningún otro propósito.
Para conocer la elegibilidad para ZDR de todas las funciones, consulta API y retención de datos.
| Supported platforms |
|
|---|
Was this page helpful?