Arquitetura Multi-Agent: Supervisor + Subagentes Especializados¶
Proposta de migração da arquitetura atual (single agent + multiple tools)
para um modelo de Orchestrator/Supervisor com Subagentes Especializados.
1. Diagnóstico da Arquitetura Atual¶
Estrutura atual¶
root_agent (LlmAgent)
├── AgentTool(search_agent) ← único subagente real
├── AgentTool(faq_agent) ← único subagente real
├── busca_produtos ┐
├── tem_variacao │
├── listar_variacoes │
├── listar_guias_experience │ 24 tools diretas
├── detalhes_experience │ no mesmo agente
├── detalhes_guia │
├── disponibilidade_calendario │
├── disponibilidade_horarios │
├── calcular_preco │
├── cotacao_moeda │
├── gerar_csv │
├── enviar_email_sendgrid │
├── buscar_usuario │
├── buscar_agencia │
├── criar_conta_agencia │
├── criar_conta_viajante │
├── validar_dados_reserva │
├── emitir_reserva_guia │
├── emitir_reserva_experience │
├── obter_reserva │
├── verificar_parcelas │
├── gerar_token_cartao │
└── processar_pagamento ┘
O system_prompt_v2.py tem 329 linhas descrevendo uma state machine completa
(RESEARCH → DISCOVERY → SELECTION → QUOTE → IDENTIFICATION → BOOKING → PAYMENT → DONE)
que o único agente precisa gerenciar integralmente a cada chamada ao LLM.
2. Prós e Contras¶
Arquitetura Atual (Single Agent + Multiple Tools)¶
| # | Prós | Contras |
|---|---|---|
| 1 | Simples de depurar: um único agente, um único prompt | Prompt de 329 linhas → alto consumo de tokens a cada turno |
| 2 | Context sharing trivial: todas as tools veem o mesmo tool_context e session state |
LLM precisa "saber tudo" simultaneamente: turismo, reserva, pagamento, FAQ |
| 3 | Sem overhead de delegação entre agentes | 24 tools no mesmo agente aumentam chance de hallucination de nome |
| 4 | Fácil de testar em isolamento com adk run |
State machine complexa dificulta adição de novos domínios sem regredir outros |
| 5 | Menos latência: uma única chamada LLM por turno (sem delegação) | Erro em qualquer tool derruba o fluxo inteiro sem isolamento |
| 6 | Impossível usar modelos diferentes por domínio (ex: modelo mais barato para FAQ) | |
| 7 | Sistema de memória e callbacks acoplado a um único ponto |
Arquitetura Proposta (Orchestrator + Subagentes)¶
| # | Prós | Contras |
|---|---|---|
| 1 | Cada subagente tem prompt enxuto e focado no seu domínio | Maior complexidade: mais arquivos, mais agents para manter |
| 2 | Orquestrador delega → menos tokens por chamada no subagente | Delegação via AgentTool adiciona 1 chamada LLM extra por delegação |
| 3 | Possível usar modelos diferentes por subagente (ex: Flash para busca, Pro para pagamento) | State sharing entre agentes requer atenção: cada AgentTool cria sub-session |
| 4 | Isolamento de falhas: erro no payment_agent não afeta catalog_agent |
Debugging mais complexo: logs espalhados entre múltiplos agentes |
| 5 | Fácil adicionar novos domínios sem tocar nos existentes | Latência potencialmente maior em fluxos que exigem múltiplas delegações |
| 6 | Cada subagente pode ter seus próprios callbacks e configurações | Passagem de contexto (product_id, booking_id) precisa ser feita via session state ou retorno explícito |
| 7 | Alinha com o state machine já definido: 1 estado = 1 subagente | |
| 8 | Permite escalar e versionar subagentes independentemente |
3. Arquitetura Proposta¶
Visão Geral¶
root_agent (Orchestrator)
├── AgentTool(research_agent) ← STATE: RESEARCH
├── AgentTool(catalog_agent) ← STATE: DISCOVERY + SELECTION
├── AgentTool(quote_agent) ← STATE: QUOTE
├── AgentTool(user_agent) ← STATE: IDENTIFICATION
├── AgentTool(booking_agent) ← STATE: BOOKING
├── AgentTool(payment_agent) ← STATE: PAYMENT
├── AgentTool(utility_agent) ← transversal (CSV, email)
└── AgentTool(faq_agent) ← já existe
O orquestrador não tem tools diretas — apenas delega para subagentes.
Seu único prompt descreve quando delegar para quem, não como executar.
4. Mapeamento de Tools por Subagente¶
research_agent¶
Questões sobre turismo, clima, dicas e busca na internet.
| Tool atual | Fonte |
|---|---|
google_search |
já existe em search_agent — renomear/reaproveitamento |
Prompt foco: consultor de viagens + busca web. Nunca reservas ou preços.
catalog_agent¶
Descoberta e detalhamento de produtos (experiences e guias).
| Tool atual | Arquivo |
|---|---|
busca_produtos |
tools/busca_produtos_tool.py |
detalhes_experience |
tools/detalhes_experience_tool.py |
detalhes_guia |
tools/detalhes_guia_tool.py |
listar_guias_experience |
tools/listar_guias_experience_tool.py |
Prompt foco: buscar, filtrar e apresentar produtos. Retorna product_id e detalhes para o orquestrador.
availability_agent (pode fundir com catalog_agent se quiser simplicidade)¶
Disponibilidade de datas e horários.
| Tool atual | Arquivo |
|---|---|
disponibilidade_calendario |
tools/disponibilidade_calendario_tool.py |
disponibilidade_horarios |
tools/disponibilidade_horarios_tool.py |
Prompt foco: dado product_id + mês/data, retorna datas e horários disponíveis.
quote_agent¶
Cálculo de preço, variações e conversão de moeda.
| Tool atual | Arquivo |
|---|---|
tem_variacao |
tools/tem_variacao_tool.py |
listar_variacoes |
tools/listar_variacoes_tool.py |
calcular_preco |
tools/calcular_preco_tool.py |
cotacao_moeda |
tools/cotacao_moeda_tool.py |
Prompt foco: dado product_id + data + pax, retorna preço final em BRL com breakdown.
user_agent¶
Identificação e criação de usuários/agências.
| Tool atual | Arquivo |
|---|---|
buscar_usuario |
tools/booking/buscar_usuario_tool.py |
buscar_agencia |
tools/booking/buscar_agencia_tool.py |
criar_conta_agencia |
tools/booking/criar_conta_agencia_tool.py |
criar_conta_viajante |
tools/booking/criar_conta_viajante_tool.py |
Prompt foco: dado email, retorna customer_id ou cria conta. Output limpo para o booking_agent.
booking_agent¶
Validação e emissão de reservas. (Agente já existe em
agents/booking_agent.py— refatorar)
| Tool atual | Arquivo |
|---|---|
validar_dados_reserva |
tools/booking/validar_dados_reserva_tool.py |
emitir_reserva_guia |
tools/booking/emitir_reserva_guia_tool.py |
emitir_reserva_experience |
tools/booking/emitir_reserva_experience_tool.py |
obter_reserva |
tools/booking/obter_reserva_tool.py |
Prompt foco: dado dados completos de reserva, valida e emite. Retorna booking_id + allowCheckout.
payment_agent¶
Parcelamento, tokenização e processamento de pagamento. (Agente já existe em
agents/payment_agent.py— refatorar)
| Tool atual | Arquivo |
|---|---|
verificar_parcelas |
tools/payment/verificar_parcelas_tool.py |
gerar_token_cartao |
tools/payment/gerar_token_cartao_tool.py |
processar_pagamento |
tools/payment/processar_pagamento_tool.py |
Prompt foco: dado booking_id + dados do cartão, processa pagamento. Nunca armazena dados de cartão.
utility_agent¶
Geração de CSV e envio de email.
| Tool atual | Arquivo |
|---|---|
gerar_csv |
tools/gerar_csv_tool.py |
enviar_email_sendgrid |
tools/enviar_email_sendgrid_tool.py |
Prompt foco: dado dados estruturados, gera arquivo ou envia email. Transversal a qualquer estado.
5. Estrutura de Arquivos Proposta¶
ifriend_agent/
├── agent.py ← root_agent (orchestrator) — prompt enxuto
│
├── prompts/
│ ├── orchestrator_prompt.py ← instrução do orquestrador (~60 linhas)
│ ├── catalog_prompt.py ← focado em busca e detalhes
│ ├── availability_prompt.py ← focado em datas/horários
│ ├── quote_prompt.py ← focado em preços e variações
│ ├── user_prompt.py ← focado em identificação
│ ├── booking_prompt.py ← focado em emissão de reserva
│ ├── payment_prompt.py ← focado em pagamento
│ └── utility_prompt.py ← focado em CSV/email
│
├── agents/
│ ├── research_agent.py ← renomear/refatorar search_agent existente
│ ├── catalog_agent.py ← NOVO (busca + detalhes + guias)
│ ├── availability_agent.py ← NOVO (datas + horários)
│ ├── quote_agent.py ← NOVO (preços + variações + moeda)
│ ├── user_agent.py ← NOVO (identificação + conta)
│ ├── booking_agent.py ← REFATORAR existente
│ ├── payment_agent.py ← REFATORAR existente
│ ├── utility_agent.py ← NOVO (CSV + email)
│ └── faq_agent.py ← manter como está
│
└── tools/ ← permanecem inalteradas
├── busca_produtos_tool.py
├── ...
├── booking/
└── payment/
6. Prompt do Orquestrador (esboço)¶
O orquestrador substitui o system_prompt_v2.py de 329 linhas por ~60:
Você é o iFriend Orchestrator. Sua única função é entender a intenção do usuário
e delegar para o subagente correto.
ESTADO ATUAL: {state} (gerencie via session state)
DELEGAÇÃO:
- Dúvidas sobre destinos, clima, história → research_agent
- Buscar produtos, ver detalhes, disponibilidade → catalog_agent
- Calcular preço, ver variações → quote_agent
- Identificar usuário/agência → user_agent
- Emitir reserva → booking_agent
- Processar pagamento → payment_agent
- Gerar CSV ou enviar email → utility_agent
- Perguntas frequentes → faq_agent
REGRAS:
- Nunca execute tools diretamente
- Repasse o contexto necessário (product_id, booking_id, email) ao delegar
- Apresente o retorno do subagente ao usuário sem reprocessar
- Máximo UMA pergunta por mensagem
7. Ponto Crítico: Passagem de Contexto entre Agentes¶
No ADK, quando o orquestrador chama um AgentTool, o subagente não compartilha
automaticamente o session state do pai. Há três formas de passar contexto:
Opção A — Via argumento explícito na chamada (recomendado para IDs)¶
O orquestrador inclui product_id, customer_id, booking_id nos argumentos
passados ao AgentTool. Cada subagente declara esses parâmetros em seu input schema.
Opção B — Via session.state compartilhado¶
Usar output_key no subagente para escrever resultado no state do pai:
catalog_agent = LlmAgent(
...
output_key="catalog_result" # escreve em session.state['catalog_result']
)
state['catalog_result'] e passa para o próximo subagente.
Opção C — Híbrido (mais robusto)¶
- IDs críticos → argumento explícito
- Resultados intermediários →
output_keyno state - Dados sensíveis (cartão) → nunca no state, sempre argumento direto ao
payment_agent
8. Plano de Migração Sugerido (incremental)¶
A migração pode ser feita sem big bang, estado por estado:
| Fase | O que fazer | Risco |
|---|---|---|
| 0 | Manter arquitetura atual. Separar tools em grupos nos imports do agent.py |
Nenhum |
| 1 | Criar catalog_agent com busca_produtos + detalhes_* → substituir no root via AgentTool |
Baixo |
| 2 | Criar quote_agent com calcular_preco + tem_variacao + listar_variacoes + cotacao_moeda |
Baixo |
| 3 | Refatorar booking_agent existente (já existe, só ajustar tools e prompt) |
Médio |
| 4 | Refatorar payment_agent existente (já existe, só ajustar tools e prompt) |
Médio |
| 5 | Criar user_agent e utility_agent |
Baixo |
| 6 | Substituir system_prompt_v2.py pelo prompt enxuto do orquestrador |
Alto — testar bem |
| 7 | Remover tools diretas do root_agent |
Alto — só após fase 6 validada |
9. Decisão Recomendada¶
Para o estágio atual do projeto, considera-se:
-
Fluxo transacional de reserva e pagamento → subagentes isolados agora
(booking_agentepayment_agentjá existem, refatoração de baixo risco) -
Catalog + Quote → subagentes na fase seguinte
(maior impacto no fluxo principal, testar em staging) -
Orquestrador puro (sem tools diretas) → fase final
(só após todos os subagentes estarem validados individualmente)
O principal ganho a curto prazo não é a separação em si, mas reduzir o prompt do agente principal — quanto menos o LLM precisa saber simultaneamente, menor a chance de hallucination de nome de tool e menor consumo de tokens.