Agents Vocaux en Temps Réel
Les agents en temps réel permettent des interactions vocales avec des assistants IA en utilisant le streaming audio bidirectionnel. Le crate adk-realtime fournit une interface unifiée pour la création d'agents vocaux compatibles avec l'API temps réel d'OpenAI et l'API Gemini Live de Google.
Aperçu
Les agents en temps réel diffèrent des LlmAgents basés sur le texte de plusieurs manières clés :
| Caractéristique | LlmAgent | RealtimeAgent |
|---|---|---|
| Entrée | Text | Audio/Text |
| Sortie | Text | Audio/Text |
| Connexion | HTTP requests | WebSocket |
| Latence | Requête/réponse | Streaming en temps réel |
| VAD | N/A | Détection vocale côté serveur |
Architecture
┌─────────────────────────────────────────┐
│ Agent Trait │
│ (name, description, run, sub_agents) │
└────────────────┬────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
┌──────▼──────┐ ┌─────────▼─────────┐ ┌─────────▼─────────┐
│ LlmAgent │ │ RealtimeAgent │ │ SequentialAgent │
│ (text-based)│ │ (voice-based) │ │ (workflow) │
└─────────────┘ └───────────────────┘ └───────────────────┘
RealtimeAgent implémente le même trait Agent que LlmAgent, partageant :
- Instructions (statiques et dynamiques)
- Enregistrement et exécution d'outils
- Callbacks (before_agent, after_agent, before_tool, after_tool)
- Transferts de sous-agents
Démarrage Rapide
Installation
Ajoutez à votre 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"] }
Utilisation de Base
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(())
}
Fournisseurs Pris en Charge
| Fournisseur | Modèle | Transport | Drapeau de Fonctionnalité | Format Audio |
|---|---|---|---|---|
| OpenAI | gpt-realtime | WebSocket | openai | PCM16 24kHz |
| OpenAI | gpt-realtime | WebRTC | openai-webrtc | Opus |
gemini-live-2.5-flash-native-audio | WebSocket | gemini | PCM16 16kHz/24kHz | |
| Gemini via Vertex AI | WebSocket + OAuth2 | vertex-live | PCM16 16kHz/24kHz | |
| LiveKit | N'importe quel (pont vers Gemini/OpenAI) | WebRTC | livekit | PCM16 |
gpt-realtime est le dernier modèle temps réel d'OpenAI avec une qualité de parole, une émotion et des capacités d'appel de fonctions améliorées.
Options de Transport
ADK-Realtime prend en charge plusieurs couches de transport :
- WebSocket (par défaut) : Connexion directe à OpenAI ou Gemini. Simple, faible latence, fonctionne partout.
- Vertex AI Live : Se connecte à Gemini via Google Cloud avec l'authentification OAuth2 (Application Default Credentials). À utiliser lorsque vous avez besoin d'une authentification d'entreprise et d'une intégration GCP.
- LiveKit WebRTC : Pont WebRTC de qualité production. Achemine l'audio via un serveur LiveKit pour des scénarios évolutifs et multi-participants.
- OpenAI WebRTC : Connexion WebRTC directe à OpenAI avec codec Opus et canaux de données. Nécessite cmake pour la construction de la bibliothèque C Opus.
Constructeur RealtimeAgent
Le RealtimeAgentBuilder fournit une API fluide pour configurer les agents :
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()?;
Détection d'Activité Vocale (VAD)
La VAD permet un flux de conversation naturel en détectant quand l'utilisateur commence et arrête de parler.
VAD Serveur (Recommandé)
let agent = RealtimeAgent::builder("assistant")
.model(model)
.server_vad() // Uses sensible defaults
.build()?;
Configuration VAD Personnalisée
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 Sémantique (Gemini)
Pour les modèles Gemini, vous pouvez utiliser la VAD sémantique qui prend en compte le sens :
let vad = VadConfig {
mode: VadMode::SemanticVad,
eagerness: Some("high".to_string()), // low, medium, high
..Default::default()
};
Appel d'Outils
Les agents Realtime prennent en charge l'appel d'outils pendant les conversations vocales :
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?;
}
_ => {}
}
}
Transferts Inter-Agents
Transférez les conversations entre des agents spécialisés :
// 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()?;
Lorsque le modèle appelle transfer_to_agent, le RealtimeRunner gère automatiquement le transfert.
Formats Audio
| Format | Fréquence d'échantillonnage | Bits | Canaux | Cas d'utilisation |
|---|---|---|---|---|
| PCM16 | 24000 Hz | 16 | Mono | OpenAI (par défaut) |
| PCM16 | 16000 Hz | 16 | Mono | Entrée Gemini |
| G711 u-law | 8000 Hz | 8 | Mono | Téléphonie |
| G711 A-law | 8000 Hz | 8 | Mono | Téléphonie |
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)?;
Types d'événements
Événements du serveur
| Événement | Description |
|---|---|
SessionCreated | Connexion établie |
AudioDelta | Morceau audio (PCM base64) |
TextDelta | Morceau de réponse textuelle |
TranscriptDelta | Transcription audio d'entrée |
FunctionCallDone | Requête d'appel d'outil |
ResponseDone | Réponse terminée |
SpeechStarted | Début de la parole détecté par VAD |
SpeechStopped | Fin de la parole détectée par VAD |
Error | Erreur survenue |
Événements du client
| Événement | Description |
|---|---|
AudioInput | Envoyer un morceau audio |
AudioCommit | Valider le tampon audio |
ItemCreate | Envoyer une réponse textuelle ou d'outil |
CreateResponse | Demander une réponse |
CancelResponse | Annuler la réponse actuelle |
SessionUpdate | Mettre à jour la configuration |
Vertex AI Live (Google Cloud)
Connecter Gemini Live via Vertex AI avec l'authentification d'entreprise (ADC, comptes de service, 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(())
}
Il existe également un constructeur de commodité pour ADC :
let model = GeminiRealtimeModel::vertex_adc(
"us-central1",
"my-project-id",
"models/gemini-live-2.5-flash-native-audio",
).await?;
Vertex AI Live avec appel d'outil
L'exemple vertex_live_tools démontre l'appel de fonction sur une session Vertex AI Live :
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,
_ => {}
}
}
Indicateurs de fonctionnalités
| Fonctionnalité | Dépendances | Cas d'utilisation |
|---|---|---|
vertex-live | gemini + google-cloud-auth | Vertex AI Live avec authentification ADC/compte de service |
livekit | livekit + livekit-api | Pont LiveKit WebRTC |
openai-webrtc | openai + str0m + audiopus | OpenAI WebRTC avec Opus (nécessite cmake) |
full | openai + gemini + vertex-live + livekit | Tous les transports sauf WebRTC |
full-webrtc | full + openai-webrtc | Tout (nécessite cmake) |
Pont LiveKit WebRTC
Pour les applications vocales de production, le pont LiveKit achemine l'audio via un serveur LiveKit pour des scénarios évolutifs et multi-participants.
LiveKitConfig
Configurez les identifiants LiveKit de manière sécurisée. Les clés API et les secrets sont stockés à l'aide de secrecy::SecretString et masqués dans la sortie de débogage :
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() valide le format de l'URL et rejette les identifiants vides au moment de la construction.
LiveKitRoomBuilder
Un constructeur typestate pour se connecter aux salles LiveKit. Le champ identity est requis au moment de la compilation — connect() n'est disponible qu'après qu'il soit défini :
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;
Pontage audio
Utilisez les utilitaires de pontage pour connecter l'audio LiveKit à un 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));
Exemples
Exécutez les exemples inclus :
# 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
Bonnes Pratiques
- Utiliser le VAD du serveur: Laisser le serveur gérer la détection vocale pour une latence réduite
- Gérer les interruptions: Activer
interrupt_responsepour des conversations naturelles - Garder les instructions concises: Les réponses vocales doivent être brèves
- Tester d'abord avec du texte: Déboguer la logique de votre agent avec du texte avant d'ajouter l'audio
- Gérer les erreurs avec élégance: Les problèmes réseau sont fréquents avec les connexions WebSocket
Comparaison avec le SDK OpenAI Agents
L'implémentation en temps réel de ADK-Rust suit le modèle du SDK OpenAI Agents :
| Fonctionnalité | SDK OpenAI | ADK-Rust |
|---|---|---|
| Classe de base de l'agent | Agent | Agent trait |
| Agent en temps réel | RealtimeAgent | RealtimeAgent |
| Outils | Définitions de fonctions | Tool trait + ToolDefinition |
| Passages de relais | transfer_to_agent | sub_agents + outil auto-généré |
| Callbacks | Hooks | before_* / after_* callbacks |
Précédent: ← Graph Agents | Suivant: Model Providers →