Como criar evals para agentes de IA com LLM-as-a-judge
"Tá funcionando bem" não é métrica.
Você subiu o agente, rodou três prompts na mão, viu que respondeu bonito e mandou pra produção. Aí o cliente abre um ticket que você nunca testou, o agente chama a ferramenta errada, inventa um dado e ninguém percebe até o usuário reclamar. Sem eval, todo deploy é no escuro.
Evals para agentes de IA são o conjunto de testes automatizados que medem se ele faz o que deveria. A diferença pro teste tradicional é que a saída não é determinística: o mesmo input pode gerar textos diferentes, e "certo" muitas vezes é julgamento, não comparação exata de string. É aí que entra o LLM-as-a-judge — usar um modelo para avaliar a saída de outro, contra uma rubrica que você escreve.
Neste tutorial você vai montar um pipeline de eval do zero: dataset de casos reais, critérios de avaliação, um juiz LLM que pontua com rubrica, agregação de score com barra de erro e um gate no CI que barra deploy quando o agente regride. Tudo em Python, com a API da Anthropic.
TL;DR
- O que é: pipeline de avaliação que mede se seu agente faz o que deveria, usando um LLM como avaliador onde regra fixa não dá conta.
- Stack: Python 3.11+, SDK
anthropic,pytestpro gate de CI. - Custo/Acesso: requer chave de API paga (Anthropic/OpenAI/etc.). O juiz é uma chamada extra por caso — barata, mas não zero.
- Ponto-chave: o juiz LLM precisa ser calibrado contra julgamento humano antes de você confiar nele. Sem isso, você só trocou um chute por outro.
O contexto — por que evals para agentes de IA viraram pré-requisito
Modelo bom não falta. O que separa um agente que aguenta produção de um que quebra no primeiro caso estranho é saber medir se ele funciona — e medir de novo a cada mudança de prompt, modelo ou ferramenta.
A própria Anthropic é direta sobre isso no guia de engenharia Demystifying evals for AI agents: comece com "20 a 50 tarefas simples tiradas de falhas reais". Não invente casos sintéticos bonitos. Pega os bugs que você já viu, as coisas que você confere na mão antes de cada release, as tarefas que usuários de verdade tentam.
O critério de uma boa tarefa de eval é cirúrgico: "uma boa tarefa é aquela em que dois especialistas do domínio chegariam, de forma independente, ao mesmo veredito de passou/falhou". Se dois devs sêniores discordam se a saída tá certa, o problema não é o agente — é a tarefa, que tá ambígua demais pra virar teste.
E tem uma armadilha de método que quase todo mundo cai: olhar o score e parar ali. Não vale. "Não leve scores de eval ao pé da letra até alguém abrir os detalhes do eval e ler algumas transcrições." Score de 87% sem ninguém ter lido transcrição é número de PowerPoint, não sinal de engenharia.
Pré-requisitos
Antes de escrever a primeira linha:
- [ ] Chave de API de um provedor de LLM (aqui uso a da Anthropic).
- [ ]
pip install anthropice Python 3.11+. - [ ] Um agente de IA — ou pelo menos uma função — que recebe input e devolve saída. Pode ser um wrapper simples de
messages.createcom tools. - [ ] Uns 10 a 20 casos reais de falha anotados na mão. Esse é o ativo mais valioso do pipeline. Sem dataset, não tem eval.
Se você ainda não tem nada anotado, separa meia hora e revisa as últimas conversas do agente. Os casos onde ele errou são seu dataset inicial.
Mão na massa — montando o pipeline
Passo 1: O dataset (golden set)
O dataset é uma lista de casos. Cada caso tem o input, a referência do que seria uma boa resposta e os metadados que você quer cruzar depois (categoria, dificuldade, se é um caso onde o comportamento deveria ou não deveria acontecer).
# dataset.py
golden_set = [
{
"id": "refund-001",
"input": "Comprei errado, quero reembolso de um pedido de 3 dias atrás.",
"reference": "Confirmar elegibilidade (janela de 7 dias), pedir nº do pedido, "
"explicar o prazo de estorno. NÃO prometer reembolso antes de validar.",
"category": "reembolso",
"should_use_tool": "lookup_order",
},
{
"id": "refund-002",
"input": "Quero reembolso de uma compra de 6 meses atrás.",
"reference": "Negar com educação: fora da janela de 7 dias. Oferecer alternativa.",
"category": "reembolso",
"should_use_tool": "lookup_order",
},
# ... mais 18 casos tirados de falhas reais
]
Repara no refund-002: ele testa o caso onde o agente não deve reembolsar. A Anthropic insiste nisso — teste "tanto os casos onde um comportamento deveria ocorrer quanto onde não deveria", senão você otimiza pra um lado só e o agente vira um "sim" ambulante.
Passo 2: Critérios — code-based primeiro, LLM depois
Nem tudo precisa de juiz LLM. A regra de ouro: use o método mais rápido e confiável que resolve. Existem três tipos de grader, e eles têm trade-offs bem definidos:
- Code-based (string match, schema, inspeção de tool call): rápido, barato, reproduzível. Quebra em variações válidas.
- LLM-as-a-judge (rubrica, comparação): flexível, captura nuance, escala. É não-determinístico e precisa de calibração.
- Humano: padrão-ouro, e lento e caro. Use pra calibrar e pra casos de alta aposta, não pro grosso.
Então a primeira camada é código puro. Coisas binárias e objetivas não merecem uma chamada de API:
# checks.py
def chamou_ferramenta_certa(trajectory, expected_tool):
"""Checagem determinística sobre a trajetória do agente."""
tools_usadas = [step["name"] for step in trajectory if step["type"] == "tool_use"]
return expected_tool in tools_usadas
def nao_prometeu_antes_de_validar(output, trajectory):
validou = any(s["name"] == "lookup_order" for s in trajectory if s["type"] == "tool_use")
prometeu = "reembolso aprovado" in output.lower()
return not (prometeu and not validou)
Isso roda em 100% dos casos a custo praticamente zero e pega os erros mais grosseiros — schema quebrado, ferramenta errada, alucinação óbvia. Só o que sobra dessa peneira vai pro juiz LLM.
Passo 3: O juiz LLM com rubrica
Aqui mora a parte que mais gente faz errado. Três regras que mudam o jogo:
Uma rubrica por dimensão. Não peça pro juiz avaliar "qualidade geral". A Anthropic recomenda "criar rubricas claras e estruturadas para cada dimensão da tarefa, e avaliar cada dimensão com um LLM-as-a-judge isolado, em vez de usar um só pra avaliar todas". Tom, correção factual e aderência ao processo são juízes separados.
Faça o juiz raciocinar antes de pontuar — e descarte o raciocínio. "Peça ao LLM para pensar primeiro antes de decidir a nota, e então descarte o raciocínio. Isso aumenta a performance da avaliação, em especial em tarefas de julgamento complexo."
Dê uma saída de emergência. "Dê ao LLM um jeito de escapar, como a instrução de retornar 'Unknown' quando ele não tem informação suficiente." Juiz encurralado inventa veredito.
O prompt do juiz, seguindo o padrão da doc oficial de evals da Anthropic:
# judge.py
import anthropic
client = anthropic.Anthropic()
JUDGE_PROMPT = """Você é um avaliador rigoroso. Avalie a RESPOSTA do agente
contra a RUBRICA de uma única dimensão.
<rubrica>{rubric}</rubrica>
<input_do_usuario>{user_input}</input_do_usuario>
<resposta>{output}</resposta>
Pense no seu raciocínio dentro de <thinking>. Se não houver informação
suficiente pra decidir, responda 'unknown'. Depois, emita exatamente uma
palavra em <result>: 'pass', 'fail' ou 'unknown'."""
def julgar(user_input, output, rubric, judge_model="claude-opus-4-8"):
resp = client.messages.create(
model=judge_model, # juiz != modelo avaliado
max_tokens=1024,
messages=[{"role": "user", "content": JUDGE_PROMPT.format(
rubric=rubric, user_input=user_input, output=output)}],
)
texto = resp.content[0].text.lower()
if "<result>pass</result>" in texto:
return "pass"
if "<result>unknown</result>" in texto:
return "unknown"
return "fail"
Detalhe que a doc reforça em todo exemplo: "geralmente é boa prática usar um modelo diferente para avaliar daquele usado para gerar a saída avaliada". Se o mesmo modelo gera e julga, ele tende a achar bom o próprio trabalho.
Passo 4: Score, barra de erro e os vieses do juiz
Junta as duas camadas, roda no dataset inteiro e agrega. Mas não reporte um número seco.
# run_eval.py
from dataset import golden_set
from judge import julgar
from checks import chamou_ferramenta_certa
RUBRICA_PROCESSO = "A resposta valida elegibilidade ANTES de prometer reembolso?"
def avaliar_caso(caso, agent_fn):
output, trajectory = agent_fn(caso["input"])
code_ok = chamou_ferramenta_certa(trajectory, caso["should_use_tool"])
if not code_ok: # peneira barata primeiro
return False
return julgar(caso["input"], output, RUBRICA_PROCESSO) == "pass"
def rodar(agent_fn, n=5):
"""n trials por caso porque a saída é não-determinística."""
resultados = []
for caso in golden_set:
passes = sum(avaliar_caso(caso, agent_fn) for _ in range(n))
resultados.append(passes / n)
media = sum(resultados) / len(resultados)
# erro padrão grosseiro pra ter noção de incerteza
import statistics
erro = statistics.pstdev(resultados) / (len(resultados) ** 0.5)
return media, erro
media, erro = rodar(meu_agente)
print(f"Pass rate: {media:.0%} ± {erro:.0%}")
Reportar incerteza não é firula. A Anthropic passou a publicar barras de erro nos próprios evals justamente porque a diferença entre 84% e 87% pode ser ruído. E como a saída é não-determinística, vale rodar cada caso k vezes: pass@k mede se o agente acerta em pelo menos uma de k tentativas (bom pra coding, onde dá pra tentar de novo); pass^k mede se ele acerta em todas as k (use quando consistência é o que importa).
Agora os vieses — e o juiz LLM tem dois clássicos que silenciosamente corrompem seu eval:
- Viés de posição: em comparação par a par, o juiz prefere a primeira opção. O MT-Bench (Zheng et al., 2024) mediu o slot A ganhando 10 a 15 pontos a mais só pela ordem. Mitigação: rode cada par nas duas ordens e trate veredito que muda com a ordem como empate.
- Viés de verbosidade: resposta mais longa pontua mais, mesmo com qualidade igual — 15 a 30 pontos de preferência inflada em juízes GPT-4, Claude e PaLM-2. Se seu juiz vive premiando o texto maior, é isso.
Conhecer esses vieses é o que separa um eval que mede do que enfeita.
Passo 5: O gate no CI
Eval que não roda no CI vira documentação morta. Transforme o pipeline num teste que barra o merge quando o agente regride:
# test_agent_eval.py
import pytest
from run_eval import rodar
from meu_agente import meu_agente
REGRESSION_BASELINE = 0.95 # casos que o agente JÁ resolve
def test_nao_regrediu():
media, erro = rodar(meu_agente, n=5)
assert media >= REGRESSION_BASELINE, (
f"Regressão: {media:.0%} < baseline {REGRESSION_BASELINE:.0%}. "
"Leia as transcrições antes de mergear."
)
A Anthropic separa dois tipos de eval, e a distinção importa pro threshold:
- Eval de capacidade: "deve começar com pass rate baixo, mirando tarefas em que o agente tem dificuldade." É seu roadmap — define o que o agente ainda não faz.
- Eval de regressão: "deve ter pass rate de quase 100%." É seu cinto de segurança — o que já funciona não pode quebrar.
O gate do CI usa o segundo. Capacidade você acompanha num dashboard; regressão você bloqueia no merge. Esse gate é um dos degraus de autonomia em agentic code: sem ele, você não sobe o agente de nível sem rezar.
Limitações e pontos de atenção
Onde isso quebra se você não tomar cuidado:
- Juiz não calibrado é teatro. "Graders LLM-as-a-judge devem ser calibrados de perto com especialistas humanos." Na prática: pegue 30-50 casos, faça um humano julgar, rode o juiz nos mesmos e meça concordância. Se diverge muito, conserte a rubrica antes de escalar. Sem essa etapa, você automatizou um chute.
- Custo. Cada caso vira uma (ou várias) chamada de API. Por isso a peneira de código primeiro — não desperdice juiz LLM em coisa que um
ifresolve. - Drift do juiz. Trocou o modelo do juiz? Seus scores históricos não são mais comparáveis. Versione o modelo e o prompt do juiz junto com o dataset.
- Não substitui humano em alta aposta. Eval automatizado cobre o grosso. Decisão médica, financeira ou jurídica ainda pede revisão humana nos casos de borda. Use o pipeline pra liberar o humano pro que realmente exige julgamento, não pra demiti-lo.
FAQ rápido
Que modelo usar como juiz? Um modelo capaz, e de preferência diferente do que gera a saída. Modelo de fronteira como juiz costuma valer o custo — é onde a calibração com humano fica mais alta. Não use um modelo fraquinho pra economizar e depois confiar no veredito.
Como sei que o juiz está certo? Calibração. Mede a concordância entre o juiz e um humano num conjunto de casos. Concordância alta = pode escalar. Baixa = a rubrica está vaga ou o modelo do juiz é fraco demais pra tarefa.
Code-based ou LLM-as-a-judge? Os dois, em camadas. Código pega o objetivo (schema, tool call, match exato) a custo zero. O juiz LLM pega só a nuance que sobra. Nunca jogue tudo no LLM.
Quantos casos preciso? Comece com 20 a 50 de falhas reais. Cresça em direção a centenas conforme o agente amadurece — mais casos com sinal automatizado batem poucos casos com julgamento humano artesanal.
Conclusão
Você montou o ciclo completo: dataset de falhas reais, peneira de código, juiz LLM com rubrica isolada e saída de emergência, score com barra de erro, mitigação de viés e um gate de regressão no CI. Não é um número bonito pro slide — é o instrumento que te diz, a cada commit, se o agente continua fazendo o que deveria.
O próximo salto é fechar o loop: o agente que avalia o próprio trabalho contra a rubrica antes de entregar, e o pipeline alimentando a melhoria contínua do prompt e do harness. Eval deixa de ser só portão de saída e vira parte do design do agente.
E é exatamente esse caminho — do prompt cru até o harness de um agente rodando em produção, com avaliação no meio — que a gente percorre ao vivo no workshop Do Prompt ao Harness: construindo um agente de vendas, onde o eval não é slide, é código que decide o que sobe. Porque, no fim, agente em produção não é prompt bonito: é arquitetura, contexto, avaliação e produto.
{AI Engineer} — apaixonado por Laravel, arquitetura de software e construir produtos com impacto. Compartilho aqui tutoriais, descobertas e reflexões sobre o dia a dia de engenharia.
Você também pode gostar
Avaliação de agentes de IA: como montar evals honestos
"Funciona nos meus testes" não é avaliação. Como montar evals honestos para um agente: golden set de falhas reais, métricas por etapa (recuperação, decisão de tool, resposta) e LLM como juiz com cautela.
LLM-as-a-Judge: avaliação automatizada do seu agente de ofertas sem abrir planilha
Como montar um juiz LLM que pontua cada resposta do agente contra uma rubrica objetiva: preço correto, link válido, sentimento de review coerente. Você sai do achismo e transforma iteração em ciclo mensurável.
Arquitetura de agentes de IA: o blueprint de ponta a ponta
A semana inteira em um diagrama só — as seis camadas de uma arquitetura de agentes de IA (modelo, contexto, tools/MCP, RAG, guardrails, observabilidade), como se encaixam e um checklist de produção pra defender o agente numa code review.
Agent improvement loop: o ciclo que faz o agente melhorar o próprio código
Como montar um loop de auto-melhoria de agente — gera, testa, avalia, corrige — inspirado no agent improvement loop do Agents SDK da OpenAI. Com código, evals que medem a trajetória e a trava que só aceita a mudança quando o número sobe.