Skip to content

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_agent e payment_agent são condicionais — habilitados via feature flags ENABLE_BOOKING e ENABLE_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 →