Agent Spread: Distribuindo Agentes IA por Bounded Contexts Automaticamente
Você tem uma aplicação com 15 pastas, 200 arquivos, 3 linguagens diferentes. Quer usar agentes IA para ajudar no desenvolvimento mas não quer configurar manualmente qual agente cuida de qual parte. A ideia do Agent Spread é: o sistema escaneia sua aplicação, detecta os domínios automaticamente pela estrutura de pastas e convenções de nomenclatura, e distribui agentes especializados em cada área. Cada agente conhece profundamente seu domínio (quais arquivos existem, qual tech stack, qual a complexidade) e ignora o resto. O resultado é que quando você pede "refatorar a autenticação", o agente de auth já sabe exatamente quais arquivos mexer sem precisar varrer o projeto inteiro.
Guia de tópicos:
- O Problema: Agente Genérico em Projeto Grande
- Análise Automática de Aplicação
- Detecção de Tech Stack por Padrões de Arquivo
- Identificação de Domínios por Convenção
- Cálculo de Complexidade
- Planejamento de Distribuição
- Deploy de Agentes: Criando a Estrutura
- Configuração Central com orchestra.yaml
- Considerações Finais
- Links Indicativos
O Problema: Agente Genérico em Projeto Grande
Um agente IA com contexto de 128k tokens parece ter espaço de sobra. Até você perceber que 200 arquivos de código somam facilmente 500k tokens. O agente não consegue carregar o projeto inteiro no contexto. Então ele trabalha com uma visão parcial, e essa visão parcial leva a sugestões que ignoram código existente, duplicam funcionalidades, ou quebram contratos entre módulos.
A alternativa é dar ao agente apenas os arquivos relevantes para a tarefa. Mas quem decide o que é relevante? Se o usuário pede "adicionar validação de email", é relevante o módulo de auth? O módulo de user? O módulo de notification que envia emails? Depende do projeto. E essa decisão não pode depender do usuário saber a estrutura interna de cor.
O Agent Spread resolve isso na raiz: cada domínio tem seu próprio agente que já conhece seus arquivos. Quando o orquestrador roteia a requisição para o agente certo, esse agente já tem o contexto necessário sem precisar carregar nada extra.
Análise Automática de Aplicação
O AppAnalyzer é o componente que escaneia o projeto e produz um mapa completo da estrutura:
type AppStructure struct {
RootPath string
Domains map[string]*Domain
TechStack []string
Complexity string
AgentPlan map[string][]string
}
type Domain struct {
Name string
Path string
Files []string
SubDomains map[string]*Domain
Complexity int
AgentNeeded bool
}
O AppStructure é o resultado final da análise. Contém todos os domínios detectados, a tech stack do projeto, a complexidade geral, e o plano de distribuição de agentes. Cada Domain sabe seu path, seus arquivos de código, e se precisa de um agente dedicado.
A análise acontece em quatro etapas sequenciais: detectar tech stack, analisar domínios, calcular complexidade, e planejar distribuição. Cada etapa alimenta a próxima.
Detecção de Tech Stack por Padrões de Arquivo
A detecção de tech stack funciona por presença de arquivos característicos:
func (aa *AppAnalyzer) detectTechStack() []string {
var stack []string
patterns := map[string][]string{
"Python": {"*.py", "requirements.txt", "setup.py", "pyproject.toml"},
"Go": {"*.go", "go.mod", "go.sum"},
"JavaScript": {"*.js", "package.json", "*.ts", "*.jsx", "*.tsx"},
"FastAPI": {"main.py", "app.py", "**/routers/**"},
"React": {"src/App.js", "src/App.tsx", "public/index.html"},
"Docker": {"Dockerfile", "docker-compose.yml"},
}
for tech, filePatterns := range patterns {
if aa.hasPatterns(filePatterns) {
stack = append(stack, tech)
}
}
return stack
}
A detecção diferencia linguagem de framework. Um projeto pode ser "Python + FastAPI + Docker" ou "Go + React + Kubernetes". Essa informação vai para a configuração do agente, que usa para contextualizar suas respostas. Um agente que sabe que o projeto usa FastAPI vai sugerir routers e Pydantic models em vez de Flask blueprints.
O hasPatterns faz glob matching no filesystem, incluindo busca recursiva para padrões com **. É rápido porque só verifica existência, não lê conteúdo dos arquivos.
Identificação de Domínios por Convenção
A identificação de domínios usa um mapa de padrões comuns em projetos web:
func (aa *AppAnalyzer) analyzeDomains(structure *AppStructure) error {
domainPatterns := map[string][]string{
"auth": {"auth", "authentication", "login", "users", "accounts"},
"api": {"api", "routes", "controllers", "handlers", "endpoints"},
"models": {"models", "entities", "schemas", "database", "db"},
"services": {"services", "business", "logic", "core"},
"products": {"products", "catalog", "items"},
"orders": {"orders", "cart", "checkout"},
"payment": {"payment", "billing", "transactions"},
}
return filepath.Walk(aa.rootPath, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
return nil
}
dirName := strings.ToLower(info.Name())
for domain, patterns := range domainPatterns {
for _, pattern := range patterns {
if strings.Contains(dirName, pattern) || dirName == pattern {
// Registra o domínio e conta seus arquivos
structure.Domains[domain] = &Domain{
Name: domain,
Path: path,
Files: aa.countFiles(path),
}
}
}
}
return nil
})
}
O walk percorre toda a árvore de diretórios e classifica cada pasta encontrada. Uma pasta chamada "authentication" é classificada como domínio "auth". Uma pasta chamada "cart" é classificada como domínio "orders". Se o projeto tem uma pasta "src/modules/user-management/", ela é classificada como "auth" porque contém "user".
A contagem de arquivos considera apenas arquivos de código (extensões como .py, .go, .js, .ts, .java). Arquivos de configuração, assets e documentação são ignorados porque não representam complexidade de domínio.
Cálculo de Complexidade
A complexidade do projeto determina se vale a pena distribuir agentes ou se um agente único resolve:
func (aa *AppAnalyzer) calculateComplexity(structure *AppStructure) string {
totalFiles := 0
totalDomains := len(structure.Domains)
for _, domain := range structure.Domains {
totalFiles += len(domain.Files)
}
if totalFiles < 10 && totalDomains < 3 {
return "simple"
} else if totalFiles < 50 && totalDomains < 8 {
return "medium"
} else {
return "complex"
}
}
Projetos simples (menos de 10 arquivos, menos de 3 domínios) não precisam de multi-agente. O overhead de coordenação seria maior que o benefício. Projetos medium ganham agentes por domínio mas sem orquestrador central. Projetos complex ganham agentes por domínio mais um orquestrador que coordena interações entre eles.
Os thresholds foram definidos empiricamente. 10 arquivos é mais ou menos o ponto onde um agente único começa a perder contexto relevante. 50 arquivos é onde a coordenação manual entre domínios fica inviável.
Planejamento de Distribuição
Com domínios identificados e complexidade calculada, o plano de distribuição define onde cada agente vai morar:
func (aa *AppAnalyzer) planAgentDistribution(structure *AppStructure) {
for domainName, domain := range structure.Domains {
if len(domain.Files) > 0 {
agentPath := filepath.Join(domain.Path, "agents")
structure.AgentPlan[domainName] = []string{agentPath}
}
}
// Orquestrador central para projetos complexos
if structure.Complexity == "complex" || len(structure.Domains) > 2 {
mainAgentPath := filepath.Join(structure.RootPath, "orchestra_agents")
structure.AgentPlan["orchestrator"] = []string{mainAgentPath}
}
}
Cada agente fica dentro do diretório do seu domínio, numa subpasta agents/. Isso mantém a localidade: o agente de auth fica em auth/agents/, o de products fica em products/agents/. Quando o agente precisa de contexto, os arquivos relevantes estão no diretório pai.
O orquestrador central só é criado para projetos complexos. Ele fica na raiz (orchestra_agents/) e sua responsabilidade é coordenar os outros agentes quando uma requisição cruza domínios.
Deploy de Agentes: Criando a Estrutura
O deploy cria os diretórios e gera configurações YAML para cada agente:
func (aa *AppAnalyzer) createAgentStructure(domain, agentPath string, structure *AppStructure) error {
os.MkdirAll(agentPath, 0755)
configContent := fmt.Sprintf(`name: %s_agent
domain: %s
complexity: %d
files_count: %d
tech_stack: %v
responsibilities:
- Análise de código do domínio %s
- Refatoração e otimização
- Testes e validação
- Documentação técnica
commands:
analyze: "Analisar código do domínio"
refactor: "Refatorar seguindo melhores práticas"
test: "Criar/executar testes"
document: "Gerar documentação técnica"
`, domain, domain, domainInfo.Complexity, len(domainInfo.Files), structure.TechStack, domain)
return os.WriteFile(filepath.Join(agentPath, "agent.yaml"), []byte(configContent), 0644)
}
O YAML gerado contém tudo que o agente precisa saber sobre si mesmo: qual domínio ele cuida, quantos arquivos tem, qual a tech stack, e quais comandos ele aceita. Quando o orquestrador carrega um agente, ele lê esse YAML e usa as informações para contextualizar os prompts enviados ao LLM.
Os comandos padrão (analyze, refactor, test, document) são genéricos de propósito. Cada agente pode ter comandos adicionais específicos do seu domínio, mas esses quatro cobrem as operações mais comuns em qualquer módulo de código.
Configuração Central com orchestra.yaml
Além dos agentes individuais, o sistema gera um arquivo central que mapeia toda a distribuição:
app_name: meu_projeto
complexity: complex
tech_stack: [Python, FastAPI, Docker]
total_domains: 5
agents:
auth:
- /projeto/auth/agents
products:
- /projeto/products/agents
orders:
- /projeto/orders/agents
payment:
- /projeto/payment/agents
orchestrator:
- /projeto/orchestra_agents
orchestration:
analyze_all: "Analisar todos os domínios"
refactor_all: "Refatorar aplicação completa"
test_all: "Executar todos os testes"
Esse arquivo serve como ponto de entrada para o orquestrador. Quando o usuário executa orchestra agents, o sistema lê esse YAML e sabe quais agentes existem, onde estão, e quais comandos de orquestração estão disponíveis.
Considerações Finais
O Agent Spread é a ponte entre "ter um agente IA" e "ter um agente IA que realmente conhece seu projeto". A diferença é contexto. Um agente genérico precisa redescobrir a estrutura do projeto a cada interação. Um agente distribuído já sabe onde está, o que cuida, e quais são seus vizinhos.
O que eu quero que você leve deste artigo é que a distribuição de agentes por domínio não é sobre ter mais agentes. É sobre ter agentes com contexto menor e mais relevante. Um agente que conhece 20 arquivos profundamente é mais útil que um agente que conhece 200 arquivos superficialmente. E a detecção automática por convenção de nomenclatura funciona surpreendentemente bem porque a maioria dos projetos segue padrões previsíveis de organização.
A limitação principal é que projetos com estrutura não convencional (monolitos sem separação de pastas, ou projetos com nomenclatura em idiomas que o detector não conhece) não são bem detectados. Para esses casos, a configuração manual do orchestra.yaml é o fallback. Mas na minha experiência, 80% dos projetos que se beneficiariam de multi-agente já seguem alguma convenção de pastas que o detector reconhece.
Links indicativos:
- Domain-Driven Design (Eric Evans): https://www.domainlanguage.com/ddd/
- Bounded Context (Martin Fowler): https://martinfowler.com/bliki/BoundedContext.html
- filepath.Walk (Go stdlib): https://pkg.go.dev/path/filepath#Walk