实时语音代理

实时代理通过双向音频流实现与 AI 助手的语音交互。adk-realtime crate 提供了一个统一的接口,用于构建可与 OpenAI 的 Realtime API 和 Google 的 Gemini Live API 配合使用的语音代理。

概述

实时代理与基于文本的 LlmAgents 在几个关键方面有所不同:

功能LlmAgentRealtimeAgent
输入文本音频/文本
输出文本音频/文本
连接HTTP 请求WebSocket
延迟请求/响应实时流
VAD不适用服务器端语音检测

架构

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

RealtimeAgent 实现了与 LlmAgent 相同的 Agent trait,共享:

  • 指令(静态和动态)
  • 工具注册和执行
  • 回调(before_agent, after_agent, before_tool, after_tool)
  • 子代理移交

快速开始

安装

添加到您的 Cargo.toml

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

# For Vertex AI Live (Google Cloud with ADC auth)
# adk-realtime = { version = "2.0.0", features = ["vertex-live"] }

# For LiveKit WebRTC bridge
# adk-realtime = { version = "2.0.0", features = ["livekit"] }

# For all transports (except WebRTC which needs cmake)
# adk-realtime = { version = "2.0.0", features = ["full"] }

基本用法

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

    // Create the realtime model
    let model: Arc<dyn RealtimeModel> = Arc::new(
        OpenAIRealtimeModel::new(&api_key, "gpt-realtime")
    );

    // Build the realtime agent
    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()?;

    // Or use the low-level session API directly
    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?;

    // Send text and get response
    session.send_text("Hello!").await?;
    session.create_response().await?;

    // Process events
    while let Some(event) = session.next_event().await {
        match event? {
            ServerEvent::TextDelta { delta, .. } => print!("{}", delta),
            ServerEvent::AudioDelta { delta, .. } => {
                // Play audio (delta is base64-encoded PCM)
            }
            ServerEvent::ResponseDone { .. } => break,
            _ => {}
        }
    }

    Ok(())
}

支持的提供商

提供商模型传输功能标志音频格式
OpenAIgpt-realtimeWebSocketopenaiPCM16 24kHz
OpenAIgpt-realtimeWebRTCopenai-webrtcOpus
谷歌gemini-live-2.5-flash-native-audioWebSocketgeminiPCM16 16kHz/24kHz
谷歌Gemini 经由 Vertex AIWebSocket + OAuth2vertex-livePCM16 16kHz/24kHz
LiveKit任意 (桥接到 Gemini/OpenAI)WebRTClivekitPCM16

注意: gpt-realtime 是 OpenAI 最新的实时模型,具有改进的语音质量、情感和 function calling 能力。

传输选项

ADK-Realtime 支持多种传输层:

  • WebSocket (默认): 直接连接到 OpenAI 或 Gemini。简单、低延迟、随处可用。
  • Vertex AI Live: 通过 Google Cloud 连接到 Gemini,使用 OAuth2 身份验证 (Application Default Credentials)。当您需要企业级身份验证和 GCP 集成时使用。
  • LiveKit WebRTC: 生产级 WebRTC 网桥。通过 LiveKit 服务器路由音频,适用于可扩展的多参与者场景。
  • OpenAI WebRTC: 使用 Opus codec 和 data channels 直接 WebRTC 连接到 OpenAI。需要 cmake 来构建 Opus C library。

RealtimeAgent 构建器

RealtimeAgentBuilder 提供了一个流畅的 API 来配置代理:

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

    // Instructions (same as LlmAgent)
    .instruction("You are helpful.")
    .instruction_provider(|ctx| format!("User: {}", ctx.user_name()))

    // Voice settings
    .voice("alloy")  // Options: alloy, coral, sage, shimmer, etc.

    // Voice Activity Detection
    .server_vad()  // Use defaults
    .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,
    })

    // Tools (same as LlmAgent)
    .tool(Arc::new(weather_tool))
    .tool(Arc::new(search_tool))

    // Sub-agents for handoffs
    .sub_agent(booking_agent)
    .sub_agent(support_agent)

    // Callbacks (same as 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) })

    // Realtime-specific callbacks
    .on_audio(|audio_chunk| { /* play audio */ })
    .on_transcript(|text| { /* show transcript */ })

    .build()?;

语音活动检测 (VAD)

VAD 通过检测用户何时开始和停止说话来启用自然的对话流。

let agent = RealtimeAgent::builder("assistant")
    .model(model)
    .server_vad()  // Uses sensible defaults
    .build()?;

自定义 VAD 配置

use adk_realtime::{VadConfig, VadMode};

let vad = VadConfig {
    mode: VadMode::ServerVad,
    threshold: Some(0.5),           // Speech detection sensitivity (0.0-1.0)
    prefix_padding_ms: Some(300),   // Audio to include before speech
    silence_duration_ms: Some(500), // Silence before ending turn
    interrupt_response: Some(true), // Allow interrupting assistant
    eagerness: None,                // For SemanticVad mode
};

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

工具调用

实时代理在语音对话期间支持工具调用:

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 Hz8Mono电话
G711 A-law8000 Hz8Mono电话
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输入音频转录
FunctionCallDone工具调用请求
ResponseDone响应完成
SpeechStartedVAD 检测到语音开始
SpeechStoppedVAD 检测到语音结束
Error发生错误

客户端事件

事件描述
AudioInput发送音频块
AudioCommit提交音频缓冲区
ItemCreate发送文本或工具响应
CreateResponse请求响应
CancelResponse取消当前响应
SessionUpdate更新配置

Vertex AI Live (Google Cloud)

连接到 Gemini Live 通过 Vertex AI 使用企业身份验证 (ADC, service accounts, WIF):

use adk_realtime::gemini::{GeminiLiveBackend, GeminiRealtimeModel};
use adk_realtime::{RealtimeConfig, RealtimeModel};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let project_id = std::env::var("GOOGLE_CLOUD_PROJECT")?;
    let region = std::env::var("GOOGLE_CLOUD_REGION")
        .unwrap_or_else(|_| "us-central1".to_string());

    // Use Application Default Credentials
    let credentials = google_cloud_auth::credentials::Builder::default()
        .build()
        .await?;

    let backend = GeminiLiveBackend::Vertex { credentials, region, project_id };
    let model = GeminiRealtimeModel::new(backend, "models/gemini-live-2.5-flash-native-audio");

    let config = RealtimeConfig::default()
        .with_instruction("You are a helpful voice assistant.");

    let session = model.connect(config).await?;
    session.send_text("Hello from Vertex AI!").await?;
    session.create_response().await?;

    // Process events...
    Ok(())
}

还有一个便捷构造函数用于 ADC:

let model = GeminiRealtimeModel::vertex_adc(
    "us-central1",
    "my-project-id",
    "models/gemini-live-2.5-flash-native-audio",
).await?;

Vertex AI Live 与 Tool Calling

vertex_live_tools 示例演示了函数调用通过 Vertex AI Live session:

use adk_realtime::config::ToolDefinition;
use adk_realtime::events::ToolResponse;
use serde_json::json;

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

let config = RealtimeConfig::default()
    .with_tools(tools)
    .with_instruction("Use tools to answer questions about weather.");

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

// Handle FunctionCallDone events and send ToolResponse back
while let Some(event) = session.next_event().await {
    match event? {
        ServerEvent::FunctionCallDone { call_id, name, arguments, .. } => {
            let result = match name.as_str() {
                "get_weather" => json!({"temperature": "22°C", "condition": "sunny"}),
                _ => json!({"error": "unknown tool"}),
            };
            session.send_tool_response(ToolResponse::new(&call_id, result)).await?;
        }
        ServerEvent::TextDelta { delta, .. } => print!("{delta}"),
        ServerEvent::ResponseDone { .. } => break,
        _ => {}
    }
}

功能标志

功能依赖项用例
vertex-livegemini + google-cloud-authVertex AI Live 使用 ADC/service account auth
livekitlivekit + livekit-apiLiveKit WebRTC 桥接
openai-webrtcopenai + str0m + audiopusOpenAI WebRTC with Opus (需要 cmake)
fullopenai + gemini + vertex-live + livekit所有传输,除了 WebRTC
full-webrtcfull + openai-webrtc所有 (需要 cmake)

LiveKit WebRTC 桥接

对于生产环境的语音应用,LiveKit 桥接通过 LiveKit 服务器路由音频,以实现可扩展的多参与者场景。

LiveKitConfig

安全地配置 LiveKit 凭据。API 密钥和秘密使用 secrecy::SecretString 存储,并在调试输出中进行编辑:

use adk_realtime::livekit::{LiveKitConfig, LiveKitRoomBuilder};

let config = LiveKitConfig::new(
    "wss://your-server.livekit.cloud",
    std::env::var("LIVEKIT_API_KEY")?,
    std::env::var("LIVEKIT_API_SECRET")?,
)?;

LiveKitConfig::new() 验证 URL 格式,并在构造时拒绝空凭据。

LiveKitRoomBuilder

一个用于连接 LiveKit 房间的类型状态构建器。identity 字段在编译时是必需的 — connect() 仅在其设置后可用:

let bundle = LiveKitRoomBuilder::new(config)
    .identity("my-agent")           // required — enables connect()
    .name("Voice Agent")            // optional display name
    .room_name("session-room-123")  // optional — auto-generated if omitted
    .auto_subscribe(true)           // subscribe to remote tracks
    .with_audio(24_000, 1)          // publish a local audio track (sample rate, channels)
    .connect()
    .await?;

// The bundle contains everything you need
let room = bundle.room;
let mut events = bundle.events;
let audio_source = bundle.audio_source;  // for publishing audio
let audio_track = bundle.audio_track;

桥接音频

使用桥接工具将 LiveKit 音频连接到 RealtimeRunner

use adk_realtime::livekit::{LiveKitEventHandler, bridge_input};

// Wrap your event handler to publish model audio to LiveKit
let lk_handler = LiveKitEventHandler::new(inner_handler, audio_source, 24000, 1);

// Bridge participant audio from LiveKit into the RealtimeRunner
tokio::spawn(bridge_input(remote_track, runner));

示例

运行包含的示例:

# OpenAI Realtime (WebSocket)
cargo run -p adk-realtime --example openai_session_update --features openai

# Vertex AI Live (requires gcloud auth application-default login)
cargo run -p adk-realtime --example vertex_live_voice --features vertex-live
cargo run -p adk-realtime --example vertex_live_tools --features vertex-live

# LiveKit Bridge (requires LiveKit server)
cargo run -p adk-realtime --example livekit_bridge --features livekit,openai
cargo run -p adk-realtime --example livekit_gemini_bridge --features livekit,gemini

# Debug utilities
cargo run -p adk-realtime --example debug_gemini --features gemini
cargo run -p adk-realtime --example debug_livekit_auth --features livekit

# OpenAI WebRTC (requires cmake)
cargo run -p adk-realtime --example openai_webrtc --features openai-webrtc

最佳实践

  1. 使用服务器 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 + 自动生成的工具
回调Hooksbefore_* / after_* 回调

上一页: ← Graph Agents | 下一页: 模型提供商 →

实时语音代理 - ADK-Rust 文档 | ADK-Rust