Sistemas Multi-Agente

Crie aplicaΓ§Γ΅es sofisticadas compondo agentes especializados em equipes.

VisΓ£o Geral da Hierarquia de Agentes

Rendering architecture…

O Que VocΓͺ IrΓ‘ Construir

Neste guia, vocΓͺ criarΓ‘ um Sistema de Atendimento ao Cliente onde um coordenador encaminha consultas para especialistas:

                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       User Query       β”‚                     β”‚
      ────────────────▢ β”‚    COORDINATOR      β”‚
                        β”‚  "Route to expert"  β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                   β”‚                               β”‚
                   β–Ό                               β–Ό
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚  BILLING AGENT   β”‚            β”‚  SUPPORT AGENT   β”‚
        β”‚                  β”‚            β”‚                  β”‚
        β”‚  πŸ’° Payments     β”‚            β”‚  πŸ”§ Tech Issues  β”‚
        β”‚  πŸ“„ Invoices     β”‚            β”‚  πŸ› Bug Reports  β”‚
        β”‚  πŸ’³ Subscriptionsβ”‚            β”‚  ❓ How-To       β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Conceitos Chave:

  • Coordinator - Recebe todas as solicitaΓ§Γ΅es, decide quem as processa
  • Specialists - Agentes focados que se destacam em domΓ­nios especΓ­ficos
  • Transfer - TransiΓ§Γ£o suave do coordinator para o specialist

InΓ­cio RΓ‘pido

1. Crie Seu Projeto

cargo new multi_agent_demo
cd multi_agent_demo

Adicione dependΓͺncias a Cargo.toml:

[dependencies]
adk-rust = "2.0.0"
tokio = { version = "1", features = ["full"] }
dotenvy = "0.15"

Crie .env com sua chave de API:

echo 'GOOGLE_API_KEY=your-api-key' > .env

2. Exemplo de Atendimento ao Cliente

Aqui estΓ‘ um exemplo completo e funcional:

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.5-flash")?);

    // Specialist: Billing Agent
    let billing_agent = LlmAgentBuilder::new("billing_agent")
        .description("Handles billing questions: payments, invoices, subscriptions, refunds")
        .instruction("You are a billing specialist. Help customers with:\n\
                     - Invoice questions and payment history\n\
                     - Subscription plans and upgrades\n\
                     - Refund requests\n\
                     - Payment method updates\n\
                     Be professional and provide clear information about billing matters.")
        .model(model.clone())
        .build()?;

    // Specialist: Technical Support Agent
    let support_agent = LlmAgentBuilder::new("support_agent")
        .description("Handles technical support: bugs, errors, troubleshooting, how-to questions")
        .instruction("You are a technical support specialist. Help customers with:\n\
                     - Troubleshooting errors and bugs\n\
                     - How-to questions about using the product\n\
                     - Configuration and setup issues\n\
                     - Performance problems\n\
                     Be patient and provide step-by-step guidance.")
        .model(model.clone())
        .build()?;

    // Coordinator: Routes to appropriate specialist
    let coordinator = LlmAgentBuilder::new("coordinator")
        .description("Main customer service coordinator")
        .instruction("You are a customer service coordinator. Analyze each customer request:\n\n\
                     - For BILLING questions (payments, invoices, subscriptions, refunds):\n\
                       Transfer to billing_agent\n\n\
                     - For TECHNICAL questions (errors, bugs, how-to, troubleshooting):\n\
                       Transfer to support_agent\n\n\
                     - For GENERAL greetings or unclear requests:\n\
                       Respond yourself and ask clarifying questions\n\n\
                     When transferring, briefly acknowledge the customer and explain the handoff.")
        .model(model.clone())
        .sub_agent(Arc::new(billing_agent))
        .sub_agent(Arc::new(support_agent))
        .build()?;

    println!("🏒 Customer Service Center");
    println!("   Coordinator β†’ Billing Agent | Support Agent");
    println!();

    Launcher::new(Arc::new(coordinator)).run().await?;
    Ok(())
}

Exemplo de InteraΓ§Γ£o:

You: I have a question about my last invoice

[Agent: coordinator]
Assistant: I'll connect you with our billing specialist to help with your invoice question.

[Agent: billing_agent]
Assistant: Hello! I can help you with your invoice. What specific question do you have about your last invoice?

You: Why was I charged twice?

[Agent: billing_agent]
Assistant: I understand your concern about the duplicate charge. Let me help you investigate this...

Como a TransferΓͺncia Multi-Agente Funciona

A VisΓ£o Geral

Quando vocΓͺ adiciona sub-agentes a um agente pai, o LLM ganha a capacidade de delegar tarefas:

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    User Message    β”‚                     β”‚
   ─────────────────▢    COORDINATOR      β”‚
                    β”‚                     β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚
           "This is a billing question..."
                               β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                                 β”‚
              β–Ό                                 β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  billing_agent   β”‚              β”‚  support_agent   β”‚
   β”‚  πŸ’° Payments     β”‚              β”‚  πŸ”§ Tech Issues  β”‚
   β”‚  πŸ“„ Invoices     β”‚              β”‚  πŸ› Bug Reports  β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Fluxo de TransferΓͺncia Passo a Passo

Aqui estΓ‘ exatamente o que acontece quando um usuΓ‘rio faz uma pergunta sobre faturamento:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STEP 1: User sends message                                           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                      β”‚
β”‚   User: "Why was I charged twice on my invoice?"                     β”‚
β”‚                                                                      β”‚
β”‚                              ↓                                       β”‚
β”‚                                                                      β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                          β”‚
β”‚   β”‚         COORDINATOR AGENT            β”‚                          β”‚
β”‚   β”‚  Receives message first              β”‚                          β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                          β”‚
β”‚                                                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STEP 2: LLM analyzes and decides to transfer                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                      β”‚
β”‚   🧠 LLM thinks: "This is about an invoice charge..."                β”‚
β”‚                  "Invoice = billing topic..."                        β”‚
β”‚                  "I should transfer to billing_agent"                β”‚
β”‚                                                                      β”‚
β”‚   πŸ“ž LLM calls: transfer_to_agent(agent_name="billing_agent")        β”‚
β”‚                                                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STEP 3: Runner detects transfer and invokes target                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                      β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”     transfer event      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚   β”‚ Runner  β”‚ ─────────────────────▢  β”‚  billing_agent  β”‚           β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   (same user message)   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
β”‚                                                                      β”‚
β”‚   β€’ Runner finds "billing_agent" in agent tree                       β”‚
β”‚   β€’ Creates new context with SAME user message                       β”‚
β”‚   β€’ Invokes billing_agent immediately                                β”‚
β”‚                                                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STEP 4: Target agent responds                                        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                      β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                       β”‚
β”‚   β”‚           billing_agent responds        β”‚                       β”‚
β”‚   β”‚                                         β”‚                       β”‚
β”‚   β”‚  "I can help with your duplicate        β”‚                       β”‚
β”‚   β”‚   charge. Let me investigate..."        β”‚                       β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                       β”‚
β”‚                                                                      β”‚
β”‚   βœ… User sees seamless response - no interruption!                  β”‚
β”‚                                                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

O Que Faz Funcionar

ComponenteFunΓ§Γ£o
.sub_agent()Registra especialistas sob o pai
transfer_to_agent toolAuto-injetado quando sub-agentes existem
DescriΓ§Γ΅es do AgenteAjuda o LLM a decidir qual agente lida com o quΓͺ
RunnerDetecta eventos de transferΓͺncia e invoca o agente de destino
SessΓ£o compartilhadaEstado e histΓ³rico preservados entre transferΓͺncias

Antes vs Depois de Adicionar Sub-Agentes

Sem sub-agentes - Um agente faz tudo:

User ──▢ coordinator ──▢ Response (handles billing AND support)

Com sub-agentes - Especialistas lidam com seu domΓ­nio:

User ──▢ coordinator ──▢ billing_agent ──▢ Response (billing expert)
                    ──▢ support_agent ──▢ Response (tech expert)

Sistemas Multi-Agente HierΓ‘rquicos

Para cenΓ‘rios complexos, vocΓͺ pode criar hierarquias multi-nΓ­vel. Cada agente pode ter seus prΓ³prios sub-agentes, formando uma Γ‘rvore:

Visual: Equipe de ConteΓΊdo de 3 NΓ­veis

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  PROJECT MANAGER    β”‚  ← Level 1: Top-level coordinator
                    β”‚  "Manage projects"  β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚
                               β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  CONTENT CREATOR    β”‚  ← Level 2: Mid-level coordinator  
                    β”‚  "Coordinate R&W"   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                                 β”‚
              β–Ό                                 β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚   RESEARCHER     β”‚              β”‚     WRITER       β”‚  ← Level 3: Specialists
   β”‚                  β”‚              β”‚                  β”‚
   β”‚  πŸ“š Gather facts β”‚              β”‚  ✍️ Write content β”‚
   β”‚  πŸ” Analyze data β”‚              β”‚  πŸ“ Polish text  β”‚
   β”‚  πŸ“Š Find sources β”‚              β”‚  🎨 Style & tone β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Como as SolicitaΓ§Γ΅es Descendem

User: "Create a blog post about electric vehicles"
                        β”‚
                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  PROJECT MANAGER: "This is a content task"                  β”‚
β”‚  β†’ transfers to content_creator                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CONTENT CREATOR: "Need research first, then writing"       β”‚
β”‚  β†’ transfers to researcher                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  RESEARCHER: "Here's what I found about EVs..."             β”‚
β”‚  β†’ provides research summary                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

CΓ³digo de Exemplo Completo

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.5-flash")?);

    // Level 3: Leaf specialists
    let researcher = LlmAgentBuilder::new("researcher")
        .description("Researches topics and gathers comprehensive information")
        .instruction("You are a research specialist. When asked to research a topic:\n\
                     - Gather key facts and data\n\
                     - Identify main themes and subtopics\n\
                     - Note important sources or references\n\
                     Provide thorough, well-organized research summaries.")
        .model(model.clone())
        .build()?;

    let writer = LlmAgentBuilder::new("writer")
        .description("Writes polished content based on research")
        .instruction("You are a content writer. When asked to write:\n\
                     - Create engaging, clear content\n\
                     - Use appropriate tone for the audience\n\
                     - Structure content logically\n\
                     - Polish for grammar and style\n\
                     Produce professional, publication-ready content.")
        .model(model.clone())
        .build()?;

    // Level 2: Content coordinator
    let content_creator = LlmAgentBuilder::new("content_creator")
        .description("Coordinates content creation by delegating research and writing")
        .instruction("You are a content creation lead. For content requests:\n\n\
                     - If RESEARCH is needed: Transfer to researcher\n\
                     - If WRITING is needed: Transfer to writer\n\
                     - For PLANNING or overview: Handle yourself\n\n\
                     Coordinate between research and writing phases.")
        .model(model.clone())
        .sub_agent(Arc::new(researcher))
        .sub_agent(Arc::new(writer))
        .build()?;

    // Level 1: Top-level manager
    let project_manager = LlmAgentBuilder::new("project_manager")
        .description("Manages projects and coordinates with content team")
        .instruction("You are a project manager. For incoming requests:\n\n\
                     - For CONTENT creation tasks: Transfer to content_creator\n\
                     - For PROJECT STATUS or general questions: Handle yourself\n\n\
                     Keep track of overall project goals and deadlines.")
        .model(model.clone())
        .sub_agent(Arc::new(content_creator))
        .build()?;

    println!("πŸ“Š Hierarchical Multi-Agent System");
    println!();
    println!("   project_manager");
    println!("       └── content_creator");
    println!("               β”œβ”€β”€ researcher");
    println!("               └── writer");
    println!();

    Launcher::new(Arc::new(project_manager)).run().await?;
    Ok(())
}

Hierarquia de Agentes:

project_manager
└── content_creator
    β”œβ”€β”€ researcher
    └── writer

Exemplos de prompts:

  • "Crie uma postagem de blog sobre IA na saΓΊde" β†’ PM β†’ Content Creator β†’ Writer
  • "Pesquise veΓ­culos elΓ©tricos" β†’ PM β†’ Content Creator β†’ Researcher

ConfiguraΓ§Γ£o de Sub-Agentes

Adicione sub-agentes a qualquer LlmAgent usando o mΓ©todo construtor sub_agent():

let parent = LlmAgentBuilder::new("parent")
    .description("Coordinates specialized tasks")
    .instruction("Route requests to appropriate specialists.")
    .model(model.clone())
    .sub_agent(Arc::new(specialist_a))
    .sub_agent(Arc::new(specialist_b))
    .build()?;

Pontos Chave:

  • Cada Agent pode ter mΓΊltiplos sub-agents
  • Sub-agents podem ter seus prΓ³prios sub-agents (hierarquias multi-nΓ­vel)
  • Nomes de Agent devem ser ΓΊnicos dentro da hierarquia
  • DescriΓ§Γ΅es ajudam o LLM a decidir para qual Agent transferir

Escrevendo InstruΓ§Γ΅es de TransferΓͺncia Eficazes

InstruΓ§Γ΅es do Agent Pai

let coordinator = LlmAgentBuilder::new("coordinator")
    .description("Main customer service coordinator")
    .instruction("You are a customer service coordinator. Analyze each request:\n\n\
                 - For BILLING questions (payments, invoices, subscriptions):\n\
                   Transfer to billing_agent\n\n\
                 - For TECHNICAL questions (errors, bugs, troubleshooting):\n\
                   Transfer to support_agent\n\n\
                 - For GENERAL greetings or unclear requests:\n\
                   Respond yourself and ask clarifying questions")
    .model(model.clone())
    .sub_agent(Arc::new(billing_agent))
    .sub_agent(Arc::new(support_agent))
    .build()?;

DescriΓ§Γ΅es dos Sub-Agents

let billing_agent = LlmAgentBuilder::new("billing_agent")
    .description("Handles billing questions: payments, invoices, subscriptions, refunds")
    .instruction("You are a billing specialist. Help with payment and subscription issues.")
    .model(model.clone())
    .build()?;

let support_agent = LlmAgentBuilder::new("support_agent")
    .description("Handles technical support: bugs, errors, troubleshooting, how-to questions")
    .instruction("You are a technical support specialist. Provide step-by-step guidance.")
    .model(model.clone())
    .build()?;

Melhores PrΓ‘ticas:

  • Use nomes de Agent descritivos que indiquem claramente seu propΓ³sito
  • Escreva descriΓ§Γ΅es detalhadas - o LLM as usa para decidir as transferΓͺncias
  • Inclua palavras-chave especΓ­ficas nas descriΓ§Γ΅es que correspondam a provΓ‘veis solicitaΓ§Γ΅es do usuΓ‘rio
  • ForneΓ§a regras de delegaΓ§Γ£o claras nas instruΓ§Γ΅es do Agent pai
  • Use terminologia consistente nas descriΓ§Γ΅es dos Agent

Testando Seu Sistema Multi-Agent

Executando Exemplos

cargo run --manifest-path examples/tier_examples/enterprise/Cargo.toml --bin 14-enterprise-multi-agent

Exemplos de Prompts de Teste

Atendimento ao Cliente:

  • "Tenho uma pergunta sobre minha ΓΊltima fatura" β†’ Deve ser encaminhado para billing_agent
  • "O aplicativo continua travando" β†’ Deve ser encaminhado para support_agent
  • "Como faΓ§o para atualizar meu plano?" β†’ Deve ser encaminhado para billing_agent
  • "OlΓ‘, preciso de ajuda" β†’ Deve permanecer com coordinator para esclarecimento

HierΓ‘rquico:

  • "Criar uma postagem de blog sobre IA na saΓΊde" β†’ PM β†’ Criador de ConteΓΊdo β†’ Redator
  • "Pesquisar a histΓ³ria dos veΓ­culos elΓ©tricos" β†’ PM β†’ Criador de ConteΓΊdo β†’ Pesquisador
  • "Qual Γ© o status dos nossos projetos atuais?" β†’ Deve permanecer com project_manager

Depurando Problemas de TransferΓͺncia

Se as transferΓͺncias nΓ£o estiverem funcionando como esperado:

  1. Verificar nomes de agents - Devem corresponder exatamente nas chamadas de transferΓͺncia
  2. Revisar descriΓ§Γ΅es - TornΓ‘-las mais especΓ­ficas e ricas em palavras-chave
  3. Esclarecer instruΓ§Γ΅es - Ser explΓ­cito sobre quando transferir
  4. Testar casos de borda - Tentar requisiΓ§Γ΅es ambΓ­guas para ver o comportamento de roteamento
  5. Procurar indicadores de transferΓͺncia - [Agent: name] mostra qual agent estΓ‘ respondendo

InstruΓ§Γ£o Global

Uso BΓ‘sico

let agent = LlmAgentBuilder::new("assistant")
    .description("A helpful assistant")
    .global_instruction(
        "You are a professional assistant for Acme Corp. \
         Always maintain a friendly but professional tone. \
         Our company values are: customer-first, innovation, and integrity."
    )
    .instruction("Help users with their questions and tasks.")
    .model(model.clone())
    .build()?;

InstruΓ§Γ£o Global vs. Agent InstruΓ§Γ£o

  • InstruΓ§Γ£o Global: Aplicada a todos os agents na hierarquia, define a personalidade/contexto geral
  • Agent InstruΓ§Γ£o: EspecΓ­fica para cada agent, define seu papel e comportamento particulares

Ambas as instruΓ§Γ΅es sΓ£o incluΓ­das no histΓ³rico da conversa, com a instruΓ§Γ£o global aparecendo primeiro.

InstruΓ§Γ΅es Globais DinΓ’micas

Para cenΓ‘rios mais avanΓ§ados, vocΓͺ pode usar um provedor de instruΓ§Γ£o global que calcula a instruΓ§Γ£o dinamicamente:

use adk_core::GlobalInstructionProvider;

let provider: GlobalInstructionProvider = Arc::new(|ctx| {
    Box::pin(async move {
        // Access context information
        let user_id = ctx.user_id();
        
        // Compute dynamic instruction
        let instruction = format!(
            "You are assisting user {}. Tailor your responses to their preferences.",
            user_id
        );
        
        Ok(instruction)
    })
});

let agent = LlmAgentBuilder::new("assistant")
    .description("A personalized assistant")
    .global_instruction_provider(provider)
    .model(model.clone())
    .build()?;

InjeΓ§Γ£o de VariΓ‘veis de Estado

Tanto as instruΓ§Γ΅es globais quanto as de agente suportam a injeΓ§Γ£o de variΓ‘veis de estado usando a sintaxe {variable}:

// Set state in a previous agent or tool
// state["company_name"] = "Acme Corp"
// state["user_role"] = "manager"

let agent = LlmAgentBuilder::new("assistant")
    .global_instruction(
        "You are an assistant for {company_name}. \
         The user is a {user_role}."
    )
    .instruction("Help with {user_role}-level tasks.")
    .model(model.clone())
    .build()?;

O framework injeta automaticamente valores do estado da sessΓ£o nos templates de instruΓ§Γ£o.

PadrΓ΅es Comuns de Multi-Agentes

PadrΓ£o Coordenador/Despachante

Um agente central roteia requisiΓ§Γ΅es para sub-agentes especializados:

let billing = LlmAgentBuilder::new("billing")
    .description("Handles billing and payment questions")
    .model(model.clone())
    .build()?;

let support = LlmAgentBuilder::new("support")
    .description("Provides technical support")
    .model(model.clone())
    .build()?;

let coordinator = LlmAgentBuilder::new("coordinator")
    .instruction("Route requests to billing or support agents as appropriate.")
    .sub_agent(Arc::new(billing))
    .sub_agent(Arc::new(support))
    .model(model.clone())
    .build()?;

Exemplo de Conversa:

User: I have a question about my last invoice

[Agent: coordinator]
Assistant: I'll connect you with our billing specialist.
πŸ”„ [Transfer requested to: billing]

[Agent: billing]
Assistant: Hello! I can help you with your invoice. 
What specific question do you have?

User: Why was I charged twice?

[Agent: billing]
Assistant: Let me investigate that duplicate charge for you...

Pontos Chave:

  • O coordenador analisa a requisiΓ§Γ£o e transfere para o agente de faturamento
  • O agente de faturamento responde imediatamente na mesma rodada
  • Mensagens subsequentes continuam com o agente de faturamento
  • Indicadores de transferΓͺncia (πŸ”„) mostram quando as transferΓͺncias ocorrem

DecomposiΓ§Γ£o HierΓ‘rquica de Tarefas

Hierarquias multi-nΓ­vel para decompor tarefas complexas:

// Low-level specialists
let researcher = LlmAgentBuilder::new("researcher")
    .description("Researches topics and gathers information")
    .model(model.clone())
    .build()?;

let writer = LlmAgentBuilder::new("writer")
    .description("Writes content based on research")
    .model(model.clone())
    .build()?;

// Mid-level coordinator
let content_creator = LlmAgentBuilder::new("content_creator")
    .description("Creates content by coordinating research and writing")
    .sub_agent(Arc::new(researcher))
    .sub_agent(Arc::new(writer))
    .model(model.clone())
    .build()?;

// Top-level manager
let project_manager = LlmAgentBuilder::new("project_manager")
    .description("Manages content creation projects")
    .sub_agent(Arc::new(content_creator))
    .model(model.clone())
    .build()?;

Combinando com Agentes de Fluxo de Trabalho

Sistemas multiagente funcionam bem com agentes de fluxo de trabalho (Sequential, Parallel, Loop):

use adk_agent::workflow::{SequentialAgent, ParallelAgent};

// Create specialized agents
let validator = LlmAgentBuilder::new("validator")
    .instruction("Validate the input data.")
    .output_key("validation_result")
    .model(model.clone())
    .build()?;

let processor = LlmAgentBuilder::new("processor")
    .instruction("Process data if {validation_result} is valid.")
    .output_key("processed_data")
    .model(model.clone())
    .build()?;

// Combine in a sequential workflow
let pipeline = SequentialAgent::new(
    "validation_pipeline",
    vec![Arc::new(validator), Arc::new(processor)]
);

// Use the pipeline as a sub-agent
let coordinator = LlmAgentBuilder::new("coordinator")
    .description("Coordinates data processing")
    .sub_agent(Arc::new(pipeline))
    .model(model.clone())
    .build()?;

ComunicaΓ§Γ£o Entre Agentes

Agentes em uma hierarquia se comunicam atravΓ©s de um estado de sessΓ£o compartilhado:

// Agent A saves data to state
let agent_a = LlmAgentBuilder::new("agent_a")
    .instruction("Analyze the topic and save key points.")
    .output_key("key_points")  // Automatically saves output to state
    .model(model.clone())
    .build()?;

// Agent B reads data from state
let agent_b = LlmAgentBuilder::new("agent_b")
    .instruction("Expand on the key points: {key_points}")
    .model(model.clone())
    .build()?;

A configuraΓ§Γ£o output_key salva automaticamente a resposta final de um agent no session state, tornando-a disponΓ­vel para agentes subsequentes.

Encaminhamento de Estado e Artefatos do AgentTool

Ao usar AgentTool para encapsular agents como tools, as mudanΓ§as de estado e os artefatos dos sub-agents sΓ£o automaticamente encaminhados para o contexto pai:

use adk_tool::AgentTool;

// Create a sub-agent that modifies state
let data_processor = LlmAgentBuilder::new("data_processor")
    .instruction("Process the data and save results.")
    .output_key("processed_data")
    .model(model.clone())
    .build()?;

// Wrap as a tool - state_delta and artifact_delta are forwarded
let processor_tool = AgentTool::new(Arc::new(data_processor));

// Parent agent can use the tool and see state changes
let coordinator = LlmAgentBuilder::new("coordinator")
    .instruction("Use the data_processor tool, then access {processed_data}.")
    .model(model.clone())
    .tool(Arc::new(processor_tool))
    .build()?;

O AgentTool executa sub-agents em modo nΓ£o-streaming (StreamingMode::None) internamente, entΓ£o o sub-agent acumula sua resposta completa antes de retornΓ‘-la ao pai. Isso evita problemas onde chunks de streaming parciais poderiam produzir resultados vazios.

Isso permite um fluxo de dados contΓ­nuo entre agentes pai e filho ao usar o padrΓ£o AgentTool.

Executando Sistemas Multi-Agente

Usando o Launcher

O Launcher fornece uma maneira fΓ‘cil de executar e testar sistemas multi-agente:

use adk_rust::Launcher;

let coordinator = /* your multi-agent setup */;

Launcher::new(Arc::new(coordinator))
    .run()
    .await?;

Modos de ExecuΓ§Γ£o:

# Interactive console mode
cargo run --manifest-path examples/tier_examples/enterprise/Cargo.toml --bin 14-enterprise-multi-agent

# Use a generated API project when you need HTTP serving
cargo adk new multi_agent_api --template api

Recursos:

  • Indicadores de Agente: Mostra qual agente estΓ‘ respondendo [Agent: coordinator]
  • VisualizaΓ§Γ£o de TransferΓͺncia: Exibe eventos de transferΓͺncia πŸ”„ [Transfer requested to: billing_agent]
  • TransferΓͺncias ContΓ­nuas: O agente de destino responde imediatamente apΓ³s a transferΓͺncia
  • HistΓ³rico de Conversa: MantΓ©m o contexto entre as transferΓͺncias de agente

Testando TransferΓͺncias

Para verificar se o seu sistema multi-agente funciona corretamente:

  1. Verifique se os nomes dos agentes aparecem entre colchetes quando eles respondem
  2. Procure por indicadores de transferΓͺncia (πŸ”„) quando os agentes fazem a transferΓͺncia
  3. Verifique as respostas imediatas dos agentes de destino sem re-solicitar
  4. Teste diferentes tipos de solicitaΓ§Γ£o para garantir o roteamento adequado
  5. Verifique casos extremos como a transferΓͺncia para agentes nΓ£o existentes

Depurando Problemas de TransferΓͺncia

Se as transferΓͺncias nΓ£o estiverem funcionando:

  • Verifique se os sub-agentes foram adicionados via .sub_agent()
  • Verifique as descriΓ§Γ΅es dos agentes - o LLM as usa para decidir as transferΓͺncias
  • Revise as instruΓ§Γ΅es - o pai deve mencionar quando transferir
  • Verifique os nomes dos agentes - devem corresponder exatamente nas chamadas de transferΓͺncia
  • Habilite o registro (logging) para ver as aΓ§Γ΅es de transferΓͺncia no fluxo de eventos

Melhores PrΓ‘ticas

  1. DescriΓ§Γ΅es Claras: Escreva nomes e descriΓ§Γ΅es de agentes descritivos para ajudar o LLM a tomar boas decisΓ΅es de transferΓͺncia
  2. InstruΓ§Γ΅es EspecΓ­ficas: DΓͺ a cada agente instruΓ§Γ΅es claras e focadas para sua funΓ§Γ£o
  3. Use InstruΓ§Γ£o Global: Defina personalidade e contexto consistentes em todos os agentes
  4. Gerenciamento de Estado: Use output_key e variΓ‘veis de estado para comunicaΓ§Γ£o entre agentes
  5. Limite a Profundidade da Hierarquia: Mantenha as hierarquias rasas (2-3 nΓ­veis) para melhor manutenibilidade
  6. Teste a LΓ³gica de TransferΓͺncia: Verifique se os agentes transferem para os sub-agentes corretos para diferentes solicitaΓ§Γ΅es

Anterior: ← Workflow Agents | PrΓ³ximo: Graph Agents β†’

Sistemas Multi-Agente - DocumentaΓ§Γ£o ADK-Rust | ADK-Rust