Verificar aciertos de caché con cache_read_input_tokens
Añadir un breakpoint cache_control no prueba por sí solo que tus solicitudes realmente estén alcanzando la caché.
La única señal fiable es el objeto usage en cada respuesta, específicamente cache_read_input_tokens y cache_creation_input_tokens.
Esta página muestra cómo leer esos campos correctamente, cómo incorporar una verificación ligera en tu propio código y qué valores significan realmente éxito frente a fracaso.
Resumen
response.usage contiene cuatro recuentos de tokens que son importantes para la caché: input_tokens, output_tokens, cache_creation_input_tokens y cache_read_input_tokens.
Una escritura en caché se muestra como cache_creation_input_tokens distinto de cero; un acierto de caché se muestra como cache_read_input_tokens distinto de cero.
Dado que la caché falla silenciosamente —un fallo de caché nunca genera un error—, verificar estos campos en cada solicitud, no solo durante el desarrollo, es la única forma de saber si tu configuración de caché está funcionando realmente en producción.
Esta página crea una pequeña utilidad reutilizable para esa verificación y repasa los valores que deberías esperar en cada etapa del ciclo de vida de una solicitud.
Receta
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=200,
system=[
{
"type": "text",
"text": "Eres el asistente de soporte de Acme Corp." * 200,
"cache_control": {"type": "ephemeral"},
}
],
messages=[{"role": "user", "content": "¿Cuál es tu plazo de reembolso?"}],
)
usage = response.usage
print("input_tokens:", usage.input_tokens)
print("cache_creation_input_tokens:", usage.cache_creation_input_tokens)
print("cache_read_input_tokens:", usage.cache_read_input_tokens)Cuándo usar esto:
- Justo después de añadir tu primer breakpoint
cache_control, para confirmar que funciona en absoluto. - En el registro o métricas de producción, para detectar una regresión en la caché en el momento en que ocurra.
- Al depurar una factura que es más alta de lo esperado para una carga de trabajo supuestamente cacheada.
- Cada vez que cambies el contenido del prompt y quieras confirmar que la caché sigue funcionando después.
Ejemplo de funcionamiento
import anthropic
client = anthropic.Anthropic()
SYSTEM_TEXT = "Eres el asistente de soporte de Acme Corp. A continuación se presenta material de referencia.\n" + ("Detalle de la política. " * 300)
def ask_with_cache_check(question: str) -> str:
"""Envía una solicitud cacheada e informa exactamente de lo que ocurrió con la caché."""
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=300,
system=[
{
"type": "text",
"text": SYSTEM_TEXT,
"cache_control": {"type": "ephemeral"},
}
],
messages=[{"role": "user", "content": question}],
)
usage = response.usage
if usage.cache_read_input_tokens > 0:
status = "HIT"
elif usage.cache_creation_input_tokens > 0:
status = "WRITE (primera llamada o TTL caducado)"
else:
status = "SIN ACTIVIDAD DE CACHÉ (breakpoint demasiado pequeño o ausente)"
print(
f"[{status}] read={usage.cache_read_input_tokens} "
f"write={usage.cache_creation_input_tokens} "
f"input={usage.input_tokens} output={usage.output_tokens}"
)
return response.content[0].text
ask_with_cache_check("¿Cuál es tu plazo de reembolso?")
ask_with_cache_check("¿Hacen envíos internacionales?")Lo que esto demuestra:
- Una verificación de estado en tres partes: acierto de caché, escritura de caché o ninguna actividad de caché.
- Llamar a la misma función dos veces seguidas con un bloque de sistema idéntico: la segunda llamada debería reportar
HIT. - Mostrar los cuatro campos de uso relevantes juntos, para que una regresión sea visible de un vistazo en lugar de requerir búsquedas separadas.
- Un patrón que puedes incorporar en el registro de solicitudes sin cambiar el manejo real de la respuesta de tu aplicación.
Análisis en profundidad
Cómo funciona
response.usagese rellena en cada llamada exitosa amessages.create(), ya sea que la caché esté configurada o no.cache_creation_input_tokenscuenta los tokens escritos en la caché en esta llamada: distinto de cero en una escritura nueva o después de que expire el TTL.cache_read_input_tokenscuenta los tokens leídos de una entrada de caché existente: distinto de cero solo en un acierto real.input_tokensrefleja los tokens procesados normalmente, fuera de cualquier segmento cacheado: esto suele ser pequeño una vez que la caché está funcionando, ya que es solo la cola no cacheada de tu prompt.- Ninguno de estos campos genera una advertencia o error en caso de fallo; un fallo de caché se ve exactamente como una solicitud normal que, además, lleva un valor
cache_creation_input_tokens.
Lectura de los Cuatro Campos Juntos
| Escenario | cache_creation_input_tokens | cache_read_input_tokens | input_tokens |
|---|---|---|---|
| Primera llamada (caché fría) | Alto | 0 | Bajo (solo cola no cacheada) |
| Llamada repetida, caché aún activa | 0 | Alto | Bajo (solo cola no cacheada) |
| Caché caducada, reescrita | Alto (de nuevo) | 0 | Bajo |
No se usó cache_control | 0 | 0 | Tamaño completo del prompt |
| Prefijo cambiado, caché invalidada | Alto (de nuevo) | 0 | Bajo |
Notas de Python
# Los campos de uso son enteros simples en el objeto de uso tipado del SDK;
# es seguro compararlos, sumarlos o registrarlos directamente sin análisis adicional.
usage = response.usage
total_cached_prefix_tokens = usage.cache_read_input_tokens + usage.cache_creation_input_tokens
hit_ratio = (
usage.cache_read_input_tokens / total_cached_prefix_tokens
if total_cached_prefix_tokens
else 0.0
)Parámetros y Valores de Retorno
| Campo | Tipo | Descripción |
|---|---|---|
usage.input_tokens | int | Tokens procesados normalmente, fuera de cualquier prefijo cacheado. |
usage.output_tokens | int | Tokens generados por Claude en la respuesta. |
usage.cache_creation_input_tokens | int | Tokens escritos en la caché en esta llamada. |
usage.cache_read_input_tokens | int | Tokens leídos de una entrada de caché existente en esta llamada. |
Trampas comunes
- Solo verificar
input_tokensy asumir que la caché está "funcionando".input_tokenspor sí solo no te dice si se leyó una caché; necesitas los dos campos específicos de la caché. Solución: siempre registra los cuatro campos de uso juntos, no solo los tokens totales. - Probar la caché con una sola solicitud. La primera llamada a un prefijo nuevo es siempre una escritura, nunca un acierto; probar con una llamada y ver
cache_read_input_tokens == 0es lo esperado, no un error. Solución: prueba siempre con al menos dos llamadas consecutivas que compartan el mismo prefijo. - Asumir que un
cache_creation_input_tokensdistinto de cero significa que algo está mal. Una escritura es completamente normal en la primera llamada o después de que expire un TTL; no es una señal de error en sí misma. Solución: solo considera "sin actividad de caché de ningún tipo" o "una escritura inesperada en lo que debería ser una llamada repetida" como una señal de alerta. - No registrar el uso en producción, solo en pruebas locales. Las regresiones de caché por un cambio de prompt a menudo se publican sin ser detectadas porque nadie está vigilando
cache_read_input_tokensen el sistema en vivo. Solución: emite estos campos a tu canalización de métricas o registro en cada solicitud, no solo durante el desarrollo. - Comparar la tasa de aciertos entre solicitudes con prefijos diferentes. Una caída en la tasa de aciertos agregada puede significar que un prefijo específico comenzó a fallar, no que la caché en general "dejó de funcionar". Solución: etiqueta tus métricas de caché según el prompt/endpoint de donde provienen para poder aislar el prefijo afectado.
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| Verificación de uso por solicitud (esta página) | Necesitas la verdad fundamental en cada llamada | Solo necesitas una idea aproximada del gasto general |
| Revisión del panel de facturación agregado | Verificación puntual de las tendencias generales de gasto periódicamente | Necesitas detectar una regresión en el momento en que ocurre |
Depuración manual basada en print | Investigación local única de un prompt específico | Cualquier entorno de producción o CI: no es duradero ni consultable |
Preguntas frecuentes
¿Qué campo me dice que una solicitud fue un acierto de caché?
usage.cache_read_input_tokens. Un valor distinto de cero allí significa que la solicitud reutilizó con éxito un prefijo previamente cacheado.
¿Qué campo me dice que una solicitud escribió en la caché?
usage.cache_creation_input_tokens. Un valor distinto de cero significa que esta llamada cacheó contenido que no estaba previamente cacheado, o que había caducado.
¿Es normal que la primera solicitud a un nuevo prompt muestre cero cache_read_input_tokens?
Sí, la primera llamada a cualquier prefijo dado es siempre una escritura, no un acierto. Necesitas al menos dos llamadas con un prefijo idéntico para ver una lectura.
¿Un fallo de caché genera una excepción o advertencia?
No. Un fallo de caché simplemente se ve como una solicitud normal; la única diferencia es qué campos de uso son distintos de cero. No hay una señal de error separada.
¿Qué significa si tanto cache_creation_input_tokens como cache_read_input_tokens son cero?
O no se estableció ningún breakpoint cache_control, o el contenido marcado para caché era demasiado pequeño para valer la pena cachearlo. Comprueba que tu breakpoint esté realmente presente en la solicitud.
¿Puede una sola respuesta mostrar tanto cache_creation_input_tokens como cache_read_input_tokens como distintos de cero?
Sí, si tienes múltiples breakpoints: un segmento anterior puede alcanzar una entrada de caché existente mientras que un segmento posterior escribe una nueva en la misma solicitud.
¿Cómo creo una métrica de tasa de aciertos a partir de estos campos?
Divide cache_read_input_tokens por la suma de cache_read_input_tokens y cache_creation_input_tokens para un prefijo dado, rastreado durante una ventana de solicitudes.
¿Debería registrar estos campos en producción, o solo durante el desarrollo?
En producción. Las regresiones de caché son silenciosas por diseño; la única forma de detectar una en la naturaleza es vigilando continuamente estos campos, no solo cuando configuraste la caché por primera vez.
Si input_tokens es bajo, ¿significa eso que la caché está funcionando?
No por sí solo; verifica cache_read_input_tokens directamente. Un input_tokens bajo combinado con un cache_creation_input_tokens distinto de cero solo significa que estás en medio de una escritura, no necesariamente que ya estás alcanzando la caché.
¿Cuál es la forma más rápida de confirmar que la caché está configurada correctamente?
Envía la misma solicitud exacta dos veces seguidas y verifica que la segunda respuesta muestre cache_read_input_tokens distinto de cero. Si no es así, el breakpoint o el prefijo no son estables entre las dos llamadas.
Relacionado
- Cómo funciona realmente la coincidencia de prefijos del Prompt Caching - por qué un acierto requiere contenido idéntico byte a byte.
- Conceptos básicos del Prompt Caching - el primer breakpoint que esta página verifica.
- Depuración de invalidadores de caché silenciosos en prompts largos - qué hacer cuando esta verificación revela un problema.
- Tormentas de fallos de caché de prompts - Diagnóstico de picos repentinos de costos y latencia - respuesta a incidentes de producción para un fallo generalizado de la caché.
Versiones de Stack: Escrito contra la línea de modelos Claude actual a partir de ~junio de 2026 — Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (el predeterminado) y Claude Haiku 4.5 — y el SDK oficial
anthropicde Python (última versión 0.x). Los nombres de los modelos, las versiones del SDK y los precios cambian rápidamente; verifica los detalles actuales en platform.claude.com/docs antes de confiar en ellos.