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

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
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 comnpm install -g promptfooou como dependência do projeto comnpm 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
- 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
- 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
- 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
- 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
- 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
- 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 😛
- 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
- 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
- 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
- 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:
- roda
npx promptfoo@latest init - 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)
- escreve o critério de aprovação de cada uma ANTES de rodar
- guarda o baseline com o model ID fixado, a data e a versão da ferramenta
- 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.
Formações
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Blog | Mais populares
Como Recuperar Conversas Apagadas no ChatGPT: É Possível?
Descubra neste artigo tudo o que você precisa saber sobre como recuperar conversas apagadas no ChatGPT, se isso é possível, quais alternativas existem para proteger […]
ChatGPT não funciona: saiba como corrigir erros
ChatGPT não funciona? O ChatGPT pode deixar de funcionar por diversos motivos, e a maioria deles está relacionada a problemas de conexão, cache ou instabilidade […]
Como limpar histórico do ChatGPT e proteger sua privacidade
Veja como limpar o histórico do ChatGPT e proteger sua privacidade de forma simples e eficaz, mantendo seus dados seguros online. Para apagar uma conversa […]
