Bajé mi factura de Claude 90% con prompt caching

Anthropic permite cachear el system prompt por 1 hora. Si tu app hace múltiples llamadas con instrucciones grandes, el ahorro es brutal. Aquí está cómo lo configuré y los números reales.


Mi sistema de 11 agentes hace ~4,200 llamadas a Claude al mes. Cada agente tiene un system prompt de ~2-4K tokens (rol, herramientas, restricciones, ejemplos). Sin caching, cada llamada paga esos tokens completos.

Con prompt caching de 1 hora, pago el system prompt una vez y las siguientes N llamadas dentro de la hora pagan ~10% del costo de esos tokens.

Mi cache hit rate actual: 85%. Mi factura cayó de ~$50 USD/mes a $4-5 USD/mes. Aquí está cómo.

La feature

Anthropic permite marcar bloques de tu request como cacheables:

client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=2000,
    system=[
        {
            "type": "text",
            "text": SYSTEM_PROMPT,  # tu instrucción grande
            "cache_control": {"type": "ephemeral", "ttl": "1h"},
        }
    ],
    messages=[...]
)

cache_control.ttl: "1h" extiende el cache de 5 minutos (default) a 1 hora.

Cuánto cuesta el cache

OperaciónCosto (vs input normal)
Cache write (primera vez)125% del input (+25% de penalty)
Cache read (siguientes llamadas, mientras viva el cache)10% del input
Cache miss (después del TTL)escribe de nuevo (125%)

El break-even: si una sola conversación va a hacer 2 o más llamadas con el mismo system prompt dentro de 1 hora, ya estás ahorrando.

Cuándo NO usar cache

Cuándo SÍ es genial

La medición — qué reportar

Anthropic devuelve en el response:

resp.usage.input_tokens                  # tokens nuevos (no cacheados)
resp.usage.cache_creation_input_tokens   # tokens que se escribieron al cache
resp.usage.cache_read_input_tokens       # tokens leídos del cache
resp.usage.output_tokens                 # respuesta

Mi tabla token_usage:

CREATE TABLE token_usage (
  id SERIAL PRIMARY KEY,
  agent_name TEXT NOT NULL,
  model TEXT NOT NULL,
  input_tokens INT NOT NULL DEFAULT 0,
  output_tokens INT NOT NULL DEFAULT 0,
  cache_creation_tokens INT NOT NULL DEFAULT 0,
  cache_read_tokens INT NOT NULL DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

El cache hit rate se calcula:

SELECT
  SUM(cache_read_tokens) AS reads,
  SUM(input_tokens + cache_creation_tokens + cache_read_tokens) AS total_in,
  ROUND(100.0 * SUM(cache_read_tokens) /
        NULLIF(SUM(input_tokens + cache_creation_tokens + cache_read_tokens), 0), 1)
    AS hit_rate_pct
FROM token_usage
WHERE created_at::date = CURRENT_DATE;

El número real, con cálculo correcto

Para Sonnet 4.6:

Día típico mío:

Sin caching: 450K × $3/1M = $1.35/día Con caching: 21 × 3,200 × $3.75/1M + 119 × 3,200 × $0.30/1M = $0.25 + $0.11 = $0.36/día

Ahorro: 73% solo en input. Aplicado al mes: $40 → $11 solo por esto.

El truco para mantener el cache caliente

Si tu app tiene patrón de tráfico irregular (ej: ráfaga de 10 llamadas, después nada por 2h, después otra ráfaga), el cache muere entre ráfagas.

Mi trampita: un scheduled job que cada 50 minutos hace una llamada minimalista al modelo más usado, con el system prompt cacheado. El cache se renueva continuamente.

Costo del job: 1 llamada × 3,200 tokens read + ~20 tokens output ≈ $0.001/día. Lo que me ahorra en cache misses: mucho más.

Combina con model routing

Cache + model routing es donde está el verdadero ahorro. Mi router (que ya escribí en otro post) manda el 80% de llamadas a Haiku 4.5. Haiku ya es 10× más barato que Sonnet. Sumándole 85% cache hit rate, el costo por llamada simple es:

Haiku input normal:  $0.80/1M
Haiku cache read:    $0.08/1M (10%)

Una llamada simple ahora cuesta ~$0.0001 USD. Por eso mi factura completa es $5/mes con 11 agentes corriendo 24/7.

TL;DR para tu próximo proyecto

  1. Si tu system prompt es >1K tokens y haces más de 1 llamada por sesión: activa cache con TTL 1h.
  2. Loggea cache_creation_tokens y cache_read_tokens desde el día 1 — sin medición no sabes si está funcionando.
  3. Combina con model routing — el ahorro se multiplica.
  4. Si tu tráfico es a ráfagas, considera un keep-alive job.

Los números de esta entrada vienen del bot que está atendiendo oficina.lalu.dev en este momento. Los stats del cache hit rate los puedes ver en vivo arriba a la derecha del sitio.


← todos los posts