2. Arquitetura e Fluxo de Dados¶
Visão macro: do usuário à resposta¶
Este diagrama mostra como uma mensagem flui do início ao fim, passando pelo orquestrador multi-agent:
flowchart TB
subgraph Usuários
U1[👤 Slack]
U2[👤 WhatsApp]
U3[👤 Telegram]
U4[👤 WebChat]
U5[👤 SSE Client]
end
subgraph "FastAPI (unified_bot.py)"
R[Routes / Webhooks]
end
subgraph "Messaging Layer"
AF[AdapterFactory]
SA[SlackAdapter]
WA[WhatsApp Adapters]
TA[TelegramAdapter]
WC[WebChatAdapter]
SSE[SSEAdapter]
CP[ConversationProcessor]
end
subgraph "ADK Multi-Agent"
CB1[Before Callbacks]
AG[Root Agent<br/>Orquestrador Slim]
SUB[Sub-Agentes<br/>Especializados]
CB2[After Callbacks]
end
subgraph "Backends"
REDIS[(Redis)]
CSQL[(Cloud SQL / MySQL)]
BQ[(BigQuery)]
API[API iFriend]
end
U1 & U2 & U3 & U4 & U5 -->|webhook / HTTP| R
R --> AF
AF -->|resolve| SA & WA & TA & WC & SSE
SA & WA & TA & WC & SSE -->|IncomingMessage| CP
CP -->|1. JWT + Session| REDIS
CP -->|2. run_async| CB1
CB1 -->|injeta contexto| AG
AG -->|transfer_to_agent| SUB
SUB <-->|tools do domínio| API
SUB <-->|busca| BQ
AG --> CB2
CB2 -->|salva memória| CSQL
CP -->|3. resposta| SA & WA & TA & WC & SSE
SA & WA & TA & WC & SSE -->|mensagem| U1 & U2 & U3 & U4 & U5
Arquitetura Multi-Agent (Coordinator/Dispatcher)¶
O agente usa a arquitetura Coordinator/Dispatcher do Google ADK: um orquestrador slim (root_agent) delega para sub-agentes especializados conforme a intenção do usuário.
flowchart TB
subgraph "Root Agent (Orquestrador Slim)"
direction TB
ROOT[root_agent<br/>gemini-2.5-flash]
ROOT_TOOLS["Tools:<br/>PreloadMemoryTool<br/>AgentTool research_agent<br/>faq_tool"]
end
subgraph "Sub-Agentes — LLM-driven transfer (multi-turn)"
direction LR
DISC[🔍 discovery_agent<br/>6 tools]
QUOTE[💰 quote_agent<br/>4 tools]
BOOK[📋 booking_agent<br/>8 tools]
PAY[💳 payment_agent<br/>3 tools]
UTIL[📧 utils_agent<br/>2 tools]
SUPP[🤝 support_agent<br/>0 tools]
end
subgraph "AgentTool — call-and-return (pontual)"
direction LR
RES[🌐 research_agent<br/>google_search]
FAQ[❓ faq_agent<br/>LLM knowledge]
end
ROOT -->|transfer_to_agent| DISC & QUOTE & BOOK & PAY & UTIL & SUPP
ROOT -->|AgentTool call| RES & FAQ
DISC & QUOTE & BOOK & PAY & UTIL & SUPP -->|transfer_to_agent| ROOT
style BOOK stroke-dasharray: 5 5
style PAY stroke-dasharray: 5 5
Linhas tracejadas:
booking_agentepayment_agentsão condicionais — habilitados via feature flagsENABLE_BOOKINGeENABLE_PAYMENT.
Padrões de Delegação¶
| Padrão | Mecanismo ADK | Quando usar | Agentes |
|---|---|---|---|
| LLM-driven transfer | sub_agents + transfer_to_agent |
Fluxos multi-turn (o sub-agente responde diretamente ao usuário) | discovery, quote, booking, payment, utils, support |
| Call-and-return | AgentTool |
Invocação pontual (resultado volta ao orquestrador) | research, faq |
Distribuição de Tools (24 total)¶
discovery_agent ████████████ 6 tools (busca, detalhes, disponibilidade)
booking_agent ████████████████ 8 tools (usuário, agência, reserva)
quote_agent ████████ 4 tools (variações, preço, câmbio)
payment_agent ██████ 3 tools (parcelas, token, pagamento)
utils_agent ████ 2 tools (email, CSV)
support_agent ─ 0 tools (LLM gera link WhatsApp)
research_agent ██ 1 tool (google_search)
faq_agent ─ 0 tools (LLM knowledge inline)
root_agent ███ 3 tools (PreloadMemoryTool + 2 AgentTools)
Regra: Nenhuma tool de domínio aparece em mais de um agente. Não há sobreposição.
Fluxo detalhado passo-a-passo¶
sequenceDiagram
actor User as Usuário
participant WH as Webhook (FastAPI)
participant AF as AdapterFactory
participant AD as Adapter
participant CP as ConversationProcessor
participant SS as SessionService
participant RN as ADK Runner
participant CB as Callbacks
participant ROOT as Root Agent (Orquestrador)
participant SUB as Sub-Agente Especializado
participant TL as Tools do Sub-Agente
participant API as API iFriend
participant MM as MemoryService
User->>WH: Envia mensagem (texto)
WH->>AF: Identifica plataforma pelo path
AF->>AD: Retorna adapter correto
AD->>AD: parse_webhook_request()
AD->>CP: IncomingMessage(user_id, text, jwt_token...)
CP->>CP: Decodifica JWT (se presente)
CP->>SS: get_session() ou create_session()
SS-->>CP: Session (com state)
CP->>RN: runner.run_async(session, message)
Note over CB,ROOT: before_agent_callback
RN->>CB: Executa before callbacks
CB->>CB: Injeta current_date no state
CB->>CB: Injeta jwt_context no state
RN->>ROOT: System prompt + histórico + mensagem
Note over ROOT: PreloadMemoryTool carrega memórias automaticamente
ROOT->>ROOT: Analisa intenção do usuário
ROOT->>SUB: transfer_to_agent (ex: discovery_agent)
loop Sub-agente responde diretamente ao usuário
SUB->>TL: Chama tool do seu domínio (ex: busca_produtos)
TL->>API: HTTP request com auth
API-->>TL: Resposta JSON
TL-->>SUB: Resultado da tool
SUB-->>User: Resposta parcial (via streaming)
end
SUB->>ROOT: transfer_to_agent (volta ao orquestrador)
Note over CB,MM: after_agent_callback
RN->>CB: Executa after callbacks
CB->>MM: Salva sessão na memória (resumo LLM)
RN-->>CP: Response events
CP->>AD: send_message(OutgoingMessage)
AD->>User: Envia resposta formatada
Camadas da arquitetura¶
block-beta
columns 1
block:presentation["🖥️ CAMADA DE APRESENTAÇÃO"]
columns 5
Slack WhatsApp Telegram WebChat SSE
end
block:messaging["📨 CAMADA DE MENSAGERIA"]
columns 3
Adapters["Adapters\n(parse + send)"] Factory["AdapterFactory\n(resolve)"] Processor["ConversationProcessor\n(orquestra)"]
end
block:agent["🤖 CAMADA MULTI-AGENT"]
columns 4
Callbacks["Callbacks\n(before/after)"] Orchestrator["Root Agent\n(Orquestrador)"] SubAgents["6 Sub-Agentes\n(Especializados)"] AgentTools["2 AgentTools\n(research, faq)"]
end
block:data["💾 CAMADA DE DADOS"]
columns 4
Redis["Redis\n(sessions)"] CloudSQL["Cloud SQL\n(memory)"] BigQuery["BigQuery\n(produtos)"] APIiFriend["API iFriend\n(booking)"]
end
presentation --> messaging
messaging --> agent
agent --> data
Composição dinâmica (AgentBuilder + Feature Flags)¶
O root_agent é montado dinamicamente pelo AgentBuilder com base em feature flags.
Isso permite habilitar/desabilitar agentes sem alterar código:
flowchart LR
ENV["Env Vars<br/>ENABLE_BOOKING<br/>ENABLE_PAYMENT"] --> FF[FeatureFlags<br/>validate_flags]
FF --> AB[AgentBuilder.build]
AB --> SUB["Sub-agents<br/>(always-on + condicionais)"]
AB --> PROMPT["Prompt dinâmico<br/>build_orchestrator_instruction"]
AB --> TOOLS["Tools fixas<br/>PreloadMemory + AgentTools"]
SUB & PROMPT & TOOLS --> ROOT[root_agent<br/>LlmAgent]
| ENABLE_BOOKING | ENABLE_PAYMENT | Sub-agents | Tools | Modo |
|---|---|---|---|---|
| true | true | 6 | 24 | Completo |
| true | false | 5 | 21 | Reserva sem pagamento online |
| false | false | 4 | 13 | Orçamento puro |
| false | true | — | — | Inválido (FeatureFlagError) |
Estado da sessão (o que o state carrega)¶
O session.state é compartilhado por toda a hierarquia (root + sub-agents):
flowchart TD
S[session.state]
S --> JWT["jwt_context<br/>user_id, email, roles,<br/>partner_code, company_id, token"]
S --> DT["current_date / current_year<br/>current_datetime / current_weekday"]
S --> MM["message_metadata<br/>platform, channel_id, thread_id,<br/>is_whitelabel, whitelabel_baseurl"]
S --> MEM["Memórias carregadas<br/>via PreloadMemoryTool<br/>(FULLTEXT search)"]
S --> HIST["Histórico de mensagens<br/>user ↔ agent (multi-agent)"]
Infraestrutura GCP (deploy)¶
flowchart LR
subgraph "Google Cloud Platform"
CR[Cloud Run<br/>unified_bot.py]
CSQL[(Cloud SQL<br/>MySQL)]
REDIS[(Memorystore<br/>Redis)]
BQ[(BigQuery<br/>Produtos)]
SM[Secret Manager<br/>JWT Keys]
VAI[Vertex AI<br/>Gemini]
end
subgraph "Externos"
SLACK[Slack API]
WA_EVO[Evolution API]
WA_OFF[WhatsApp Business API]
IFAPI[API iFriend]
end
CR <--> CSQL
CR <--> REDIS
CR <--> BQ
CR --> SM
CR <--> VAI
CR <--> SLACK
CR <--> WA_EVO
CR <--> WA_OFF
CR <--> IFAPI
Resumo das interações¶
| De → Para | Protocolo | O que trafega |
|---|---|---|
| Plataformas → FastAPI | HTTP/Webhook | Mensagens do usuário |
| FastAPI → Adapter | Interno | IncomingMessage |
| Adapter → Processor | Interno | Mensagem parseada + JWT + whitelabel metadata |
| Processor → ADK Runner | Interno | Content ADK |
| Runner → Root Agent | Interno ADK | Prompt + histórico |
| Root Agent → Gemini | gRPC/Vertex AI | Prompt slim (~60 linhas) |
| Root Agent → Sub-Agent | transfer_to_agent |
Delegação LLM-driven |
| Sub-Agent → Gemini | gRPC/Vertex AI | Prompt focado (~30-55 linhas) + tools do domínio |
| Sub-Agent Tools → API iFriend | HTTP/REST | Dados de booking/catálogo |
| Sub-Agent Tools → BigQuery | gRPC | Queries SQL + embeddings |
| Processor → Redis | TCP | Session get/set |
| Callbacks → Cloud SQL | TCP | Memory save/load (FULLTEXT search) |
| Adapter → Plataformas | HTTP/API | Resposta formatada |
Anterior: ← Visão Geral · Próximo: O Agente iFriend →