Como montar um eval de regressão para saber se a atualização do modelo piorou o seu caso

eval de regressão comparando respostas de um modelo de IA antes e depois de uma atualização
Resposta rápida

Um eval de regressão é um conjunto fixo de tarefas reais do seu backlog, com critério de aprovação escrito antes, que você roda de novo a cada mudança de modelo, de prompt ou de ferramenta. Ele não serve pra ranquear modelo: serve pra flagrar piora silenciosa no SEU caso. Dá pra montar com o promptfoo (npx promptfoo@latest init e npx promptfoo@latest eval) ou com a Evals API da OpenAI. O segredo é guardar um baseline com o model ID fixado e comparar rodada contra rodada, em vez de discutir no achismo 🙂

Aquela sensação de que o modelo "ficou pior" essa semana é a discussão mais improdutiva que existe hoje na nossa área

Você não mudou nada, o prompt é o mesmo, o projeto é o mesmo, e mesmo assim a entrega veio capenga

Aí vem a timeline: metade jura que degradaram o modelo, a outra metade jura que é impressão sua

Sem um conjunto fixo de casos pra rodar de novo, ninguém tem como provar nada, e o papo morre em achismo

A ideia deste post é bem específica: montar um eval de regressão pro SEU caso

Não é ranking, não é benchmark público, não é descobrir qual modelo é o melhor do mundo

É ter um alarme que dispara quando aquilo que funcionava no seu fluxo parou de funcionar, beleza?

Por que a piora costuma ser silenciosa (e o que os postmortems mostram)

A piora quase nunca chega com aviso na tela

Ela chega como "tá estranho hoje", e você não tem nada pra comparar

E isso não é paranoia de dev cansado: já foi documentado

No postmortem An update on recent Claude Code quality reports, publicado em 23 de abril de 2026, a Anthropic admitiu que três mudanças diferentes, feitas em janelas próximas, degradaram o comportamento do Claude Code e geraram uma onda de reclamações de qualidade

Se liga no que eram essas mudanças:

  • o esforço de raciocínio padrão do Claude Code foi trocado de high para medium, pra reduzir latência: alterado em 4 de março, revertido em 7 de abril de 2026
  • uma mudança de 26 de março de 2026 limpava o raciocínio antigo em sessões ociosas por mais de uma hora, só que um bug fez isso acontecer a cada turno pelo resto da sessão, deixando o modelo repetitivo e esquecido
  • uma instrução de system prompt pra reduzir verbosidade, combinada com outras mudanças de prompt, prejudicou a qualidade de código: adicionada em 16 de abril, revertida em 20 de abril de 2026

Repara no formato disso

Nenhuma dessas três coisas aparece pra você como erro

A sessão continua rodando, o modelo continua respondendo, e o que muda é a qualidade no meio do caminho

E tem o episódio anterior, no postmortem A postmortem of three recent issues, de 17 de setembro de 2025, quando três bugs de infraestrutura degradaram intermitentemente a qualidade das respostas do Claude

Formação Claude Code
Formação Recomendada

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 114 aulas
  • 4 projetos
  • 9h 18min

Ali a Anthropic afirma que nunca reduz a qualidade do modelo por causa de demanda, horário ou carga de servidor, e mostra os números do estrago: um bug de 5 de agosto afetou cerca de 0,8% das requisições ao Sonnet 4, na pior hora, em 31 de agosto, 16% das requisições ao Sonnet 4 foram afetadas, e cerca de 30% dos usuários de Claude Code que fizeram requisições no período tiveram ao menos uma mensagem roteada pro tipo errado de servidor

Olha o tamanho da pegadinha: 0,8% é um número que NENHUMA percepção humana pega

Você só sente que "hoje tá ruim"

Mas fixar o model ID não me protege?

Protege bastante, e vale usar

Todo model ID da Claude API é um snapshot fixado, e a partir da geração Claude 4.6 os IDs passaram a usar formato sem data, mas continuam sendo snapshot fixado, não um ponteiro que muda sozinho

Só que fixar não é pra sempre

A Anthropic trabalha com um ciclo de vida de quatro estados (Active, Legacy, Deprecated e Retired), avisa clientes com implantações ativas pelo menos 60 dias antes da aposentadoria de modelos lançados publicamente, e requisições a modelos aposentados falham

Ou seja: o ID te dá estabilidade, e o eval te dá a prova de que o resto do sistema (prompt, CLI, ferramenta, roteamento) não mexeu no seu resultado

O que você precisa antes de começar

Pouca coisa, e provavelmente você já tem tudo:

  • Node e npm na máquina, pra rodar o promptfoo via npx, instalar global com npm install -g promptfoo ou como dependência do projeto com npm install promptfoo
  • Chave de API do seu provedor, a mesma que você já usa
  • O model ID exato que você usa hoje, anotado num arquivo, não na memória
  • Uma lista de tarefas reais já resolvidas do seu backlog, com a saída que você considerou boa na época

Esse último item é o insumo mais importante do post inteiro

Eval de regressão bom não nasce de caso inventado: nasce de coisa que você JÁ mandou pro modelo e JÁ aprovou

E o que NÃO é pré-requisito: dataset gigante, time de dados, plataforma paga, pipeline de MLOps

Dá pra começar com um arquivo YAML e uma pasta 😀

Passo a passo: montando o eval de regressão do seu caso

  1. Garimpe tarefas reais do seu backlog

Abre o histórico das suas sessões e pega tarefas que você mandou de verdade: aquele componente, aquela migration, aquele refactor, aquele parser chato

A documentação da Anthropic sobre construir avaliações recomenda priorizar volume de casos sobre perfeição de cada caso, e diz pra preferir mais questões com sinal um pouco menor a poucas questões corrigidas à mão

Traduzindo pro nosso contexto: melhor vinte casos meia boca do que três casos lindos

O erro comum deste passo: inventar caso sintético bonitinho que nunca apareceu no seu trabalho

Caso sintético passa sempre, e não protege nada

  1. Escreva o critério de aprovação ANTES de ver a resposta nova

Pra cada caso, escreve numa linha o que faz aquilo ser considerado aprovado: precisa ter tal função exportada, precisa citar tal campo, precisa não inventar dependência, precisa vir com teste

O erro comum deste passo: rodar primeiro, olhar a saída e só então decidir o critério

Aí você não tem um eval, você tem uma justificativa

  1. Escolha o método de correção

A doc da Anthropic descreve três caminhos: exact match (com normalização de espaços e caixa), correção por código, e LLM como juiz instruído a responder apenas ‘correct’/’incorrect’ ou uma nota de 1 a 5

Regra prática: se dá pra checar por código, cheque por código

Juiz LLM entra quando o critério é qualitativo mesmo (tipo "a explicação está clara")

O erro comum deste passo: juiz LLM com instrução aberta do tipo "avalie a qualidade"

Instrução vaga gera nota vaga, e nota vaga oscila entre rodadas sem o modelo ter mudado nada

  1. Rode o init do promptfoo

O promptfoo é uma CLI e biblioteca open source pra avaliar aplicações e agentes de IA, configurada por um arquivo YAML

npx promptfoo@latest init

Isso cria o promptfooconfig.yaml, que tem três blocos centrais: prompts, providers e test cases

Se você conhece arquivo de config de linter, a lógica é a mesma: o comportamento todo mora num arquivo versionado

O erro comum deste passo: esquecer que a avaliação roda no diretório criado, e depois ficar procurando resultado na pasta errada

  1. Fixe o model ID como snapshot no provider

No bloco de providers, cole o model ID exato que você usa hoje, aquele que você anotou lá nos pré-requisitos

prompts:
  - "{{tarefa}}"

providers:
  - id: "<cole aqui o model ID exato que você usa hoje>"

tests:
  - vars:
      tarefa: "Refatore o service de pagamento pra separar validacao de persistencia"
    assert:
      - type: contains
        value: "validate"

Sem o ID fixado, você compara duas coisas diferentes e chama isso de regressão

O erro comum deste passo: deixar o provider genérico e depois não saber contra o que o baseline foi gerado

  1. Rode a avaliação e salve como baseline
npx promptfoo@latest eval

Com instalação global ou como dependência, é só promptfoo eval

Essa primeira execução é o seu retrato do "antes"

Guarda ela junto do model ID, da data e da versão da ferramenta que você usa

O erro comum deste passo: rodar, olhar a telinha, achar bonito e não guardar nada

Baseline que não foi salvo não existe 😛

  1. Use o threshold nas assertions pra aceitar pass parcial

O promptfoo tem o campo threshold nas assertions, que define o critério de pass/fail por desempenho das asserções do caso

Isso serve pro caso realista, aquele com cinco exigências onde falhar uma não significa que o modelo destruiu tudo

tests:
  - vars:
      tarefa: "Gere o endpoint de listagem com paginacao e teste"
    threshold: 0.8
    assert:
      - type: contains
        value: "limit"
      - type: contains
        value: "offset"
      - type: llm-rubric
        value: "Responda apenas correct ou incorrect: o codigo inclui teste automatizado?"

O erro comum deste passo: exigir 100% em todo caso e transformar o eval num alarme que toca todo dia

Alarme que toca sempre é alarme desligado

  1. Cuide do cache antes de comparar

O promptfoo guarda respostas de API em cache em disco por padrão, com TTL de 14 dias, o que barateia rodar o mesmo eval de novo

Ótimo pra economia, PÉSSIMO se você trocou de modelo e esqueceu disso

promptfoo eval --no-cache
promptfoo cache clear

Na config, dá pra desligar com { evaluateOptions: { cache: false } }

O erro comum deste passo: comparar resposta velha em cache com modelo novo e concluir que "não mudou nada"

Já me ferrei com esse tipo de armadilha em outros contextos, e é sempre o mesmo roteiro: horas debatendo um resultado que era só cache

  1. Plugue no CI e quebre o build quando cair

O promptfoo devolve exit code 100 quando há pelo menos 1 caso falhando ou quando a taxa de aprovação fica abaixo de PROMPTFOO_PASS_RATE_THRESHOLD

Se o seu runner precisa de outro código de saída, dá pra trocar pela variável PROMPTFOO_FAILED_TEST_EXIT_CODE

PROMPTFOO_PASS_RATE_THRESHOLD=0.9 promptfoo eval

O erro comum deste passo: rodar o eval no CI mas ignorar o código de saída, deixando o job verde com o eval vermelho

  1. Automatize a comparação antes/depois nos PRs de prompt

O promptfoo tem uma GitHub Action que, a cada PR que modifica um prompt, roda uma comparação completa entre a versão anterior e a nova

É o cenário mais comum de regressão silenciosa: alguém "melhora" o system prompt e três casos param de funcionar

E se o seu caso é agente de código, a documentação oficial mantém um guia específico, o ‘Evaluate Coding Agents’, que vale a leitura antes de modelar os casos

O erro comum deste passo: tratar prompt como texto solto fora do versionamento

Prompt que não passa por PR não tem como ter comparação antes/depois

promptfoo ou Evals API da OpenAI: qual usar no seu caso

Os dois resolvem o mesmo problema por caminhos diferentes

Item promptfoo Evals API da OpenAI
Formato CLI e biblioteca open source API, com eval criada e reexecutada
Configuração promptfooconfig.yaml com prompts, providers e test cases data_source_config (esquema dos dados) e testing_criteria (os graders)
Correção exact match, código e LLM como juiz string_check, TextSimilarityGrader, PythonGrader e ScoreModelGrader
Referência aos dados vars do YAML nos test cases {{item.nome_da_variavel}} e saída do modelo em {{sample.output_text}}
Cache cache em disco por padrão, TTL de 14 dias não coberto aqui
CI exit code 100 e GitHub Action de comparação em PR a mesma eval roda em modelos e parâmetros diferentes
Extra guia ‘Evaluate Coding Agents’ guias ‘Evaluation best practices’ e ‘Evaluate agent workflows’

Resumo do meu ponto de vista: se você quer rodar local, versionar no repo e quebrar build, promptfoo entrega isso com config em arquivo

Se a sua stack já vive dentro da OpenAI, a Evals API te dá a mesma eval rodando em modelos e parâmetros diferentes, que é exatamente o que a gente quer numa comparação de regressão

Dá pra ter os dois também, sem drama

Quando disparar o eval de novo

Eval de regressão só vale se tiver gatilho, senão vira aquele script que ninguém roda

  • Troca de model ID: o gatilho mais óbvio, e o mais fácil de esquecer quando a mudança vem de uma config compartilhada do time
  • Mudança de system prompt ou de CLAUDE.md: aqui o eval mostra se aquela sua instrução nova de "seja mais direto" cobrou um preço em qualidade, do mesmo jeito que a instrução de verbosidade adicionada em 16 de abril e revertida em 20 de abril de 2026
  • Atualização da CLI ou da ferramenta: o comportamento pode mudar sem o modelo mudar, e o eval separa uma coisa da outra
  • Mudança de parâmetros: mexeu em esforço de raciocínio ou em qualquer knob de execução, roda de novo, porque foi exatamente isso que aconteceu no ajuste de high pra medium de 4 de março, revertido em 7 de abril de 2026
  • Aviso de deprecation: quando um modelo entra em Legacy ou Deprecated, você tem pelo menos 60 dias pra testar o substituto com dados seus antes de virar a chave
  • Suspeita subjetiva de "ficou pior": esse é o melhor uso de todos, porque transforma sensação em dado

E antes de decretar culpa do modelo nesse último caso, vale revisar o prompt antes de culpar o coitado

Muita regressão percebida é prompt que envelheceu junto com o projeto

Eval verde e usuário reclamando: sinais falsos e como evitar

Essa é a parte que ninguém conta: eval mal montado mente com uma cara linda de dashboard verde

O eval passa, mas o uso real piorou

Causa provável: seus casos não representam o backlog de verdade, e cobrem só o pedaço fácil

Como prevenir: ampliar o volume de casos, seguindo a orientação da Anthropic de preferir mais questões com sinal um pouco menor a poucas questões corrigidas à mão

O resultado ficou idêntico demais depois de trocar de modelo

Causa provável: cache em disco servindo resposta antiga, com aquele TTL de 14 dias trabalhando contra você

Como prevenir: rodar com --no-cache ou limpar com promptfoo cache clear sempre que o provider mudar

Tudo falha de uma vez

Causa provável: critério exato demais, sem normalização

Como prevenir: usar exact match com normalização de espaços e caixa, ou migrar aquele critério pra correção por código

A nota do juiz oscila a cada rodada

Causa provável: instrução vaga pro LLM juiz

Como prevenir: instruir o juiz a responder apenas ‘correct’/’incorrect’ ou uma nota de 1 a 5, sem espaço pra ele filosofar

A regressão só aparece em sessão longa

Causa provável: seu eval só tem caso de um turno só

E olha que esse cenário é REAL: a mudança de 26 de março de 2026 limpava raciocínio antigo em sessões ociosas por mais de uma hora, e o bug fez isso acontecer a cada turno pelo resto da sessão, deixando o modelo repetitivo e esquecido

Um eval de um turno passaria voando por isso

Como prevenir: incluir casos multi turno, que simulem a sessão comprida que você vive de verdade

O que medir além do acerto: tempo, contexto e custo

Pass/fail é só metade da história

Uma atualização pode manter o acerto e destruir o custo, ou manter o custo e dobrar o tempo

Por isso eu anoto métrica operacional junto do resultado

Um exemplo concreto de como isso se parece na prática: quando testei o Kimi K3 no vídeo do canal, eu segui o meu método de sempre, que é rodar o mesmo tipo de projeto de referência (um analisador de contratos, partindo de uma pasta em branco, com o setup preparado antes) pra poder comparar com o que eu já vi em lançamentos anteriores

Eu não aceito benchmark como prova: muito número por aí é autorreportado, e só o teste próprio dá certeza

O que eu registrei ali:

  • tempo do scaffold inicial: cerca de 10 minutos, e eu comparo isso com o tempo que costumo ver em outros modelos bons na mesma tarefa
  • consumo de contexto: 7% a 8% da janela na primeira parte do teste, e 10% no momento em que rodei a compactação
  • custo acumulado: apareceu 0,63 em uma das etapas (a unidade não dá pra identificar na tela), e eu comentei que aquela etapa saiu mais cara do que eu esperava

Além dos números, tem o que eu checo com o olho: abro a aplicação no navegador e confiro item por item o que pedi, design, microinterações, fontes e seções da landing page

Nesse teste faltaram seções que eu tinha pedido no prompt, e eu registrei como falha em vez de aceitar a entrega

É exatamente esse tipo de checagem que vira asserção no seu eval depois

Eu também acompanho a lista de tarefas que a CLI mostra durante a execução, pra ver se o que está sendo feito bate com o que foi pedido, e valorizo o modelo rodar testes e build antes de entregar, porque sem build passando o deploy vira tiro no escuro

E testar o mesmo modelo em ambientes diferentes muda o resultado: numa tentativa anterior dentro do Claude Code, o Kimi não funcionou tão bem quanto na CLI própria

Deixando explícito: isso foi um teste generalista de outro modelo, serve como ilustração de baseline operacional, e não como benchmark do seu caso

O seu baseline tem que sair do seu projeto

Pra registrar custo direito vale a mesma lógica de saber se a economia foi real: sem número anotado antes, qualquer comparação depois é conversa

Pra começar do zero com esse método de comparar um modelo novo contra o que você já viu, esse vídeo do canal mostra o teste inteiro rodando, com o tempo do scaffold, o consumo de contexto e o custo aparecendo na tela

Conclusão: comece com dez casos ainda hoje

Eval de regressão não é sobre eleger o melhor modelo do mundo

É sobre proteger o seu caso de uma piora que você não consegue provar no olho

Os postmortems mostram bem esse padrão: mudanças pequenas, feitas em janelas próximas, gerando uma onda de reclamação de qualidade, e falhas de infraestrutura em fatias de requisição que nenhuma percepção humana pega

O próximo passo é bem curto:

  1. roda npx promptfoo@latest init
  2. cola dez tarefas do seu backlog no arquivo (dez é só pra você começar hoje, não é número mágico de fonte nenhuma, e quanto mais casos, melhor o sinal)
  3. escreve o critério de aprovação de cada uma ANTES de rodar
  4. guarda o baseline com o model ID fixado, a data e a versão da ferramenta
  5. agenda a reexecução pra próxima mudança de modelo ou de prompt

Daí, na próxima vez que aparecer aquele "tá pior hoje", você não entra na discussão de achismo

Você roda o eval e mostra o número 😀

até o próximo post!

Perguntas frequentes

Quanto tempo leva pra montar a primeira versão de um eval de regressão?

Não dá pra cravar um tempo aqui, porque isso depende de quantos casos você garimpar do seu backlog e de quão detalhado é o critério de aprovação de cada um. O que dá pra dizer é que a primeira versão é curta: o npx promptfoo@latest init já cria o promptfooconfig.yaml, e o resto é colar tarefas reais que você já mandou pro modelo e escrever o que faz cada uma ser aprovada. Comece pequeno, com uma lista enxuta de casos reais em vez de um dataset gigante, e vá aumentando o volume com o tempo.

Preciso usar o promptfoo ou dá pra montar o eval de regressão com outra ferramenta?

O promptfoo é só uma opção, configurada por um arquivo promptfooconfig.yaml e rodada com npx promptfoo@latest eval. Se você já usa a API da OpenAI, a Evals API dela também serve, criando a avaliação com data_source_config e testing_criteria. Em ambos os casos a lógica do eval de regressão é a mesma: casos fixos, critério fixo, resultado comparável ao longo do tempo.

Como faço o eval de regressão quebrar o build automaticamente no CI?

O promptfoo devolve o código de saída 100 quando pelo menos um caso falha ou quando a taxa de aprovação fica abaixo do limite definido em PROMPTFOO_PASS_RATE_THRESHOLD. Esse código pode ser trocado pela variável PROMPTFOO_FAILED_TEST_EXIT_CODE, se o seu pipeline precisar de outro valor. Ele também tem uma GitHub Action que roda a comparação completa entre a versão anterior e a nova a cada PR que altera um prompt.

O cache do promptfoo não corre o risco de esconder uma regressão real?

O promptfoo guarda respostas de API em cache em disco por padrão, com TTL de 14 dias, justamente pra baratear rodar o mesmo eval de novo. Quando você suspeita de uma mudança recente e quer garantir uma chamada nova de verdade, dá pra desligar com promptfoo eval --no-cache, desativar na config com { evaluateOptions: { cache: false } }, ou limpar tudo com promptfoo cache clear.

Dá pra usar eval de regressão pra avaliar agente de código, não só resposta de texto solta?

Sim, o promptfoo mantém um guia específico chamado ‘Evaluate Coding Agents’ pra esse cenário. Ele também permite exigir que só parte das asserções passe, usando o campo threshold em cada caso de teste, o que ajuda quando a saída do agente tem vários critérios de qualidade diferentes rodando juntos.

Preciso corrigir cada resposta do eval de regressão manualmente?

Não precisa, e a própria documentação da Anthropic recomenda o contrário: prefira mais casos com correção automática a poucos casos corrigidos à mão. Os métodos citados são exact match com normalização de espaços e caixa, correção por código, e LLM como juiz respondendo apenas ‘correct’/’incorrect’ ou uma nota de 1 a 5. A regra prática é simples: se dá pra checar por código, checa por código, e deixa o juiz LLM só pra critério qualitativo mesmo.




Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares