Capa: Prompt Caching, como cortar ate 90% do custo de LLMs

Prompt Caching: como cortar até 90% do custo de LLMs sem perder qualidade

Se você já colocou uma aplicação de IA generativa em produção, conhece a sensação: a solução funciona lindamente na POC e, quando o volume cresce, a fatura de tokens vira o assunto da reunião. A boa notícia é que grande parte desse custo é desperdício evitável — você está pagando, repetidamente, para o modelo “reler” o mesmo contexto a cada chamada.

O prompt caching resolve exatamente isso. Neste artigo eu explico o que é, como funciona por baixo do capô, mostro a arquitetura, dou exemplos reais nas três plataformas que mais uso (Anthropic, Azure OpenAI e GitHub Models) e fecho com a matemática de custo e as boas práticas que separam quem economiza de quem só acha que economiza.

O problema: LLMs não têm memória entre chamadas

Modelos de linguagem são stateless. Cada requisição à API é independente: o modelo não “lembra” da chamada anterior. Para dar continuidade a uma conversa ou fornecer contexto (um documento, instruções de sistema, exemplos few-shot), você precisa reenviar tudo a cada requisição.

Na prática, um prompt típico de produção é composto assim:

[ System prompt + instruções        ]  <- grande, estável, repetido sempre
[ Documentos / base de conhecimento  ]  <- grande, muda pouco
[ Histórico da conversa              ]  <- cresce a cada turno
[ Pergunta atual do usuário          ]  <- pequeno, sempre diferente

O problema fica evidente com números. Imagine um assistente com 30.000 tokens de contexto fixo (instruções + documentação) e uma pergunta de 200 tokens. A cada mensagem você paga por 30.200 tokens de entrada — sendo que 30.000 são exatamente iguais à chamada anterior. Multiplique por milhares de requisições e você entende de onde vem a conta.

Numa das minhas análises reais de consumo, uma ferramenta de IA acumulou ~195 milhões de tokens de entrada em 638 chamadas — cerca de 305 mil tokens por chamada. Isso só é possível quando o mesmo contexto enorme é reenviado a cada interação. É o cenário perfeito para caching.

O que é prompt caching

Prompt caching é a capacidade do provedor de armazenar o estado interno de processamento de um trecho do prompt (o prefixo) e reutilizá-lo em chamadas seguintes, em vez de reprocessá-lo do zero.

Tecnicamente, o que fica em cache não é o texto — é o resultado da computação do modelo sobre aquele texto: os estados de atenção (KV cache) das camadas do transformer para aqueles tokens. Quando você reenvia o mesmo prefixo, o provedor reconhece o hash e “pula” o trabalho pesado de recomputar essas ativações.

O efeito é duplo:

  1. Custo menor — tokens lidos do cache custam uma fração do preço normal (tipicamente ~10%).
  2. Latência menor — pular o pré-preenchimento (prefill) de dezenas de milhares de tokens acelera o time-to-first-token de forma perceptível.

A regra de ouro: o cache é por prefixo exato

Esta é a parte que mais gente erra. O cache funciona sobre o prefixo do prompt, da esquerda para a direita, e exige correspondência byte a byte. Se o primeiro caractere mudar, todo o cache a partir dali é invalidado.

Chamada 1:  [A][B][C][pergunta_1]     -> processa tudo, grava cache de [A][B][C]
Chamada 2:  [A][B][C][pergunta_2]     -> cache HIT em [A][B][C], processa só a pergunta OK
Chamada 3:  [X][A][B][C][pergunta_3]  -> prefixo mudou no início, cache MISS total

Corolário prático: coloque o conteúdo estável no começo e o variável no fim.

Arquitetura

O diagrama abaixo mostra o caminho de uma requisição com caching e onde o ganho acontece.

              Usuário / App
                   |
             (prefixo estável + entrada variável)
                   v
              Gateway / SDK
                   |
                   v
            API do provedor LLM
                   |
           Prefixo já está em cache?
             /                  \
          HIT                    MISS
           |                      |
   Lê KV-cache             Processa do zero
   ~10% do input           grava no cache
   latência menor          ~125% do input
           \                      /
            \                    /
             v                  v
        Geração da resposta (saída = preço normal)
                   |
                   v
                Resposta -> Usuário

Anatomia de um prompt otimizado para cache:

|============ PREFIXO CACHEÁVEL (não muda) ============|== SUFIXO DINÂMICO ==|
[ System prompt ] [ Documentos / RAG ] [ Few-shot ] || [ Histórico ] [ Pergunta ]
                                          ^
                                   cache breakpoint (cache_control)

A ideia central: você marca um ponto de corte (breakpoint) logo depois do bloco estável. Tudo à esquerda vira candidato a cache; tudo à direita é sempre recomputado.

Exemplos práticos

1. Anthropic (Claude) — controle explícito

Na API da Anthropic o caching é explícito: você marca os blocos com cache_control. É o modelo mais transparente e o que dá mais controle.

import anthropic

client = anthropic.Anthropic()

DOC_GRANDE = open("manual_produto.md").read()  # ex.: 30k tokens

response = client.messages.create(
    model="claude-opus-4-20250514",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "Você é um especialista de suporte técnico. Cite a seção do manual.",
        },
        {
            "type": "text",
            "text": DOC_GRANDE,
            # tudo ATÉ AQUI vira um bloco cacheável
            "cache_control": {"type": "ephemeral"},
        },
    ],
    messages=[
        {"role": "user", "content": "Como faço o rollback de uma release?"}
    ],
)

print(response.usage)
# cache_creation_input_tokens : tokens gravados no cache (1a vez, ~1,25x)
# cache_read_input_tokens     : tokens lidos do cache (~0,1x)
# input_tokens                : tokens novos processados normalmente

Pontos-chave da Anthropic:

  • Você pode ter até 4 breakpoints de cache.
  • TTL padrão de 5 minutos (há opção estendida de 1 hora com preço diferente).
  • A primeira escrita custa ~1,25× o input normal; leituras subsequentes custam ~0,1×.
  • Requer um mínimo de tokens para ativar (ex.: ~1024 para Opus/Sonnet).

2. Azure OpenAI — caching automático

No Azure OpenAI (e OpenAI direto), o caching é automático e transparente para prompts acima de ~1.024 tokens. Você não marca nada; o serviço detecta prefixos repetidos.

from openai import AzureOpenAI

client = AzureOpenAI(
    api_version="2024-10-21",
    azure_endpoint="https://SEU-RECURSO.openai.azure.com",
)

SYSTEM = "Instruções longas e estáveis... (>1024 tokens para ativar o cache)"

resp = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": SYSTEM},   # prefixo estável primeiro
        {"role": "user", "content": "Pergunta variável do usuário"},
    ],
)

# O ganho aparece em usage.prompt_tokens_details.cached_tokens
print(resp.usage.prompt_tokens_details.cached_tokens)

Pontos-chave do Azure OpenAI:

  • Automático — ativa a partir de 1.024 tokens de prompt, em blocos de 128.
  • Tokens em cache costumam ter desconto significativo sobre o input.
  • Você não controla o breakpoint: por isso a disciplina de “estável primeiro, variável depois” é ainda mais importante.
  • Métrica em usage.prompt_tokens_details.cached_tokens.

3. GitHub Models — prototipagem e produção leve

O GitHub Models expõe modelos (incluindo família OpenAI e outros) por uma API compatível com OpenAI, ótimo para prototipar. O caching segue o comportamento do provedor subjacente (automático nos modelos OpenAI).

from openai import OpenAI

client = OpenAI(
    base_url="https://models.github.ai/inference",
    api_key="SEU_GITHUB_TOKEN",   # PAT com escopo de models
)

resp = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[
        {"role": "system", "content": "Contexto estável e longo aqui..."},
        {"role": "user", "content": "Pergunta do usuário"},
    ],
)
print(resp.choices[0].message.content)

Atenção ao modelo de cobrança do GitHub Models: o plano gratuito é por rate limit (ótimo para experimentar), e o uso pago é medido em requisições/tokens. Para produção com alto volume, o caminho natural é migrar para Azure OpenAI mantendo o mesmo código (API compatível).

A matemática do custo

Vamos aos números com um exemplo concreto. Suponha o modelo Opus com preços de referência de $15 por milhão de tokens de entrada e $75 por milhão de saída, e um workload de 638 chamadas, ~195M tokens de entrada (dominados por contexto repetido) e ~1,12M tokens de saída.

Cenário A — sem caching

Item Tokens Preço Custo
Entrada 195M $15/M $2.925,00
Saída 1,12M $75/M $84,00
Total ≈ $3.009

Cenário B — com 90% de cache hit

Cache read a ~$1,50/M (10% do input). 90% da entrada vira leitura de cache, 10% é processada normalmente:

Item Tokens Preço Custo
Entrada — cache read (90%) 175,4M $1,50/M $263,10
Entrada — normal (10%) 19,5M $15/M $292,50
Saída 1,12M $75/M $84,00
Total ≈ $640

Resultado: de ~$3.009 para ~$640 — uma redução de ~79% na fatura, sem mudar uma linha da lógica de negócio. Em workloads com contexto muito grande e estável, a economia real frequentemente passa dos 80%.

Fórmula geral

custo_input = tokens_normais     * preço_input
            + tokens_cache_write * (preço_input * 1.25)
            + tokens_cache_read  * (preço_input * 0.10)

custo_total = custo_input + tokens_saída * preço_saída

O ponto de equilíbrio: como a escrita custa 1,25× e a leitura 0,10×, o cache “se paga” a partir de ~2 leituras do mesmo prefixo. Ou seja, qualquer contexto reutilizado mais de uma vez em poucos minutos já vale a pena.

Boas práticas de produção

  1. Estável primeiro, variável por último. System prompt, instruções, documentos e few-shots no começo; histórico e pergunta no fim. É o requisito nº 1 para qualquer caching funcionar.
  2. Não injete conteúdo volátil no prefixo. Timestamps, IDs de sessão, “hora atual”, nomes de usuário no meio do system prompt — tudo isso quebra o cache. Mova para o fim ou remova.
  3. Padronize o prefixo entre chamadas. Whitespace, ordem de campos, serialização de JSON — qualquer diferença byte a byte causa miss. Gere o prefixo de forma determinística.
  4. Respeite o TTL. O cache é efêmero (~5 min). Requisições esparsas não se beneficiam. Se o tráfego for intermitente, considere o TTL estendido (onde disponível) ou “aquecer” o cache com um ping periódico.
  5. Meça de verdade. Instrumente cache_read_input_tokens / cached_tokens e acompanhe a taxa de cache hit como um KPI de FinOps. Sem medir, você está adivinhando.
  6. Segmente por versão. Ao mudar o system prompt, você invalida todo o cache. Faça deploys de prompt de forma consciente e agrupe requisições pela mesma versão.
  7. Combine com outras técnicas. Caching reduz o custo do input, mas não substitui RAG bem feito, truncamento de histórico e escolha adequada de modelo (nem tudo precisa de Opus).
  8. Cuidado com dados sensíveis. O cache é isolado por conta/organização, mas trate contexto com PII com as mesmas políticas de governança do resto do pipeline.

Onde o caching NÃO ajuda

  • Prompts curtos e sempre diferentes. Sem prefixo estável significativo, não há o que cachear.
  • Prefixos abaixo do mínimo (ex.: menos de 1024 tokens): o caching nem ativa.
  • Tráfego muito esparso, com intervalos maiores que o TTL entre chamadas semelhantes.
  • Redução de tokens de saída: caching age no input; a geração continua no preço cheio.

Checklist de implementação

  • O bloco estável (system + docs + few-shot) está no início do prompt?
  • Todo conteúdo volátil (timestamps, IDs) foi movido para o fim?
  • O prefixo é gerado de forma determinística (mesmo byte a byte)?
  • O prefixo estável tem mais de ~1.024 tokens?
  • Você está medindo a taxa de cache hit em produção?
  • As chamadas semelhantes acontecem dentro do TTL (~5 min)?
  • (Anthropic) Os cache_control estão nos pontos certos?
  • (Azure/OpenAI) Você confia no caching automático e organizou o prompt para ele?

Conclusão

Prompt caching é uma das poucas otimizações de IA generativa que entrega ganho grande com esforço pequeno: você reorganiza o prompt, marca (ou confia no) breakpoint e passa a pagar uma fração pelo contexto repetido. No exemplo real deste artigo, foi a diferença entre uma fatura de ~$3.000 e ~$640 para o mesmo trabalho.

O segredo não é mágico — é disciplina de arquitetura: contexto estável primeiro, conteúdo variável por último, e medição constante. Faça isso, e o caching deixa de ser um detalhe técnico para virar uma alavanca real de FinOps na sua plataforma de IA.


Eron Cavalcante

Eron Cavalcante atua como Cloud Solution Architect na Microsoft, com foco em plataformas de dados, IA generativa e arquitetura de nuvem para o setor financeiro. Combina experiência técnica em Azure, Databricks e engenharia de dados com uma visão de negócio orientada a valor, apoiando clientes na adoção responsável de IA em escala.

Deixe um comentário