Agents Vocaux en Temps Réel
Les agents en temps réel permettent des interactions vocales avec des assistants IA à l'aide d'un 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 importantes :
| Caractéristique | LlmAgent | RealtimeAgent |
|---|---|---|
| Entrée | Texte | Audio/Texte |
| Sortie | Texte | Audio/Texte |
| Connexion | Requêtes HTTP | WebSocket |
| Latence | Requête/réponse | Streaming en temps réel |
| Détection d'activité vocale (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 des outils
- Callbacks (before_agent, after_agent, before_tool, after_tool)
- Transferts vers des sous-agents
Démarrage rapide
Installation
Ajoutez ceci à votre Cargo.toml :
[dependencies]
adk-realtime = { version = "0.2.0", features = ["openai"] }
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-4o-realtime-preview-2024-12-17")
);
// 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 | Drapeau de Fonctionnalité | Format Audio |
|---|---|---|---|
| OpenAI | gpt-4o-realtime-preview-2024-12-17 | openai | PCM16 24kHz |
| OpenAI | gpt-realtime | openai | PCM16 24kHz |
gemini-2.0-flash-live-preview-04-09 | gemini | PCM16 16kHz/24kHz |
Note:
gpt-realtimeest le dernier modèle temps réel d'OpenAI avec une qualité de parole, des émotions et des capacités d'appel de fonctions améliorées.
Générateur RealtimeAgent
Le RealtimeAgentBuilder fournit une API fluide pour la configuration des 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() // Utilise des valeurs par défaut pertinentes
.build()?;
Configuration VAD Personnalisée
use adk_realtime::{VadConfig, VadMode};
let vad = VadConfig {
mode: VadMode::ServerVad,
threshold: Some(0.5), // Sensibilité de détection de la parole (0.0-1.0)
prefix_padding_ms: Some(300), // Audio à inclure avant la parole
silence_duration_ms: Some(500), // Silence avant de terminer le tour de parole
interrupt_response: Some(true), // Autoriser l'interruption de l'assistant
eagerness: None, // Pour le mode SemanticVad
};
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()), // faible, moyen, élevé
..Default::default()
};
Appel d'outils
Les agents temps réel prennent en charge l'appel d'outils pendant les conversations vocales :
use adk_realtime::{config::ToolDefinition, ToolResponse};
use serde_json::json;
// Définir les outils
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?;
// Gérer les appels d'outils dans la boucle d'événements
while let Some(event) = session.next_event().await {
match event? {
ServerEvent::FunctionCallDone { call_id, name, arguments, .. } => {
// Exécuter l'outil
let result = execute_tool(&name, &arguments);
// Envoyer la réponse
let response = ToolResponse::new(&call_id, result);
session.send_tool_response(response).await?;
}
_ => {}
}
}
Transferts multi-agents
Transférer les conversations entre des agents spécialisés :
// Créer des sous-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()?);
// Créer l'agent principal avec des sous-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};
// Créer un format audio
let format = AudioFormat::pcm16_24khz();
// Travailler avec des morceaux audio
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 serveur
| Événement | Description |
|---|---|
SessionCreated | Connexion établie |
AudioDelta | Morceau audio (PCM base64) |
TextDelta | Morceau de réponse texte |
TranscriptDelta | Transcription audio d'entrée |
FunctionCallDone | Requête d'appel d'outil |
ResponseDone | Réponse terminée |
SpeechStarted | Début de parole détecté par VAD |
SpeechStopped | Fin de parole détectée par VAD |
Error | Erreur survenue |
Événements client
| Événement | Description |
|---|---|
AudioInput | Envoyer un morceau audio |
AudioCommit | Valider le tampon audio |
ItemCreate | Envoyer du texte ou une réponse d'outil |
CreateResponse | Demander une réponse |
CancelResponse | Annuler la réponse actuelle |
SessionUpdate | Mettre à jour la configuration |
Exemples
Exécuter les exemples inclus :
# Session texte basique uniquement
cargo run --example realtime_basic --features realtime-openai
# Assistant vocal avec VAD
cargo run --example realtime_vad --features realtime-openai
# Appel d'outils
cargo run --example realtime_tools --features realtime-openai
# Transferts multi-agents
cargo run --example realtime_handoff --features realtime-openai
Bonnes Pratiques
- Utiliser le VAD du serveur : Laisser le serveur gérer la détection vocale pour une latence plus faible
- 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 de réseau sont courants avec les connexions WebSocket
Comparaison avec le SDK OpenAI Agents
L'implémentation temps réel d'adk-rust suit le modèle du SDK OpenAI Agents :
| Fonctionnalité | OpenAI SDK | ADK-Rust |
|---|---|---|
| Classe de base d'Agent | Agent | Trait Agent |
| Agent en temps réel | RealtimeAgent | RealtimeAgent |
| Outils | Définitions de fonctions | Trait Tool + ToolDefinition |
| Transferts | transfer_to_agent | sub_agents + outil auto-généré |
| Rappels | Hooks | Callbacks before_* / after_* |
Précédent: ← Graph Agents | Suivant: Model Providers →