PTENES
Saltar al contenido
MÓDULO 2.3

🔎 Invalidación en profundidad

La anatomía completa de la invalidación: la jerarquía de 3 tiers, lo que no elimina el caché, el 20-block lookback, los invalidadores silenciosos, el timing del fan-out y cómo auditar con usage.

6
Temas
~35
Minutos
Técnico
Nivel
Práctica
Tipo
0% 0 de 6
1

🪜 Jerarquía de 3 niveles

La invalidación sigue una jerarquía de 3 tiers: un cambio solo invalida el su nivel y los de abajo. Como el orden es tools → system → messages, tocar más el inicio tiene un mayor radio de daño.

Qué es

Los tres tiers son capas en cascada. El modelo es la raíz: cambiarlo invalida todo. Después vienen tools, system y messages, cada uno se invalida a sí mismo y a los que vienen después.

Por qué aprenderlo

Porque permite calcular el "radio de daño" de cualquier cambio antes de hacerlo: cambiar un mensaje cuesta poco; modificar tools o cambiar el modelo cuesta el prefijo entero.

nivel 1 · tools (posición 0) nivel 2 · system nivel 3 · messages cambia tools → invalida los 3 cambia system → system + messages cambia el mensaje → solo messages cambiar de modelo = raíz de todo → reinicio total

Cuanto más al principio (tools) ocurre el cambio, mayor es el efecto en cascada. Un mensaje nuevo al final casi no cuesta.

Conceptos clave

CambioLo que lo invalida
cambiar de modelotodo (tools + system + messages)
cambiar toolstodo (tools + system + messages)
cambiar systemsystem + messages
cambiar mensajesolo messages
2

🎚️ tool_choice / thinking on-off

No todo lo que cambia por solicitud rompe el caché. Cambiar tool_choice en cada solicitud, o activar/desactivar thinking, mantiene el caché de tools+system. Son parámetros que no entran en el prefijo almacenable en caché — no tienes que preocuparte por ellos.

Qué es

tool_choice e thinking son controles de comportamiento del request, no bytes del prefijo. Cambiarlos no modifica la coincidencia del prefijo.

Por qué aprenderlo

Porque evita la paranoia. Es fácil pensar que "cualquier cosa que cambie por request derriba el caché"; entonces dejas de usar recursos útiles por un miedo infundado.

✓ Puede variar libremente

  • ✓tool_choice diferente por request.
  • ✓Activar/desactivar thinking.

✗ Sigue provocando caídas

  • ✗Cambiar la lista tools.
  • ✗Editar el system prompt.

Conceptos clave

tool_choice no entra en el prefijo.

thinking on/off conserva tools+system.

Lo que lo derriba es contenido del prefijo.

Sin paranoia: no todos los parámetros fallan.

3

🔭 20-block lookback

Cada breakpoint busca la entrada anterior revisando como máximo 20 bloques hacia atrás. Un turno que agrega más de 20 bloques — loops con muchos tool_use/tool_result — puede hacer que el siguiente turno hacer que el caché falle silenciosamente.

Qué es

El lookback es la ventana de búsqueda del breakpoint: solo encuentra el prefijo almacenado en caché si está dentro de los 20 bloques anteriores. Si queda más atrás, no lo encuentra, aunque la caché exista.

Por qué aprenderlo

Porque es la causa "invisible" de fallos de caché en agentes que hacen muchas llamadas a herramientas por turno. El prefijo no cambió, pero el breakpoint no llega a la entrada anterior.

entrada de caché anterior (fuera de la ventana) ✗ no alcanzable ventana de lookback = últimos 20 bloques breakpoint un bucle con > 20 tool_use/tool_result expulsa la entrada anterior → miss silencioso Fix: un breakpoint intermedio cada ~15 bloques

Recreación ilustrativa. Lo importante: en loops largos, inserta un breakpoint intermedio antes de superar los 20 bloques.

Consejo práctico

Si tu agente hace muchas llamadas a herramientas por turno y el caché «desaparece» sin que haya cambiado el prefijo, sospecha del lookback. Un breakpoint intermedio cada ~15 bloques mantiene la entrada dentro de la ventana.

Conceptos clave

Lookback = 20 bloques hacia atrás.

Turno con >20 bloques = riesgo de miss.

Común en loops de tool_use/tool_result.

Fix: un breakpoint cada ~15 bloques.

4

👻 Invalidadores silenciosos

Invalidadores silenciosos son bytes que cambian en el prefijo sin que te des cuenta. Los clásicos: 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 (if flag: system += ...).

Qué es

Son fuentes de no determinismo que alteran el prefijo en cada solicitud, incluso con el caché caliente. A diferencia del write frío (por tiempo), aquí el problema es que el contenido cambia.

Por qué aprenderlo

Porque son la causa n.º 1 de que el caché "nunca funcione". El síntoma siempre es el mismo: cache_read_input_tokens siempre 0.

✗ Invalidantes silenciosos comunes

  • ✗datetime.now() / Date.now() / uuid en system.
  • ✗json.dumps sin sort_keys=True.
  • ✗Iterar set (orden variable).
  • ✗Tools montadas por el usuario.
  • ✗Sección condicional en el system (if flag: system += ...).

✓ Correcciones

  • ✓Inyecta fecha/hora en las messages, no en el system.
  • ✓Serializa con sort_keys=True.
  • ✓Ordena con sorted(...) antes de montar.
  • ✓Congela el system; mueve lo dinámico al final.

Síntoma

cache_read_input_tokens siempre 0 al repetir el mismo prefijo. Es la señal de que hay un invalidator silencioso activo.

5

🌐 Timing concurrente (fan-out)

La entrada del caché solo queda legible DESPUÉS que la 1.ª respuesta empieza a transmitir. Entonces N solicitudes paralelos con el mismo prefijo pagan todos a precio completo — ninguno ha visto la caché del otro todavía.

Qué es

En el fan-out (lanzar varios agentes/solicitudes a la vez), el primer request todavía no terminó de guardar el prefijo cuando los demás se inician. Todos guardan desde cero.

Por qué aprenderlo

Porque lanzar todo junto parece más rápido, pero desperdicia el caché compartido. Un pequeño cambio en el orden de lanzamiento permite ahorrar mucho.

✗ N al mismo tiempo → todos llenos plan solicitud · 1× solicitud · 1× solicitud · 1× ✓ 1 primero → luego los N-1 solicitud 1 guarda (espera el 1.er token) lee · 0,1× lee · 0,1× lee · 0,1×

Fix: enviar 1, esperar el 1.er token (el caché queda legible) y solo entonces lanzar los N-1, que ahora leen desde el caché a bajo costo.

Conceptos clave

Entrada legible solo después del 1.º stream.

N en paralelo con el mismo prefijo = todos 1×.

Fix: 1 → esperar el 1.er token → N-1.

Aplica al fan-out / a los subagentes paralelos.

6

🧪 Verificar con usage

El objeto es el instrumento de medición usage en la respuesta: cache_read_input_tokens e cache_creation_input_tokens. Cero en solicitudes repetidas = tiene un invalidator. Entonces haces diff de los bytes del prompt entre dos requests iguales para encontrar el byte que cambia.

Qué es

Auditar con usage es comparar los campos de caché entre dos solicitudes que deberían ser idénticas. Si la lectura no aumenta, algo está cambiando en el prefijo.

Por qué aprenderlo

Porque es la diferencia entre adivinar y demostrar. Con el diff de bytes localizas el invalidator silencioso exacto: la fecha, el uuid, la clave fuera de orden.

Ejemplo copy-run — auditar silent invalidators del pipeline

prompt · pega en Claude Code

Objetivo: hacer que Claude Code revise el código que arma el prompt y enumere cada silent invalidator + cómo corregirlo.

Audite o pipeline em <caminho da pasta/arquivo que monta
o prompt>. Procure especificamente, no que alimenta o
PREFIXO (tools + system), por:

  - datetime.now() / Date.now() / uuid interpolados no system
  - json.dumps(...) SEM sort_keys=True
  - iteração de set (ordem não-determinística)
  - montagem de `tools` a partir de set/dict sem sorted(...)
  - seções condicionais no system (if flag: system += ...)

Para cada ocorrência, aponte:
  1. arquivo e linha;
  2. por que quebra o cache (muda os bytes do prefixo);
  3. a correção (mover o dinâmico para as messages,
     sort_keys=True, sorted(...), congelar o system).

Cómo verificar: después de aplicar las correcciones, ejecuta el mismo pedido dos veces seguidas y compara el usage. O cache_read_input_tokens debe dejar de ser 0 en el 2.º request. Si todavía queda en 0, haz el diff de los bytes del prompt entre los dos requests para encontrar qué cambió.

Conceptos clave

usage = instrumento de medición.

Read 0 repetido = invalidator activo.

El diff de bytes localiza el cambio exacto.

Demostrar > adivinar: mide siempre.

Resumen del módulo

Jerarquía de 3 tiers — un cambio invalida su tier y los inferiores.
tool_choice / thinking no lo invalidan — no entran en el prefijo.
20-block lookback — los loops largos rompen la caché; fix: un breakpoint cada ~15 bloques.
Invalidadores silenciosos — fecha, uuid, dumps sin ordenar, set, condicional en el system.
Fan-out y usage — dispara 1 antes de los N-1; audita con usage.

Siguiente ruta:

Trilha 3 — Boas práticas avançadas (cache vs compactação, arquitetura pró-cache, prompts prontos)