🔧 Técnico — el caché en acción
Ahora que los términos están claros, veamos el caché funcionando de verdad: cómo se comporta en una conversación que crece, qué adjunta sin romper y lo que reinicia la posición 0, y la invalidación a fondo, con ejemplos copy-run para ejecutarlo en tu Claude Code.
La caché no es una batería que se descarga: la parte leída de la caché crece en cada turno. Un turno con algo nuevo (por ejemplo, una skill grande) marca menos; el resto se convierte en lectura barata en el siguiente.
Todo en esta ruta parte de un único invariante: el prompt caching es un
coincidencia de prefijo. La clave del caché son los bytes exactos del prompt
hasta el punto de corte, y el orden de montaje siempre es
tools → system → messages. Guarda esta frase: explica
por qué agregar al final es seguro y por qué cambiar la lista de herramientas lo rompe todo.
Los tres campos que auditarás todo el tiempo: cache_read_input_tokens
(leído desde la caché, ~0,1×), cache_creation_input_tokens (guardado, ~1,25×)
y input_tokens (solo el resto que no está en caché, precio completo). La
suma de los tres es el tamaño del prompt. Si el campo de lectura queda
cero al repetir el mismo prefijo, hay un invalidator silencioso.
Mapa de la ruta
Contenido detallado
💬 El caché en una conversación
El prefijo estable crece, cada turno vuelve a leerlo a bajo costo y el % de caché SUBE: no se descarga. Dónde entra la escritura en frío y por qué la pausa larga cuesta.
system + tools + todo el historial (incluida la última respuesta) forman el prefijo estable, que crece en cada turno.
Es lo que hace que la conversación sea barata: cuanto mayor sea el prefijo estable, más tokens cuestan ~0,1×.
Prefijo = comienzo idéntico que se repite; solo el final nuevo queda fuera del caché.
Con cada mensaje nuevo, solo cambia el final; la API vuelve a leer todo el prefijo del caché (~0,1×) y escribe solo el bloque nuevo.
Explica por qué el segundo turno en adelante es mucho más barato que el primero.
Hit = lectura de la caché; write = registro del bloque nuevo de ese turno.
Mientras respondas dentro de ~5 min, la ventana se renueva y el caché sigue caliente.
Trabajar a un ritmo continuo mantiene todo barato sin esfuerzo.
TTL = tiempo de vida de la entrada; cada uso reinicia el reloj de los 5 min.
Un turno puede marcar 40% (hubo contenido nuevo, por ejemplo, una skill grande). Ese bloque se convierte en read barato en el próximo turno, y el porcentaje sube.
Corrige la intuición equivocada de que el caché "se acaba"; solo mejora a medida que avanza la conversación.
Turno actual: 40k leído / 60k nuevo = 40%; próximo turno: ~100k leído / ~1k nuevo ≈ 99%.
El 1.er mensaje escribe el caché (cuesta un poco más); no hay un prefijo anterior que leer.
Evita el susto de ver el 1.º turno «caro»: es el único que escribe todo.
Write ~1,25× (TTL 5 min); a partir del 2.º turno predomina la lectura ~0,1×.
Pasados ~5 min sin actividad, el TTL vence y el siguiente mensaje vuelve a pagar la escritura.
Explica por qué retomar después del almuerzo «cuesta»: fue una escritura en frío, no un bug.
Para el tráfico con intervalos > 5 min, existe el TTL de 1 h (write ~2×).
🧩 Skills y herramientas: anexar vs. romper
El contenido nuevo al final (FIM) es seguro; modificar la lista de tools reinicia la posición 0. Por qué Tool Search lo agrega a propósito.
(a) LA DESCRIPCIÓN de la skill (línea breve en la lista) siempre queda en el prefijo estable. (b) EL CONTENIDO completo solo se incorpora cuando se invoca la skill.
Sin separar los dos, piensas que «toda skill es cara»; solo pesa el contenido, y una vez.
La descripción siempre está presente y es barata; el contenido se carga bajo demanda.
El contenido de la skill se añade AL FINAL del historial (no en la posición 0). Todo lo anterior sigue siendo válido y se lee a bajo costo; solo se escribe el bloque nuevo.
Quita el miedo a invocar skills en medio de la conversación: es un único write, no un reinicio.
Anexar al final = seguro; en los turnos siguientes, la skill ya es una lectura barata.
Las herramientas se renderizan en la posición 0 (antes de system e historial). Cambiar la lista tools invalida todo a partir de ahí.
Es el invalidante silencioso más costoso: un byte en la posición 0 descarta todo el prefijo.
Orden de montaje: tools → system → messages.
(1) Conectar/desconectar MCP a mitad de camino; (2) cambiar description/input_schema de una tool; (3) armar tools de un set/dict sin ordenar; (4) activar/desactivar tools según el modo o los permisos.
Son las 4 causas más comunes de que el caché «desaparezca» sin motivo aparente.
Basta con que cambie una palabra en una description para invalidar la posición 0.
Tool Search carga el esquema de una herramienta AÑADIÉNDOLO (no reemplazando la lista); está hecho justamente para NO romper la caché.
Distingue entre "descubrir una tool mediante Tool Search" (seguro) y "conectar un MCP que reescribe la lista" (la rompe).
Anexar el schema al final = una única escritura; reescribir tools = reinicio.
El contenido nuevo al final (FIM) es seguro. Modificar la lista de tools o en el system prompt = reinicio de la posición 0.
Una frase que resuelve el 90% de las decisiones cotidianas sobre el cache.
Pregunta siempre: "¿esto cambia el comienzo o solo añade algo al final?"
🔎 Invalidación en profundidad
Jerarquía de 3 tiers, el lookback de 20 bloques, los invalidadores silenciosos y el timing concurrente en el fan-out. Cómo auditar con usage.
El cambio solo invalida su tier y los inferiores: cambiar las tools O cambiar de modelo = reinicio total; cambiar el system = invalida system+messages; cambiar un mensaje = solo messages.
Calculas el «radio de impacto» de cualquier cambio antes de hacerlo.
Tiers en orden tools → system → messages; el modelo es la raíz de todo.
Cambiar tool_choice por request o activar/desactivar thinking mantiene la caché de tools+system.
Evita la paranoia: no todos los parámetros que cambian por request rompen el caché.
Estos dos no entran en el prefijo cacheable; no tienes que preocuparte.
Cada breakpoint busca la entrada anterior revisando como máximo 20 bloques. Un turno que agrega >20 bloques (bucles con muchos tool_use/tool_result) puede hacer que el siguiente turno no encuentre la caché sin avisar.
Es la causa «invisible» de que falle la caché en agentes que hacen muchas llamadas a herramientas por turno.
Fix: un breakpoint intermedio cada ~15 bloques.
datetime.now()/Date.now()/uuid en system; json.dumps sin sort_keys=True; iterar set; herramientas montadas por el usuario; sección condicional en el system.
Son cambios que no «ves», pero que alteran los bytes del prefijo en cada solicitud.
Síntoma común: cache_read_input_tokens siempre 0.
La entrada solo se puede leer DESPUÉS de que comienza a transmitirse la 1.ª respuesta. N solicitudes paralelas con el mismo prefijo pagan todas el precio completo.
Lanzar todo de una vez parece rápido, pero descarta el caché compartido.
Fix: enviar 1, esperar el 1.er token y lanzar los N-1.
cache_read_input_tokens / cache_creation_input_tokens en la respuesta. Cero en requests repetidos = tiene invalidator.
Es el instrumento de medición: sin él, estimas; con él, lo pruebas.
Compara los bytes del prompt entre dos requests iguales para encontrar el byte que cambia.