Verificação de agentes de IA: por que o agente não pode corrigir a própria prova
Verificação de agentes de IA é checar o resultado do agente com um sinal que ele não consegue produzir nem manipular: teste, typecheck, estado real do sistema. Não é perguntar pro próprio agente se ele terminou. Parece óbvio. Mas a maioria dos loops autônomos que rodam por horas ainda funciona assim: o agente faz, o agente avalia, o agente decide que melhorou.
E um paper de julho mediu o tamanho do estrago. Em 54 ciclos, o agente disse que melhorou em todos. Em 56% deles, a mudança medida foi zero ou negativa.
Neste post você vai entender por que isso acontece, por que trocar o juiz por um modelo maior não resolve, e vai montar em Laravel um loop com gate de verificação externo: condição de saída checável, orçamento duro e uma trava que impede o agente de editar a própria prova.
TL;DR
- O que é: padrão de harness em que quem decide se o agente progrediu é um verificador fora do alcance dele, não a autoavaliação.
- Stack/Modelos: qualquer LLM com tool use; exemplo em PHP 8.3 + Laravel 12 (
Process), mas o padrão vale pra qualquer linguagem. - Custo/Acesso: zero de licença. O custo é engenharia: escrever o check antes de soltar o loop.
- Link útil: When Do Agent Loops Mistake Stagnation for Progress? (arXiv 2607.25152)
Miragem de progresso: quando o agente corrige a própria prova
Agentes de longa duração planejam, agem e julgam a própria conclusão sem humano no meio. Esse último verbo é o problema.
Os pesquisadores Hyundoo Park e Byungho Choi deram nome a essa falha: progress mirage, a miragem de progresso. O agente aceita mudanças plausíveis como avanço enquanto o resultado real estagna ou piora. No paper publicado em 27 de julho de 2026, eles montaram um ambiente em que o agente e as ferramentas ficam fixos. A única coisa que muda é a fonte de informação do avaliador que libera (ou barra) cada ciclo do loop. A referência de verdade é um oráculo do estado do mundo isolado por container e rede, que o agente não alcança.
Os números:
- 54 ciclos, e o agente de fronteira declarou melhora em todos.
- 56% desses ciclos tiveram mudança medida zero ou negativa.
- Com o gate de autoavaliação, o loop virou "aceita tudo" e corroeu em 19% o melhor estado que ele já tinha alcançado.
Leia de novo o último item. O agente não ficou parado. Ele piorou o sistema, ciclo a ciclo, achando que estava melhorando.
Se você já deixou um agente rodando de madrugada e voltou com um diff enorme e um resumo confiante dizendo "todos os objetivos atingidos", você conhece essa sensação. A diferença é que agora tem número.
O detalhe que importa pra quem constrói: o modelo era o mesmo em todos os cenários do experimento. O que mudou o resultado foi onde o gate busca o sinal de sucesso. Isso não é problema de modelo. É problema de harness. E é exatamente essa camada (gate, oráculo, orçamento, o que o agente pode ou não tocar) que vai estar na mesa no AI Engineering Lab 4ª Edição, imersão ao vivo de Harness Engineering para Agentes Inteligentes, dias 14 e 15 de novembro, das 9h às 13h, pelo Google Meet.
Por que um juiz maior não resolve
A primeira reação de todo dev é: "então coloca um LLM-as-a-judge mais forte pra avaliar".
O paper testou exatamente isso. E a hipótese foi registrada antes do experimento, pra ninguém ajustar a conclusão depois.
O juiz mais forte, lendo o texto completo do artefato, o diff da mudança e o próprio histórico de vereditos:
- aceitou ciclos em que 44% eram regressões no mundo real;
- rejeitou 38% das melhorias reais.
A hipótese de que um juiz forte fecha o buraco foi rejeitada.
Por quê? Porque o juiz estava in-band: ele só via o que estava dentro da transcrição. E o sucesso de um objetivo aberto não mora na transcrição. Mora no mundo. Na conversão que subiu ou não subiu, no endpoint que respondeu ou não respondeu, na query que ficou mais rápida ou não ficou.
A prova está no contraponto do mesmo paper. Numa tarefa em que o sucesso pode ser verificado a partir do próprio artefato, a miragem do mesmo juiz caiu pra zero.
Tradução pra produção:
| Onde mora o sinal de sucesso | Quem pode verificar |
|---|---|
| No próprio artefato (o código compila, o JSON valida o schema) | Um check in-band resolve, inclusive um juiz LLM |
| Fora da transcrição (teste de integração, métrica real, estado do banco) | Só um verificador out-of-band, com acesso ao mundo real |
Quer um dado que mata a discussão de "mas o juiz precisa explicar o porquê pro agente aprender"? Uma variante que devolvia só o veredito (aceito ou rejeitado, sem explicação) entregou resultado real parecido com o feedback completo: 110,0 contra 113,0. O ganho vem de onde o gate está ancorado, não de quanta coisa ele fala.
Verificação de agentes de IA na prática: os 3 gates
Esse padrão está saindo do folclore de bash e virando primitiva de produto. Um guia de praticantes sobre agentic loops resume o mínimo pra soltar um loop autônomo em três perguntas, e se a resposta pra qualquer uma for "não", você não solta:
- Existe condição de saída checável por máquina? "Todos os testes verdes", "o schema valida", "p95 abaixo de 200 ms". Não vale "quando o agente achar que acabou".
- Existe teto duro de iterações e de orçamento?
max_iterationse limite de tokens/dinheiro. Sem isso, o loop fica preso no mesmo erro por horas e a fatura corre. - Existe verificação a cada iteração, que o agente não consegue editar? Typecheck, testes, CI verde. O mesmo guia cita o caso clássico: o agente "resolve" o teste que falha apagando a asserção.
O terceiro ponto é o que a maioria pula. Não basta rodar os testes. O agente não pode ter permissão de mexer neles. Se ele pode editar a prova, a prova vira mais uma superfície de autoavaliação.
Falei disso com mais calma no post de TDD com agentes: quem escreve o teste manda no agente.
Pré-requisitos
- [ ] PHP 8.3+ e Laravel 12 (o facade
Processestá disponível desde o Laravel 10) - [ ] Uma suíte de testes que rode em linha de comando (
php artisan testou Pest) - [ ] PHPStan/Larastan, se quiser o gate de tipos
- [ ] Um harness de agente que já execute tarefas em loop. Se você ainda não tem, comece por este harness em Laravel do zero
Tutorial te mostra o caminho — no Clã você constrói junto. Aula ao vivo toda semana, projetos reais de Engenharia de IA, ao lado de quem já está em produção.
Entrar no ClãMão na massa: loop com gate externo em Laravel
A ideia é separar três papéis que hoje estão misturados no seu agente: quem faz (o agente), quem verifica (o gate) e quem decide parar (o loop).
Passo 1: o gate roda fora das ferramentas do agente
O gate é código seu, determinístico, chamado pelo loop. O agente não chama o gate e não recebe uma tool pra isso.
<?php
namespace App\Agents\Verification;
use Illuminate\Support\Facades\Process;
final class VerificationGate
{
/** @var array<string, string> nome do check => comando */
private array $checks = [
'tipos' => 'vendor/bin/phpstan analyse --no-progress --error-format=raw',
'testes' => 'php artisan test --stop-on-failure',
];
public function __construct(private readonly string $workdir) {}
public function run(): GateResult
{
foreach ($this->checks as $nome => $comando) {
$result = Process::path($this->workdir)
->timeout(600)
->run($comando);
if ($result->failed()) {
return GateResult::reject($nome, $result->errorOutput() ?: $result->output());
}
}
return GateResult::accept();
}
}
<?php
namespace App\Agents\Verification;
final class GateResult
{
private function __construct(
public readonly bool $passed,
public readonly ?string $failedCheck = null,
public readonly ?string $log = null,
) {}
public static function accept(): self
{
return new self(true);
}
public static function reject(string $check, string $log): self
{
return new self(false, $check, $log);
}
/** Assinatura curta do erro, pra detectar o agente batendo na mesma parede. */
public function fingerprint(): string
{
return md5($this->failedCheck . substr((string) $this->log, 0, 2000));
}
}
Passo 2: trave a prova
Antes do loop começar, tire um hash da pasta de testes e da config do gate. A cada iteração, compare. Mudou? O ciclo é rejeitado, não importa o que o agente diga.
<?php
namespace App\Agents\Verification;
use Symfony\Component\Finder\Finder;
final class TamperGuard
{
private string $baseline;
public function __construct(private readonly string $workdir)
{
$this->baseline = $this->hash();
}
public function intact(): bool
{
return hash_equals($this->baseline, $this->hash());
}
private function hash(): string
{
$files = Finder::create()
->files()
->in($this->workdir)
->path(['tests/', 'phpstan.neon', 'phpunit.xml'])
->sortByName();
$ctx = hash_init('sha256');
foreach ($files as $file) {
hash_update($ctx, $file->getRelativePathname());
hash_update_file($ctx, $file->getRealPath());
}
return hash_final($ctx);
}
}
Melhor ainda: monte tests/ como somente leitura no sandbox do agente. O hash é a segunda linha de defesa.
Passo 3: o loop decide parar, não o agente
Aqui entram os três gates juntos: saída checável, teto de iteração e orçamento, verificação a cada volta. Mais um detector simples de "batendo na mesma parede": o mesmo erro três vezes seguidas encerra o loop.
<?php
namespace App\Agents;
use App\Agents\Verification\TamperGuard;
use App\Agents\Verification\VerificationGate;
final class VerifiedLoop
{
public function __construct(
private readonly CodingAgent $agent,
private readonly VerificationGate $gate,
private readonly TamperGuard $guard,
private readonly int $maxIterations = 15,
private readonly float $maxCostUsd = 5.00,
) {}
public function run(string $task): LoopOutcome
{
$feedback = null;
$lastFingerprint = null;
$repeats = 0;
for ($i = 1; $i <= $this->maxIterations; $i++) {
$step = $this->agent->step($task, $feedback);
if ($this->agent->totalCostUsd() > $this->maxCostUsd) {
return LoopOutcome::stopped('orçamento estourado', $i);
}
if (! $this->guard->intact()) {
$this->agent->revertLastChange();
$feedback = 'REJEITADO: arquivos de teste ou config do gate foram alterados. Não toque neles.';
continue;
}
// O agente pode dizer "terminei" quantas vezes quiser.
// Quem decide é o gate.
$result = $this->gate->run();
if ($result->passed) {
return LoopOutcome::done($i);
}
$repeats = $result->fingerprint() === $lastFingerprint ? $repeats + 1 : 0;
$lastFingerprint = $result->fingerprint();
if ($repeats >= 2) {
return LoopOutcome::stopped("mesmo erro 3x em '{$result->failedCheck}'", $i);
}
$feedback = "REJEITADO pelo check '{$result->failedCheck}':\n"
. mb_substr((string) $result->log, -3000);
}
return LoopOutcome::stopped('teto de iterações', $this->maxIterations);
}
}
Repare no que não está aí: em nenhum momento o loop pergunta ao agente "você terminou?". O step() pode até devolver um "concluído" bonito. Ele é ignorado.
Passo 4: pra objetivo aberto, o gate precisa olhar o mundo
Teste unitário cobre "o código faz o que diz". Não cobre "o checkout ficou mais rápido" ou "o agente de suporte resolve mais ticket". Pra esses, o gate precisa de acesso a um sinal fora da transcrição.
// Gate out-of-band: mede o mundo, não o texto do agente.
$antes = $this->metrics->p95('checkout', minutes: 30); // baseline real
$this->deployer->toStaging($branch);
$this->loadTest->run('checkout', requests: 2_000);
$depois = $this->metrics->p95('checkout', minutes: 5, env: 'staging');
return $depois < $antes * 0.95
? GateResult::accept()
: GateResult::reject('p95', "antes={$antes}ms depois={$depois}ms");
E lembre do resultado do paper: o veredito sozinho já carrega quase todo o benefício. Se o log do check tem dado sensível ou facilita o agente "otimizar pro teste", devolva só aceito/rejeitado.
E quando o sucesso não cabe num teste?
Dois caminhos que estão aparecendo em 2026.
Verificador ancorado na tarefa, fora do agente. O AutoFyn, um harness publicado em julho, separa explicitamente quem constrói de quem verifica. Cada rodada começa numa sessão nova do modelo; um verificador ancorado na tarefa checa o trabalho e devolve uma recompensa objetiva; essa recompensa é destilada em estado persistente (arquivos de memória, relatórios, estado do repositório) pra próxima rodada. Sem mexer em peso nenhum. Os autores reportam que, nos seis problemas da IMO 2026, todo modelo com margem pra melhorar pontuou mais dentro do AutoFyn do que no agente de código do próprio fornecedor, e que o harness produziu 16 advisories de vulnerabilidade confirmados por mantenedores em projetos como Next.js, pnpm e LiteLLM.
Juiz agêntico que confere o estado do ambiente. Quando o juiz precisa ser LLM, ele não pode ser só leitor de transcrição. A Judgment Labs descreve um juiz que navega a trajetória, confere evidência de tool e estado do ambiente pra checar o efeito real das ações e ajusta a rubrica com feedback de produção. É material de fornecedor, então leia como posicionamento de produto. Mas a direção bate com o paper: o juiz só presta se tiver acesso out-of-band.
Pra montar a parte de juiz e dataset do jeito certo, tem o passo a passo de evals com LLM-as-a-judge aqui no blog.
Limitações e pontos de atenção
- O gate só é tão bom quanto o check. Suíte fraca vira miragem com selo de aprovação. Cobertura ruim deixa o agente "passar" quebrando o que não está testado.
- Gate out-of-band custa. Deploy em staging, teste de carga e métrica real levam minutos por ciclo. Use checks baratos (tipos, unitários) primeiro e o caro só quando os baratos passarem.
- Reward hacking não some, muda de lugar. O agente vai procurar o caminho mais curto até o gate verde. Trave a prova (hash + somente leitura), revise os primeiros ciclos de perto e desconfie de diff que mexe em config de teste.
- Isolamento é parte do verificador. No paper, o oráculo era garantido por isolamento de container e rede. Se o agente tem credencial pra escrever na mesma base que o gate lê, o gate não é externo.
- Dados de produção. Gate que mede o mundo real lê dado real. Não jogue esse log cru de volta no contexto do agente sem mascarar.
- Os números são de um testbed. 54 ciclos num ambiente controlado. A direção é forte; a porcentagem exata no seu sistema vai ser outra.
FAQ rápido
O que é autoavaliação em agentes de IA?
É quando o próprio agente (ou um juiz que só vê o texto que ele produziu) decide se a tarefa avançou. Funciona quando o sucesso é verificável no próprio artefato. Falha quando o sucesso mora fora da transcrição: aí o agente aceita mudança plausível como progresso. É a miragem de progresso descrita no paper 2607.25152.
LLM-as-a-judge ainda serve pra alguma coisa?
Serve, e muito: pra critério que está no próprio artefato (tom, formato, cobertura de requisito) e pra eval offline com dataset. O que não serve é juiz in-band como único gate de um loop autônomo com objetivo aberto. Combine com check determinístico e sinal do mundo real.
Qual o teto de iterações certo?
Não tem número mágico. Comece baixo (10 a 15), meça quantas iterações as tarefas bem-sucedidas usam de verdade e ajuste. O teto de orçamento em dinheiro é ainda mais importante que o de iteração. Mais freios práticos no post sobre agente em loop infinito.
Isso vale pra agente que não escreve código?
Vale. Agente de suporte: o gate é o ticket fechado sem reabrir. Agente de dados: a query bate com o número auditado. Agente de vendas: o registro no CRM existe e está consistente. Sempre a mesma pergunta: qual sinal o agente não consegue fabricar?
Conclusão
O agente não é mentiroso. Ele só não tem como saber, de dentro da transcrição, se o mundo mudou. E dar um juiz maior pra ele ler a mesma transcrição não muda isso.
A verificação de agentes de IA que funciona é chata e determinística: condição de saída que a máquina checa, teto de iteração e orçamento, gate a cada volta, prova que o agente não pode editar e, pra objetivo aberto, um sinal que vem do mundo real.
O próximo passo dessa tendência é o verificador virar peça de primeira classe do harness, com o mesmo cuidado que hoje a gente dá ao prompt. Se você quer ver onde isso encaixa na régua de autonomia, do autocomplete ao agente que abre PR sozinho, leia os 4 níveis de autonomia em agentic code.
{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.
Conteúdo é o que não falta. Falta quem desembaralhe: o que importa agora é como implementar do jeito certo. No Clã você tem isso ao vivo, toda semana, com quem já filtrou o ruído.
Entrar no Clã