Cache de prompts de LLM em Python: tutorial prático com código
Conteúdo
- 0. Configuração
- 1. Chamada com suporte a cache (igual em todos os provedores)
- 2. Anthropic Claude — Marcadores cache_control explícitos
- 3. OpenAI GPT-5.x — Cache automático
- 4. Google Gemini — Cache implícito
- 5. DeepSeek-v4-flash — Cache automático em disco
- 6. Alibaba Qwen — Hit informado, desconto variável
- 7. Benchmark entre provedores (medido em 2026-05-25)
- 8. Checklist antes do lançamento
- 9. Padrões que consideram o TTL
- 8.1 Workloads vinculados à sessão (chat, assistentes de IDE)
- 8.2 Heartbeat para batch / cron
- 8.3 Documentos em armazenamento frio
- 10. O que o gateway realmente acrescenta
- FAQ
TL;DR — Um único SDK da OpenAI, um único base_url, todos os principais LLMs. Os números deste artigo foram medidos no gateway da Synthorai em produção em 2026-05-25, com um system prompt estável de aproximadamente 7.300 tokens. A proposta do gateway aqui é simples: um único endpoint, um único header de autenticação e um campo usage.cost que elimina a necessidade de manter uma tabela de preços por provedor. A matemática dos Transformers por trás do cache está na Parte 1: princípios do cache; as decisões de cada provedor estão na Parte 2: comparação entre provedores.
Série: Parte 3 de 5 · Anteriormente: Parte 1 — Princípios do cache · Parte 2 — Comparação e avaliação de provedores · A seguir: Parte 4 — Melhor LLM por caso de uso · Parte 5 — Integração com LangChain
0. Configuração
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",
)
O gateway usa o protocolo da OpenAI para todos os modelos que disponibiliza (GPT, Claude, Gemini, DeepSeek e Qwen). Basta trocar o campo model, sem mudar o SDK. A autenticação usa Authorization: Bearer <key>.
IDs de modelos com suporte a cache disponíveis no gateway público (snapshot 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. A lista completa e atualizada está em GET /v1/models.
1. Chamada com suporte a cache (igual em todos os provedores)
Não é preciso habilitar nada. Quando o modelo oferece cache de prompts no provedor de origem, o gateway apenas repassa os metadados da resposta. Dois campos mostram o que aconteceu:
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 indica quantos tokens de entrada acertaram o cache de prefixo do provedor. usage.cost contém o preço calculado pelo gateway para essa chamada, em USD. Assim, não é preciso manter localmente uma tabela de preços por provedor.
Duas regras derivadas da arquitetura valem para todos os provedores:
- Conteúdo estável no início, conteúdo volátil no fim. A comparação do prefixo começa no token zero; alterar um único byte no início invalida todo o prefixo.
- Não coloque dados dinâmicos no system prompt. Timestamp atual, ID de sessão e UUID da requisição invalidam o cache.
Os exemplos abaixo apenas aplicam esse mesmo padrão a cada provedor.
2. Anthropic Claude — Marcadores cache_control explícitos
Claude pertence à família de marcadores explícitos: a API da Anthropic não cria cache automaticamente. Para obter um cache hit, marque até quatro pontos de interrupção com cache_control no array system ou messages. Leituras do cache custam cerca de 10% do preço normal de entrada; gravações custam 125%, um adicional de 25%.
A forma mais simples de usar cache_control pelo gateway é apontar o SDK oficial anthropic para o endpoint nativo da Anthropic. O caminho /chat/completions, compatível com OpenAI, ainda não propaga os marcadores cache_control. Para o cache do Claude, use /v1/messages.
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=...)
Opções de TTL. {"type": "ephemeral"} usa por padrão um TTL deslizante de 5 minutos. Cada hit adia a expiração. Para workloads com períodos ociosos acima de 5 minutos, solicite um TTL de 1 hora no mesmo marcador:
"cache_control": {"type": "ephemeral", "ttl": "1h"}
Pontos de interrupção em camadas. Com até quatro marcadores, é possível armazenar separadamente conteúdo que “nunca muda”, “raramente muda” e “muda por tarefa”. Esse é o melhor padrão para workloads de agentes e RAG, nos quais diferentes trechos do prompt mudam em frequências distintas. Mesmo que a camada final, como os documentos recuperados, mude entre as chamadas, as camadas anteriores continuam acertando o cache.
Escolha do modelo. IDs do Claude disponíveis no gateway em 2026-05: claude-haiku-4-5, claude-sonnet-4-5 / 4-6, claude-opus-4-5 / 4-6 / 4-7. Use Haiku para chats econômicos, Sonnet para uso geral e para o padrão mais robusto de cache com agentes, e Opus para as tarefas de raciocínio mais difíceis.
Referência medida de cache hit, gravação e ausência de cache (2026-05-25, system prompt com aproximadamente 7.976 tokens, max_tokens=64):
| Modelo | Gravação no cache | Leitura do cache | Referência sem cache | Desconto na leitura | TTFT com hit (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 |
O desconto é uniforme em toda a família. A gravação custa cerca de 25% a mais do que uma chamada sem cache, conforme a tarifa documentada pela Anthropic; um único cache hit já compensa esse adicional.
3. OpenAI GPT-5.x — Cache automático
A OpenAI armazena automaticamente qualquer requisição que tenha um prefixo longo o suficiente. Não é preciso alterar o código nem adicionar marcadores.
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
O mesmo prompt de 6.887 tokens foi enviado duas vezes. Na segunda chamada, 93% do system prompt acerta o cache, e a latência total cai de 3.6 s para 1.2 s. O custo quase não muda neste caso porque o desconto do cache foi compensado por uma conclusão mais longa na primeira chamada. A §7 traz números mais comparáveis entre provedores.
No gpt-5.4-nano, o desconto aparece com mais clareza: o custo caiu 44% no cache hit. Em interfaces de chat nas quais o principal indicador é o tempo até o primeiro token, os números de streaming são mais relevantes:
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 na chamada com cache: 0.73 s para gpt-5.4-mini e 1.00 s para gpt-5.4-nano.
4. Google Gemini — Cache implícito
O cache do Gemini também é automático quando a chamada passa pelo gateway. Não é preciso executar antes uma etapa de criação de cachedContent.
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)
Em um hit medido no gemini-2.5-flash, com um system prompt de aproximadamente 7.300 tokens, 7.140 tokens vieram do cache (97%). O custo caiu de $0.00198 para $0.00024, uma redução de 88% nessa chamada.
Duas armadilhas conhecidas:
- As variantes
*-prodo Gemini são modelos de raciocínio. Commax_tokensbaixo, é comum recebercompletion_tokens=0, pois o orçamento é consumido pelo raciocínio interno. Para respostas exibidas ao usuário, aumentemax_tokenspara ≥256. - O TTL do cache implícito é curto e não está documentado oficialmente. Em nosso teste, duas chamadas separadas por 5 s geraram um hit; uma terceira chamada, cerca de 10 s depois, às vezes resultava em miss. Não crie lógica que dependa do hit. Verifique
cached_tokense trate o miss sem interromper o fluxo.
5. DeepSeek-v4-flash — Cache automático em disco
O cache automático do DeepSeek dura mais do que os caches residentes na memória da GPU de outros provedores. O formato da chamada é o mesmo:
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 em streaming na chamada com cache: 2.93 s. O DeepSeek não tem a menor latência deste conjunto. Os principais ganhos estão no custo e no fato de o cache permanecer aquecido mesmo após intervalos de horas.
6. Alibaba Qwen — Hit informado, desconto variável
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
Há uma ressalva em nossa execução: cached_tokens registrou um hit, com 7.040 de 7.234 tokens, ou 97%, mas usage.cost não caiu na chamada com cache e permaneceu em aproximadamente $0.0055. O cache hit ocorreu no provedor, como mostra o TTFT menor, de 1.53 s em vez de 3.03 s sem cache. Porém, nessa data, o campo de custo calculado pelo gateway ainda não refletia o desconto do cache para esse provedor. Se o custo do Qwen for crítico para seu workload, monitore cached_tokens e use as páginas de preços do provedor como referência até que o valor seja normalizado.
7. Benchmark entre provedores (medido em 2026-05-25)
Uma única execução sequencial. System prompt estável com 7.284 caracteres, equivalentes a aproximadamente 6.900–7.300 tokens, dependendo do tokenizer. max_tokens=64. Uma chamada com miss seguida imediatamente por uma chamada com hit.
Provedores com cache automático, sem necessidade de marcadores:
| Modelo | Custo do miss | Custo do hit | Variação do custo | Total no miss | Total no hit | TTFT com hit (stream) | Taxa de cache hit |
|---|---|---|---|---|---|---|---|
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%) |
* Na chamada com miss do gpt-5.4-mini, a conclusão teve 44 tokens, contra 19 no hit. A diferença de custo combina o desconto do cache com a variação no tamanho da conclusão. A queda de latência, de 3.63 para 1.23 s, é um indicador mais confiável neste caso.
† Custo da chamada em streaming, na qual cached_tokens foi informado. Para o Gemini, a chamada sem streaming às vezes retornou cached_tokens=null, sem redução de custo. Os metadados do gateway para o Gemini ainda são inconsistentes; quando cached_tokens estiver presente, use esse valor.
‡ Os modelos de raciocínio *-pro / *-flash do Gemini frequentemente não emitem tokens de conteúdo quando max_tokens é baixo. Nesse orçamento, o TTFT não é significativo. Aumente max_tokens ao medir isso em produção.
§ Consulte a §6. O cache hit ocorreu no provedor e reduziu a latência, mas, nessa data, o campo usage.cost do gateway não refletia o desconto para qwen3-max.
O Anthropic Claude exige marcadores explícitos. Os números ficam em uma tabela separada porque o desconto depende da ativação com cache_control; o padrão está na §2. Mesmo prompt, comparando gravação e leitura do cache:
| Modelo | Custo de gravação | Custo de leitura | Desconto na leitura | TTFT com hit (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 |
Seus resultados variarão conforme a região, o horário e o aquecimento dos prefixos de outros tenants. Esta foi uma única execução em uma única data; não trate os resultados como referência definitiva.
8. Checklist antes do lançamento
Antes de colocar em produção um prompt com suporte a cache:
- Conteúdo estável no início — system prompt, base de conhecimento e schemas de ferramentas no topo de
messages. - Conteúdo volátil no fim — entrada do usuário, documentos recuperados e timestamps no final.
- Nenhuma variável dinâmica em
system— hora atual, ID do usuário e seeds aleatórios invalidam o prefixo. - Registre
cached_tokensem todas as chamadas. Se a taxa de hit em produção estiver abaixo de 50%, seu prefixo não é realmente estável. Inspecione os prompts que geraram miss. - Não confie em um único hit. Os TTLs são curtos; projete para
hit_rate ∈ [0, 1), não para “sempre haverá hit”.
9. Padrões que consideram o TTL
O problema mais comum em produção não é “esqueci de habilitar o cache”, mas “minha taxa de hit é 12% porque as requisições não chegam dentro da janela do TTL”.
8.1 Workloads vinculados à sessão (chat, assistentes de IDE)
A cadência natural fica bem abaixo do TTL. Estruture o prompt corretamente e o cache permanecerá aquecido sozinho. Não é preciso criar nenhum mecanismo adicional.
8.2 Heartbeat para batch / cron
Suponha que um relatório diário seja executado às 09:00 e faça 50 chamadas ao modelo em 3 minutos. A primeira gravação no cache às 09:00 será desperdiçada, pois o cache esfriou durante a noite. A partir das 08:55, envie um “ping” de 1 token com o prefixo armazenado a cada TTL/2 para mantê-lo aquecido:
def keepalive():
oai.chat.completions.create(
model="gpt-5.4-mini",
max_tokens=1,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "."},
],
)
O custo de cada ping corresponde aos tokens de entrada multiplicados pela tarifa de cache. Para nosso prefixo de 7 mil tokens no gpt-5.4-mini, isso fica em torno de $0.0026, muito menos do que deixar o job batch pagar pelo prefill completo nas primeiras 50 chamadas reais.
8.3 Documentos em armazenamento frio
Para documentos consultados esporadicamente, como uma vez por hora ao longo do dia, os caches em memória ficarão frios na maior parte do tempo. No momento da publicação, o gateway não oferece um endpoint hospedado para criar caches explícitos. Se precisar de TTL longo, use deepseek-v4-flash, cujo cache em disco sobrevive na prática a intervalos de horas, ou chame diretamente a API nativa cachedContent do Google fora do gateway.
10. O que o gateway realmente acrescenta
Não seria correto afirmar que o gateway “faz o cache para você”. O cache acontece na camada do modelo; o gateway apenas expõe o que já existe. Em comparação com o uso direto do SDK nativo de cada provedor, ele acrescenta três coisas:
- Um base_url, um header de autenticação, todos os modelos. Troque o campo
modele mantenha o mesmo formato de chamada. O arraymessagese a estrutura do campousagecontinuam iguais. Não é preciso manter cinco SDKs para cinco provedores. usage.costem USD por chamada. O gateway calcula o custo em dólares usando as tarifas atuais do provedor e o inclui em todas as respostas. Você não precisa manter uma tabela de preços no código nem acompanhar notificações de alteração de preço de cada provedor.- Campo
cached_tokensuniforme. A Anthropic informa hits comocache_read_input_tokens; a OpenAI, comoprompt_tokens_details.cached_tokens; e a DeepSeek, comoprompt_cache_hit_tokens. O gateway normaliza esses campos para o formato da OpenAI, evitando condicionais por provedor no código de observabilidade.
Essa é toda a proposta. O restante, como decidir quando usar cache, estruturar os prompts e escolher o modelo, fica para o próximo artigo.
A seguir: Parte 4 — Como escolher o melhor LLM por caso de uso: chat, API e agentes de IA — uma matriz de decisão que associa cada tipo de workload ao modelo e à estratégia de cache ideais, incluindo o cálculo de custos.
FAQ
Por que usar o SDK da OpenAI com modelos de outros provedores?
O gateway usa o protocolo da OpenAI para todos os provedores que disponibiliza. O SDK oficial openai oferece respostas tipadas, novas tentativas automáticas e helpers de streaming. Não há motivo para implementar e manter cinco clientes HTTP diferentes.
O cache funciona com respostas em streaming?
Sim. O objeto usage no último chunk informa a quantidade de cache hits quando stream_options={"include_usage": True} é enviado. O ganho de latência aparece com mais clareza no streaming, pois o TTFT é o que o usuário percebe.
Qual provedor oferece o maior desconto de cache para meu workload?
Com os preços de 2026-05 e uma taxa de hit acima de 70%, gemini-2.5-flash e deepseek-v4-flash são os mais baratos na tabela da §7. O gpt-5.4-mini tem o melhor TTFT. Para obter o desconto documentado de 90% no cache do Claude, marque até quatro pontos de interrupção com cache_control, como mostrado na §2. Execute o mesmo benchmark com seu próprio prompt. É um teste de um dia, não uma migração de várias semanas.
Quando preciso usar marcadores cache_control?
Somente ao chamar o Anthropic Claude; consulte a §2. Em OpenAI, Gemini, DeepSeek e Qwen, o provedor armazena automaticamente qualquer prefixo longo o suficiente. Nenhum marcador é necessário, e esses provedores simplesmente ignoram o campo.
Esses números são recentes? Foram medidos em 2026-05-25 no gateway público. Trate-os como um único ponto de referência; preços e latência mudam a cada ciclo de lançamento.
E o Anthropic Claude?
O gateway oferece suporte ao Claude com marcadores cache_control explícitos. Use o SDK anthropic com base_url="https://synthorai.io/"; o SDK acrescenta /v1/messages. Atualmente, o caminho /chat/completions, compatível com OpenAI, não propaga os marcadores. Para usar especificamente o cache do Claude, siga o caminho nativo da Anthropic mostrado na §2.
Fontes e verificação: Todos os números foram medidos em https://synthorai.io/v1 em 2026-05-25, usando o SDK openai 2.38.0. Páginas de preços dos provedores: Cache de prompts da Anthropic · Cache de prompts da OpenAI · Cache de contexto do Google Gemini · Guia de KV Cache da DeepSeek · Cache de contexto do Alibaba Bailian.