Lição 1: “Parece pronto” não é “está pronto”
Objetivos de aprendizado:
- Explicar por que o Claude para quando o trabalho parece pronto, e quem acaba fazendo a verificação quando isso acontece
- Usar o contraste entre sistemas determinísticos e não determinísticos para explicar por que as premissas de “entrada X, caminho Y, saída Z” dos testes tradicionais desmoronam com agentes
- Diante de um relatório de conclusão, distinguir quais frases são afirmações e quais são evidências, e identificar o que ainda falta para a aprovação
Pré-requisitos: concluir os 9 primeiros cursos desta série; escrever à mão loops de harness guiados por stop_reason; entender checkpoints e recuperação | Próxima: Lição 2 >>
Publicado na terça, quebrado na sexta
Terça à tarde, você pede a um agente que adicione um recurso de “importação em massa de usuários” a um painel administrativo interno: subir um CSV, fazer o parse, validar os campos, gravar no banco de dados. Você detalha os requisitos com clareza e sai para uma reunião.
Quando você volta, a sessão parou. A última mensagem é assim:
Você passa os olhos no diff. As funções estão bem separadas, a nomenclatura combina com a dos módulos vizinhos, os casos extremos parecem considerados — arquivos vazios retornam um erro explícito, o regex de e-mail não está obviamente quebrado. Você faz o merge. Você publica.
Sexta à tarde, o pessoal de operações posta no canal: “Por que a gente acabou de importar 400 usuários vazios?”
A causa é simples. Operações gerou aquele CSV com um “Salvar como” do Excel, o que adicionou um BOM — três bytes invisíveis que o Excel gosta de colocar no início de arquivos UTF-8. Com isso, o nome da primeira coluna foi parseado como email em vez de email, todo o mapeamento de campos desandou, e cada linha virou “todos os campos são undefined”. E aquela camada de validação? Ela checava “o formato do e-mail é válido”, mas undefined tomou outro ramo e foi tratado como “esta coluna não foi preenchida”, então passou.
Ninguém fez corpo mole aqui. O agente escreveu código que roda. Ele se testou com um CSV que ele mesmo gerou — e claro que o CSV dele não tem BOM. Quando você revisou o diff, você estava checando “este código está escrito corretamente”, não “o que acontece quando este código encontra entrada do mundo real”. Os dois lados fizeram o melhor que podiam. A lacuna aconteceu do mesmo jeito.
O problema está no momento em que ele parou. Quando o agente parou, o que ele tinha era “escrevi, li uma vez, parece bom”. Ele não parou em “confirmei que está pronto”. Ele parou em “parece pronto”. E, pelo histórico da conversa, você não consegue distinguir os dois.
Ele para onde as coisas parecem prontas
A documentação do Claude Code diz isso de forma direta: o Claude para quando o trabalho parece pronto; sem uma verificação que ele possa rodar, “parece pronto” é o único sinal disponível, e você vira o loop de verificação — todo erro fica esperando você notar1.
Vale ler essa frase duas vezes, palavra por palavra. Ela não está dizendo “o Claude às vezes faz corpo mole”, nem “o modelo ainda não é capaz”. Ela descreve um fato estrutural: se nada no pipeline inteiro consegue produzir um resultado objetivo, então “parece pronto” é o único sinal que existe neste sistema. O modelo só consegue decidir com esse sinal. Ele não tem mais nada.
A mesma documentação dá um nome a esse fenômeno: a trust-then-verify gap (lacuna do confiar-e-depois-verificar) — o Claude produz uma implementação de aparência plausível que não lida com casos extremos1. Em português claro: você confia primeiro (o código parece bom), e a verificação ou não acontece ou acontece tarde demais (sexta à tarde, no canal de operações). O exemplo do BOM acima é a forma padrão dessa lacuna: não é código errado, é que ninguém perguntou “e se o arquivo tiver sido exportado do Excel?”.
Há aqui uma segunda camada fácil de perder. A correção sugerida pela documentação termina assim: se você não consegue verificar, não publique1. A ênfase não está em “verificar” — está em “não publique”. Isso reconhece que existem coisas que você simplesmente não consegue verificar. Quando é o caso, o movimento correto não é “confiar no faro só desta vez”. É estreitar o escopo, mudar o requisito, ou segurar a publicação.
Afirmação e evidência: qual é a diferença?
Volte àquela mensagem de conclusão. Quebre-a em frases individuais e faça a mesma pergunta para cada uma: eu consigo confirmar esta frase sem ler código, usando apenas o que ela me mostrou?
- “Adicionado
src/importer/parseCsv.js” — você consegue confirmar. Se o arquivo existe dá para checar de relance. Isso é evidência (embora do tipo mais fraco).
- “A implementação segue o estilo de código dos módulos existentes” — você não consegue confirmar. Isso é o julgamento estético do modelo. Afirmação.
- “Nenhum erro durante a execução” — soa como evidência, mas na verdade é uma afirmação. Ela diz que as ferramentas chamadas não lançaram exceções, não que a saída está correta. Todas as ferramentas retornarem sucesso enquanto o resultado está completamente errado — perfeitamente possível.
- “Checar formato de e-mail e campos obrigatórios” — você não consegue confirmar. Isso descreve intenção, não comportamento. O que aquele regex de fato permite ou rejeita? Esta frase não diz nada a respeito.
Onde fica a linha? Evidência é algo que uma segunda pessoa consegue re-executar exatamente da mesma forma: um comando mais sua saída bruta, um código de saída, uma lista de nomes de testes que falharam, uma captura de tela, uma comparação numérica antes/depois. Afirmações são coisas em que você só pode escolher acreditar ou não: “a lógica está correta”, “deve estar tudo bem”, “já otimizado”, “não vai acontecer de novo”.
A documentação oficial traça exatamente essa linha: faça o Claude mostrar evidências em vez de afirmar sucesso — a saída dos testes, o comando que ele rodou e o que ele retornou, ou uma captura de tela do resultado. Revisar evidências é mais rápido do que refazer a verificação você mesmo, e funciona para sessões que você não estava acompanhando1.
Essa última meia-frase é a chave. Se você estava olhando o tempo todo, a distinção “afirmação ou evidência” não rende muito — você viu com os próprios olhos. Mas no momento em que você desvia o olhar, tudo o que sobra no histórico da conversa é texto, e em texto as afirmações parecem tão confiantes quanto as evidências.
Por que agentes esbarram especialmente neste problema
A gente também vê “parece certo mas está errado” em software tradicional. Por que isso merece uma lição dedicada no caso dos agentes?
Porque os testes tradicionais se apoiam em uma premissa que os agentes não satisfazem.
Comece pelas definições. Em computação, sistemas determinísticos produzem a mesma saída toda vez, dadas entradas idênticas, enquanto sistemas não determinísticos — como os agentes — podem gerar respostas variadas mesmo com as mesmas condições iniciais2. Isso não é “tem bugs, por isso é instável”. É assim que funciona. Mesmo que você não mude nada no seu prompt, não há garantia de que as decisões de duas execuções coincidam3.
Assim, a premissa da avaliação tradicional desmorona. Avaliações tradicionais costumam assumir que a IA segue as mesmas etapas toda vez: dada a entrada X, o sistema deveria seguir o caminho Y para produzir a saída Z3. Sistemas multiagente não funcionam assim. Mesmo com pontos de partida idênticos, agentes podem tomar caminhos válidos completamente diferentes para chegar ao objetivo — um agente pode buscar em três fontes enquanto outro busca em dez, ou eles podem usar ferramentas diferentes para achar a mesma resposta3.
Concretamente, é assim que isso aparece:
Você não pode chamar nenhuma das duas trajetórias de “errada”. A segunda execução leu um arquivo a mais, modificou um lugar a mais e rodou os testes duas vezes — talvez ela tenha dado uma volta, ou talvez tenha pego um acoplamento que a primeira deixou passar. Se você escrever uma asserção dizendo “precisa ler schema.sql primeiro”, a segunda execução é reprovada — mas pode ser que a segunda tenha feito um trabalho melhor.
Conferir a trajetória contra um roteiro prescrito não funciona aqui: como nem sempre sabemos quais são as etapas certas, em geral não dá para simplesmente checar se os agentes seguiram as etapas “corretas” que prescrevemos de antemão3.
Acrescente mais uma camada: erros em sistemas de agentes se acumulam. Um bug pequeno em software tradicional, quando atinge um agente, pode descarrilar a tarefa inteira — a falha de uma única etapa pode fazer os agentes explorarem trajetórias completamente diferentes, levando a resultados imprevisíveis3. Isso não é como um programa tradicional em que “uma função retorna um valor ruim e ele se propaga para cima”. Um agente pega um resultado ruim e toma novas decisões com base nesse resultado ruim: leu um arquivo errado, pode concluir “este módulo não existe” e criar um novo; depois segue trabalhando em torno desse módulo novo. Quando você vê a saída final, o erro já não está mais no lugar de origem. Ele virou outra coisa.
A própria conclusão da Anthropic aterrissa aqui: a natureza autônoma dos agentes significa custos mais altos e o potencial de erros que se acumulam. Eles recomendam testes extensivos em ambientes sandbox, junto com os guardrails apropriados4. E mais uma frase direta — o LLM potencialmente vai operar por muitos turnos, e você precisa ter algum nível de confiança na tomada de decisão dele4.
Repare na expressão “algum nível de confiança”. Ela não diz “você tem que confiar”. Ela diz que essa confiança precisa vir de algum lugar. E a confiança só tem duas fontes: você mesmo acompanhou (e então o agente não te economizou tempo nenhum), ou alguma coisa acompanhou por você. Este curso inteiro é sobre a segunda.
A saída: dê a ele uma verificação que ele possa rodar
Toda essa preparação aterrissa em uma frase: dê ao Claude uma verificação que ele possa rodar — testes, um build, uma captura de tela para comparar. É a diferença entre uma sessão que você acompanha e uma da qual você pode se afastar1.
De onde vem a diferença? Dê ao Claude algo que produza um passa ou falha, e o loop se fecha sozinho. O Claude faz o trabalho, roda a verificação, lê o resultado e itera até a verificação passar1.
Dá para mapear essa frase de volta para o loop de harness do curso 7 desta série. Primeiro veja onde o seu loop atual para:
O que end_turn significa? Significa que o modelo acha que terminou de falar neste turno. Só isso. Não significa que o trabalho está correto, e nem sequer garante que a resposta está completa — este loop só reconhece tool_use; se stop_reason virar qualquer outra coisa ele sai, inclusive quando a saída foi cortada no meio da frase por max_tokens. Nada na condição de saída tem a ver com “qualidade da saída”.
Então, como é ligar uma verificação? Duas posições funcionam.
Posição um: transforme a verificação em uma ferramenta que ele possa chamar, deixe rodar dentro do loop:
Posição dois: coloque uma comporta depois que o loop sai; não confie no autorrelato dele, rode você mesmo:
O código em si não tem truque. O ponto é que a condição de saída mudou de dono: de “o modelo diz que não quer chamar mais ferramentas” para “um pedaço de código determinístico retornou 0”. A primeira é a autoavaliação do modelo. A segunda não é.
Então, o que pode ser uma “verificação”? A documentação oficial dá uma faixa mais ampla do que você imaginaria: a verificação é qualquer coisa que retorne um sinal que o Claude consiga ler na conversa — uma suíte de testes, o código de saída de um build, um linter, um script que compara a saída com um fixture, ou uma captura de tela do navegador comparada com um design1.
Explicando “fixture”: é um “arquivo de resposta padrão-ouro” que você salvou de antemão; depois de rodar, você compara a saída com ele, e não pode diferir nem em um caractere. Parece grosseiro, mas para tarefas do tipo “o formato da saída precisa ser estável”, é a forma de verificação mais simples e mais confiável.
Essa linha de raciocínio se alinha com a recomendação da Anthropic para a execução de agentes: durante a execução, é crucial que os agentes obtenham “ground truth” do ambiente a cada etapa (como resultados de chamadas de ferramenta ou execução de código) para avaliar o próprio progresso4. Repare em “do ambiente” — não do próprio raciocínio dele. O raciocínio do modelo é autogerado. Os valores de retorno do ambiente não são.
O que as próximas cinco lições resolvem
Com “dê a ele uma verificação que rode” como fio condutor, as perguntas restantes ficam concretas.
Lição 2: o que verificar. Já que conferir a trajetória contra um roteiro prescrito não funciona, o que você confere? Resposta: o estado final primeiro — avalie se ele alcançou o estado final correto, não se ele seguiu algum processo específico; para fluxos complexos, quebre a avaliação em checkpoints discretos onde mudanças de estado específicas deveriam ter ocorrido3. Essa lição também vai cobrir como transformar um requisito difuso em um critério de sucesso mensurável.
Lição 3: verificadores determinísticos. Como escolher e escrever verificações capazes de produzir passa/falha. Correspondência exata, comparação por script, suítes de testes — o que serve para quê, e uma armadilha contraintuitiva: um verificador estrito demais vai rejeitar respostas corretas. O catálogo concreto de verificadores e a ordem de prioridade ficam naquela lição; não vamos expandir aqui.
Lição 4: juiz LLM. Texto livre não dá para comparar por string; você tem que pedir a um modelo que pontue. Como escrever rubricas, como restringir o formato da saída, se é melhor raciocinar antes ou pontuar antes, e por que o modelo que faz o trabalho não deveria corrigir a si mesmo — já tocamos nisso no quiz mais acima. O desenho específico de rubricas está na lição 4.
Lição 5: conjuntos de avaliação. Uma verificação dá conta de uma tarefa; um conjunto de tarefas forma um conjunto de avaliação. Como coletar casos do uso real, como preencher os casos extremos, para que serve um conjunto de holdout, e “quantos são suficientes” — tudo respondido na lição 5; a resposta pode ser menor do que você imagina.
Lição 6: construa você mesmo. Junte as cinco primeiras lições: uma tarefa de avaliação recebe um loop de harness, rode e produza um relatório; troque uma versão do prompt e veja se a pontuação se mexeu.
Proporcionalidade: não embrulhe cada coisinha em um processo de aprovação
A esta altura, é fácil pender para o outro extremo: supor que toda tarefa precisa de testes, de um juiz e de um conjunto de avaliação. Não é assim.
A frase original da Anthropic é: a chave para o sucesso, como em qualquer funcionalidade com LLM, é medir o desempenho e iterar sobre as implementações. Repetindo: você deveria considerar adicionar complexidade apenas quando ela comprovadamente melhora os resultados4. O mesmo artigo traz uma recomendação de rota mais específica — comece com prompts simples, otimize-os com avaliação abrangente, e só adicione sistemas agênticos de múltiplas etapas quando as soluções mais simples não derem conta4.
Aplicado à verificação, os critérios de decisão se resumem a poucas linhas:
- Esta tarefa vai rodar repetidamente? Um script pontual, um processamento de dados ad hoc, um trabalho de três minutos que você pretende acompanhar — montar um mecanismo de aprovação é prejuízo líquido. Coisas que rodam repetidamente, que outras pessoas modificam, ou que rodam enquanto você não está por perto — aí vale.
- Quem arca com o custo de um erro? Você corrige um typo errado, você mesmo reverte e pronto. Você quebra a lógica de cobrança, o financeiro arca com o custo. Quanto mais lá na frente estiver o custo e mais difícil for reverter, mais você deveria colocar uma comporta logo na entrada.
- Quanto tempo você gasta verificando isso hoje? Se toda vez você tem que abrir três páginas na mão e compará-las, transformar essa comparação de três páginas em script é o que mais merece automação — você já está pagando esse custo; só não percebeu.
Mais um caso que vale destacar em separado: algumas verificações você já tem, só não as ligou ao agente. Aquela suíte de testes no projeto, aquele comando de lint, aquele script de build — provavelmente já existiam. Escrevê-los na descrição da tarefa ou transformá-los em ferramenta custa quase nada, mas a natureza da sessão muda. Esta é a etapa de maior ROI, e é o ponto de partida das próximas lições deste curso.
💻 Exercícios
Recapitulação
- O Claude para quando o trabalho parece pronto. Sem uma verificação que ele possa rodar, “parece pronto” é o único sinal disponível, e você vira o loop de verificação: todo erro fica esperando você notar1.
- A documentação oficial dá nome a essa lacuna: a trust-then-verify gap — o Claude produz uma implementação de aparência plausível que não lida com casos extremos. A segunda metade da correção que vem junto é igualmente importante: se você não consegue verificar, não publique1.
- A linha entre afirmação e evidência é “uma segunda pessoa consegue re-executar isso exatamente da mesma forma”. Faça o Claude mostrar evidências — saída dos testes, o comando que ele rodou e o que ele retornou, uma captura de tela do resultado — e não afirmações de sucesso. Revisar evidências é mais rápido do que refazer a verificação você mesmo, e funciona para sessões que você não estava acompanhando1.
- Agentes são sistemas não determinísticos: mesmo com as mesmas condições iniciais, eles podem gerar respostas variadas2; mesmo com prompts idênticos, não há garantia de que as decisões de execuções diferentes coincidam3. Por isso a premissa da avaliação tradicional, “dada a entrada X, siga o caminho Y, produza a saída Z”, falha3 — pontos de partida idênticos podem produzir caminhos completamente diferentes, mas válidos3.
- Erros em sistemas de agentes se acumulam: a falha de uma única etapa pode fazer os agentes explorarem trajetórias completamente diferentes, levando a resultados imprevisíveis3. A autonomia traz custos mais altos e potencial de erros que se acumulam, então recomendam-se testes extensivos em ambientes sandbox com guardrails4.
- A saída é dar a ele uma verificação que rode. Com algo que produza passa ou falha, o loop se fecha sozinho: faça o trabalho, rode a verificação, leia o resultado, itere até passar1. A verificação pode ser uma suíte de testes, o código de saída de um build, um linter, um script que compara a saída com um fixture, ou uma captura de tela do navegador comparada com um design1.
- Durante a execução, deixe o agente obter “ground truth” do ambiente a cada etapa (resultados de ferramentas, resultados de execução de código) para avaliar o progresso, e não do próprio raciocínio dele4.
- O LLM potencialmente vai operar por muitos turnos, e você precisa ter algum nível de confiança na tomada de decisão dele4 — mas essa confiança precisa vir de algum lugar.
- Não embrulhe cada coisinha em um mecanismo completo de aprovação. Você deveria considerar adicionar complexidade apenas quando ela comprovadamente melhora os resultados4; verifique primeiro se esta tarefa roda repetidamente, quem arca com o custo dos erros, e quanto tempo você gasta verificando na mão hoje.
- A etapa de maior ROI costuma ser esta: aquela suíte de testes, aquele comando de lint, aquele script de build já existem no seu projeto — você só ainda não os ligou ao agente.
>> Lição 2: O que verificar: estado final primeiro, processo como rede de segurança