다중 에이전트 시스템

전문 에이전트를 팀으로 구성하여 정교한 애플리케이션을 구축하세요.

에이전트 계층 구조 개요

Rendering architecture…

구축할 내용

이 가이드에서는 코디네이터가 쿼리를 전문가에게 라우팅하는 고객 서비스 시스템을 생성합니다:

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

주요 개념:

  • 코디네이터 - 모든 요청을 수신하고 누가 처리할지 결정합니다.
  • 전문가 - 특정 도메인에 탁월한 집중 에이전트
  • 전환 - 코디네이터에서 전문가로의 원활한 인계

빠른 시작

1. 프로젝트 생성

cargo new multi_agent_demo
cd multi_agent_demo

Cargo.toml에 의존성을 추가합니다:

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

API 키로 .env을 생성합니다:

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

2. 고객 서비스 예시

다음은 완전한 작동 예시입니다:

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(())
}

예시 상호작용:

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...

다중 에이전트 전환 작동 방식

큰 그림

하위 에이전트를 상위 에이전트에 추가하면 LLM는 작업을 위임하는 기능을 얻습니다:

                    ┌─────────────────────┐
    User Message    │                     │
   ─────────────────▶    COORDINATOR      │
                    │                     │
                    └──────────┬──────────┘
                               │
           "This is a billing question..."
                               │
              ┌────────────────┴────────────────┐
              │                                 │
              ▼                                 ▼
   ┌──────────────────┐              ┌──────────────────┐
   │  billing_agent   │              │  support_agent   │
   │  💰 Payments     │              │  🔧 Tech Issues  │
   │  📄 Invoices     │              │  🐛 Bug Reports  │
   └──────────────────┘              └──────────────────┘

단계별 전환 흐름

사용자가 청구 관련 질문을 할 때 정확히 어떤 일이 발생하는지 살펴보겠습니다:

┌──────────────────────────────────────────────────────────────────────┐
│ 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!                  │
│                                                                      │
└──────────────────────────────────────────────────────────────────────┘

작동 원리

구성 요소역할
.sub_agent()부모 아래에 전문가를 등록합니다
transfer_to_agent tool하위 Agent가 존재할 때 자동 주입됩니다
Agent 설명LLM가 어떤 Agent가 무엇을 처리할지 결정하는 데 도움을 줍니다
Runner전송 이벤트를 감지하고 대상 Agent를 호출합니다
공유 Session전송 전반에 걸쳐 상태 및 기록이 보존됩니다

서브 에이전트 추가 전후

서브 에이전트 없음 - 하나의 Agent가 모든 것을 수행합니다:

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

서브 에이전트 있음 - 전문가들이 각자의 영역을 처리합니다:

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

계층적 다중 Agent 시스템

복잡한 시나리오의 경우, 다단계 계층 구조를 생성할 수 있습니다. 각 Agent는 자체 서브 Agent를 가질 수 있으며, 이는 트리 형태를 이룹니다:

시각 자료: 3단계 콘텐츠 팀

                    ┌─────────────────────┐
                    │  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 │
   └──────────────────┘              └──────────────────┘

요청이 하위로 흐르는 방식

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                                │
└─────────────────────────────────────────────────────────────┘

전체 예시 코드

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(())
}

Agent 계층 구조:

project_manager
└── content_creator
    ├── researcher
    └── writer

예시 프롬프트:

  • "AI 헬스케어에 대한 블로그 게시물 작성" → PM → Content Creator → Writer
  • "전기차 연구" → PM → Content Creator → Researcher

서브 Agent 구성

어떤 LlmAgent에든 sub_agent() 빌더 메서드를 사용하여 서브 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()?;

핵심 사항:

  • 각 Agent는 여러 서브 Agent를 가질 수 있습니다.
  • 서브 Agent는 자체 서브 Agent를 가질 수 있습니다 (다단계 계층 구조).
  • Agent 이름은 계층 구조 내에서 고유해야 합니다.
  • 설명은 LLM가 어떤 Agent로 전환할지 결정하는 데 도움이 됩니다.

효과적인 전환 지침 작성

성공적인 Agent 전환을 위해 명확한 지침과 설명을 제공하세요:

상위 Agent 지침

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

서브 Agent 설명

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

모범 사례:

  • 목적을 명확하게 나타내는 설명적인 Agent 이름을 사용하세요.
  • 자세한 설명을 작성하세요 - LLM는 이를 사용하여 전환을 결정합니다.
  • 설명에 예상되는 사용자 요청과 일치하는 특정 키워드를 포함하세요.
  • 상위 Agent 지침에 명확한 위임 규칙을 제공하세요.
  • Agent 설명 전반에 걸쳐 일관된 용어를 사용하세요.

다중 Agent 시스템 테스트

예시 실행

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

예시 테스트 프롬프트

고객 서비스:

  • "지난 인보이스에 대해 질문이 있습니다" → billing_agent로 라우팅되어야 합니다.
  • "앱이 계속 충돌합니다" → support_agent로 라우팅되어야 합니다.
  • "요금제를 어떻게 업그레이드하나요?" → billing_agent로 라우팅되어야 합니다.
  • "안녕하세요, 도움이 필요합니다" → 명확화를 위해 coordinator에 머물러야 합니다.

계층적:

  • "AI 헬스케어에 대한 블로그 게시물 작성" → PM → Content Creator → Writer
  • "전기차의 역사 연구" → PM → Content Creator → Researcher
  • "현재 프로젝트의 상태는 어떻습니까?" → project_manager에 머물러야 합니다.

전환 문제 디버깅

전환이 예상대로 작동하지 않는 경우:

  1. Agent 이름 확인 - 전환 호출에서 정확히 일치해야 합니다.
  2. 설명 검토 - 더 구체적이고 키워드가 풍부하게 만드세요.
  3. 지침 명확화 - 언제 전환할지 명시적으로 지정하세요.
  4. 엣지 케이스 테스트 - 모호한 요청을 시도하여 라우팅 동작을 확인하세요.
  5. 전환 지표 확인 - [Agent: name]는 어떤 Agent가 응답하는지 보여줍니다.

전역 지침

기본 사용법

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

전역 지침 vs Agent 지침

  • 전역 지침: 계층 구조의 모든 Agent에 적용되며, 전반적인 성격/맥락을 설정합니다.
  • Agent 지침: 각 Agent에 특화되어 있으며, 특정 역할과 동작을 정의합니다.

두 지침 모두 대화 기록에 포함되며, 전역 지침이 먼저 나타납니다.

동적 전역 지침

더 고급 시나리오의 경우, 지침을 동적으로 계산하는 전역 지침 제공자를 사용할 수 있습니다:

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

상태 변수 주입

전역 및 Agent 지침 모두 {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()?;

프레임워크는 세션 상태의 값을 지침 템플릿에 자동으로 주입합니다.

일반적인 다중 Agent 패턴

코디네이터/디스패처 패턴

중앙 Agent가 전문 서브 Agent에게 요청을 라우팅합니다:

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

예시 대화:

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...

핵심 사항:

  • 코디네이터는 요청을 분석하고 청구 Agent로 전환합니다.
  • 청구 Agent는 동일한 턴에 즉시 응답합니다.
  • 후속 메시지는 청구 Agent와 계속됩니다.
  • 전환 지표 (🔄)는 핸드오프가 발생할 때를 보여줍니다.

계층적 작업 분해

복잡한 작업을 분해하기 위한 다단계 계층 구조:

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

워크플로 Agent와 결합

다중 Agent 시스템은 워크플로 Agent (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()?;

Agent 간 통신

계층 구조의 Agent는 공유 세션 상태를 통해 통신합니다:

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

output_key 구성은 Agent의 최종 응답을 세션 상태에 자동으로 저장하여 후속 Agent가 사용할 수 있도록 합니다.

AgentTool 상태 및 아티팩트 전달

Agent를 Tool로 래핑하기 위해 AgentTool를 사용할 때, 서브 Agent의 상태 변경 및 아티팩트는 상위 컨텍스트로 자동으로 전달됩니다:

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는 서브 Agent를 내부적으로 비스트리밍 모드(StreamingMode::None)로 실행하므로, 서브 Agent는 전체 응답을 상위로 반환하기 전에 축적합니다. 이는 부분 스트리밍 청크가 빈 결과를 생성할 수 있는 문제를 방지합니다.

이를 통해 AgentTool 패턴을 사용할 때 상위 Agent와 하위 Agent 간의 원활한 데이터 흐름이 가능해집니다.

다중 Agent 시스템 실행

런처 사용

Launcher는 다중 Agent 시스템을 실행하고 테스트하는 쉬운 방법을 제공합니다:

use adk_rust::Launcher;

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

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

실행 모드:

# 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

기능:

  • Agent 지표: 어떤 Agent가 응답하는지 보여줍니다 [Agent: coordinator]
  • 전환 시각화: 전환 이벤트를 표시합니다 🔄 [Transfer requested to: billing_agent]
  • 원활한 핸드오프: 전환 후 대상 Agent가 즉시 응답합니다.
  • 대화 기록: Agent 전환 전반에 걸쳐 컨텍스트를 유지합니다.

전환 테스트

다중 Agent 시스템이 올바르게 작동하는지 확인하려면:

  1. Agent가 응답할 때 대괄호 안에 Agent 이름이 나타나는지 확인하세요.
  2. Agent가 핸드오프할 때 전환 지표 (🔄)를 찾으세요.
  3. 다시 프롬프트하지 않고 대상 Agent로부터 즉각적인 응답을 확인하세요.
  4. 올바른 라우팅을 보장하기 위해 다양한 요청 유형을 테스트하세요.
  5. 존재하지 않는 Agent로 전환하는 것과 같은 엣지 케이스를 확인하세요.

전환 문제 디버깅

전환이 작동하지 않는 경우:

  • .sub_agent()를 통해 서브 Agent가 추가되었는지 확인하세요.
  • Agent 설명을 확인하세요 - LLM는 이를 사용하여 전환을 결정합니다.
  • 지침을 검토하세요 - 상위 Agent는 언제 전환할지 언급해야 합니다.
  • Agent 이름을 확인하세요 - 전환 호출에서 정확히 일치해야 합니다.
  • 이벤트 스트림에서 전환 작업을 확인하려면 로깅을 활성화하세요.

모범 사례

  1. 명확한 설명: LLM가 올바른 전환 결정을 내릴 수 있도록 설명적인 Agent 이름과 설명을 작성하세요.
  2. 구체적인 지침: 각 Agent에 역할에 대한 명확하고 집중된 지침을 제공하세요.
  3. 전역 지침 사용: 모든 Agent에 걸쳐 일관된 성격과 컨텍스트를 설정하세요.
  4. 상태 관리: Agent 통신을 위해 output_key 및 상태 변수를 사용하세요.
  5. 계층 깊이 제한: 더 나은 유지 관리를 위해 계층을 얕게 유지하세요 (2-3단계).
  6. 전환 로직 테스트: Agent가 다른 요청에 대해 올바른 서브 Agent로 전환하는지 확인하세요.

이전: ← 워크플로 Agent | 다음: Graph Agent →