Toda demo de agente termina igual
O modelo escreve o arquivo, roda a coisa, imprime "pronto". Ninguém confere.
A entrega que parecia terminada às 2 da manhã vira um arquivo que não existe, um
teste que nunca rodou e um resumo confiante.
Batemos nisso vezes suficientes para parar de acreditar na palavra do agente que
fez o trabalho. Não porque o modelo é preguiçoso — porque um LLM não consegue
certificar o próprio artefato. Ele declara sucesso de dentro, onde não vê a falha.
Três falhas, uma causa
Construir um laço de validação para os nossos agentes expôs três modos de quebra:
- Autoavaliação forjada. O modelo que gerou o artefato é o modelo que o avalia. Mesmo contexto, mesmos pontos cegos. Ele diz "parece correto" sobre um diff que nunca executou.
- FoFo — Found on False. A IA não pode corrigir a própria prova. Quem escreve o código não escreve o teste que o valida, e quem julga não compartilha contexto com quem construiu.
-
Verificação fraudável. Se o verificador mora onde o agente alcança, o
agente falsifica o verificador. Um
pytest.pyfalso que devolve 0 não é hipótese — é o movimento óbvio.
As duas primeiras são sobre autoridade: só evidência externa pode declarar
PRONTO. A terceira é sobre alcance: a evidência tem de ser produzida num lugar
que o construtor não toca.
O gate cego
Então a arquitetura parte o laço e põe a prova do lado de fora:
Tarefa ──▶ [SOUL / Builder] ──▶ [Gate cego] ──▶ [Juiz / Revisor] ──▶ Envelope
▲ │ FAIL │ REJECT
└──── required_fix ──┘ │ (max_attempts → ESCALADO)
(re-gate, estrito) ▼ APROVADO → SUCESSO
-
Builder / SOUL. Rascunha a partir de persona + memória procedural + tarefa.
Pode referenciar um segredo pelo nome (
$VAULT_X), nunca pelo valor. -
Gate cego. O ambiente inalcançável. Roda a ferramenta de verdade — HTTP via
curl,nc,ffprobe,EXPLAINem seco, HMAC-SHA256, um regex declarado — e devolve(passou: bool, log: str). A evidência é refeita a cada tentativa. Gate verde da rodada 1 nunca é reaproveitado na rodada 2. -
Juiz / Revisor. Uma sessão sem o histórico do Builder, confrontando rascunho
- log do gate contra as regras injetadas. Ele emite um veredito de roteamento, não
o texto final. A rejeição injeta
required_fixno próximo prompt do Builder, invisível ao canal humano.
- log do gate contra as regras injetadas. Ele emite um veredito de roteamento, não
o texto final. A rejeição injeta
O contrato é tipado (Pydantic v2 — sem LangChain, sem LangGraph, decisão
documentada): o envelope carrega soul_id, um status restrito a
SUCCESS | ESCALATED_TO_DM | TOOL_FAILURE, e uma trilha de auditoria com
self_correction_count, rules_applied, latency_ms, hedge_warning e o
gate_log cru.
A regra de ouro do laço
O LLM pode sugerir que terminou. Só evidência externa pode declarar PRONTO.
SUCCESS só existe quando gate_pass == true e judge_pass == true. Todo o
resto termina em ESCALATED_TO_DM (teto de tentativas) ou TOOL_FAILURE. O agente
para onde a autorização termina — o que provamos num piloto ao vivo que bateu num
404 real e devolveu nenhum payload inventado em vez de alucinar um.
O que é preciso para confiar no testador
Gates vêm em dois tipos, ambos declarados num registro só:
-
subprocess: argv renderizado com o artefato, executado como processo do host. -
static: validador determinístico em processo (um regex de promptMEDIA:), ainda fora do intérprete do LLM e ainda declarado no registro.
Parâmetros entram por string.Template, então literal de shell/HTTP/JSON
(%{http_code}, {"exact":false}) nunca colide com interpolação.
O harness mede a si mesmo com função pura, sem LLM no meio, em seis dimensões —
contratos determinísticos, autoteste do orquestrador, orquestração ponta a ponta,
política de custo, operação viva, documentação. Cada dimensão devolve um de quatro
estados (PASS | FAIL | NOT_VERIFIABLE | ERROR), e o veredito é derivado, não julgado:
APTO todas as dimensões PASS e total >= 90% do teto (fixo)
COM RESSALVAS nenhum FAIL/ERROR, mas algo é NOT_VERIFIABLE (>= 70%)
REPROVADO qualquer FAIL/ERROR, ou total < 70%
Dimensão não executada fica no denominador, e os códigos de saída são 0 / 1 / 2 —
para o CI poder chamar. Inconclusivo nunca passa o gate: essa regra veio de uma
máquina quebrada que, sem ela, teria entregue verde.
Onde está hoje
Números honestos, todos medidos localmente:
- 44 testes pytest verdes
- 2 pilotos ponta a ponta (dois projetos sem relação, mesmo motor)
-
1 entrega real num canal humano (
message_id=43843) - política de custo imposta: o gate nunca chama modelo pago
Não é framework. Sem montanha de dependência, sem marketing de agente-de-agentes.
A alegação é estreita de propósito: não deixa seu agente mais inteligente, deixa o
"pronto" valer alguma coisa.
A versão de código aberto do motor do laço, incluindo o registro de gates e o
harness de qualidade, está aqui:
Top comments (1)
Separating the agent that writes code from the one that certifies it is a strong control, especially when they do not share the same assumptions or context window. The independence is more meaningful if the verifier can run the tests, inspect the diff, and reject without being asked to repair.