Skip to main content
Os padrões de qualidade (Self-Refine, CoVe, Reflexion) fazem o ChatCLI verificar a própria resposta enquanto trabalha. Isso ajuda a resposta do momento, mas não deixa nada para comparar entre uma versão e outra, e um modelo verificando a si mesmo carrega os próprios pontos cegos. Os evals cobrem essa lacuna. Uma suíte de evals é um conjunto fixo de casos com critério de aprovação conhecido, rodado sempre do mesmo jeito. O resultado é um placar (taxa de aprovação, nota média, custo e latência) que você pode salvar como baseline e usar como gate no CI. O chatcli eval é esse harness. Use-o para provar que uma mudança de prompt, modelo ou engine deixou o ChatCLI melhor, e não pior, e para comparar modelos e providers nas mesmas tarefas.
Evals gastam tokens de verdade: cada caso é uma chamada real ao modelo, e as checagens de juiz somam outras. Use --max-cost para limitar uma execução e validate/list para conferir uma suíte sem gastar nada.

Começo rápido

Uma execução real da suíte inicial, com Claude Haiku 5.5 como candidato e Claude Sonnet 5.5 como juiz, comparada com uma execução anterior em que o caso de bugfix em Go tinha estourado o tempo. Durante a execução, cada tentativa concluída imprime uma linha no stderr; no fim, o resumo vai para o stdout:
Um caso que reprova lista as checagens que falharam logo abaixo da linha dele, por exemplo ✗ testes passam: saiu com 1 (esperado 0): --- FAIL: TestSum …. O repositório traz uma suíte inicial em evals/: idioma no chat, formato JSON, aritmética, não inventar uma flag, corrigir um bug em Go, criar um arquivo e responder sem mexer em arquivos.

Como uma tentativa roda

1

Sandbox

Um diretório temporário é criado. A fixture do caso é copiada para ele, os files inline são escritos e os comandos de setup são executados (por exemplo git init). Se o setup falhar, a tentativa é marcada como erro e o candidato nem roda.
2

Policy do coder

Em casos coder, é gravado um coder_policy.json local (merge: true, ou seja, por cima da sua policy global). Por padrão ele libera o @coder, inclusive o exec, dentro do workspace descartável. Use policy: no caso para restringir. Operações safety-immune continuam pedindo aprovação, e como num eval não há ninguém para aprovar, elas são negadas. Não existe uma chave de “aprovar tudo” para isso.
3

Candidato

O binário real roda chatcli -p "<prompt>" --raw --no-anim (com /coder na frente nos casos coder), sem stdin e dentro do timeout do caso. Por padrão a execução é hermética: memória de longo prazo, bootstrap, recall de memória e de sessão, autosave de sessão, checkpoints do coder e histórico do REPL ficam desligados, então o resultado depende só da suíte. Com --with-memory, a avaliação usa a sua memória e o seu recall reais. Os seus hooks nunca disparam num candidato, com ou sem --with-memory: são efeitos colaterais na sua máquina, e um hook que roda um eval entraria em recursão.
4

Registro

Pelo CHATCLI_EVAL_RECORD, o one-shot informa a resposta final, as tool calls, os turnos, tokens, custo e transcript num arquivo fora do sandbox, que o candidato não consegue ler nem alterar.
5

Avaliação

Cada checagem roda sobre a resposta e sobre o sandbox. Comandos como go test ./... rodam dentro dele. A tentativa só passa se todas as checagens passarem, e a nota dela é a média ponderada das notas das checagens.
6

Limpeza

O sandbox é apagado. Com --keep ele fica no disco, e o relatório guarda o caminho.
Com --with-memory a execução também pode escrever na sua memória: um one-shot enfileira o turno para extração de memória como qualquer outra execução. Use execuções herméticas para baselines.

Formato da suíte

A suíte é um arquivo YAML. Passando um diretório, são carregados todos os *.yaml / *.yml que estão diretamente nele. Subdiretórios não são varridos, então as fixtures podem ter YAML próprio. As chaves são estritas: uma chave escrita errada é erro, e nunca vira uma checagem ignorada em silêncio.
A fixture costuma estar quebrada de propósito, então mantenha-a longe das ferramentas que varrem o repositório que a hospeda. Um diretório de fixture que é um módulo Go precisa de um go.mod próprio, o que o deixa fora do go test ./.... Fixtures pequenas podem ir inline em files:, e uma âncora YAML (files: &nome … files: *nome) as compartilha entre casos. É o que a suíte inicial faz.

Checagens

As checagens determinísticas vêm primeiro: são baratas, reprodutíveis e não abrem margem para discussão. Use o juiz só para o que não tem teste determinístico. Toda checagem aceita name: (aparece nos relatórios) e weight: (o peso dela na nota da tentativa, padrão 1). Os caminhos nas checagens e em files precisam ser relativos e ficar dentro do sandbox: caminhos absolutos e escapes com .. são recusados já ao carregar a suíte.

O juiz

O juiz recebe a tarefa, a rubrica, a resposta de referência (reference, opcional), as ferramentas que o candidato chamou e a resposta do candidato. Ele não fica sabendo qual modelo gerou a resposta. Responde com {"score": 0..1, "reasoning": "..."}, e a leitura é tolerante: aceita bloco de código e normaliza uma nota dada em escala de 0 a 10 ou de 0 a 100. Uma chamada ao juiz que falha ou não pode ser lida conta como amostra zero. Nunca vira aprovação silenciosa.
  • Qual modelo julga: --judge-provider/--judge-model; senão, o primeiro judge: declarado numa suíte; senão, o seu padrão configurado.
  • Autoavaliação é sinalizada: quando o juiz é o mesmo modelo do candidato, o relatório marca a execução como self_judged e avisa.
  • O gasto do juiz entra no seu cost tracker real e aparece separado do gasto do candidato.

Tentativas, pass@k e pass^k

A saída de LLM varia, então um caso pode rodar trials vezes. Para cada caso o relatório traz: O veredito do caso segue a pass_policy. all (o padrão, pass^k) é rígido: um caso que passa duas vezes em três é instável e reprova, e o relatório mostra isso em vez de esconder. any e majority estão disponíveis por caso. Uma tentativa em que a execução quebrou ou estourou o tempo conta como erro, separado de reprovação, para que “o ChatCLI quebrou” nunca seja lido como “o ChatCLI errou”.

Baselines e o gate de CI

--out salva o relatório JSON. Uma execução posterior com --baseline compara caso a caso:
  • Regressões: casos que passavam e agora não passam.
  • Correções: casos que não passavam e agora passam.
  • Casos novos e removidos.
  • Taxa de aprovação, nota média e custo antes e depois, medidos só sobre os casos avaliados nas duas execuções. Assim, uma execução filtrada comparada com um baseline completo compara a mesma coisa.
--markdown grava o mesmo resultado em Markdown (tabela de resumo, delta contra o baseline e checagens que falharam), pronto para comentário de PR ou resumo de job de CI.

Referência de comandos

Ctrl+C para de agendar tentativas novas e encerra as que estão rodando. O relatório as marca como puladas.
CHATCLI_EVAL_RECORD é o contrato privado do harness com o binário que ele dirige: quando definida, uma execução one-shot grava o registro nesse caminho ao sair. Sem ela, que é o caso de toda execução que não vem do chatcli eval, o one-shot não grava nada.

Evals e o pipeline de qualidade

Os padrões de qualidade mudam como o ChatCLI responde. Os evals mostram se a mudança valeu a pena. Para medir, por exemplo, se ligar o CoVe melhora um modelo nas suas tarefas, rode a mesma suíte duas vezes e compare:
O candidato herda o ambiente, então qualquer configuração CHATCLI_* pode ser comparada assim, e o mesmo vale para o env: de um caso.