Documentação

Documentação

cache de prompts

Marque uma vez um prefixo estável do prompt com cache_control — ou acesse um modelo Claude no formato OpenAI, que não tem esse campo, e a Kunavo insere os pontos de interrupção para você. Em cada chamada subsequente que reutiliza o prefixo, ele é cobrado por uma fração do preço de entrada — 10% da entrada na maioria dos modelos de chat, chegando a apenas 2.5%. A camada de roteamento da Kunavo mantém o cache aquecido, fixando sua conversa na mesma chave upstream.

Em um prompt de sistema com 30 mil tokens e Claude Sonnet 5, uma leitura do cache custa $0.14 / 1M em vez de $1.4 / 1M. Para um agente que reenvia o mesmo contexto 50 vezes por sessão, o cache economiza cerca de 90% do custo de entrada.

Como habilitar

Adicione um ponto de interrupção cache_control: { type: "ephemeral" } a qualquer bloco de sistema, mensagem ou definição de ferramenta. O modelo armazena em cache o trecho até esse ponto na primeira chamada; as chamadas subsequentes que compartilham os mesmos bytes de prefixo acertam o cache.

cache_example.py
from openai import OpenAI

client = OpenAI(
    api_key="sk-kn-...",
    base_url="https://api.kunavo.com/v1",
)

# Mark the large, stable prefix once with cache_control.
# Every subsequent call that sends the same prefix reads it back
# from cache at 0.10× the input rate on Claude Sonnet 5.
# Per-model rates are in the pricing table below.
SYSTEM = [
    {
        "type": "text",
        "text": open("long_system_prompt.txt").read(),
        "cache_control": {"type": "ephemeral"},
    },
]

resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[
        {"role": "system", "content": SYSTEM},
        {"role": "user", "content": "Summarize the doc above in 3 bullets."},
    ],
)

u = resp.usage
# OpenAI-compat fields populated by Kunavo:
# - prompt_tokens_details.cached_tokens — read from cache
# - cache_creation_input_tokens          — written to cache this call
print(u.prompt_tokens_details.cached_tokens,
      getattr(u, "cache_creation_input_tokens", 0))

Formato de transmissão idêntico ao da API Messages nativa — cache_control é repassado ao Claude sem tradução:

messages_api.sh
# Native Anthropic Messages API — cache_control passes through untranslated.
curl https://api.kunavo.com/v1/messages \
  -H "Authorization: Bearer $KUNAVO_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "system": [
      {
        "type": "text",
        "text": "<your large stable system prompt>",
        "cache_control": { "type": "ephemeral" }
      }
    ],
    "messages": [
      { "role": "user", "content": "Summarize the doc above in 3 bullets." }
    ],
    "max_tokens": 1024
  }'
A estabilidade dos bytes importa. A chave do cache é baseada no conteúdo. Um único caractere diferente em qualquer parte do prefixo invalida o cache desse trecho. Coloque o conteúdo dinâmico (marcas de tempo, nomes de usuário, IDs por chamada) depois do bloco em cache, e não dentro dele.

Pontos de interrupção automáticos nos endpoints no formato OpenAI

Os formatos OpenAI Chat Completions e Responses não têm nenhum campo cache_control — a OpenAI faz cache implicitamente em seus próprios servidores. O Claude não: ele armazena em cache apenas o que um ponto de interrupção marca. Portanto, um cliente que usa OpenAI não tem como solicitar o cache, e uma tradução direta da solicitação chega ao Claude sem nenhum ponto de interrupção — assim, cada turno de uma conversa longa volta a ser cobrado pelo histórico inteiro, à tarifa integral de entrada.

Assim, quando você acessa um modelo Claude por /v1/chat/completions ou /v1/responses, a Kunavo define os pontos de interrupção que o protocolo não consegue transportar. Não há nada para ativar. Isso se aplica apenas aos modelos Claude — todas as outras famílias são atendidas por um protocolo cujo fornecedor faz cache implicitamente, sem pontos de interrupção a inserir.

no_cache_control.py
# Plain OpenAI Chat Completions — no cache_control anywhere in the body.
# The format has no field for one; Kunavo inserts the breakpoints instead.
resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[
        {"role": "system", "content": LONG_SYSTEM_PROMPT},
        {"role": "user", "content": "first question"},
        {"role": "assistant", "content": "...previous answer..."},
        {"role": "user", "content": "follow-up"},
    ],
)

u = resp.usage
# Turn that writes the cache:
#   u.cache_creation_input_tokens            -> 18,000
#   u.prompt_tokens_details.cached_tokens    ->      0
# Next turn, same prefix, inside the 5-minute window:
#   u.cache_creation_input_tokens            ->    240   (only the new turn)
#   u.prompt_tokens_details.cached_tokens    -> 18,000
#
# Both stuck at 0 on a conversation well over the threshold? The prefix is
# changing between calls — a timestamp or request id inside the cached span.

Onde eles são inseridos e em que ordem o orçamento é usado:

  • Um ponto de interrupção móvel na última mensagem — no último bloco de conteúdo da última mensagem, para armazenar em cache tudo o que vem antes; se a solicitação terminar com uma mensagem de sistema que permanece na conversa (veja abaixo), ele fica, em vez disso, no bloco logo antes dessa mensagem. Ele é adicionado somente quando messages já contém um turno do assistente: uma gravação no cache é cobrada a 1.25× da entrada, então marcar um prompt que ninguém reenviará custa um quarto a mais e não economiza nada. Um turno anterior do assistente é a evidência de que exatamente esse prefixo está prestes a ser enviado novamente.
  • Um em system e outro em tools — no início estável do prompt. Vale a pena marcá-lo até mesmo em uma chamada única, porque quem envia um prompt de sistema uma vez quase sempre envia o mesmo na próxima chamada.
  • Antes de uma mensagem de sistema que permanece na conversa — o que o ponto móvel e os pontos em system e tools deixarem do orçamento, no bloco logo antes da última mensagem desse tipo que tenha algo depois dela, e em seguida antes da anterior. Preenchido por último, porque só um cliente que move uma mensagem assim de um turno para outro precisa dele; uma conversa sem mensagens desse tipo, que são quase todas, não tem essa posição.

Há dois limites. Para prompts com menos de 8.192 caracteres — mensagens, system e esquemas de ferramentas em conjunto — nada é inserido: a Anthropic ignora silenciosamente um ponto de interrupção em um prefixo abaixo do comprimento mínimo que pode armazenar em cache (1.024 tokens, 2.048 no Haiku) e não cobra nem gravação nem leitura; portanto, inseri-lo não traria benefício. Além disso, a Anthropic aceita no máximo 4 pontos de interrupção por solicitação — um quinto resulta em um erro 400, não em uma operação ignorada silenciosamente.

Uma mensagem de sistema ou de desenvolvedor enviada depois da primeira resposta do modelo permanece na conversa, no turno em que foi enviada, em vez de ser levada para system: levá-la mudaria o início do prompt no turno em que ela é adicionada e gravaria todo o histórico no cache de novo. O Claude a recebe como mensagem de sistema onde o upstream aceita uma e, caso contrário, como texto dentro desse turno do usuário, entre tags <system-reminder>. Uma mensagem de sistema enviada antes da primeira resposta do modelo, ou uma cujo próprio ponto de interrupção pede o cache de uma hora, continua indo para system.

Seus próprios pontos de interrupção nunca são movidos nem removidos. Eles contam para o mesmo limite de 4, e a Kunavo só preenche posições que você deixou vazias. Envie seu próprio layout com 4 pontos e nada será adicionado; envie 1 e até 3 poderão ser adicionados ao redor dele. Quando o limite está apertado, a posição mais profunda é preenchida primeiro — um ponto de interrupção mais adiante no prompt armazena em cache tudo o que vem antes, então o ponto móvel é o mais valioso. No endpoint nativo /v1/messages, nada é inserido: seu corpo é repassado exatamente como enviado, e todos os pontos de interrupção nele são seus.
Um ponto de interrupção não é um acerto de cache. Ele marca um prefixo como passível de cache; ainda é necessário que os mesmos bytes do prefixo sejam enviados novamente dentro da janela efêmera da Anthropic — cinco minutos, renovados a cada leitura — e que a solicitação chegue à mesma chave upstream, finalidade do roteamento por afinidade descrito abaixo. A primeira chamada com um prefixo novo é sempre uma gravação, nunca uma leitura, e um prompt que muda a cada turno não terá acertos, independentemente da posição dos pontos de interrupção.

Nada muda nos relatórios: os mesmos campos cached_tokens e cache_creation_input_tokens descritos em Campos da resposta são preenchidos, quer os pontos de interrupção venham de você ou do gateway. Assim, o objeto de uso permite verificar se um ponto inserido realmente gerou um acerto.

Preços

As tarifas de cache são derivadas do preço de entrada de cada modelo, segundo as proporções definidas pelo próprio fornecedor — as tabelas abaixo são a referência, e todas as tarifas são calculadas a partir do preço de entrada do modelo, em vez de serem inseridas manualmente. As leituras do cache são cobradas a 0.10× da entrada tanto na Anthropic quanto na OpenAI, com 2 exceções: 0.025× on Claude Fable 5.1, 0.05× on Claude Opus 5.5. As gravações no cache são cobradas a 1.25× da entrada em todos os modelos Claude e em GPT-6 Astra, GPT-6 Sol, GPT-6 Luna, GPT-5.6 Sol e GPT-5.6 Terra. A Kunavo cobra pelas gravações com TTL de 1 hora do Claude a mesma tarifa de 1.25×, abaixo dos 2× cobrados pela Anthropic. Nenhum outro modelo tem um preço de gravação separado: suas gravações são cobradas pela tarifa normal de entrada. De qualquer forma, um prefixo reutilizado ao menos uma vez custa menos em cache do que se fosse enviado novamente sem cache. Cada categoria mantém o desconto próprio do modelo; portanto, os preços de cache têm o mesmo desconto em relação à tabela do fornecedor que os preços de entrada e saída.

Anthropic

ModelInputCache readCache write
Claude Fable 5.1$7$0.175 0.025×$8.75 1.25×
Claude Fable 5$7$0.7 0.10×$8.75 1.25×
Claude Opus 5.5$2.8$0.14 0.050×$3.5 1.25×
Claude Opus 5$3.5$0.35 0.10×$4.375 1.25×
Claude Opus 4.8$3.5$0.35 0.10×$4.375 1.25×
Claude Opus 4.7$3.5$0.35 0.10×$4.375 1.25×
Claude Opus 4.6$3.5$0.35 0.10×$4.375 1.25×
Claude Sonnet 5$1.4$0.14 0.10×$1.75 1.25×
Claude Sonnet 4.6$2.1$0.21 0.10×$2.625 1.25×
Claude Haiku 4.5$0.7$0.07 0.10×$0.875 1.25×

OpenAI

ModelInputCache readCache write
GPT-6 Astra$4$0.4 0.10×$5 1.25×
GPT-6 Sol$0.8$0.08 0.10×$1 1.25×
GPT-6 Luna$0.04$0.004 0.10×$0.05 1.25×
GPT-5.6 Sol$2$0.2 0.10×$2.5 1.25×
GPT-5.6 Terra$0.7$0.07 0.10×$0.875 1.25×
GPT-5.5$2$0.2 0.10×$2 1×
Prompts longos são cobrados pela categoria de contexto longo do fornecedor. Acima do limite, a solicitação inteira é cobrada por um múltiplo dos preços de entrada e saída do modelo, incluindo leituras e gravações no cache: acima de 272K tokens de entrada em GPT-6 Astra, GPT-6 Sol, GPT-6 Luna, GPT-5.6 Sol, GPT-5.6 Terra e GPT-5.5 (2× de entrada, 1.5× de saída). O Claude não tem sobretaxa por contexto longo: seu contexto de 1 milhão de tokens é cobrado pela tarifa padrão.
O piso do catálogo considera o cache. A Kunavo cobra max(catalog_cost, upstream × markup) por chamada — o piso é calculado com base na tarifa de entrada em cache, e não na tarifa sem cache, para que a economia chegue até você em vez de ser anulada.
As tarifas acima são os preços do catálogo. A cobrança real por chamada é calculada com base nos créditos upstream que o modelo efetivamente consumiu (com uma margem) e, em seguida, comparada com o piso definido pela tarifa do catálogo. Em acertos de cache, o provedor upstream cobra menos créditos — portanto, o valor calculado com base no upstream mais a margem geralmente fica abaixo do catálogo, e prevalece a tarifa do catálogo. Em resumo: a tarifa do catálogo é o seu preço de pior caso; chamadas em cache podem ficar abaixo dela, mas nunca acima.

O roteamento por afinidade mantém o cache aquecido

Os caches de prompt upstream são vinculados à chave de API. Se cada solicitação chegar a uma chave upstream aleatória, a taxa de acerto do cache será de ~1/N. A Kunavo deriva um hash estável do prompt de sistema + da primeira mensagem do usuário e encaminha todas as chamadas com o mesmo prefixo para a mesma chave upstream — usando hashing rendezvous ponderado, de modo que apenas ~1/N das chaves seja remapeada quando o conjunto muda.

Você não precisa configurar nada. O roteamento por afinidade se aplica automaticamente a todas as chamadas de chat. (Imagem / vídeo / TTS usam roteamento aleatório — não há cache por chave para essas modalidades.)

Métricas do painel

Quando suas chamadas começarem a acertar o cache, /app/usage exibirá duas métricas agregadas para o período selecionado:

  • Taxa de acerto — tokens de entrada em cache ÷ total de tokens de entrada. Valor exato, calculado com base na contagem de tokens de cada chamada.
  • Economia — USD economizados neste período, calculados por modelo usando a tarifa real de leitura do cache de cada um (sem aproximações por média simples). É uma estimativa baseada nas tarifas do catálogo — como as cobranças reais têm o piso do catálogo e chamadas em cache podem ficar abaixo desse piso, o valor é um limite superior bastante preciso da economia real. Em cargas de trabalho típicas de chat, os dois valores diferem por poucos pontos percentuais.

A página de detalhes de cada chamada (/app/usage/<id>) mostra as contagens de tokens em cache e de gravação no cache quando diferentes de zero, além do valor efetivamente cobrado.

Campos da resposta

A Kunavo disponibiliza os tokens de cache nos dois formatos de resposta. No endpoint compatível com OpenAI /v1/chat/completions:

CampoSignificado
usage.prompt_tokensTotal de tokens de entrada (inclui os tokens em cache e de gravação no cache).
usage.prompt_tokens_details.cached_tokensParcela da entrada atendida pelo cache.
usage.cache_creation_input_tokensTokens gravados no cache nesta chamada (cobrados pela tarifa de gravação no cache do modelo, indicada nas tabelas acima).

Na API Messages nativa em /v1/messages, os campos originais da Anthropic são repassados:

CampoSignificado
input_tokensEntrada nova (fora do cache).
cache_read_input_tokensAtendido pelo cache, cobrado a 0.10× da entrada (0,025× no Claude Fable 5.1, 0,05× no Claude Opus 5.5).
cache_creation_input_tokensGravados no cache nesta chamada (cobrados a 1,25× a entrada — também para gravações com TTL de 1 hora, abaixo dos 2× da Anthropic).

Próximos passos

  • Referência da API Messages — formato nativo da Anthropic, com exemplos práticos de cache.
  • Cache de prompt Claude — os números do objeto de uso que permitem diagnosticar um cache e as três maneiras pelas quais o roteamento por um gateway reduz a taxa de acerto.
  • Cobrança e livro-razão — como o piso max() que considera o cache interage com o custo upstream.
  • Tabela completa de preços — preços de entrada sem cache / de saída para todos os modelos de chat, com a tabela de cache na parte inferior.