Runner

adk-runner의 실행 런타임으로, agent 실행을 조율합니다.

개요

Runner는 agent 실행의 전체 라이프사이클을 관리합니다:

  • Session 관리 (session 생성/조회)
  • Memory 주입 (관련 memory 검색 및 주입)
  • Artifact 처리 (범위가 지정된 artifact 접근)
  • Event 스트리밍 (event 처리 및 전달)
  • Agent 전송 (다중 agent 핸드오프 처리)

설치

[dependencies]
adk-runner = "0.2.0"

RunnerConfig

필수 서비스로 runner를 구성합니다:

use adk_runner::{Runner, RunnerConfig};
use adk_session::InMemorySessionService;
use adk_artifact::InMemoryArtifactService;
use std::sync::Arc;

let config = RunnerConfig {
    app_name: "my_app".to_string(),
    agent: Arc::new(my_agent),
    session_service: Arc::new(InMemorySessionService::new()),
    artifact_service: Some(Arc::new(InMemoryArtifactService::new())),
    memory_service: None,
    run_config: None,
};

let runner = Runner::new(config)?;

구성 필드

FieldTypeRequiredDescription
app_nameString애플리케이션 식별자
agentArc<dyn Agent>실행할 루트 agent
session_serviceArc<dyn SessionService>Session 저장 백엔드
artifact_serviceOption<Arc<dyn ArtifactService>>아니요Artifact 저장소
memory_serviceOption<Arc<dyn Memory>>아니요장기 memory
run_configOption<RunConfig>아니요실행 옵션

Agent 실행

사용자 입력으로 agent를 실행합니다:

use adk_core::Content;
use futures::StreamExt;

let user_content = Content::new("user").with_text("Hello!");

let mut stream = runner.run(
    "user-123".to_string(),
    "session-456".to_string(),
    user_content,
).await?;

while let Some(event) = stream.next().await {
    match event {
        Ok(e) => {
            if let Some(content) = e.content() {
                for part in &content.parts {
                    if let Some(text) = part.text() {
                        print!("{}", text);
                    }
                }
            }
        }
        Err(e) => eprintln!("Error: {}", e),
    }
}

실행 흐름

┌─────────────────────────────────────────────────────────────┐
│                     Runner.run()                            │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  1. 세션 검색                               │
│                                                             │
│   SessionService.get(app_name, user_id, session_id)        │
│   → 존재하지 않으면 새 세션을 생성합니다                   │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  2. Agent 선택                              │
│                                                             │
│   활성 agent를 위해 세션 상태를 확인합니다                 │
│   → root agent 또는 전송된 agent를 사용합니다              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                3. 컨텍스트 생성                             │
│                                                             │
│   InvocationContext 포함:                                   │
│   - Session (가변)                                          │
│   - Artifacts (세션 범위)                                  │
│   - Memory (구성된 경우)                                  │
│   - Run config                                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  4. Agent 실행                              │
│                                                             │
│   agent.run(ctx) → EventStream                             │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                 5. 이벤트 처리                              │
│                                                             │
│   각 이벤트에 대해:                                         │
│   - 세션 상태 업데이트                                      │
│   - 전송 처리                                               │
│   - 호출자에게 전달                                         │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  6. 세션 저장                               │
│                                                             │
│   SessionService.append_event(session, events)             │
└─────────────────────────────────────────────────────────────┘

InvocationContext

실행 중에 에이전트에 제공되는 컨텍스트:

pub trait InvocationContext: CallbackContext {
    /// The agent being executed
    fn agent(&self) -> Arc<dyn Agent>;
    
    /// Memory service (if configured)
    fn memory(&self) -> Option<Arc<dyn Memory>>;
    
    /// Current session
    fn session(&self) -> &dyn Session;
    
    /// Execution configuration
    fn run_config(&self) -> &RunConfig;
    
    /// Signal end of invocation
    fn end_invocation(&self);
    
    /// Check if invocation has ended
    fn ended(&self) -> bool;
}

RunConfig

실행 옵션:

pub struct RunConfig {
    /// Streaming mode for responses
    pub streaming_mode: StreamingMode,
}

pub enum StreamingMode {
    /// No streaming, return complete response
    None,
    /// Server-Sent Events (default)
    SSE,
    /// Bidirectional streaming (realtime)
    Bidi,
}

참고: max_turnsinclude_history와 같은 추가 필드는 향후 릴리스에서 계획되어 있습니다.

에이전트 전환

Runner는 다중 에이전트 전환을 자동으로 처리합니다:

// In an agent's tool or callback
if should_transfer {
    // Set transfer in event actions
    ctx.set_actions(EventActions {
        transfer_to_agent: Some("specialist_agent".to_string()),
        ..Default::default()
    });
}

Runner는 다음을 수행합니다:

  1. 이벤트에서 전환 요청을 감지합니다.
  2. sub_agents에서 대상 Agent를 찾습니다.
  3. 새로운 활성 Agent로 세션 상태를 업데이트합니다.
  4. 새로운 Agent로 실행을 계속합니다.

Launcher와의 통합

Launcher는 내부적으로 Runner를 사용합니다:

// Launcher creates Runner with default services
Launcher::new(agent)
    .app_name("my_app")
    .run()
    .await?;

// Equivalent to:
let runner = Runner::new(RunnerConfig {
    app_name: "my_app".to_string(),
    agent,
    session_service: Arc::new(InMemorySessionService::new()),
    artifact_service: Some(Arc::new(FileArtifactService::new("./artifacts")?)),
    memory_service: None,
    run_config: None,
})?;

사용자 지정 Runner 사용법

고급 시나리오의 경우, Runner를 직접 사용하세요:

use adk_runner::{Runner, RunnerConfig};
use adk_session::DatabaseSessionService;
use adk_artifact::S3ArtifactService;
use adk_memory::QdrantMemoryService;

// Production configuration
let config = RunnerConfig {
    app_name: "production_app".to_string(),
    agent: my_agent,
    session_service: Arc::new(DatabaseSessionService::new(db_pool)),
    artifact_service: Some(Arc::new(S3ArtifactService::new(s3_client))),
    memory_service: Some(Arc::new(QdrantMemoryService::new(qdrant_client))),
    run_config: None,  // Uses default SSE streaming
};

let runner = Runner::new(config)?;

// Use in HTTP handler
async fn chat_handler(runner: &Runner, request: ChatRequest) -> Response {
    let stream = runner.run(
        request.user_id,
        request.session_id,
        request.content,
    ).await?;
    
    // Stream events to client
    Response::sse(stream)
}

이전: ← 코어 타입 | 다음: Launcher →