- Escrever dois casos: um de coder, verificado por testes Go reais, e um de chat, avaliado por um LLM-juiz. O código vai inline na suíte ou fica em arquivos de verdade que a suíte lê com
!file. - Rodar e salvar o resultado como baseline.
- Montar uma pasta por mudança a testar, cada uma com uma cópia da suíte com aquela única mudança.
- Testar uma mudança de configuração que parece perigosa, mas que no fim só custa mais.
- Testar uma mudança de policy que quebra o coder de verdade e ver a execução sair com exit code 3.
- Comparar as três execuções, offline, e ligar o gate no CI.
Evals gastam tokens de verdade.
chatcli eval validate e chatcli eval list não custam nada: use-os enquanto escreve a suíte, e ponha um teto em toda execução com --max-cost.1. Escreva a suíte
Crieevals-demo/demo.yaml. O caso de coder entrega ao agente um módulo Go cuja Reverse inverte bytes, o que quebra acentos, ideogramas e emoji; os testes já cobrem esses casos e falham. O caso de chat pede uma explicação curta em português.
evals-demo/demo.yaml
Prefere arquivos de verdade? Leia-os com !file
Para manter o módulo como arquivos normais que você edita no IDE, coloque-os numa pasta ao lado da suíte e marque cada entrada de files: com !file. A suíte fica sem nenhum código:
- Os caminhos são resolvidos em relação ao arquivo da suíte, como no
fixture:, e o!filemantém as permissões do arquivo de origem, então um script que você roda nosetup:continua executável. - Para a pasta inteira, use
fixture: testdata/strutil: copia a árvore numa linha. Ofixture:precisa apontar para um diretório; apontar para um arquivo falha com uma mensagem que diz isso e sugere o!file. - Os dois se misturam. A fixture é copiada primeiro, depois os
files:são gravados por cima, depois osetup:roda. Mantenha o módulo numa fixture e troque um arquivo por caso, inline ou com!file. - Chame a pasta de
testdata/.go build,go test ./...ego veta ignoram, então o módulo quebrado fica fora do repositório que hospeda a suíte.
chatcli eval validate lê todo !file enquanto confere a suíte, então um caminho errado, um diretório ou uma tag escrita errada (!fiel) aparecem antes de você gastar qualquer coisa. Arquivos no disco ou inline lista todas as mensagens, e Padrões de workspace mostra sete formas de combinar fixture, files e setup, além de como conferir um workspace sem chamar modelo.
2. Confira de graça
3. Rode e salve um baseline
Use um juiz que seja um modelo diferente do candidato: um modelo avaliando a si mesmo carrega os próprios pontos cegos, e o relatório marca uma execução assim comoself_judged. Duas tentativas por caso mostram se a aprovação é consistente.
- Cada linha de tentativa e de caso mostra o custo do candidato mais o do juiz. As tentativas de chat custaram uns US 0,00014 por resposta. A linha de resumo separa os dois (
custo $0.0157 + juiz $0.0065). 2/2 tentativascom apass_policy: allpadrão é o pass^k: todas as tentativas passaram. Duas em três mostrariam o caso como instável, e ele reprovaria.- O
run1.jsoné o seu baseline. Guarde-o.
4. Leia o relatório
O relatório JSON guarda toda checagem de toda tentativa, o raciocínio do juiz, as ferramentas chamadas e a resposta final. Algumas linhas dejq respondem à maioria das perguntas:
tests pass e tests untouched rodaram por conta própria no sandbox.
5. Monte o baseline e as variantes
Para testar uma mudança, rode a mesma suíte com aquela única mudança contra o baseline. Guarde cada variante numa pasta própria, ao lado da suíte que ela altera:- Uma mudança por variante. Quando uma variante regride, você sabe qual mudança causou. Duas mudanças na mesma variante deixam você adivinhando.
- O mesmo
namede suíte e os mesmosids de caso em toda cópia. A comparação casa os casos por<suíte>/<id>. Renomeie um dos dois e ocompareinforma o caso como removido e um novo como adicionado, em vez de compará-los. - Variantes em subpastas ficam fora das execuções normais.
chatcli eval run evals-demo/carrega só os*.yamlque estão diretamente naquela pasta; subpastas não são varridas. A execução do baseline nunca pega uma variante por acidente, e cada variante só roda quando você indica o arquivo dela. - Um relatório por execução, numerado. Toda variante é comparada com o mesmo
run1.json.
diff que nada mais mudou:
chatcli eval validate badcfg/demo.yaml confere a cópia de graça, antes de você gastar qualquer coisa com ela.
6. Teste uma mudança que só custa mais
Imagine que alguém baixa o teto de tokens de saída para economizar. Coloque a mudança noenv: da suíte, não na sua linha de comando:
name da suíte e os ids dos casos, para que a comparação case caso a caso, e rode contra o baseline:
0. O loop do coder percebe uma resposta cortada no limite de tokens, aumenta o limite e continua, então um teto baixo não o quebra. Mesmo assim a mudança aparece no relatório, como turnos a mais:
turns, output_tokens e cost_usd entre os relatórios para ver isso.
7. Teste uma mudança que quebra o coder
Agora imagine que alguém endurece a policy do coder de modo que ele não consiga mais alterar arquivos. Opolicy: de um caso instala regras só para aquele caso, mescladas sobre a sua policy global:
write, patch e multipatch são os subcomandos que editam arquivos. O exec também é negado: sem isso, o agente ainda conseguiria editar pelo shell.
- Só o caso afetado reprova. O caso de chat não usa ferramentas e continua passando.
-
A nota diz o quanto piorou. Quatro das seis checagens continuam passando (os testes estão intactos, o
@coderfoi chamado, turnos e custo ficaram no orçamento), então a tentativa fica com 0,67, não 0. O veredito continua sendo reprovação, porque uma tentativa só passa quando todas as checagens passam. - Exit code 3 significa regressão contra o baseline. É o código que faz um job de CI falhar.
-
O comportamento do agente diante do bloqueio também fica visível. A resposta final dele não afirmou ter corrigido e não ficou tentando outras formas de contornar a regra:
Num eval ninguém pode responder à pergunta do agente, então o caso reprova. É exatamente o ponto: foi a mudança de policy que o quebrou.
8. Compare as três execuções
Lado a lado, os três relatórios contam três histórias diferentes:
Os turnos vêm dos relatórios (
jq '.cases[].trials[] | .turns' runN.json). Nem a taxa de aprovação nem o exit code mostram o custo da segunda mudança; os turnos mostram.
Offline, sem chamar modelo
Ocompare refaz a comparação a partir de dois relatórios salvos, sem chamar modelo, com os mesmos gates e exit codes do run:
9. Gate de pull requests no CI
Commite a suíte e um baseline gerado namain, e rode a suíte contra esse baseline em todo pull request. Um job de GitHub Actions:
.github/workflows/evals.yml
- O
--max-costlimita cada execução: quando o gasto de candidato mais juiz chega ao valor, nenhuma tentativa nova começa e as restantes aparecem como puladas. - O
--markdowngrava o resumo, o delta contra o baseline e as checagens que falharam, pronto para o resumo do job ou um comentário de pull request. - Atualize o baseline de propósito, depois de uma mudança que você aceita, rodando de novo na
maincom--out evals/baseline.json.
Armadilhas
Relacionados
Evals
Todo campo, checagem, flag e exit code.
Segurança do Coder
As regras de policy que o campo
policy: de um caso usa.