Caché de prompts LLM #3: tutorial funcional en Python
Contenido
- 0. Configuración
- 1. La llamada consciente del caché (igual en todos los proveedores)
- 2. Anthropic Claude — marcadores cache_control explícitos
- 3. OpenAI GPT-5.x — caché automático
- 4. Google Gemini — caché implícito
- 5. DeepSeek-v4-flash — caché automático respaldado en disco
- 6. Alibaba Qwen — acierto reportado, descuento variable
- 7. Benchmark entre proveedores (medido el 2026-05-25)
- 8. Lista de verificación previa al lanzamiento
- 9. Patrones conscientes del TTL
- 8.1 Cargas de trabajo ligadas a la sesión (chat, asistentes de IDE)
- 8.2 Latido para batch / cron
- 8.3 Documentos en almacenamiento en frío
- 10. Lo que la pasarela realmente añade
- Preguntas frecuentes
TL;DR — Un solo SDK de OpenAI, una sola base_url, todos los grandes LLM. Las cifras de este artículo se midieron contra la pasarela Synthorai en producción el 2026-05-25 con un prompt de sistema estable de unos 7.300 tokens. El propósito de la pasarela aquí es modesto y honesto: un único endpoint, una única cabecera de autenticación y un campo usage.cost que te ahorra mantener una matriz de precios por proveedor. Las matemáticas del Transformer detrás del caché se cubren en la Parte 1: Principios del caché; las decisiones de diseño por proveedor están en la Parte 2: Comparación de proveedores.
Serie: Parte 3 de 4 · Anteriormente: Parte 1 — Principios del caché · Parte 2 — Comparación y evaluación de proveedores · Siguiente: Parte 4 — El mejor LLM por caso de uso
0. Configuración
pip install openai
# common.py — reused across every example
import os, time
from openai import OpenAI
oai = OpenAI(
api_key=os.environ["SYNTHORAI_KEY"],
base_url="https://synthorai.io/v1",
)
La pasarela habla el formato de transmisión de OpenAI para cada modelo que expone (GPT, Claude, Gemini, DeepSeek, Qwen). Cambias el campo model, no el SDK. La autenticación usa Authorization: Bearer <key>.
IDs de modelos con capacidad de caché disponibles en la pasarela pública (instantánea de 2026-05): claude-haiku-4-5, claude-sonnet-4-5 / 4-6, claude-opus-4-5 / 4-6 / 4-7, gpt-5.4-mini, gpt-5.4-nano, gpt-5.2, gpt-5.5-pro, gemini-2.5-flash, gemini-2.5-pro, gemini-3.1-pro-preview, deepseek-v4-flash, qwen3-max, qwen3.5-flash. La lista completa en vivo está en GET /v1/models.
1. La llamada consciente del caché (igual en todos los proveedores)
No tienes que optar por ello. Para cualquier modelo que admita caché de prompt en el upstream, la pasarela simplemente reenvía los metadatos de la respuesta. Dos campos te dicen qué ocurrió:
resp = oai.chat.completions.create(
model="gpt-5.4-mini",
max_tokens=128,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT}, # ~7K tokens
{"role": "user", "content": "First question"},
],
)
print(resp.usage.prompt_tokens_details.cached_tokens) # cache hit count
print(resp.usage.cost) # USD, gateway-computed
cached_tokens es el número de tokens de entrada que dieron en la caché de prefijo del upstream. usage.cost es el precio calculado por la pasarela para esta única llamada en USD — no hay necesidad de mantener localmente una tabla de tarifas por proveedor.
Dos reglas que se derivan de la arquitectura y se aplican a todos los proveedores:
- El contenido estable primero, el contenido volátil al final. El prefijo se compara desde el token cero; un solo byte modificado al principio invalida todo el prefijo.
- Mantén los datos dinámicos fuera del prompt de sistema. Las marcas de tiempo actuales, los IDs de sesión y los UUID de solicitud invalidarán el caché.
Todo lo que sigue son simplemente ejemplos por proveedor del mismo patrón.
2. Anthropic Claude — marcadores cache_control explícitos
Claude pertenece a la familia de marcadores explícitos — la API de Anthropic no almacena en caché automáticamente. Para obtener un acierto de caché, marca hasta cuatro puntos de ruptura cache_control en tu array system o messages. Las lecturas de caché cuestan ~10 % de la tarifa de entrada; las escrituras de caché cuestan 125 % (una prima del 25 %).
La forma más limpia de usar cache_control a través de la pasarela es con el SDK oficial anthropic apuntando al endpoint nativo de Anthropic de la pasarela (la ruta compatible con OpenAI /chat/completions no propaga actualmente los marcadores cache_control — usa /v1/messages para el caché de Claude).
import os
from anthropic import Anthropic
anth = Anthropic(
api_key=os.environ["SYNTHORAI_KEY"],
base_url="https://synthorai.io/", # SDK appends /v1/messages
)
msg = anth.messages.create(
model="claude-sonnet-4-5",
max_tokens=512,
system=[
{"type": "text", "text": SYSTEM_INSTRUCTIONS,
"cache_control": {"type": "ephemeral"}}, # BP 1: never changes
{"type": "text", "text": TOOL_DESCRIPTIONS,
"cache_control": {"type": "ephemeral"}}, # BP 2: rarely changes
{"type": "text", "text": RETRIEVED_DOCUMENTS}, # changes per call — not cached
],
messages=[{"role": "user", "content": question}],
)
print(msg.usage)
# Usage(input_tokens=18, output_tokens=64,
# cache_creation_input_tokens=0, cache_read_input_tokens=8123,
# cost=...)
Opciones de TTL. {"type": "ephemeral"} usa por defecto un TTL deslizante de 5 minutos (cada acierto empuja la expiración hacia adelante). Para cargas de trabajo con periodos de inactividad de más de 5 minutos, solicita el TTL de 1 hora en el mismo marcador:
"cache_control": {"type": "ephemeral", "ttl": "1h"}
Puntos de ruptura por capas. Hasta cuatro marcadores te permiten almacenar en caché «nunca cambia» + «rara vez cambia» + «cambia por tarea» de forma independiente — lo mejor de su clase para cargas de trabajo de agentes y RAG donde las secciones del prompt cambian a diferentes cadencias. Incluso cuando la capa final (p. ej. los documentos recuperados) cambia entre llamadas, las capas anteriores siguen acertando.
Elegir un modelo. IDs de Claude disponibles en la pasarela a fecha de 2026-05: claude-haiku-4-5, claude-sonnet-4-5 / 4-6, claude-opus-4-5 / 4-6 / 4-7. Haiku para chat económico; Sonnet para uso general con el patrón de caché de agente más sólido; Opus para las tareas de razonamiento más difíciles.
Referencia medida de acierto de caché / escritura / sin caché (2026-05-25, prompt de sistema de ~7.976 tokens, max_tokens=64):
| Modelo | Escritura de caché | Lectura de caché | Ref. sin caché | Descuento lectura | TTFT acierto (stream) |
|---|---|---|---|---|---|
claude-haiku-4-5 | $0.00916 | $0.00086 | $0.00725 | −88% | 1.31 s |
claude-sonnet-4-5 | $0.02713 | $0.00247 | $0.02175 | −89% | 1.76 s |
claude-sonnet-4-6 | $0.02736 | $0.00253 | $0.02198 | −88% | 1.81 s |
claude-opus-4-5 | $0.04522 | $0.00409 | $0.03624 | −89% | 2.08 s |
claude-opus-4-6 | $0.04522 | $0.00411 | $0.03625 | −89% | 2.55 s |
claude-opus-4-7 | $0.06545 | $0.00609 | $0.05259 | −88% | 2.30 s |
El descuento se mantiene uniforme en toda la familia. La prima de escritura es de aproximadamente un 25 % por encima de sin caché (la tarifa documentada de Anthropic); el punto de equilibrio es un solo acierto de caché.
3. OpenAI GPT-5.x — caché automático
OpenAI almacena automáticamente en caché cualquier solicitud con un prefijo lo suficientemente largo. Sin cambio de código, sin marcador.
def ask_gpt(question: str):
t0 = time.perf_counter()
resp = oai.chat.completions.create(
model="gpt-5.4-mini",
max_tokens=64,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": question},
],
)
return resp, time.perf_counter() - t0
r1, t1 = ask_gpt("Which export formats are supported?")
r2, t2 = ask_gpt("How long is the refund window for annual plans?")
print(t1, r1.usage.prompt_tokens_details.cached_tokens, r1.usage.cost)
# 3.63 0 0.00267
print(t2, r2.usage.prompt_tokens_details.cached_tokens, r2.usage.cost)
# 1.23 6400 0.00257
El mismo prompt de 6.887 tokens dos veces. Segunda llamada: el 93 % del prompt de sistema da en la caché, la latencia total cae de 3,6 s a 1,2 s. El coste apenas cambia aquí porque el descuento de caché se compensa con una completación más larga en la primera llamada — consulta §7 para cifras más limpias entre proveedores.
gpt-5.4-nano muestra el descuento con más claridad (reducción de coste del 44 % en el acierto). Para interfaces de chat donde solo te importa el tiempo hasta el primer token, lo que cuenta son las cifras de streaming:
def ttft(model, question):
t0 = time.perf_counter()
stream = oai.chat.completions.create(
model=model, max_tokens=64,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": question},
],
stream=True, stream_options={"include_usage": True},
)
for ev in stream:
if ev.choices and ev.choices[0].delta and ev.choices[0].delta.content:
return time.perf_counter() - t0 # first content token
TTFT medido en la pasada con caché: 0,73 s para gpt-5.4-mini, 1,00 s para gpt-5.4-nano.
4. Google Gemini — caché implícito
El caché de Gemini también es automático cuando pasas por la pasarela. No hay ningún paso de creación cachedContent que debas realizar.
r = oai.chat.completions.create(
model="gemini-2.5-flash",
max_tokens=128,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "Summarize section 6 in two bullets."},
],
)
print(r.usage.prompt_tokens_details.cached_tokens, r.usage.cost)
Un acierto medido en gemini-2.5-flash para un prompt de sistema de ~7.300 tokens: 7.140 tokens en caché (97 %), el coste cae de $0.00198 a $0.00024 — un 88 % menos para esa pasada.
Dos trampas que vale la pena conocer:
- Las variantes
*-prode Gemini son modelos de razonamiento. Con unmax_tokenspequeño, a menudo vescompletion_tokens=0porque el presupuesto lo consume el pensamiento oculto. Aumentamax_tokensa ≥256 para cualquier cosa orientada al usuario. - El TTL del caché implícito es corto y no está especificado oficialmente. En nuestra prueba, un acierto entre dos llamadas separadas por 5 s tuvo éxito; una tercera llamada unos 10 s después a veces falló. No diseñes lógica que asuma el acierto; comprueba
cached_tokensy degrada con elegancia.
5. DeepSeek-v4-flash — caché automático respaldado en disco
El caché automático de DeepSeek sobrevive más tiempo que los cachés residentes en memoria GPU de otros proveedores. La misma forma de llamada:
r1 = oai.chat.completions.create(
model="deepseek-v4-flash", max_tokens=128,
messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "Q1"}],
)
# r1.usage.cost = $0.00091, cached_tokens = 0
r2 = oai.chat.completions.create(
model="deepseek-v4-flash", max_tokens=128,
messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "Q2"}],
)
# r2.usage.cost = $0.00023, cached_tokens = 6784 → 74% saved
TTFT en streaming en la pasada con caché: 2,93 s. DeepSeek no es la opción de menor latencia de este conjunto — las ventajas están en el coste y en el hecho de que el caché se mantiene caliente a lo largo de intervalos de horas.
6. Alibaba Qwen — acierto reportado, descuento variable
r = oai.chat.completions.create(
model="qwen3-max", max_tokens=128,
messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "Q1"}],
)
print(r.usage.prompt_tokens_details.cached_tokens, r.usage.cost)
# 7040 0.00549
Salvedad observada en nuestra ejecución de prueba: cached_tokens reporta un acierto (7.040 de 7.234 = 97 %), pero usage.cost no bajó en la pasada con caché (sigue siendo ≈ $0.0055). Esto significa que el acierto de caché del upstream ocurrió (TTFT más rápido, 1,53 s frente a 3,03 s en frío), pero el campo de coste de la pasarela para este proveedor aún no reflejaba el descuento de tarifa de caché en esa fecha. Si eres sensible al coste en Qwen, vigila cached_tokens y confía en las páginas de precios del upstream hasta que esto se normalice.
7. Benchmark entre proveedores (medido el 2026-05-25)
Ejecución secuencial única. Prompt de sistema estable de 7.284 caracteres (~6.900–7.300 tokens según el tokenizador). max_tokens=64. Una llamada fallida seguida inmediatamente de una llamada acertada.
Los proveedores de caché automático (no se requiere marcador):
| Modelo | Coste fallo | Coste acierto | Δ coste | Total fallo | Total acierto | TTFT acierto (stream) | Tasa de acierto de caché |
|---|---|---|---|---|---|---|---|
gpt-5.4-nano | $0.00131 | $0.00074 | −44% | 2.18 s | 1.48 s | 1.00 s | 5,888 / 6,887 (85%) |
gpt-5.4-mini | $0.00267 | $0.00257 | −4%* | 3.63 s | 1.23 s | 0.73 s | 6,400 / 6,887 (93%) |
gemini-2.5-flash | $0.00198 | $0.00024† | −88% | 2.49 s | 1.37 s | n/a‡ | 7,140 / 7,322 (97%) |
gemini-2.5-pro | $0.00824 | $0.00205† | −75% | 2.99 s | 1.76 s | n/a‡ | 6,120 / 7,328 (84%) |
deepseek-v4-flash | $0.00091 | $0.00023 | −74% | 4.02 s | 3.71 s | 2.93 s | 6,784 / 7,101 (96%) |
qwen3-max | $0.00553 | $0.00549 | −1%§ | 4.80 s | 2.37 s | 1.53 s | 7,040 / 7,234 (97%) |
* La completación de la llamada fallida de gpt-5.4-mini fue de 44 tokens frente a 19 en el acierto — el delta de coste mezcla el descuento de caché con la diferencia de longitud de completación. La caída de latencia (3,63 → 1,23 s) es la señal más limpia aquí.
† Coste de la pasada en streaming (donde se reportó cached_tokens); la pasada sin stream a veces devolvía cached_tokens=null para Gemini y el coste no bajaba. Los metadatos de la pasarela para Gemini son actualmente inconsistentes — confía en cached_tokens cuando esté presente.
‡ Los modelos de razonamiento *-pro / *-flash de Gemini a menudo emiten cero tokens de contenido con un max_tokens pequeño, por lo que el TTFT carece de sentido con ese presupuesto. Aumenta max_tokens si mides esto en producción.
§ Consulta §6 — el acierto de caché del upstream ocurrió (la latencia bajó), pero el campo usage.cost de la pasarela no reflejó el descuento para qwen3-max en esa fecha.
Anthropic Claude se controla mediante marcadores explícitos; las cifras están en una tabla separada porque el descuento es opcional vía cache_control (consulta §2 para el patrón). El mismo prompt, escritura de caché medida frente a lectura de caché:
| Modelo | Coste escritura | Coste lectura | Descuento lectura | TTFT acierto (stream) |
|---|---|---|---|---|
claude-haiku-4-5 | $0.00916 | $0.00086 | −88% | 1.31 s |
claude-sonnet-4-5 | $0.02713 | $0.00247 | −89% | 1.76 s |
claude-sonnet-4-6 | $0.02736 | $0.00253 | −88% | 1.81 s |
claude-opus-4-5 | $0.04522 | $0.00409 | −89% | 2.08 s |
claude-opus-4-6 | $0.04522 | $0.00411 | −89% | 2.55 s |
claude-opus-4-7 | $0.06545 | $0.00609 | −88% | 2.30 s |
Tus cifras diferirán según la región, la hora del día y la temperatura de los prefijos de otros inquilinos. Ejecución única, fecha única — no las cites como verdad absoluta de benchmark.
8. Lista de verificación previa al lanzamiento
Antes de desplegar un prompt consciente del caché:
- Contenido estable primero — prompt de sistema, base de conocimiento, esquemas de herramientas al principio de
messages. - Contenido volátil al final — entrada del usuario, documentos recuperados, marcas de tiempo al final.
- Sin variables dinámicas en
system— la hora actual, el ID de usuario, las semillas aleatorias destruirán tu prefijo. - Registra
cached_tokensen cada llamada. Si la tasa de acierto está por debajo del 50 % en producción, tu prefijo no es realmente estable. Inspecciona los prompts que fallan. - No confíes en una sola pasada acertada. Los TTL son cortos; diseña para
hit_rate ∈ [0, 1)en lugar de «siempre acierto».
9. Patrones conscientes del TTL
El modo de fallo más común en producción no es «olvidé activar el caché» — es «mi tasa de acierto es del 12 % porque mis solicitudes no llegan realmente dentro de la ventana de TTL».
8.1 Cargas de trabajo ligadas a la sesión (chat, asistentes de IDE)
La cadencia natural está muy por debajo del TTL. Estructura tu prompt correctamente y el caché se mantiene caliente por sí solo — no diseñes nada más.
8.2 Latido para batch / cron
Si ejecutas un informe diario a las 09:00 que llama a tu modelo 50 veces en una ráfaga de 3 minutos, la primera escritura de caché a las 09:00 se desperdicia porque el caché se enfrió durante la noche. A partir de las 08:55, envía un «ping» de 1 token con el prefijo en caché cada TTL/2 para mantenerlo caliente:
def keepalive():
oai.chat.completions.create(
model="gpt-5.4-mini",
max_tokens=1,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "."},
],
)
El coste por ping es tokens de entrada × tarifa de caché, que para nuestro prefijo de 7K tokens en gpt-5.4-mini es de alrededor de $0.0026 — mucho menos que dejar que tu trabajo por lotes pague el prefill completo en las primeras 50 llamadas reales.
8.3 Documentos en almacenamiento en frío
Para documentos consultados de forma esporádica (una vez por hora a lo largo del día), los cachés en memoria estarán fríos la mayor parte del tiempo. Al momento de escribir esto, la pasarela no expone un endpoint alojado de creación de caché explícito — para necesidades de TTL largo usa deepseek-v4-flash (respaldado en disco; sobrevive en la práctica a intervalos de horas) o llama directamente a la API nativa cachedContent de Google fuera de la pasarela.
10. Lo que la pasarela realmente añade
Sería deshonesto afirmar que la pasarela «hace el caché por ti». El caché ocurre en la capa del modelo — la pasarela expone lo que hay allí. Lo que sí añade, medido frente al uso directo del SDK nativo de cada proveedor, son tres cosas:
- Una base_url, una cabecera de autenticación, todos los modelos. Intercambia el campo
modely la forma de la llamada permanece sin cambios. El mismo arraymessages, la misma estructura del campousage. No cargas cinco SDK para cinco proveedores. usage.costen USD por llamada. La pasarela calcula el coste en dólares usando las tarifas actuales del upstream y lo incluye en cada respuesta. No mantienes una matriz de precios en tu código, ni tienes que suscribirte a notificaciones de cambio de precio por proveedor.- Un campo
cached_tokensuniforme. Anthropic reporta los aciertos de caché comocache_read_input_tokens, OpenAI comoprompt_tokens_details.cached_tokens, DeepSeek comoprompt_cache_hit_tokens. La pasarela los normaliza al formato de OpenAI para que tu código de observabilidad no se ramifique según el proveedor.
Ese es todo el argumento. Todo lo demás — cuándo almacenar en caché, cómo estructurar los prompts, qué modelo elegir — es el trabajo del próximo artículo.
Siguiente: Parte 4 — Cómo elegir el mejor LLM por caso de uso: chat, API y agentes de IA — una matriz de decisión que asocia el tipo de carga de trabajo con el modelo óptimo + estrategia de caché, con cálculos de coste.
Preguntas frecuentes
¿Por qué usar el SDK de OpenAI para modelos que no son de OpenAI?
La pasarela habla el formato de transmisión de OpenAI para cada proveedor que expone. El SDK oficial openai te ofrece respuestas tipadas, reintentos automáticos y ayudantes de streaming — no hay razón para programar a mano cinco clientes HTTP.
¿Funciona el caché con respuestas en streaming?
Sí. El objeto usage en el último fragmento reporta los recuentos de acierto de caché (cuando pasas stream_options={"include_usage": True}). La ventaja de latencia es más visible en streaming porque el TTFT es lo que ven los usuarios.
¿Qué proveedor tiene el descuento de caché más profundo para mi carga de trabajo?
A los precios de 2026-05 y con una tasa de acierto superior al 70 %, gemini-2.5-flash y deepseek-v4-flash son los más baratos en la tabla de §7. gpt-5.4-mini gana en TTFT. Para el descuento de caché documentado del 90 % de Claude, marca hasta cuatro puntos de ruptura cache_control (consulta §2). Ejecuta el mismo benchmark contra tu propio prompt — es un ejercicio de un día, no una migración de varias semanas.
¿Cuándo necesito marcadores cache_control?
Solo al llamar a Anthropic Claude — consulta §2. Para OpenAI/Gemini/DeepSeek/Qwen el upstream almacena automáticamente en caché cualquier prefijo lo suficientemente largo, por lo que no se requiere marcador; el campo se ignora silenciosamente con esos proveedores.
¿Qué tan recientes son estas cifras? Medidas el 2026-05-25 en la pasarela pública. Trátalas como un único punto de datos — los precios y la latencia cambian en cada ciclo de versión.
¿Y Anthropic Claude?
Claude se admite a través de la pasarela con marcadores cache_control explícitos — usa el SDK anthropic con base_url="https://synthorai.io/" (el SDK añade /v1/messages). La ruta compatible con OpenAI /chat/completions no propaga los marcadores hoy en día; específicamente para el caché de Claude, usa la ruta nativa de Anthropic mostrada en §2.
Fuentes y verificación: todas las cifras se midieron contra https://synthorai.io/v1 el 2026-05-25 usando el SDK openai 2.38.0. Páginas de precios de los proveedores: Anthropic Prompt Caching · OpenAI Prompt Caching · Google Gemini Context Caching · DeepSeek KV Cache Guide · Alibaba Bailian Context Cache.