Pular para o conteúdo

Uma equipe editorial e uma comunidade que criam com IA

← Vibe engineering

Vibe engineering · · 9 min de leitura

Arquitetura de sistemas com agentes de IA

Como conduzir agentes de IA no nível do sistema: contratos de módulos, fronteiras e o que fica com o humano.

A maioria das equipes usa agentes de IA no nível do arquivo: “adicione este endpoint”, “corrija este teste”, “adicione validação”. Isso funciona enquanto a mudança cabe em um único arquivo. O problema começa mais acima, onde as decisões envolvem as fronteiras entre módulos, os contratos entre eles e quem é dono do quê. Conduzir um agente no nível do sistema é uma disciplina diferente de conduzi-lo no nível do arquivo. Exige que um humano (um sênior, um tech lead, um arquiteto) mantenha o controle sobre aquilo que o agente não vai inventar sozinho: o modelo de dados, as fronteiras e os requisitos não funcionais.

O módulo e seu contrato como unidade de trabalho do agente

Um arquivo é uma unidade de trabalho ruim para um agente, porque não tem semântica própria. A unidade certa é um módulo com um contrato explícito: entrada, saída, erros e invariantes claramente descritos. Quando você diz a um agente “implemente o módulo de faturamento seguindo este contrato”, você entrega a ele um espaço fechado, onde ele pode ser criativo sem se espalhar pelo sistema inteiro.

Na prática, o contrato são os tipos na borda do módulo (sua interface pública), o schema dos dados de entrada (por exemplo, Zod), os casos de erro definidos e uma lista curta de invariantes, ou seja, coisas que precisam ser verdadeiras independentemente da implementação. O agente recebe o contrato como entrada, e não como algo que ele mesmo deve “completar”. Isso transfere a decisão mais importante, o formato da fronteira, do modelo para o humano.

Há ainda um benefício que você só vai valorizar em escala. Quando um módulo tem um contrato fechado, você pode entregar a implementação dele a um agente e o módulo vizinho a outro, em paralelo e sem colisões. A fronteira do contrato é também a fronteira do paralelismo. Sem ela, dois agentes trabalhando na mesma área começam a sobrescrever as premissas um do outro, e você passa a noite fazendo merge de visões contraditórias do mesmo serviço. Contrato não é burocracia: é o protocolo que permite que muitos agentes (e humanos) trabalhem lado a lado sem pisar no pé um do outro.

Por que interfaces claras pesam mais quando quem escreve o código é um agente

Quem escreve código carrega na cabeça um contexto não dito: sabe que este serviço “na verdade” não deveria chamar o banco de dados diretamente, que aquele cache é temporário. O agente não tem nada desse contexto. Ele lê o que está escrito nos tipos e nas assinaturas e trata isso como a verdade completa. Se uma interface é vaga, o agente preenche a lacuna com a suposição mais simples que compila, e não necessariamente com a que é correta para o domínio.

Daí a regra: quanto mais código o agente escreve, mais precisas suas interfaces precisam ser. Assinaturas estreitas e explícitas, nada de parâmetros “mágicos” como options: any, nada de efeitos colaterais ocultos. Uma boa interface é para o agente o que uma boa documentação é para um humano: diz o que é permitido e o que não é. Uma fronteira ruim não desacelera o agente. Pelo contrário: ele vai atravessá-la alegremente em dez arquivos de uma vez antes que você perceba.

Uma consequência prática: compensa tornar estados inválidos impossíveis de representar no próprio tipo. Se uma função recebe status: string, mais cedo ou mais tarde o agente vai passar um “peding” com erro de digitação, e o código vai compilar. Se ela recebe uma união estreita de literais, o compilador pega o erro antes que ele chegue ao review. Cada decisão de tipagem como essa é uma barreira que o agente não consegue pular, e ela funciona sempre, sem depender da atenção de um humano. É uma forma de controle mais barata do que pegar o mesmo bug no olho no décimo PR da semana.

O que precisa ficar nas mãos de um humano

Há três áreas que você não entrega a um agente. Não porque ele não consiga escrevê-las, mas porque são decisões, não gerações.

  • O modelo de dados. O formato das entidades, os relacionamentos, as chaves, as fronteiras de consistência. É a fundação sobre a qual todo o resto se apoia: o agente pode propor um schema, mas a aprovação e as consequências da migração são suas.
  • As fronteiras dos módulos. Onde uma responsabilidade termina e outra começa. É a decisão sobre o que vai ser barato de mudar e o que vai ser caro. O agente não enxerga a trajetória do seu produto daqui a um ano.
  • Requisitos não funcionais. Latência, custo de LLM por requisição, orçamento de memória, caminho de rollback, modelo de segurança. Por padrão, o agente otimiza para “funciona”, e não para “funciona em 50 ms e custa centavos”. Você precisa declarar essas restrições de forma explícita.

O denominador comum: são coisas cujo custo do erro cresce exponencialmente com o tempo. Uma fronteira de módulo mal posicionada na primeira semana é um refactor de um dia. A mesma fronteira depois de seis meses significa reescrever um quarto do sistema.

Mudanças pequenas e revisáveis no nível da arquitetura

A tentação com agentes é encomendar uma única mudança enorme (“reescreva a camada de persistência para um novo ORM”) e receber cem arquivos para revisar. Isso é um antipadrão. Ninguém revisa cem arquivos com rigor; a pessoa revisa os cinco primeiros e confia no resto. E o bug está justamente no resto.

Divida as mudanças arquiteturais em uma sequência de passos pequenos e reversíveis, cada um deixando o sistema funcionando. Primeiro, introduza a nova interface ao lado da antiga. Depois, migre um módulo. Depois, o próximo. Cada passo é um PR próprio, um build verde próprio, um ponto de rollback próprio. Um agente executa esses passos muito bem, desde que quem desenhou a sequência tenha sido você, e não ele. O plano de migração é uma decisão arquitetural; executar um único passo é trabalho que você pode delegar.

Documentação que o agente consome

Num mundo de agentes, a documentação deixa de ser “para quem acabou de entrar no time”. Ela vira entrada para o modelo: o contexto sobre o qual o agente constrói suas decisões. Isso muda o formato dela.

  • ADRs (Architecture Decision Records). Registros curtos de uma decisão: o que foi decidido, em que contexto, quais eram as alternativas e as consequências. Um agente que lê um ADR entende por que a fronteira está aqui e não ali, e não vai “consertá-la” contra a intenção original.
  • Specs de módulos. O contrato, os invariantes, os casos de borda, um “fora do escopo” explícito. É o documento que você entrega ao agente antes da implementação, não depois.
  • Um mapa de fronteiras. Uma página: quais são os módulos, quem conversa com quem, o que não pode ser chamado diretamente. É a bússola que mantém o agente na linha no nível do sistema.

Documentação que o agente não lê está morta. Documentação que você passa para ele no contexto vira um mecanismo ativo de direção, mais barato e mais rápido do que pegar erros no review.

Modos de falha: o agente mexe na arquitetura sem supervisão

Quando você deixa um agente tomar decisões arquiteturais sozinho, as falhas seguem um padrão que se repete. Vale conhecê-las, porque cada uma é previsível.

  • Erosão de fronteiras. O agente chama um módulo interno lá do outro lado do sistema “por conveniência”, porque é o caminho mais curto. Depois de vinte atalhos desses, os módulos estão emaranhados e o contrato virou ficção.
  • Deriva do modelo de dados. Cada mudança acrescenta um campo “por via das dúvidas”. As entidades incham, a semântica fica difusa e ninguém sabe qual campo é a fonte da verdade.
  • Duplicação invisível. O agente não encontra a abstração existente e escreve uma terceira versão da mesma lógica. Localmente parece tudo certo; globalmente, você tem três implementações que divergem.
  • Regressão não funcional silenciosa. O código funciona, os testes passam, mas a latência dobrou ou o custo de LLM por requisição disparou. Ninguém percebe, porque ninguém mede isso em uma verificação automática.

A causa comum das quatro: o agente otimiza localmente e no curto prazo, porque é só isso que ele enxerga no contexto. Arquitetura é otimização global e de longo prazo, e essa é exatamente a parte que você não delega.

O mais importante: esses modos de falha não fazem barulho. Nenhum deles quebra o build ou acende uma luz vermelha no CI, porque localmente tudo está correto. Eles só aparecem como um atrito crescente: cada nova mudança custa um pouco mais, cada onboarding demora um pouco mais, cada incidente fica mais difícil de diagnosticar. Isso é dívida arquitetural e, ao contrário da dívida em um único arquivo, quase nunca é o agente quem a paga. Quem paga é a equipe, na mão, ao longo de meses. Por isso, a supervisão da arquitetura não é algo para acoplar “depois”; é a condição para que a velocidade que o agente oferece se sustente.

Como organizar isso na prática

  1. Um humano define o modelo de dados e as fronteiras dos módulos, registrados em ADRs e em um mapa de fronteiras.
  2. Cada módulo ganha um contrato (tipos, schema, invariantes, fora do escopo).
  3. O agente implementa dentro de um único módulo, com o contrato como entrada.
  4. Mudanças arquiteturais saem como uma sequência de PRs pequenos e reversíveis.
  5. Os requisitos não funcionais têm suas próprias verificações automáticas (latência, custo, bundle), e não apenas testes.
  6. O review entre módulos é feito por um humano; o agente pode revisar dentro de um módulo.

TL;DR

Conduzir um agente no nível do sistema é diferente de conduzi-lo no nível do arquivo. A unidade de trabalho é um módulo com contrato explícito, não um arquivo. Quanto mais código o agente escreve, mais precisas suas interfaces precisam ser, porque o agente só lê o que está escrito. O humano fica com o modelo de dados, as fronteiras dos módulos e os requisitos não funcionais: são decisões, não gerações. Divida as mudanças arquiteturais em passos pequenos e reversíveis e trate a documentação (ADRs, specs, mapa de fronteiras) como entrada para o modelo, não como arquivo morto. Sem supervisão, o agente corrói fronteiras, incha o modelo de dados, duplica lógica e quebra silenciosamente os requisitos não funcionais, porque otimiza localmente, enquanto a arquitetura é global.

Arquitetura de sistemas com agentes de IA | vibecoding.inc