Prompt caching no es un flag mágico que activas y ya. Es una técnica con una mecánica muy específica — y si no entiendes esa mecánica, vas a implementarlo y seguir pagando precio completo sin saber por qué.
El caching de prompts funciona sobre coincidencia de prefijo exacto. Esto significa que el sistema toma los bytes exactos del prompt renderizado hasta un punto de corte (`cache_control`) y los compara con la ejecución anterior. Si un solo byte cambia en cualquier parte de ese prefijo, todo lo que viene después de ese punto se invalida — no solo la parte que cambió.
El orden de renderizado es siempre: herramientas (`tools`) → prompt de sistema (`system`) → mensajes (`messages`). Un breakpoint puesto al final del bloque de sistema cachea tools + system juntos.
Esto tiene una implicación práctica enorme: el contenido estable debe ir *físicamente antes* que el contenido volátil en tu prompt renderizado. Si metes la fecha actual o un UUID al principio del system prompt, invalidas el caché en cada request sin importar cuántos `cache_control` pongas después.
Para TTL de una hora en vez de cinco minutos: `{"type": "ephemeral", "ttl": "1h"}`. El máximo son 4 breakpoints por request, y se pueden poner en cualquier bloque de contenido: texto del sistema, definiciones de herramientas, o bloques dentro de los mensajes.
Un cache read cuesta aproximadamente 10% del precio de input normal. Pero un cache write no es gratis: cuesta 1.25x el precio normal con TTL de 5 minutos, y 2x con TTL de 1 hora. Esto significa que el punto de equilibrio depende de cuántas veces vas a reutilizar ese prefijo:
- Con TTL de 5 minutos: necesitas al menos 2 requests para salir ganando (1.25x + 0.10x = 1.35x, contra 2x sin cachear). - Con TTL de 1 hora: necesitas al menos 3 requests (2x + 0.20x = 2.2x, contra 3x sin cachear).
Si tu prefijo compartido solo se usa una vez, cachearlo te cuesta más, no menos. La técnica solo paga cuando hay reutilización real — sesiones de chat multi-turno, el mismo documento de contexto consultado repetidamente, o el mismo set de herramientas en un agente que hace muchas llamadas.
**System prompt compartido entre muchas requests.** Un breakpoint en el último bloque de texto del system prompt cachea tools + system juntos — el patrón más simple y el de mayor impacto en la mayoría de las apps.
**Conversaciones multi-turno.** Pon el breakpoint en el último bloque de contenido del turno más reciente. Cada request subsecuente reutiliza todo el prefijo previo de la conversación; los breakpoints anteriores siguen siendo puntos de lectura válidos, así que los hits se acumulan de forma incremental conforme crece la conversación.
**Prefijo compartido con sufijo variable** (few-shot examples + pregunta distinta cada vez, o contexto recuperado + pregunta del usuario): el breakpoint va al final de la parte *compartida*, no al final del prompt completo.
Cuando el caching "no funciona" (`cache_read_input_tokens` en cero request tras request), casi siempre es uno de estos:
| Patrón | Por qué rompe el caché | |---|---| | `datetime.now()` en el system prompt | El prefijo cambia en cada request | | UUIDs o IDs de request al inicio del contenido | Mismo problema — cada request es única | | `json.dumps(d)` sin `sort_keys=True`, o iterar un `set` | Serialización no determinista → los bytes difieren aunque el contenido sea "el mismo" | | Secciones condicionales de sistema (`if flag: system += ...`) | Cada combinación de flags es un prefijo distinto | | Set de herramientas que varía por usuario | Las herramientas se renderizan en la posición 0 — nada cachea entre usuarios distintos |
La forma de diagnosticar esto es simple: compara byte a byte el prompt renderizado entre dos requests que "deberían" ser idénticas. En el 90% de los casos el problema salta a la vista en los primeros 500 caracteres.
No todos los cambios invalidan el caché completo. Hay tres niveles: caché de herramientas, de sistema, y de mensajes. Cambiar `tool_choice`, activar/desactivar `thinking`, o agregar imágenes invalida sistema y mensajes pero no herramientas. Cambiar el modelo o la definición de una herramienta sí invalida todo. Saber esto evita el error de asumir que cualquier ajuste menor te obliga a reconstruir el caché desde cero.
Si la latencia del primer request es visible para el usuario (chat interactivo, no un job en batch), puedes eliminar el costo de ese primer cache-miss enviando una request con `max_tokens: 0` al arrancar tu servicio. El sistema ejecuta el prefill — escribe el caché en tu breakpoint — y regresa de inmediato sin cobrar tokens de salida.
Solo vale la pena si tu tráfico tiene huecos más largos que el TTL del caché — si las requests reales llegan cada menos de 5 minutos, ya se mantienen calientes solas y un pre-calentamiento adicional es puro gasto extra.
Bien implementado, el prompt caching es la optimización de costo con mayor retorno por hora de trabajo en cualquier arquitectura de LLM en producción — pero solo si entiendes la mecánica de prefijo lo suficiente para no romperla sin darte cuenta.
Carlos Montiel es arquitecto de soluciones IA empresarial. Implementa LLMs, Agentes, RAG y orquestadores en empresas de Guatemala y Latinoamérica. Contáctalo para una consultoría.
Contactar a Carlos Montiel