Em 8 de outubro de 2026, a Asana publicou um estudo de 144 execuções mostrando que conseguiu reduzir em 76 vezes o custo e em 5 vezes o tempo do seu agente de navegador. No dia seguinte, a OpenAI publicou o case no próprio blog. O número é real, mas a leitura rápida engana: o ganho não veio de um modelo novo milagroso, veio de arrumar como o agente usava o cache do prompt. A mesma otimização, rodada no modelo que a Asana já tinha em produção (chamado Model B), cortou o custo em 29x sozinha. GPT-6.1 Sol forneceu os 2,6x restantes.
Este artigo é sobre a parte que transfere para qualquer agente que você rode em qualquer modelo: a mecânica de prefixo de cache e por que a maneira como você monta o histórico destrói ou preserva esse desconto.
Como funciona o prompt caching em um agente de navegador
Um agente de navegador é um loop. A cada passo ele manda para o modelo três coisas: as instruções fixas (system prompt), as definições das ferramentas que pode chamar (clicar, digitar, tirar screenshot, ler texto) e o histórico do que já aconteceu até agora (texto das páginas visitadas e screenshots). O modelo responde com a próxima ação, o navegador executa, e o histórico cresce. Repete.
A cada chamada o agente reenvia tools, system prompt e esse histórico crescente de texto e screenshots. Isso é caro porque o histórico é a parte que mais cresce e é a maior parte do input.
A ideia do prompt caching é cobrar barato por aquilo que o provedor já viu na requisição anterior. Nos modelos testados pela Asana, leitura de cache custa entre 0,05x e 0,1x do preço normal de input. Ou seja, se o seu prefixo bater, você paga de 5% a 10% do que pagaria sem cache naquela parte.
O detalhe que decide tudo: o cache só reusa o maior prefixo inalterado da requisição. Não é um cache por pedaço, não é um cache por chave. É prefixo. Se qualquer byte no meio mudar, do ponto de mudança em diante o desconto some.
Uma analogia que carrega a mecânica
Pense numa pilha de livros em cima de uma mesa. O desconto é por quantos livros, de baixo para cima, estão exatamente iguais aos da pilha anterior. Se você mantém os de baixo intactos e só coloca livros novos no topo, conta todos de baixo como “iguais”. Se você tira um livro do meio para reorganizar, do ponto em que você mexeu para cima nada conta mais, mesmo que lá em cima tudo esteja idêntico. A analogia quebra num ponto: o cache tem janela de tempo e tamanho máximo, enquanto a pilha de livros não evapora sozinha. Fora isso, a mecânica é essa.
Os dois erros que compunham
A Asana descobriu, usando o GPT-6 Astra dentro do Codex para auditar o código, dois problemas que se amplificavam:
O agente em produção fazia cache das instruções fixas e das definições de ferramentas mas não do histórico de navegação. E editava esse histórico quase a cada passo: largava o screenshot anterior toda vez e cortava texto antigo para caber num budget de histórico. Cada edição invalidava o prefixo, então o cache seria quase inútil mesmo que estivesse ligado.
Os dois erros se multiplicavam. Sem cache no histórico, você já paga caro pelo pedaço que mais cresce. E, por editar no meio, mesmo que ligasse o cache ele estouraria toda chamada.
A correção: histórico append-only e batch pruning
A solução tem duas partes:
Primeiro, fazer cache do histórico também, com um marcador de cache no último resultado de ferramenta. Segundo, parar de editar o histórico a cada chamada. O batch pruning mantém screenshots e os remove em lotes: na proporção 20:1, o agente guarda até 20 e então corta de volta para 1, de modo que cerca de 19 chamadas consecutivas reusam o histórico em cache.
Em vez de remover o screenshot anterior toda chamada (edição no meio, prefixo quebra), você deixa acumular até 20 e só então faz uma poda. Entre podas, você só anexa. Append-only no histórico significa que o prefixo cresce sem mudar o que já está lá, e o cache bate em quase tudo.
A Asana também fez uma mudança não óbvia: aumentou o budget de histórico de 120.000 para 480.000 caracteres. Contraintuitivo se você acha que menos tokens é sempre melhor, mas faz sentido na mecânica de cache: se o budget é apertado e você corta texto antigo para caber, você está editando o prefixo. Com budget maior, você raramente precisa cortar, e cada caractere adicional entra no desconto de cache em vez do preço cheio.
O que isso significa na prática
O número que explica o resultado:
No GPT-6.1 Sol com o budget maior, a nova política de cache e screenshots reduziu o custo em 4x, de 1,97 para 0,47 dólares por execução. Cada chamada ficou cerca de 3x mais barata, porque 89% do input vinha do cache a 5% do preço não cacheado.
Guarde esse 89%. É a métrica que você mesmo precisa medir no seu agente: qual fração do input de cada chamada é cache read. Se está baixa, não adianta trocar de modelo, adianta arrumar o prefixo.
Um pseudocódigo do loop corrigido, para ancorar:
historico = []
screenshots = []
MAX_SCREENSHOTS = 20
while not terminou:
# append-only: so adiciona no fim
historico.append(nova_observacao_texto)
screenshots.append(novo_screenshot)
# poda em lote: so quando estourar, e de uma vez so
if len(screenshots) > MAX_SCREENSHOTS:
screenshots = [screenshots[-1]] # corta para 1
requisicao = montar(
system_prompt, # fixo, cacheado
tools, # fixo, cacheado
historico, # cresce, agora cacheado
screenshots, # muda em lotes, cacheavel entre podas
cache_marker_no_ultimo_tool_result=True,
)
acao = modelo.chamar(requisicao)
executar(acao)
O que o código antigo fazia de errado estava escondido num detalhe banal: dentro de montar(), o agente dropava o screenshot anterior antes de concatenar. Operação de uma linha, consequência de ordem de grandeza no custo.
Esse padrão aparece fora de agentes de navegador também. Numa extensão de navegador que construí para escrever direto num CRM, a decisão de validar o payload antes de executar a escrita custa latência extra justamente porque obriga uma chamada de modelo adicional, e cada chamada paga de novo o custo do contexto. Quando o contexto é grande, a diferença entre cache read e input cru decide se validar antes é viável ou não. Chamada bem sucedida de API não diz nada sobre o payload fazer sentido, então validar vale a pena, mas só porque dá para fazer o cache absorver quase todo o input.
Onde quebra
Nem tudo transfere igual, e o próprio estudo mostra onde:
A Asana rodou um follow-up perguntando se é preciso podar. Em certos casos manter todos os screenshots custou 1,2x menos por chamada que a melhor condição de poda no Model B e no GPT-6.1 Sol, e cerca de 5% menos no Model C. Poda ainda importa para tarefas longas, janelas de contexto pequenas e leituras de cache mais caras.
Ou seja, o 20:1 não é uma receita universal. Depende de quão caro é cache read no seu modelo, de quão grande é a janela e de quanto dura a tarefa. Se seus screenshots forem pesados e o modelo tiver janela pequena, não podar vai estourar contexto antes do fim. Se cache read for barato o suficiente, segurar tudo pode ser mais barato que a lógica de poda.
Outros limites reais:
- O desconto só existe se o provedor que você usa oferece prompt caching e se você está montando a requisição de um jeito que ele reconhece. Em alguns provedores você precisa marcar explicitamente o ponto de corte do cache, em outros é automático pelo prefixo. Confira a documentação do seu antes de supor.
- Cache tem TTL. Se seu agente faz pausas longas entre chamadas, o cache expira e você paga o preço cheio no próximo passo. A economia depende de cadência.
- Aumentar o budget de histórico para 480k caracteres só é barato porque quase tudo entra no cache. Se o cache não bater, você está pagando input cheio em um prompt gigante, pior que antes.
- O 76x é um número de teste, não de produção estável. Rodaram três vezes cada condição, não durante semanas em usuários reais. O ganho esperado em produção depende da variância de tarefas que você não controla.
O que não dá para afirmar ainda
O material público é um resumo com números principais e um post técnico do time do StackAI, mas várias peças ficaram de fora:
- Qual é o Model B exatamente. O estudo chama de A, B e C os três modelos de fronteira não-OpenAI, sem nomear. Então não dá para dizer se seu caso de uso em outro provedor se comporta como esse Model B.
- Qual era o conjunto de tarefas do benchmark. O estudo diz que os custos foram calculados pelos próprios contadores de token de cada provedor e que cada resposta foi avaliada contra uma referência preparada de forma independente, mas o detalhe das tarefas e dos critérios de qualidade não está no resumo público.
- O impacto em qualidade da resposta nas condições otimizadas. O post diz que o objetivo era baratear sem reduzir qualidade, mas o resumo não mostra os números de qualidade por condição.
- Como o cache marker é implementado em cada provedor. A ideia é portável, a API de cada um não é.
Nada disso invalida o resultado. Só delimita o que você pode copiar com confiança (a mecânica de prefixo, append-only, poda em lote) e o que você precisa medir no seu próprio contexto (números absolutos, limiar ideal de poda, qualidade final).
Como testar isso você mesmo
Um caminho pequeno, que cabe numa tarde:
- Escolha um agente simples que você já tenha, de preferência um que faça várias chamadas numa tarefa. Pode ser um agente de pesquisa, um de preenchimento de formulário, qualquer loop com histórico crescente.
- Instrumente cada chamada ao modelo e salve, do retorno da API, dois números: tokens de input totais e tokens de input lidos do cache. Quase todo provedor expõe isso. Divida um pelo outro: essa é sua taxa de cache hit.
- Rode a tarefa com o código atual. Anote a taxa de cache hit por chamada. Se estiver abaixo de 50% a partir da terceira chamada, há prefixo quebrando no meio.
- Audite onde você edita o histórico. Qualquer
remove,pop,slice, truncate ou substituição de item antigo é suspeito. Transforme em append-only. - Se precisar podar (contexto apertado), implemente poda em lote. Comece com um limiar de 10 ou 20 e meça. O número 20:1 da Asana foi o que performou melhor no caso deles, não uma constante universal.
- Rode a mesma tarefa de novo. Compare taxa de cache hit, custo total e tempo. Se cache hit subiu e custo caiu sem queda de qualidade, você reproduziu o mecanismo.
O ponto a levar deste caso não é que exista um modelo mágico. É que a maior parte do ganho veio de parar de editar o meio do prompt. Isso é uma decisão de arquitetura do seu loop, não do fornecedor do modelo.





