PTENES
Saltar al contenido
MÓDULO 3.2

🏛️ Arquitectura pro caché y auditoría

La mejor caché es la que nunca invalida sin querer. Aquí diseñas el prefijo —system congelado, tools determinísticas, un modelo por loop, forks que copian al padre— y obtienes una lista de verificación y un prompt de auditoría para ejecutar en Claude Code.

6
Temas
~45
Minutos
Avanzado
Nivel
Práctica
Tipo
1

🧊 System prompt congelado

O prompt de sistema (el texto de instrucciones antes de la conversación) queda justo al principio del prefijo. Si interpolas fecha/hora, modo o nombre del usuario ahí, cada solicitud tiene bytes diferentes al comienzo — y invalida todo. La regla es: system congelado; el contexto dinámico va después, en las messages.

✗ system interpolado system + "hoy es {data}, user {nome}" cambia en cada turno messages → la caché se invalida en cada turno ✓ system congelado system fijo (sin variables) 🧊 idéntico byte a byte messages + "hoy es {data}, usuario {nome}" → prefijo estable, caché caliente

Leyenda: lo dinámico no desaparece — cambia de lugar. Sale de adelante (system) y va al final (messages), donde no rompe el prefijo.

Congela

System sin variables

Dinámico

Va al final de los messages

Frente

System está casi en la posición 0

1 byte

Basta para invalidar

2

🔤 Tools deterministas

La lista de tools se muestra en la posición 0 — antes que todo. Si la armas de una set/dict sin ordenar, el orden varía entre solicitudes y la caché nunca coincide. Serializa siempre en el mismo orden: ordena por nombre.

✗ Orden variable

tools = [t for t in registry]
# registry é um set/dict
# ordem muda entre requests → miss

✓ Orden estable

tools = sorted(registry, key=lambda t: t["name"])
# mesma ordem sempre → prefixo idêntico
# cache_read para de ser 0
Prompt listo — revisión para optimizar el caché (system + tools)

Objetivo

Hacer que Claude Code señale qué, en tu system prompt y en el montaje de las tools, está impidiendo el caché, y reescribir para maximizar el hit.

Prompt (pégalo en Claude Code)

Revise meu system prompt e a montagem de `tools` em <caminho/do/arquivo>.
Aponte o que está impedindo o prompt caching:
1) interpolação dinâmica no system (data/hora, nome do usuário, modo,
   uuid, qualquer coisa que muda entre requests);
2) ordem não-determinística das tools (montadas de set/dict sem sort).
Depois reescreva: (a) congele o system e mova o dinâmico pro fim das
messages; (b) serialize as tools em ordem estável (ordene por nome).
Mostre o diff e explique por que cada mudança preserva o prefixo.

Cómo verificar

Haz dos solicitudes iguales después del cambio y revisa el usage: cache_read_input_tokens debe dejar de ser 0 a partir de la 2.ª. Si aún aparece 0, quedó un invalidator en el prefijo (consulta el tema 5).

Posición 0

Tools van antes que todo

sorted()

Ordena por nombre

set/dict

El orden varía = miss

Estable

Mismos bytes = hit

3

🚫 No cambiar de modelo a mitad de camino

La caché es por modelo. Cambiar de modelo a mitad de camino lo invalida todo: el prefijo almacenado en caché de un modelo no sirve para el otro. ¿Necesitas un modelo más barato para una subtarea? Usa un subagente, manteniendo el loop principal en un solo modelo.

Bucle principal — un solo modelo (caché caliente) modelo A modelo A modelo A delega una subtarea subagente · modelo económico caché propia, no toca la del padre cambiar al modelo B en el loop → reset total

Leyenda: el loop morado queda en un solo modelo; el subagente cian usa otro modelo sin tocar la caché del padre.

Por qué lo resuelve un subagente

El subagente tiene su propio prefijo y su propia caché. Ejecuta la subtarea con el modelo más económico y devuelve el resultado como texto; el bucle principal sigue usando el mismo modelo, con la caché intacta.

Por modelo

La caché no se comparte entre modelos

Cambiar = reset

Invalida todo

Subagente

Modelo barato aparte

Uno por loop

Mantiene la caché caliente

4

🌿 Fork reutiliza el prefijo del padre

Una operación lateral — un resumen, un subagente — que vuelve a armar system/tools/model diferentes pierde la caché del padre. Para reutilizar el prefijo caliente, el fork necesita copiar system/tools/model verbatim y solo anexar lo específico al final.

PADRE — prefijo caliente tools → system → model ya está en caché ✓ copia verbatim + añade al final tools → system → model (idénticos) + tarea reutiliza la caché del padre · solo guarda el bloque nuevo ✗ vuelve a ensamblar system/tools/model diferentes paga el prefijo desde cero

Leyenda: el fork cian hereda el prefijo del padre (solo guarda el sufijo); el fork rojo lo reconstruye y vuelve a cobrar todo.

✓ Fork que reutiliza

  • ✓Copia system byte a byte
  • ✓Mantiene la misma lista de tools y el mismo model
  • ✓Anexa la instrucción específica solo al final

✗ Fork que pierde

  • ✗Escribe un system nuevo «conciso» para el resumen
  • ✗Pasa otro conjunto de tools u otro modelo
  • ✗Resultado: prefijo diferente, caché desde cero
Verbatim

Copia system/tools/model

Al final

Anexa lo específico

Hereda

Reutiliza el caché del padre

Volver a montar

= pagar desde cero

5

🔎 Lista de verificación de invalidadores silenciosos

Uno invalidator silencioso no da error — solo hace cache_read_input_tokens quedar siempre en 0. Antes de culpar al modelo, revisa todo lo que alimenta el prefijo y busca a estos sospechosos.

Revisa lo que entra en el prefijo tools system messages buscando variación reloj · uuid · sort · set

Leyenda: cualquier fuente de variación en lo que se convierte tools/system cambia el prefijo y derriba la caché en silencio.

Los 6 sospechosos de siempre

  • ☐datetime.now() / Date.now() en system
  • ☐uuid o un id aleatorio en el prefijo
  • ☐json.dumps sin sort_keys=True
  • ☐Iterar un set (orden no garantizado)
  • ☐tools configurados por usuario/modo
  • ☐Sección condicional en el system (if flag: system += …)

Síntoma → causa

cache_read_input_tokens siempre 0 en requests repetidos = hay un invalidador. Compara con diff los bytes del prefijo entre dos requests iguales y el byte que cambia es el culpable (el tema 4 del módulo 3.3 tiene el prompt listo para eso).

Silencioso

No da error

leer = 0

El único síntoma

6 sospechosos

Revisa el prefijo

Diff

Encuentra el byte responsable

6

🔥 Precalentamiento y TTL 1h

Una solicitud con max_tokens: 0 al iniciar la app guarda el caché del prefijo y regresa de inmediato — elimina la latencia del primer request real. Solo sirve si se cumplen tres condiciones; y, para el tráfico con pausas largas, existe también el TTL de 1h (escritura ~2×).

tiempo la app inicia max_tokens: 0 guarda el caché · regresa de inmediato 1.er usuario prefijo ya caliente → respuesta rápida

Leyenda: el precalentamiento paga el write antes del tráfico, para que el primer usuario no note la latencia de la escritura.

✓ Precargar vale cuando

  • ✓La 1.ª latencia es visible para el usuario
  • ✓El prefijo es grande (vale la pena guardarlo)
  • ✓Hay un momento antes del tráfico (boot/deploy)

TTL de 1h

  • •Write más caro (~2× en lugar de ~1,25×)
  • •Aplica al tráfico con gaps > 5 min
  • •Mantiene caliente el caché durante pausas largas
max_tokens: 0

Registra sin generar una respuesta

Antes del tráfico

Boot/deploy

TTL 1h

Brechas > 5 min

~2×

Write de 1h

Resumen del módulo

✓
System congelado — nada de fecha/hora/nombre; lo dinámico va al final de las messages.
✓
Tools deterministas — ordena por nombre; set/dict sin sort = miss.
✓
Un modelo por loop — cambiar de modelo reinicia; usa un subagente para una subtarea de bajo costo.
✓
Fork copia al padre — system/tools/model verbatim + específico al final.
✓
Lista de verificación de invalidadores — reloj, uuid, sort, set, tools por usuario, condicional en system.
✓
Calentamiento y TTL de 1h — max_tokens: 0 en el boot; 1 h para gaps largos.

Siguiente módulo

3.3 — Prompts listos (copiar y ejecutar): el kit de 6 prompts para auditar y corregir la caché en Claude Code.