pular para o conteúdo
voltar ao mapa
componente
etapa: evaluate
4 min de leitura

Regression evals - suite fixa no PR

Regression evals é a suite imutável: dataset fechado, gate no merge, comparação contra baseline. É o que transforma 'acho que ficou melhor' em 'a métrica X caiu 2 pontos, bloquear o PR'.

pytestDeepEvalBraintrust CIpromptfoo

O que é

Regression eval é uma suite de casos que não muda junto com o código. Você congela o dataset (input, gabarito, métrica), e cada PR é avaliado contra esse dataset. Se uma métrica cai abaixo do baseline, o PR falha e o merge trava. O objetivo é simples: parar de discutir se a mudança melhorou ou piorou.

A diferença para o eval genérico é a imutação. O eval do PR pode crescer, ser editado, incluir casos novos. O regression eval é contrato: igual ao da última release, com a única mudança permitida sendo a versão baseline.

Dataset imutável versus dataset vivo

A manutenção do dataset é onde a maioria dos times erra. Dois caminhos. Imutável puro: dataset freezeado a cada release, só cresce quando uma regressão é detectada e adicionada como caso novo. Versátil: dataset versionado (git LFS), PR pode propor casos, merge só aceita se aumentar a cobertura.

A escolha muda o que 'regressão' significa. Imutável puro detecta só drift; versátil detecta drift e adiciona novos buracos. Para times que ainda estão aprendendo o que medir, versátil vence. Para times que têm o produto estável há meses, imutável vence, porque a suite vira contrato de SLA.

Gate no PR: o esqueleto

O esqueleto abaixo mistura duas referências conhecidas (promptfoo e Braintrust) para mostrar a mecânica real: arquivo de casos em YAML, runner que compara contra baseline, e veredito booleano que o step de CI consome.

regression/run.ts (estilo promptfoo + Braintrust CI)typescript
import fs from "node:fs";
import { runAgent } from "../src/agent";
import { assertFidelidade, assertRelevancia } from "./asserts";
import { loadBaseline, saveBaseline } from "./baseline";

type Case = { id: string; pergunta: string; gabarito: string; contexto: string };

type Metric = "fidelidade" | "relevancia";

async function runOne(c: Case) {
  const out = await runAgent({ pergunta: c.pergunta, contexto: c.contexto });
  return {
    id: c.id,
    fidelidade: await assertFidelidade(out, c.gabarito, c.contexto),
    relevancia: await assertRelevancia(out, c.pergunta),
  };
}

export async function runRegressionSuite(path: string) {
  const cases: Case[] = parseCases(fs.readFileSync(path, "utf8"));
  const baseline = loadBaseline("regression.baseline.json");
  const results = await Promise.all(cases.map(runOne));
  const report: Record<Metric, number> = { fidelidade: 0, relevancia: 0 };
  for (const m of ["fidelidade", "relevancia"] as Metric[]) {
    const avg = results.reduce((a, r) => a + r[m], 0) / results.length;
    report[m] = avg;
    const drop = baseline[m] - avg;
    if (drop > 0.02) throw new Error(`regressão em ${m}: baseline ${baseline[m]} vs atual ${avg}`);
  }
  return report; // CI consome e decide gate

Baseline, limiar e amostragem

O baseline é o último release verde. Você persiste (em artefato, em git, em object store) a métrica por caso, e o runner compara caso a caso. Limiar define o quanto pode cair antes de falhar. Limiar de 0.02 (2 pontos percentuais) costuma ser conservador; abaixo disso, falso positivo come tempo do time. Acima, regressão real vira release.

Nem todo PR precisa rodar a suite completa. Para PR pequeno, amostragem aleatória de 20% dos casos resolve. Para PR de release, suíte completa. O custo é o principal motivo de times abandonarem suite fixa: rodar 500 casos a cada PR custa cinco minutos e logo vira alvo de bypass.

Onde entra na pipeline

Antes do merge, em step dedicado de CI, com baseline congelado por branch protegido (main/release). O gate não é opcional: pipeline sem suite fixa não conta como eval. É como rodar deploy sem teste de fumaça.

Depois do merge, uma versão completa roda noturna para detectar drift acumulado. O resultado alimenta o dataset: caso novo que apareceu na noturna vira caso da suite fixa no próximo release.

Como manter a suite saudável

Regra de ouro: quando uma regressão aparece em produção mas passa na suite, o caso vira caso novo da suite no mesmo PR. Sem essa política a suite vira cobertura falsa e o time perde a fé nela.

A segunda regra é auditar a suite uma vez por trimestre. Casos desatualizados (gabarito errado, contexto removido) viram ruído e contaminam o baseline. Limpar é trabalho, mas limpar é o que mantém a suite útil.

Pontos fortes

  • bloqueio automático: regressão real vira CI fail, sem precisar de alguém lendo o PR
  • histórico rastreável: cada baseline é um commit, e qualquer queda aponta para o PR que causou
  • cultura: time para de discutir opinião e começa a discutir número, e o número tem dono

Limitações

  • falso negativo: a suite só pega regressões cobertas, o resto vira incidente de produção
  • manutenção constante: dataset desatualizado mente, e a manutenção é trabalho que ninguém pede
  • custo de runtime: rodar 500 casos a cada PR precisa de orçamento de tempo e de API

conexões no mapa

atualizado em 14/10/2026 · fontes para aprofundar · reportar erro

em outros domínios

Estude antes

teste o que entendeu

Carregando perguntas…