Alejandro Rioja.
AI Agents Operations

Prompt Caching com a API da Claude: Reduza Seus Custos de Entrada Sem Trocar de Modelo

Alejandro Rioja
Alejandro Rioja
10 min de leitura
TL;DR

O prompt caching reduz o custo de entradas grandes e estáveis — seu prompt de sistema, definições de ferramentas, exemplos few-shot — para cerca de 10% do preço normal de entrada em requisições repetidas. O mecanismo é uma correspondência de prefixo: coloque um marcador cache_control no final do seu conteúdo estável e mantenha tudo o que é volátil depois dele. O erro que destrói a taxa de acerto do cache é deixar um timestamp ou UUID flutuar para dentro do prefixo.

Newsletter gratuita

Toda quarta-feira. 28.400+ operadores. Zero enrolação.

Table of contents

Open Table of contents

O que o prompt caching realmente faz

Toda chamada à API da Claude envia tokens. Sem cache, cada token da sua requisição — prompt de sistema, definições de ferramentas, exemplos few-shot e a mensagem do usuário — é cobrado pela taxa normal de entrada. Com cache, um prefixo desses tokens fica armazenado nos servidores da Anthropic após a primeira requisição. Nas requisições seguintes que compartilham exatamente esse prefixo, você paga um preço de leitura de cache em vez de reprocessá-los do zero.

A diferença de custo é real:

Uma vez ultrapassado o ponto de equilíbrio — o que acontece rápido em qualquer agente executado mais do que algumas vezes por dia — cada acerto de cache adicional representa um desconto de ~90% sobre esses tokens.

A invariante de correspondência de prefixo

Esta é a regra que tudo o mais segue: a chave de cache é uma correspondência de prefixo do seu prompt renderizado.

Os servidores da Anthropic armazenam o conteúdo renderizado desde o início do seu prompt até o marcador cache_control. Para que ocorra um acerto de cache na próxima requisição, cada token desde o início do prompt até esse marcador precisa ser idêntico — byte por byte.

A ordem de renderização para a correspondência de prefixo é: tools → system → messages. Ou seja, seu array de ferramentas é processado por hash primeiro, depois o bloco de sistema, e então as mensagens em ordem.

O que isso significa na prática: o conteúdo estável precisa vir primeiro. Se o seu prompt de sistema referencia qualquer coisa dinâmica — a data atual, um ID de usuário, um ID de rastreamento da requisição — e isso aparece antes do marcador cache_control, o cache vai falhar em todas as requisições, porque o prefixo fica mudando.

Em que colocar um marcador de cache

Os alvos de maior alavancagem são:

1. Seu prompt de sistema

Prompts de sistema costumam ser o maior bloco estável. Uma persona de agente detalhada, uma lista de regras de comportamento, um conjunto de instruções de formato de saída — tudo isso é idêntico em cada invocação do mesmo agente. Marque-o:

typescript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const response = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1024,
  system: [
    {
      type: "text",
      text: `You are a content operations agent for alejandrorioja.com.
Your job is to draft blog posts in Alejandro's voice: direct, practitioner, 
first-person, numbered lists, honest caveats. No hedging. No filler. 
Every section must earn its place.

[... 2000 more tokens of stable instructions ...]`,
      cache_control: { type: "ephemeral" },
    },
  ],
  messages: [
    {
      role: "user",
      content: "Draft a post about prompt caching.",
    },
  ],
});

O cache_control: { type: "ephemeral" } no bloco de sistema diz à Claude para armazenar em cache tudo até e incluindo esse bloco. O array messages é volátil — diferente a cada requisição — e fica fora do limite do cache.

2. Definições de ferramentas

Se o seu agente usa ferramentas, essas definições podem ser substanciais. Um schema de ferramenta bem documentado, com descrição, nomes de parâmetros e valores de enum, pode chegar a 500–1.000 tokens por ferramenta. Com 5 ferramentas, isso são até 5.000 tokens que você paga para reprocessar em cada chamada:

typescript
const response = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1024,
  tools: [
    {
      name: "search_airtable",
      description: "Search the Airtable content queue...",
      input_schema: { type: "object", properties: { query: { type: "string" } } },
    },
    // ... more tools ...
    {
      name: "post_to_kit",
      description: "Schedule a broadcast via the Kit API...",
      input_schema: { /* ... */ },
      // Mark the last tool to cache the entire tools array
    } as Anthropic.Tool & { cache_control: { type: "ephemeral" } },
  ],
  system: "...",
  messages: [...],
});

Marque a última ferramenta do array. A correspondência de prefixo cobrirá todo o array de ferramentas a partir desse ponto.

3. Exemplos few-shot nas mensagens

Se você passa exemplos few-shot estáticos como mensagens iniciais no array messages, eles também podem ser armazenados em cache. Estruture-os como as primeiras N mensagens e marque o último turno de exemplo:

typescript
const messages: Anthropic.MessageParam[] = [
  {
    role: "user",
    content: [
      {
        type: "text",
        text: "Here are examples of posts in my voice:\n\n[Example 1...]\n\n[Example 2...]",
        cache_control: { type: "ephemeral" },
      } as Anthropic.TextBlockParam & { cache_control: { type: "ephemeral" } },
    ],
  },
  {
    role: "assistant",
    content: "Understood. I'll follow that voice.",
  },
  // The actual user turn follows — this is volatile, no cache marker
  {
    role: "user",
    content: actualUserRequest,
  },
];

O que NÃO armazenar em cache (invalidadores silenciosos)

Estas são as coisas que parecem estáveis, mas não são — e vão destruir sua taxa de acerto silenciosamente. A API não vai avisar você. Você simplesmente vai ver cache_creation_input_tokens em cada requisição e se perguntar por quê.

Timestamps no prompt de sistema. O erro mais comum de todos:

typescript
// This invalidates the cache on every request
const system = `You are an agent. Current time: ${new Date().toISOString()}`;

Mova os timestamps para a mensagem do usuário, que é onde eles pertencem:

typescript
// Stable system prompt — cacheable
const system = `You are an agent. Use the current time provided by the user.`;

// Volatile user message — not cached
const userMessage = `Current time: ${new Date().toISOString()}. Run the daily brief.`;

UUIDs aleatórios e IDs de rastreamento. Mesmo problema. Se você injeta um ID de rastreamento no bloco de sistema para fins de log, cada requisição recebe um prefixo novo.

Serialização de JSON não determinística. Se você serializa um objeto dentro do prompt de sistema e a ordem das chaves não é garantida, a string renderizada pode diferir mesmo quando os dados subjacentes são os mesmos. Serialize com uma ordem de chaves estável ou use uma template string.

Seleção dinâmica de few-shot. Se você escolhe exemplos few-shot com base na consulta atual e os coloca no prefixo armazenado em cache, você tornou o prefixo “estável” dependente da consulta. Ou comprometa-se com exemplos fixos para a camada de cache, ou mova os exemplos dinâmicos para o turno de mensagem não armazenado em cache.

Verificando sua taxa de acerto de cache

Toda resposta inclui metadados de uso. Confira-os:

typescript
const response = await client.messages.create({ /* ... */ });

console.log({
  inputTokens: response.usage.input_tokens,
  cacheRead: response.usage.cache_read_input_tokens,
  cacheWrite: response.usage.cache_creation_input_tokens,
  outputTokens: response.usage.output_tokens,
});

Na primeira requisição: cache_creation_input_tokens será diferente de zero, cache_read_input_tokens será 0. Essa é a escrita.

Em um acerto de cache: cache_read_input_tokens será diferente de zero, cache_creation_input_tokens será 0. Essa é a leitura.

Se você está vendo cache_creation_input_tokens em cada requisição, seu prefixo está mudando. Adicione uma instrução de log que imprima os primeiros 200 caracteres do seu prompt de sistema renderizado antes de cada chamada — um timestamp flutuante salta aos olhos imediatamente.

O TTL de 1 hora: quando vale o custo extra de escrita

O TTL padrão é de 5 minutos. Se o seu agente roda em baixa frequência — menos de uma vez a cada 5 minutos — você estará pagando custos de escrita de cache na maioria das requisições sem obter leituras.

typescript
// Opt into a 1-hour TTL
cache_control: { type: "ephemeral", ttl: "1h" }

A escrita de 1 hora custa ~2× o preço base de entrada em vez de 1,25×. A conta: se você está acertando o cache 3 ou mais vezes por hora, o TTL de 1 hora economiza dinheiro. Se o seu agente roda uma vez por dia (como meu briefing diário), nem mesmo o TTL de 1 hora ajuda — você paga custos de escrita toda vez. Nesse caso, o benefício do cache é modesto, a menos que o prompt de sistema seja enorme.

Meu agente de briefing diário tem um prompt de sistema de 3.000 tokens, mas roda uma vez por dia. O cache não ajuda. Meu agente de newsletter roda dezenas de vezes por sessão enquanto escreve rascunhos — o cache economiza substancialmente.

Pré-aquecimento: tornando a primeira requisição barata

Se você tem um pico de tráfego conhecido a caminho — um job em lote, o lançamento de uma API — você pode pré-aquecer o cache com uma requisição fictícia de baixo custo:

typescript
// Pre-warm: write the cache at near-zero output cost
await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1, // minimal output
  system: [{ type: "text", text: stableSystemPrompt, cache_control: { type: "ephemeral" } }],
  messages: [{ role: "user", content: "ping" }],
});

// Now the real requests read from cache

Isso é útil principalmente para processamento em lote, onde você sobe muitas requisições paralelas e quer que cada uma acerte um cache quente, em vez de competir para escrevê-lo.

Prompt caching em loops agênticos

Em um loop agêntico de múltiplos turnos, o histórico da conversa cresce a cada turno. O cache é inteligente o suficiente para lidar com isso: ele usa uma janela de lookback de 20 blocos, encontrando o maior prefixo correspondente dentro dos últimos 20 blocos de conteúdo.

A implicação prática: mantenha seu conteúdo estável (prompt de sistema, definições de ferramentas) ancorado no topo. O histórico crescente da conversa no final do array de mensagens não quebrará a correspondência de prefixo dos blocos estáveis — eles vêm antes do conteúdo volátil, e a correspondência de prefixo começa do topo.

Na prática, meus agentes estruturam os turnos assim:

code
System (cached) → Tools (cached) → Few-shot (cached) → Turn 1 → Turn 2 → ... → Current turn

O cache cobre tudo até o marcador de few-shot. O histórico crescente de turnos depois dele é reprocessado a cada vez, mas tudo bem — esses tokens são específicos da sessão e pequenos em relação ao prefixo estável.

Como isso aparece na fatura

Tome um agente de alta frequência: 100 chamadas por dia, prompt de sistema de 4.000 tokens, preços do Sonnet.

Sem cache:

Com cache (TTL de 5 min, supondo 50 chamadas/hora no pico):

Isso é uma redução de aproximadamente 90% sobre esses tokens de entrada. Em escala — 1.000 chamadas por dia — a diferença se acumula ainda mais. E isso vem por cima de qualquer economia de roteamento de modelo da matemática Haiku vs Sonnet: o cache funciona em todos os tiers.

A conclusão do operador

O prompt caching é a otimização de custo mais fácil na API da Claude: um campo adicional nos blocos de conteúdo que você já está escrevendo. A restrição é disciplina em torno da estabilidade do prefixo — nada dinâmico antes do marcador de cache. Se você conseguir manter seu prompt de sistema, suas ferramentas e quaisquer exemplos estáticos livres de conteúdo volátil, você pagará ~10% do custo normal de entrada em cada acerto de cache. Para agentes de alta frequência com prompts grandes e estáveis, essa é uma alavanca maior do que trocar de tier de modelo.


Relacionados: Matemática de Custo de Agentes de IA: Quando o Haiku Vence o Sonnet · Agentes Acionados por Eventos vs Agendados · As 5 Ferramentas de IA Que Realmente Uso Para Tocar Meu Negócio

Continue lendo

Receba o manual de IA na sua caixa de entrada

Toda quarta-feira. 28.400+ operadores. Zero enrolação.

↵ ver todos os resultados esc esc para fechar