Objetivo: ao final, o consultor escolhe entre grader determinístico e modelo como juiz conforme a natureza da tarefa, escreve uma rubrica utilizável, e conhece os vieses do juiz e como mitigá-los.
| Tarefa | Grader | Como |
|---|---|---|
| Classificação com rótulo fechado | Código | saida.strip().upper() == esperado |
| Extração de campo (número de pedido, data) | Código | Comparação por campo, com tolerância declarada |
| Saída em JSON com schema | Código | Validação de schema + comparação campo a campo |
| Resposta que cita a fonte | Código | Verificar se o trecho citado existe mesmo no documento |
| Resumo | Modelo juiz | Rubrica com critérios de cobertura e fidelidade |
| Tom de e-mail para cliente | Modelo juiz | Escala de 1 a 5 com níveis descritos |
| Explicação de causa raiz | Modelo juiz | Rubrica; e revisão humana amostral por cima |
| Regra de negócio numa FS | Humano | Não delegue: é onde o erro sai caro (aula 3.4.3) |
A quarta linha merece destaque porque quase sempre é tratada como subjetiva sem ser: verificar se uma citação existe no documento é uma busca de substring. Boa parte do que parece exigir juiz é, na verdade, verificação mecânica disfarçada.
def grader_exato(saida: dict, esperado: str) -> bool:
return saida.get("rotulo", "").strip().upper() == esperado.strip().upper()
def avaliar(casos, classificar):
resultados = []
for caso in casos:
saida = classificar(caso["ticket"])
resultados.append({
"id": caso["id"],
"tipo": caso["tipo"],
"acertou": grader_exato(saida, caso["esperado"]),
"obtido": saida.get("rotulo"),
"esperado": caso["esperado"],
})
return resultados
def relatorio(resultados):
total = len(resultados)
acertos = sum(r["acertou"] for r in resultados)
print(f"Geral: {acertos}/{total} = {acertos / total:.1%}")
for tipo in sorted({r["tipo"] for r in resultados}):
fatia = [r for r in resultados if r["tipo"] == tipo]
print(f" {tipo}: {sum(r['acertou'] for r in fatia)}/{len(fatia)}")
A função relatorio faz o que a aula 3.6.2 pediu: além do número agregado, a leitura por fatia. É a diferença entre "78%" e "91% nos típicos, 43% nos ambíguos".
RUBRICA = """Você avalia resumos de reunião de projeto SAP.
Compare o resumo com a transcrição e atribua uma nota de 1 a 5:
5 — Registra todas as decisões tomadas, cada uma com responsável e prazo quando
mencionados na transcrição. Não afirma nada que não esteja na transcrição.
4 — Registra todas as decisões, mas omite responsável ou prazo em alguma delas.
3 — Omite uma decisão, ou registra todas sem responsáveis.
2 — Omite mais de uma decisão, ou inclui uma afirmação que não está na transcrição.
1 — Não registra as decisões, ou contradiz a transcrição.
Penalize em um nível se o resumo tiver mais de 300 palavras: extensão não é qualidade.
Responda apenas com o número."""
def grader_juiz(transcricao: str, resumo: str) -> int:
r = client.messages.create(
model="claude-opus-5", # modelo diferente do que gerou o resumo
max_tokens=16,
system=RUBRICA,
messages=[{
"role": "user",
"content": f"<transcricao>{transcricao}</transcricao>\n<resumo>{resumo}</resumo>",
}],
)
texto = next(b.text for b in r.content if b.type == "text")
return int(texto.strip())
Três coisas nesse código não são decorativas:
max_tokens=16. O juiz devolve um número. Espaço para explicação convida o juiz a redigir, e você paga por isso em cada caso.| Rubrica fraca | Rubrica utilizável |
|---|---|
| "Avalie a qualidade de 1 a 5" | Cinco níveis, cada um com o que precisa estar presente |
| "5 = excelente" | "5 = registra todas as decisões com responsável e prazo" |
| "Seja rigoroso" | O rigor está nos níveis, não num adjetivo à parte |
| Nível definido pelo que falta | Nível definido pelo que se observa na saída |
O teste de uma rubrica: dê a mesma saída para duas pessoas diferentes com a rubrica na mão. Se elas divergirem em mais de um nível, o modelo juiz também vai divergir — e a variância dele vai parecer variância do prompt.
| Viés | O que acontece | Mitigação |
|---|---|---|
| Verbosidade | Resposta mais longa recebe nota melhor | Critério explícito de concisão na rubrica |
| Posição | Em comparação A/B, a primeira leva vantagem | Alternar a ordem entre rodadas e agregar |
| Autopreferência | O juiz prefere o que ele mesmo escreveria | Usar modelo diferente do gerador |
Some a isso uma prática barata: calibre o juiz uma vez. Pegue vinte casos, dê nota humana, rode o juiz nos mesmos vinte e compare. Se ele concordar razoavelmente, você pode confiar nos outros duzentos. Se ele discordar de forma sistemática, o problema é a rubrica — não o juiz.
Regra Wayon Em avaliação de entregável que vai ao cliente, o modelo juiz não é o modelo gerador e a rubrica é revisada por alguém que não escreveu o prompt. Para regra de negócio — alçada, condição de pagamento, cálculo de imposto — não existe grader automático aceitável: vale a revisão humana e a segunda opinião fria da aula 3.4.3.
📖 Criar avaliações empíricas · Testes como portão e segunda opinião — aula 3.4.3
Relevância exigiria juiz; existência do trecho, não — e é essa a verificação em questão.
Correto. Boa parte do que parece exigir juiz é verificação mecânica disfarçada.
Consegue, e de forma exata: ou o trecho está no documento ou não está.
O custo é o mesmo em qualquer combinação de modelos; o problema é de viés, não de preço.
A chamada do juiz é independente e não carrega a sessão da geração.
Correto. É por isso que a documentação recomenda explicitamente juiz diferente do gerador.
Correto. Sem critério observável por nível, a nota vira impressão e perde poder de distinção.
Ele avalia — o problema é justamente que avalia, com uma régua que não é a sua.
Não é ruído uniforme; é concentração enviesada, que é mais difícil de perceber.
A explicação sai da leitura dos casos que falharam; pagar juiz por caso para isso é caro e menos confiável.
Correto. A regra é: se dá para verificar em código, verifique em código.
Não há o que confirmar: em rótulo fechado a comparação é exata, e o juiz só acrescenta custo e variância.