Sistemas Multiagentes

Crie aplicações sofisticadas compondo agentes especializados em equipes.

Visão geral da hierarquia de agentes

Rendering architecture…

O que você criará

Neste guia, você criará um Sistema de Atendimento ao Cliente, no qual um coordenador encaminha as consultas a especialistas:

                        ┌─────────────────────┐
       User Query       │                     │
      ────────────────▶ │    COORDINATOR      │
                        │  "Route to expert"  │
                        └──────────┬──────────┘
                                   │
                   ┌───────────────┴───────────────┐
                   │                               │
                   ▼                               ▼
        ┌──────────────────┐            ┌──────────────────┐
        │  BILLING AGENT   │            │  SUPPORT AGENT   │
        │                  │            │                  │
        │  💰 Payments     │            │  🔧 Tech Issues  │
        │  📄 Invoices     │            │  🐛 Bug Reports  │
        │  💳 Subscriptions│            │  ❓ How-To       │
        └──────────────────┘            └──────────────────┘

Conceitos principais:

  • Coordenador - Recebe todas as solicitações e decide quem as atenderá
  • Especialistas - Agentes focados que se destacam em domínios específicos
  • Transferência - Encaminhamento contínuo do coordenador para um especialista

TeamSpec portátil

Use TeamSpec quando a mesma equipe precisar ser executada de forma idêntica em projetos gerados, no CLI, na visualização do Studio e em implantações Enterprise. A especificação consiste em dados serializáveis; compile associa cada nome declarado a qualquer implementação Agent existente e retorna uma raiz CompiledTeam executável. Ela não adiciona um novo tipo de agente atômico.

use adk_agent::{
    Agent, RelationshipKind, TeamMemberSpec, TeamRelationship, TeamSpec,
};
use std::sync::Arc;

let spec = TeamSpec {
    name: "support_team".into(),
    description: "Customer support routing".into(),
    coordinator: "coordinator".into(),
    members: vec![
        TeamMemberSpec::new("coordinator"),
        TeamMemberSpec::new("billing_agent"),
        TeamMemberSpec::new("research_agent"),
    ],
    relationships: vec![
        TeamRelationship::new(
            "coordinator", "billing_agent", RelationshipKind::Handoff,
        ),
        TeamRelationship::new(
            "coordinator", "research_agent", RelationshipKind::Delegate,
        ),
    ],
    policy: Default::default(),
};

let root = spec.compile(vec![
    Arc::new(coordinator) as Arc<dyn Agent>,
    Arc::new(billing_agent),
    Arc::new(research_agent),
])?;

Para usar o crate diretamente, habilite o recurso team-tools de adk-agent quando a especificação contiver Delegate. Com o crate abrangente, habilite tools (ou a camada standard). As especificações que contêm apenas transferências são compiladas com o conjunto de recursos base adk-agent.

RelaçãoComportamento de controleMecanismo reduzido
HandoffO chamador transfere o controle e não retomatransfer_to_agent do executor
DelegateO chamador invoca um membro, recebe seu resultado e retomaAgentTool

Os alvos são exatos para cada membro. O compilador rejeita membros e arestas duplicados, endpoints ausentes, ciclos, membros inacessíveis, limites inválidos, associações de agentes ausentes e associações extras. As arestas de delegação podem transportar Schemas de entrada/saída JSON, projeção de contexto e histórico, chaves de estado exatas, requisitos de tempo limite e aprovação, comportamento de nova tentativa/fallback e um disjuntor. As arestas de transferência oferecem suporte a nova tentativa/fallback de inicialização com limites; campos exclusivos de delegação são rejeitados em vez de serem ignorados silenciosamente. Os fallbacks devem ser arestas declaradas separadamente; a validação nunca amplia sua autoridade.

A política de toda a equipe limita a profundidade de transferência/delegação, a concorrência, os eventos, as chamadas de modelo e de ferramenta, os tokens, o custo, as contagens de relacionamentos e o tempo total. As regras de término podem interromper com base em uma escalada, em um autor final exato ou em um marcador de texto. Cada evento contém um recibo de execução serializável em __adk_team_execution_v1, incluindo a lista congelada de membros, as arestas causais de delegação/transferência, o uso agregado e o status terminal. Use CompiledTeam::execution_snapshot para inspecioná-lo e restore_execution_snapshot antes de retomar com o mesmo ID de invocação. Uma transferência ativa é retomada no alvo congelado. Uma delegação não resolvida não é reproduzida automaticamente, pois o contrato genérico Agent não pode provar que uma chamada de ferramenta é idempotente; em vez disso, o runtime retorna um erro acionável. Retome essa delegação por meio de seu próprio mecanismo de checkpoint ou falhe/reinicie explicitamente a operação.

Para arquiteturas reutilizáveis, TeamArchitectureTemplate reduz as predefinições de supervisor, roteador e hierárquicas a dados explícitos de TeamSpec. WorkflowArchitectureTemplate compila predefinições sequenciais, paralelas, de fan-out/fan-in e de loop de revisão limitado a partir de agentes de fluxo de trabalho existentes. A resolução baseada em capacidades está disponível por meio de TeamAgentRegistry; a seleção é determinística, pode exigir rótulos de integridade, versão, digest e confiança, e o elenco escolhido é congelado no recibo de execução.

Capacidades do plano de execução

A compilação verifica o AgentCapabilities declarado pelo agente de origem. Uma origem delegada deve consumir ferramentas de execução com escopo da invocação, uma origem de transferência deve emitir transferências, e uma delegação aprovada deve oferecer suporte à confirmação de chamada exata. LlmAgent e CodeActAgent declaram suas capacidades de execução compatíveis; agentes personalizados mantêm padrões conservadores e podem substituir capabilities().

As equipes mantêm o comportamento padrão de ADK: plug-ins do Runner, callbacks de agente/modelo/ferramenta, controles de proteção, cancelamento, identidade da solicitação, memória, artefatos, sessões e persistência de eventos continuam envolvendo os agentes-membro existentes. compile_with_hooks adiciona callbacks assíncronos ordenados de TeamLifecycleHook para os limites da equipe, do membro e do relacionamento exato. Os hooks podem observar sucesso/falha ou negar uma operação pendente sem ampliar seu alvo. O Runner também chama o hook assíncrono govern_transfer da raiz imediatamente antes de uma transferência validada.

Os spans de rastreamento nativos de team.run, team.member.run e team.relationship.execute transportam a identidade da equipe/membro/aresta, o status e a duração do relacionamento por meio do exportador normal de adk-telemetry. As falhas de execução usam códigos estruturados estáveis, como agent.team.policy_denied, agent.team.budget_exceeded e agent.team.resume_unsafe.

Os contratos de delegação distinguem leituras de estado (stateKeys) de gravações (stateWriteKeys). stateMerge: rejectConflicts rejeita uma gravação filha quando o valor pai mudou durante a delegação, e artifactPrefixes limita os nomes de artefatos. AgentTool independente expõe os mesmos controles. Seu padrão continua sendo last-writer-wins por compatibilidade; as relações de Team têm como padrão a rejeição de conflitos.

CompiledTeam::resume_plan descreve a única próxima ação segura após restaurar um recibo: coordenador, destino da transferência, delegado ciente de checkpoint ou delegação insegura com fail-closed. validate_team_replay verifica a integridade causal do recibo, enquanto analyze_execution relata a cobertura da topologia sem provedor, as falhas e a profundidade causal máxima para testes e pipelines de avaliação.

BlackboardSpec abrange o round-robin governado e o chat em grupo orientado por seletor. Ele limita as rodadas e a projeção da transcrição, e as transições do seletor usam listas de permissões exatas. A composição existente de sub_agent continua sendo compatível com versões anteriores, mas é uma árvore em memória, e não uma definição de equipe portátil.


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.1.0"
tokio = { version = "1", features = ["full"] }
dotenvy = "0.15"

Crie .env com sua chave 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-3.7-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(())
}

Interação de exemplo:

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 funciona a transferência entre múltiplos agentes

Visão geral

Quando você adiciona subagentes a um agente pai, o LLM ganha a capacidade de transferir o controle:

                    ┌─────────────────────┐
    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

Veja exatamente o que acontece quando um usuário faz uma pergunta sobre cobrança:

┌──────────────────────────────────────────────────────────────────────┐
│ 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 isso funcionar

ComponenteFunção
.sub_agent()Registra especialistas sob o agente pai
transfer_to_agent toolInjetado automaticamente quando existem subagentes
Descrições dos agentesAjuda LLM a decidir qual agente lida com cada tarefa
ExecutorDetecta eventos de transferência e invoca o agente de destino
Sessão compartilhadaEstado e histórico preservados entre transferências

Antes e depois de adicionar subagentes

Sem subagentes — Um agente faz tudo:

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

Com subagentes — Especialistas cuidam de seus domínios:

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

Sistemas multiagente hierárquicos

Para cenários complexos, você pode criar hierarquias multinível. Cada agente pode ter seus próprios subagentes, formando uma árvore:

Visualização: 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 fluem

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-3.7-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 publicação de blog sobre IA na área da saúde" → PM → Criador de conteúdo → Redator
  • "Pesquise sobre veículos elétricos" → PM → Criador de conteúdo → Pesquisador

Configuração de subagentes

Adicione subagentes 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 principais:

  • Cada agente pode ter vários subagentes
  • Os subagentes podem ter seus próprios subagentes (hierarquias multinível)
  • Os nomes dos agentes devem ser exclusivos dentro da hierarquia
  • As descrições ajudam o LLM a decidir para qual agente transferir

Como escrever instruções eficazes de transferência

Para obter transferências de agentes bem-sucedidas, forneça instruções e descrições claras:

Instruções do agente 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 subagentes

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()?;

Práticas recomendadas:

  • Use nomes de agentes descritivos que indiquem claramente sua finalidade
  • Escreva descrições detalhadas — o LLM as utiliza para decidir as transferências
  • Inclua palavras-chave específicas nas descrições que correspondam às prováveis solicitações dos usuários
  • Forneça regras claras de delegação nas instruções do agente pai
  • Use terminologia consistente em todas as descrições dos agentes

Testando seu sistema multiagente

Executando exemplos

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

Prompts de teste de exemplo

Atendimento ao Cliente:

  • "Tenho uma pergunta sobre minha última fatura" → Deve encaminhar para billing_agent
  • "O aplicativo continua travando" → Deve encaminhar para support_agent
  • "Como faço para atualizar meu plano?" → Deve encaminhar para billing_agent
  • "Olá, preciso de ajuda" → Deve permanecer com coordinator para esclarecimento

Hierárquico:

  • "Crie uma publicação de blog sobre IA na área da saúde" → PM → Criador de Conteúdo → Redator
  • "Pesquise 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

Depuração de Problemas de Transferência

Se as transferências não estiverem funcionando conforme o esperado:

  1. Verifique os nomes dos agentes - Eles devem corresponder exatamente nas chamadas de transferência
  2. Revise as descrições - Torne-as mais específicas e ricas em palavras-chave
  3. Esclareça as instruções - Seja explícito sobre quando transferir
  4. Teste casos extremos - Tente fazer solicitações ambíguas para observar o comportamento do roteamento
  5. Procure indicadores de transferência - [Agent: name] mostra qual agente 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. Instrução do Agente

  • Instrução Global: Aplicada a todos os agentes na hierarquia, define a personalidade e o contexto gerais
  • Instrução do Agente: Específica para cada agente, define sua função e seu 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ções globais 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

As instruções globais e dos agentes são compatíveis com 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 os valores do estado da sessão nos modelos de instrução.

Padrões Comuns de Multiagentes

Padrão de Coordenador/Despachante

Um agente central encaminha solicitações para subagentes 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 principais:

  • O coordenador analisa a solicitação e transfere para o agente de cobrança
  • O agente de cobrança responde imediatamente no mesmo turno
  • As mensagens subsequentes continuam com o agente de cobrança
  • Os indicadores de transferência (🔄) mostram quando ocorrem os encaminhamentos

Decomposição Hierárquica de Tarefas

Hierarquias de vários níveis para dividir 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()?;

Combinação com Agentes de Fluxo de Trabalho

Os sistemas multiagente funcionam bem com agentes de fluxo de trabalho (Sequencial, Paralelo, 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

Os agentes em uma hierarquia se comunicam por meio do estado compartilhado da sessão:

// 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 agente no estado da sessão, disponibilizando-a para os agentes subsequentes.

AgentTool Encaminhamento de Estado e Artefatos

Ao usar AgentTool para encapsular agentes como ferramentas, as alterações de estado e os artefatos dos subagentes são encaminhados automaticamente 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()?;

AgentTool executa internamente os subagentes no modo sem streaming (StreamingMode::None), fazendo com que o subagente acumule sua resposta completa antes de retorná-la ao agente pai. Isso evita problemas em que partes parciais do streaming poderiam produzir resultados vazios.

Isso permite um fluxo de dados contínuo entre agentes pai e filho ao usar o padrão AgentTool.

Execução de Sistemas Multiagente

Usando o Inicializador

O Launcher oferece uma maneira fácil de executar e testar sistemas multiagente:

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ências: 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 da conversa: Mantém o contexto entre transferências de agentes

Testando transferências

Para verificar se o sistema multiagente funciona corretamente:

  1. Verifique os nomes dos agentes que aparecem entre colchetes quando eles respondem
  2. Procure indicadores de transferência (🔄) quando os agentes encaminharem a conversa
  3. Verifique as respostas imediatas dos agentes de destino, sem solicitar novamente
  4. Teste diferentes tipos de solicitação para garantir o roteamento correto
  5. Verifique casos extremos, como transferências para agentes inexistentes

Depurando problemas de transferência

Se as transferências não estiverem funcionando:

  • Verifique se os subagentes foram adicionados por meio de .sub_agent()
  • Verifique as descrições dos agentes — o LLM as utiliza para decidir as transferências
  • Revise as instruções — o agente pai deve mencionar quando transferir
  • Verifique os nomes dos agentes — eles devem corresponder exatamente nas chamadas de transferência
  • Ative o registro para visualizar as ações de transferência no fluxo de eventos

Práticas recomendadas

  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: Forneça a cada agente instruções claras e focadas para sua função
  3. Use a 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 a comunicação entre agentes
  5. Limite a profundidade da hierarquia: Mantenha as hierarquias superficiais (2 a 3 níveis) para facilitar a manutenção
  6. Teste a lógica de transferência: Verifique se os agentes transferem as solicitações para os subagentes corretos

Anterior: ← Agentes de fluxo de trabalho | Próximo: Agentes de grafo →

Sistemas Multiagentes - Documentação ADK-Rust | ADK-Rust