Engenharia

A gente constrói a Apollo com um conselho de agentes

Vários agentes escrevem código. Dois se recusam a deixar trabalho ruim entrar. Um mantém todos eles honestos. O revisor mais duro do time não é humano.

ASR

Apollo Space Research

Apollo Space

· 10 min de leitura

Um agente escritor termina uma feature, roda os testes, vê verde, e escreve as palavras que todo revisor teme: parece pronto. Na maioria dos setups, essa frase é o fim da história, a mudança entra. No nosso, é o começo de uma briga. Um segundo agente que nunca tocou no código puxa a branch, ignora os testes verdes, e tenta quebrar a coisa de propósito. Um terceiro agente lê os dois e decide quem está certo.

Essa briga é como cada linha da Apollo é construída.

Vários agentes escrevem código. Dois se recusam a deixar trabalho ruim entrar. Um mantém todos eles honestos. O revisor mais duro do time não é humano.

Este texto é sobre por que a gente roda assim, e por que a ideia mais útil que a gente pegou emprestado não veio de um paper de pesquisa sobre agentes. Veio do jeito que um bom projeto open-source diz não.

A versão ingênua: um agente, um prompt, um merge

O jeito óbvio de construir software com agentes é o jeito que as demos mostram. Você dá uma tarefa a um agente capaz. Ele planeja, ele escreve, ele roda os testes, ele te reporta de volta. Se os testes passam, você sobe.

Funciona absurdamente bem por uma tarde. Aí para de funcionar.

A falha não é que o agente escreve código ruim. Os agentes escrevem código bom. A falha é que a mesma mente que escreveu o código está dando nota nele, e uma mente avaliando o próprio trabalho é o juiz menos confiável que existe. Foi ela que escreveu o teste, então o teste afirma o que o código já faz. Foi ela que definiu “pronto”, então “pronto” é o que ela por acaso terminou. Ela nunca imaginou a entrada que não tratou, porque se tivesse imaginado, teria tratado. Testes verdes numa mudança auto-avaliada te dizem que o autor e o avaliador concordaram. Eles não te dizem que a mudança está correta.

Um time humano resolveu esse problema faz muito tempo, e não com engenheiros melhores. Com um segundo par de olhos que não tem interesse no trabalho que está sendo feito. Code review existe justamente porque o autor é a pior pessoa pra certificar o próprio código. A correção pra agentes que se auto-avaliam é a mesma correção: tirar a avaliação de quem fez o trabalho.

Então foi o que a gente fez. A gente entregou a avaliação a agentes cujo trabalho inteiro é desacreditar do que foi afirmado.

O conselho: escritores, porteiros, e um mestre

Imagine uma base de código open-source excelente. Tem contribuidores, muitos deles, mandando pull requests o dia inteiro. Tem mantenedores, bem menos, que leem esses pull requests com um olho frio. E em algum lugar tem aquela pessoa cujo nome está no projeto, que mantém a coisa toda coerente e de vez em quando diz ainda não pra uma mudança que todo mundo gostou.

A gente reconstruiu essa estrutura a partir de agentes.

Um conselho de agentes constrói a Apollo: vários agentes escritores abrem mudanças em paralelo, dois agentes porteiros adversariais tentam quebrar cada mudança antes que ela passe, e um agente mestre decide o que tem permissão de entrar na branch principal.

Os escritores são os contribuidores. Vários rodam ao mesmo tempo, cada um na própria cópia isolada do repositório, cada um na própria tarefa. Eles planejam, eles implementam, eles escrevem os testes, eles defendem que a mudança está pronta. O paralelismo é o ponto: a base de código de uma empresa tem mais trabalho do que qualquer agente sozinho consegue segurar na cabeça de uma vez, então a gente espalha.

Os porteiros são os mantenedores, e de propósito são poucos. Um é um revisor adversarial cujo único instinto é quebrar a mudança, achar a entrada que ninguém testou, o caminho que nunca foi exercitado, o caso de borda que o escritor varreu pra debaixo do tapete. O outro guarda o padrão: ele recusa trabalho que não traz evidência de verdade. Não “os testes passam”, mas quais testes, contra o quê, provando qual comportamento. Uma afirmação sem prova executável por trás é, pra esse agente, a mesma coisa que nenhuma afirmação.

O mestre é o mantenedor-oficial. Ele lê a defesa do escritor e as objeções dos porteiros, re-confere a afirmação contra o que a mudança realmente deveria fazer, e bate o martelo. É o agente que diz ainda não, você não testou isso, e fala sério.

Vários agentes escrevem código. Dois se recusam a deixar trabalho ruim entrar. Um mantém todos eles honestos. Os papéis não são decoração. Eles são o motivo de a saída poder ser confiável sem um humano ler cada linha.

Por que adversarial, e não só “um segundo agente”

Existe uma versão mais branda dessa ideia que não funciona, e vale dar nome a ela, porque é a primeira que a maioria das pessoas tenta.

A versão branda é: adicionar um agente revisor que confere o escritor de novo. Bonito na teoria. Na prática, um revisor sem mandato adversarial vira carimbo de aprovação. Pergunte a um agente “isso parece correto?” e ele tem uma forte inclinação a concordar, a mudança é plausível, os testes estão verdes, a explicação do escritor é coerente, então claro, parece correto. Você adicionou uma segunda assinatura ao mesmo ponto cego. Agora dois agentes concordam que o trabalho está pronto. Nenhum dos dois tentou provar que não está.

A correção é mudar a pergunta. Os nossos porteiros não recebem a pergunta “isso está certo?” Eles recebem “como você quebraria isso?” e “o que faria isso falhar na frente de um usuário real?” Esse reenquadramento é o mecanismo inteiro. Um agente mandado achar a falha sai atrás da falha, e um agente atrás da falha enumera a entrada hostil, o teste que falta, a concorrência que o escritor ignorou, o caso em que duas coisas acontecem ao mesmo tempo. O adversário não está sendo mau. Ele está sendo a coisa que o autor estruturalmente não consegue ser: cético em relação a um trabalho do qual não tem orgulho nenhum.

A outra metade do padrão é igualmente simples. Uma mudança não passa só porque diz que está completa.

Uma afirmação não é um resultado.

“Funciona” é um sentimento; “este fluxo exato rodou de ponta a ponta e aqui está o trace” é um resultado. O porteiro do padrão existe pra manter essa distinção afiada, pra rebaixar parece pronto de volta pra não pronto toda santa vez que a evidência for um sentimento vestido de check.

Dois jeitos de construir com agentes. À esquerda, um escritor se auto-avalia, faz merge do próprio trabalho, e o bug sobe. À direita, um conselho roteia a mudança por um porteiro que nunca escreveu o código, re-avalia a afirmação contra o fluxo real, e só faz merge quando passa de verdade.

O agente mestre é o que diz não

Aqui está a parte que surpreende as pessoas: o agente mais valioso do time é o que produz menos código.

O mestre quase não escreve nada. A contribuição inteira dele é julgamento, a releitura fria, o cruzamento de informação, a recusa. Quando um escritor reporta sucesso, o mestre trata esse relato como uma afirmação a interrogar, não um fato a repassar. Ele percorre a mudança contra o que ela realmente deveria fazer, em ordem, e a cada passo pergunta: esta parte foi provada, ou só afirmada? Uma prova faltando e a mudança volta, não importa o quão bom o resto pareça.

Quem já manteve um projeto open-source sério reconhece essa pessoa na hora. É o mantenedor que revisa o seu pull request lindo e responde com duas palavras e um link: ainda não. No momento, é enlouquecedor. Também é o único motivo de a base de código não ter apodrecido. Um projeto só é tão saudável quanto o padrão que o mantenedor está disposto a defender quando defendê-lo dá trabalho.

Esse é o papel que a gente não conseguiu pular. O conselho inteiro desmorona sem ele, porque escritores em paralelo e revisores adversariais ainda precisam de alguém pra resolver a briga, e esse alguém tem que ser inflexível em uma coisa.

O trabalho está pronto quando está pronto, não quando parece pronto.

O revisor mais duro do time não é humano, e é exatamente por isso que ele nunca se cansa de dizer não.

O que isso compra, e o que custa

A contabilidade honesta importa, porque isso não é de graça.

Custa mais. Rodar vários escritores e vários porteiros numa mudança queima mais compute do que um agente sozinho que sobe no verde. A gente paga de propósito. A coisa cara em software nunca foi escrever, foi o bug que chegou no usuário, a regressão que ficou escondida por uma semana, o parece pronto que não estava. Pegar isso antes do merge é barato comparado a pegar em produção, e um adversário que roda em segundos é o lugar mais barato pra pegar.

O que isso compra é uma propriedade difícil de conseguir de qualquer outro jeito: a saída é confiável sem um humano dando nota em cada linha. Não porque os escritores são infalíveis, não são, mas porque nada do que eles produzem chega na branch principal sem sobreviver a um agente feito pra rasgar tudo e a um agente feito pra recusar. A confiança mora na estrutura, não na confiabilidade de nenhum agente isolado. É pelo mesmo motivo que um bom projeto open-source consegue aceitar código de estranhos: não porque confia nos estranhos, mas porque confia na revisão.

A virada: um padrão é uma coisa que você constrói, não uma coisa que você tem

Tire os agentes e o que sobra é uma verdade antiga sobre construir qualquer coisa bem.

Qualidade não é uma propriedade das pessoas que fazem o trabalho. É uma propriedade do processo que decide o que tem permissão de contar como pronto. Os melhores times de engenharia sempre souberam disso, o padrão não está na cabeça de ninguém, está na revisão pela qual toda mudança tem que passar, e ele se sustenta até no dia em que todo mundo está cansado e o prazo é hoje à noite. A gente não inventou isso. A gente só reparou que transfere. Um agente pode escrever código, um agente pode atacar código, e um agente pode segurar a linha sobre o que entra, e quando você os arruma do jeito que uma base de código excelente arruma as suas pessoas, você ganha um time que é duro com o trabalho e leve com a velocidade.

Os escritores vão ficar cada vez mais rápidos. O modelo embaixo deles vai ficar cada vez mais esperto. Nada disso é o que faz o resultado ser bom. O que faz ele ser bom é o agente que lê uma mudança brilhante e mesmo assim diz ainda não, você não testou isso, e o momento em que a gente parar de deixar ele dizer isso é o momento em que a coisa toda começa a apodrecer.


A gente constrói a Apollo desse jeito porque está construindo ela pra isso, um sistema operacional nativo em IA onde agentes não só fazem o trabalho, eles cobram um padrão uns dos outros. Se você já subiu um parece pronto que não estava, você já sabe por que o revisor mais duro do time nunca deveria ser quem escreveu o código.

A Apollo cuida da operação repetitiva da sua empresa pro seu time não precisar.

Entre na lista de espera: acesso antecipado, preço de usuário fundador e um lugar na primeira fila enquanto a gente constrói.

Entrar na lista de espera