リアルタイム音声エージェント

リアルタイムエージェントは、双方向オーディオストリーミングを使用してAIアシスタントとの音声ベースの対話を可能にします。adk-realtime crate は、OpenAIの Realtime API および Googleの Gemini Live API と連携する音声対応エージェントを構築するための統一されたインターフェースを提供します。

概要

リアルタイムエージェントは、テキストベースの LlmAgent といくつかの重要な点で異なります。

特徴LlmAgentRealtimeAgent
入力テキスト音声/テキスト
出力テキスト音声/テキスト
接続HTTPリクエストWebSocket
レイテンシリクエスト/レスポンスリアルタイムストリーミング
VADN/Aサーバー側音声検出

アーキテクチャ

              ┌─────────────────────────────────────────┐
              │              Agent Trait                │
              │  (name, description, run, sub_agents)   │
              └────────────────┬────────────────────────┘
                               │
       ┌───────────────────────┼───────────────────────┐
       │                       │                       │
┌──────▼──────┐      ┌─────────▼─────────┐   ┌─────────▼─────────┐
│  LlmAgent   │      │  RealtimeAgent    │   │  SequentialAgent  │
│ (text-based)│      │  (voice-based)    │   │   (workflow)      │
└─────────────┘      └───────────────────┘   └───────────────────┘

RealtimeAgentLlmAgent と同じ Agent trait を実装しており、以下を共有します。

  • 命令 (静的および動的)
  • ツール登録と実行
  • コールバック (before_agent, after_agent, before_tool, after_tool)
  • サブエージェントへの引き渡し

クイックスタート

インストール

Cargo.toml に追加します。

[dependencies]
adk-realtime = { version = "0.2.0", features = ["openai"] }

基本的な使い方

use adk_realtime::{
    RealtimeAgent, RealtimeModel, RealtimeConfig, ServerEvent,
    openai::OpenAIRealtimeModel,
};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("OPENAI_API_KEY")?;

    // リアルタイムモデルを作成
    let model: Arc<dyn RealtimeModel> = Arc::new(
        OpenAIRealtimeModel::new(&api_key, "gpt-4o-realtime-preview-2024-12-17")
    );

    // リアルタイムエージェントを構築
    let agent = RealtimeAgent::builder("voice_assistant")
        .model(model.clone())
        .instruction("You are a helpful voice assistant. Be concise.")
        .voice("alloy")
        .server_vad()  // Enable voice activity detection
        .build()?;

    // または低レベルのsession APIを直接使用
    let config = RealtimeConfig::default()
        .with_instruction("You are a helpful assistant.")
        .with_voice("alloy")
        .with_modalities(vec!["text".to_string(), "audio".to_string()]);

    let session = model.connect(config).await?;

    // テキストを送信し、応答を取得
    session.send_text("Hello!").await?;
    session.create_response().await?;

    // イベントを処理
    while let Some(event) = session.next_event().await {
        match event? {
            ServerEvent::TextDelta { delta, .. } => print!("{}", delta),
            ServerEvent::AudioDelta { delta, .. } => {
                // 音声の再生 (deltaはbase64エンコードされたPCM)
            }
            ServerEvent::ResponseDone { .. } => break,
            _ => {}
        }
    }

    Ok(())
}

サポートされているプロバイダー

プロバイダーモデルフィーチャーフラグオーディオ形式
OpenAIgpt-4o-realtime-preview-2024-12-17openaiPCM16 24kHz
OpenAIgpt-realtimeopenaiPCM16 24kHz
Googlegemini-2.0-flash-live-preview-04-09geminiPCM16 16kHz/24kHz

: gpt-realtimeは、OpenAIの最新のリアルタイムモデルであり、音声品質、感情、FunctionTool呼び出し機能が向上しています。

RealtimeAgent ビルダー

RealtimeAgentBuilderは、Agentを設定するための流暢なAPIを提供します。

let agent = RealtimeAgent::builder("assistant")
    // 必須
    .model(model)

    // 指示 (LlmAgent と同じ)
    .instruction("You are helpful.")
    .instruction_provider(|ctx| format!("User: {}", ctx.user_name()))

    // 音声設定
    .voice("alloy")  // オプション: alloy, coral, sage, shimmer など

    // 音声活動検出 (VAD)
    .server_vad()  // デフォルトを使用
    .vad(VadConfig {
        mode: VadMode::ServerVad,
        threshold: Some(0.5),
        prefix_padding_ms: Some(300),
        silence_duration_ms: Some(500),
        interrupt_response: Some(true),
        eagerness: None,
    })

    // Tool (LlmAgent と同じ)
    .tool(Arc::new(weather_tool))
    .tool(Arc::new(search_tool))

    // ハンドオフ用のサブAgent
    .sub_agent(booking_agent)
    .sub_agent(support_agent)

    // コールバック (LlmAgent と同じ)
    .before_agent_callback(|ctx| async { Ok(()) })
    .after_agent_callback(|ctx, event| async { Ok(()) })
    .before_tool_callback(|ctx, tool, args| async { Ok(None) })
    .after_tool_callback(|ctx, tool, result| async { Ok(result) })

    // リアルタイム固有のコールバック
    .on_audio(|audio_chunk| { /* 音声を再生 */ })
    .on_transcript(|text| { /* トランスクリプトを表示 */ })

    .build()?;

音声活動検出 (VAD)

VADは、ユーザーが話し始めたり、話し終えたりするのを検出することで、自然な会話の流れを可能にします。

サーバーVAD (推奨)

let agent = RealtimeAgent::builder("assistant")
    .model(model)
    .server_vad()  // 適切なデフォルトを使用
    .build()?;

カスタムVAD設定

use adk_realtime::{VadConfig, VadMode};

let vad = VadConfig {
    mode: VadMode::ServerVad,
    threshold: Some(0.5),           // 音声検出感度 (0.0-1.0)
    prefix_padding_ms: Some(300),   // 発話前に含めるオーディオ
    silence_duration_ms: Some(500), // ターン終了前の無音
    interrupt_response: Some(true), // アシスタントの中断を許可
    eagerness: None,                // SemanticVadモード用
};

let agent = RealtimeAgent::builder("assistant")
    .model(model)
    .vad(vad)
    .build()?;

セマンティックVAD (Gemini)

Geminiモデルの場合、意味を考慮するセマンティックVADを使用できます。

let vad = VadConfig {
    mode: VadMode::SemanticVad,
    eagerness: Some("high".to_string()),  // low、medium、high
    ..Default::default()
};

ツール呼び出し

リアルタイム Agent は、音声会話中にツール呼び出しをサポートしています。

use adk_realtime::{config::ToolDefinition, ToolResponse};
use serde_json::json;

// Define tools
let tools = vec![
    ToolDefinition {
        name: "get_weather".to_string(),
        description: Some("Get weather for a location".to_string()),
        parameters: Some(json!({
            "type": "object",
            "properties": {
                "location": { "type": "string" }
            },
            "required": ["location"]
        })),
    },
];

let config = RealtimeConfig::default()
    .with_tools(tools)
    .with_instruction("Use tools to help the user.");

let session = model.connect(config).await?;

// Handle tool calls in the event loop
while let Some(event) = session.next_event().await {
    match event? {
        ServerEvent::FunctionCallDone { call_id, name, arguments, .. } => {
            // Execute the tool
            let result = execute_tool(&name, &arguments);

            // Send the response
            let response = ToolResponse::new(&call_id, result);
            session.send_tool_response(response).await?;
        }
        _ => {}
    }
}

マルチ Agent ハンドオフ

専門の Agent 間で会話を転送します。

// Create sub-agents
let booking_agent = Arc::new(RealtimeAgent::builder("booking_agent")
    .model(model.clone())
    .instruction("Help with reservations.")
    .build()?);

let support_agent = Arc::new(RealtimeAgent::builder("support_agent")
    .model(model.clone())
    .instruction("Help with technical issues.")
    .build()?);

// Create main agent with sub-agents
let receptionist = RealtimeAgent::builder("receptionist")
    .model(model)
    .instruction(
        "Route customers: bookings → booking_agent, issues → support_agent. \
         Use transfer_to_agent tool to hand off."
    )
    .sub_agent(booking_agent)
    .sub_agent(support_agent)
    .build()?;

モデルが transfer_to_agent を呼び出すと、RealtimeRunner が自動的にハンドオフを処理します。

オーディオ形式

形式サンプルレートビットチャンネル用途
PCM1624000 Hz16モノOpenAI (デフォルト)
PCM1616000 Hz16モノGemini 入力
G711 u-law8000 Hz8モノ電話
G711 A-law8000 Hz8モノ電話
use adk_realtime::{AudioFormat, AudioChunk};

// Create audio format
let format = AudioFormat::pcm16_24khz();

// Work with audio chunks
let chunk = AudioChunk::new(audio_bytes, format);
let base64 = chunk.to_base64();
let decoded = AudioChunk::from_base64(&base64, format)?;

イベントタイプ

サーバーイベント

イベント説明
SessionCreated接続確立
AudioDeltaオーディオチャンク (base64 PCM)
TextDeltaテキスト応答チャンク
TranscriptDelta入力オーディオの文字起こし
FunctionCallDoneTool 呼び出しリクエスト
ResponseDone応答完了
SpeechStartedVADが音声の開始を検出
SpeechStoppedVADが音声の終了を検出
Errorエラー発生

クライアントイベント

イベント説明
AudioInputオーディオチャンクを送信
AudioCommitオーディオバッファをコミット
ItemCreateテキストまたは Tool 応答を送信
CreateResponse応答をリクエスト
CancelResponse現在の応答をキャンセル
SessionUpdate設定を更新

含まれている例を実行します。

# 基本的なテキストのみのセッション
cargo run --example realtime_basic --features realtime-openai

# VAD付き音声アシスタント
cargo run --example realtime_vad --features realtime-openai

# Tool Calling
cargo run --example realtime_tools --features realtime-openai

# マルチ Agent ハンドオフ
cargo run --example realtime_handoff --features realtime-openai

ベストプラクティス

  1. Server VAD を使用する: 低遅延のために、サーバーに音声検出を処理させる
  2. 中断を処理する: 自然な会話のために interrupt_response を有効にする
  3. 指示を簡潔にする: 音声応答は短くするべきです
  4. まずテキストでテストする: オーディオを追加する前に、テキストで Agent ロジックをデバッグする
  5. エラーを適切に処理する: WebSocket 接続ではネットワークの問題がよく発生します

OpenAI Agents SDK との比較

ADK-Rust のリアルタイム実装は、OpenAI Agents SDK のパターンに従っています:

機能OpenAI SDKADK-Rust
Agent 基底クラスAgentAgent trait
リアルタイム AgentRealtimeAgentRealtimeAgent
ツール関数定義Tool trait + ToolDefinition
ハンドオフtransfer_to_agentsub_agents + 自動生成ツール
コールバックフックbefore_* / after_* コールバック

前へ: ← Graph Agents | 次へ: モデルプロバイダー →