O agent que constrói suas próprias ferramentas
Quando o agent escreve a função que precisa em vez de esperar alguém lançá-la, a linha entre usar uma ferramenta e fazer uma desaparece, e o guardrail se move para onde pertence.
Apollo Space Research
Apollo Space
Um agent está no meio de uma tarefa. Ele precisa somar uma coluna de números que vivem em três lugares diferentes, em três formatos diferentes, nenhum dos quais se alinha. Ele tem uma ferramenta de calculadora, uma ferramenta de busca, uma dúzia de integrações, e nenhuma delas faz exatamente isso. No setup comum, é aqui que o agent para, dá de ombros em prosa, e arquiva um pedido para um humano construir a função que falta. No nosso, ele escreve a função, roda numa caixa que não pode machucar nada, obtém o número, e segue em frente.
O desvio todo levou segundos. Ninguém lançou uma feature.
Essa é a ideia sobre a qual este post é, e é menor do que soa: no momento em que um agent consegue escrever a ferramenta que lhe falta, “usar ferramentas” e “construir ferramentas” param de ser dois trabalhos diferentes. Eles viram um único movimento contínuo. A parte interessante não é que seja possível. É onde você coloca o guardrail quando é.
Por que a lista de ferramentas sempre acaba
Comece com o jeito que todo agent funciona hoje, porque a falha está embutida no formato.
Você dá a um agent uma lista de ferramentas. Cada uma é uma função com um nome, uma descrição e um schema, send_email, create_task, search_docs. O modelo lê a tarefa, escolhe uma ferramenta, preenche os argumentos, e o runtime a executa. Esse é um bom design. Uma ferramenta é uma promessa com um formato, e esse formato é o que torna as escolhas do agent verificáveis. Não estamos argumentando contra ferramentas.
Estamos argumentando contra a lista ser finita.
Porque a lista é sempre finita, e o mundo não é. Quem construiu o agent imaginou algum conjunto de coisas que ele precisaria fazer, escreveu uma ferramenta para cada uma, e parou. A primeira vez que o agent encontra uma tarefa que cai entre duas ferramentas, some estas três colunas incompatíveis, reformate este export de formato estranho, faça o diff do relatório de ontem contra o de hoje, ele não tem nada. A capacidade que ele precisa está a uma pequena função de distância, e essa função não existe, porque ninguém imaginou exatamente este pedido com antecedência.
Aqui está a parte que dói: a função que falta geralmente é trivial. Dez linhas. Um loop, um parse, uma soma. Um engenheiro júnior a escreveria num minuto. Mas o agent não consegue, porque na arquitetura comum o agent é um usuário de ferramentas, nunca um autor delas. Então ele faz a única coisa que um usuário pode fazer quando o catálogo fica aquém. Ele improvisa em linguagem natural, “o total parece ser aproximadamente…”, e erra sutilmente. Ou trava e pede a um humano para ir construir a função de dez linhas, que cai num backlog, que é onde coisas pequenas e óbvias vão esperar atrás de coisas grandes.
A correção ingênua é adicionar mais ferramentas. Antecipe mais. Lance um catálogo maior. Mas você não consegue pré-construir toda função de dez linhas que uma empresa real um dia vai precisar, do mesmo jeito que você não consegue pré-escrever toda frase que alguém possa dizer. O catálogo cresce, a lacuna se move, e o agent ainda está parado na beira dela. O gargalo nunca desaparece. Ele só se move para a próxima coisa que ninguém pensou em construir.
Deixe o agent escrever a função
Então inverta a arquitetura. Em vez de entregar ao agent uma lista fixa de ferramentas, entregue a ele mais uma ferramenta, uma ferramenta que faz ferramentas.
A ideia é simples. A ideia central é sempre simples; vamos ver por que esta funciona. O agent já fala a linguagem em que ferramentas são escritas. O mesmo modelo que escolhe send_email e preenche seus argumentos também consegue escrever o corpo de uma pequena função do zero, isso é só código, e código é algo em que ele é fluente. O catálogo nunca foi um limite no que o agent conseguia expressar. Era um limite no que ele tinha permissão de rodar.
Quando o agent bate numa tarefa sem ferramenta correspondente, ele não para. Ele escreve uma pequena função que faria o trabalho, entrega essa função a uma ferramenta de síntese, e o runtime executa o código recém-escrito num sandbox, retorna o resultado, e o agent dobra a resposta de volta no seu trabalho. A capacidade que faltava existiu por exatamente o tempo que a tarefa precisou.
Essa é a jogada que colapsa os dois trabalhos. Usar uma ferramenta é escolher uma função e preencher seus argumentos. Construir uma ferramenta é escrever uma função e dar a ela um formato. Quando o agent consegue fazer ambos no mesmo fôlego, a parede entre eles se foi. Ele não está mais alcançando dentro de um catálogo. Ele está alcançando uma capacidade, e se a capacidade não está lá, ele a escreve.
E note o que isso faz com o backlog. A função de dez linhas que costumava esperar atrás das grandes features, o reformatador, o diff pontual, a somazinha estranha, nunca entra no backlog. Ela é escrita, rodada e descartada dentro de uma única tarefa, porque nunca valeu a tarde de um humano e agora não precisa de uma. No momento em que um agent consegue escrever a ferramenta que lhe falta, “usar ferramentas” e “construir ferramentas” param de ser dois trabalhos diferentes.
Se você parar de ler aqui, estaria certo em ficar nervoso. Um agent que escreve e roda o próprio código soa exatamente como a coisa que você não quer solta nos sistemas de uma empresa. Que é o assunto real deste post.
O guardrail não desaparece. Ele se move.
Todo instinto diz: isso é perigoso, então proíba. Não deixe o agent escrever código. Mantenha o catálogo trancado.
Esse instinto está buscando o controle errado. Proibir a síntese não torna o agent seguro; torna o agent inútil exatamente no momento em que ele poderia ter sido mais útil, e empurra o mesmo risco para um lugar mais silencioso. Porque o agent que não consegue escrever uma função vai em vez disso adivinhar a resposta em prosa, e um número errado confiante sem código por trás é muito mais perigoso do que uma função que você consegue ler. Você não removeu o risco. Você o escondeu dentro de inglês fluente onde nada consegue verificar.
Então a gente não proíbe a escrita. A gente move o guardrail.
Aqui está o princípio, e é o que sustenta tudo: você não torna um agent que escreve código seguro impedindo-o de escrever código. Você o torna seguro controlando o que o código tem permissão de tocar. O perigo nunca foi que o agent autorou uma função. O perigo é o que essa função consegue alcançar, a rede, o filesystem, o banco de dados de produção, o dinheiro do cliente. Tranque essas coisas e a autoria é inofensiva. A função roda numa caixa sem porta para o lado de fora; ela recebe inputs, retorna um valor, e o pior que uma ruim pode fazer é retornar um valor ruim, que a próxima camada é construída para pegar mesmo.
A versão ingênua de segurança é uma lista de ações proibidas, não delete arquivos, não chame esta API, não gaste dinheiro, escrita num prompt e torcida. Isso falha do jeito que todas as regras-de-prompt falham: o modelo pode ser convencido a abandoná-las, e uma regra que o modelo consegue contornar com raciocínio não é um guardrail, é uma sugestão. A versão real não é uma regra que o agent lê. É uma parede que o agent não consegue ver além. O sandbox não pede para a função se comportar. Ele remove a capacidade de se comportar mal, sem rede a menos que concedida, sem filesystem a menos que concedido, um teto rígido em tempo e memória para que um loop descontrolado morra na caixa em vez de em produção.
Há um segundo guardrail, mais silencioso que o sandbox e tão importante quanto: uma ferramenta que o agent escreve uma vez não tem que ser escrita do zero na próxima. Quando uma função sintetizada se revela boa, ela rodou limpa, retornou o formato certo, resolveu uma tarefa que uma pessoa real de fato tinha, ela pode ser promovida. Revisada do jeito que qualquer mudança é revisada, recebe um nome estável e um schema, e é adicionada ao catálogo como uma ferramenta de primeira classe. O próximo agent que precisar dela não a re-deriva. Ele só a escolhe, do jeito que escolhe send_email.
Esse caminho de promoção é o que impede a síntese de virar caos. As funções descartáveis ficam descartáveis. As que se provam se formam, de uma coisa que um agent improvisou num sandbox para uma ferramenta em que o sistema inteiro pode confiar, com um formato que você consegue verificar e um histórico que você consegue auditar. O catálogo para de ser uma lista fixa que alguém escreveu com antecedência. Ele vira uma coisa que cresce do uso real, uma função provada por vez.
O que um agent de fato faz com isso
Vale aterrar isso, porque “escreve as próprias ferramentas” pode soar mais grandioso do que a realidade do dia a dia, e a realidade do dia a dia é o ponto.
A maior parte do que uma ferramenta de síntese é usada é sem glamour. Remodelar um export bagunçado no formato que o próximo passo espera. Computar algo que a calculadora não consegue expressar, um total ponderado, uma diferença de datas atravessando a fronteira de um trimestre, uma checagem de que duas listas de fato batem. Parsear um formato que ninguém antecipou. Esses não são feitos de engenharia. São as pequenas funções conectivas que ficam entre as grandes ferramentas, a cola que um operador humano escreveria sem pensar e um catálogo fixo nunca consegue cobrir bem.
Digamos que um agent está reconciliando dois registros que deveriam concordar e não concordam, uma contagem num sistema, uma contagem em outro. Nenhuma ferramenta os compara; por que haveria uma, para exatamente este par? Então ele escreve a comparação de seis linhas, roda na caixa, e reporta as três linhas que diferem. A capacidade viveu por uma tarefa e então evaporou, e o agent nunca teve que dizer “não consigo fazer isso, por favor construa uma ferramenta para mim”. Ele construiu a ferramenta. A coisa toda foi invisível.
Essa invisibilidade é o sinal de que está funcionando. Ninguém arquivou um pedido de feature. Ninguém esperou uma sprint. O agent encontrou uma lacuna e a fechou, dentro do próprio turno, e o único rastro que ele deixa é uma função num log que um revisor pode ler se um dia precisar perguntar como ele chegou a esse número. A resposta está bem ali, em código, que é exatamente onde você quer que a resposta esteja, não enterrada numa frase que o modelo escreveu, onde nada consegue auditar.
A virada: capacidade para de ser algo que você lança
Recue do sandbox e dos schemas, e aqui está o que de fato mudou.
Por toda a história do software, capacidade era algo que você lançava. Alguém decidia que o produto deveria fazer uma coisa, um engenheiro construía a coisa, ela passava por revisão e release, e então, semanas depois, se você tivesse sorte, os usuários conseguiam fazer a coisa. A lista do que o software conseguia fazer sempre foi uma lista que alguém escreveu com antecedência, e a lacuna entre “eu preciso disso” e “eu consigo fazer isso” era medida em releases. A maioria das pequenas necessidades nunca atravessava essa lacuna, porque não valiam um release, então elas simplesmente ficavam necessidades para sempre.
Um agent que escreve as próprias ferramentas silenciosamente apaga essa lacuna para as coisas pequenas, e as coisas pequenas são a maior parte das coisas. A função de dez linhas que nunca teria justificado a tarde de um engenheiro agora é escrita no instante em que é necessária e esquecida no instante em que não é. Capacidade para de ser uma coisa que você lança num cronograma e vira uma coisa que aparece sob demanda, dentro do trabalho, enquanto você dorme. O produto não é mais o conjunto fixo de coisas que alguém construiu. É o conjunto aberto de coisas que o agent consegue construir, cercado pelo que você o deixa tocar.
Essa é a parte que vale sentar e refletir. A pergunta difícil para de ser quais features lançamos. Ela vira o que estamos dispostos a deixar um agent alcançar, e essa é uma pergunta muito melhor, porque é a que sempre foi de fato estrutural. A cerca é o produto agora. Acerte a cerca e a capacidade cuida de si mesma.
É isso que estamos construindo na Apollo, não um agent mais inteligente com uma lista mais longa de botões, mas um agent que escreve o botão que lhe falta e o roda em algum lugar onde ele não pode causar dano. A linha entre usar uma ferramenta e fazer uma nunca foi uma lei da natureza. Era só uma parede que ninguém tinha uma razão segura para derrubar ainda.
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 esperaO imposto oculto dos agents em paralelo é um diamante de migrations
Seis agents escrevendo para um schema conflitam no banco de dados, não no código, e a CI morre em "multiple heads".
EngenhariaUm orchestrator que não sobrevive ao próprio crash não é um
Um crash que apaga o raciocínio do orchestrator perde a única coisa que você não consegue reconstruir.
EngenhariaColoque um portão determinístico na frente do seu revisor mais esperto
A pega-defeito mais barata é um script burro que checa se duas branches mergeadas ainda sobem antes de qualquer julgamento.