Echtzeit-Sprach-Agents
Realtime agents ermöglichen sprachbasierte Interaktionen mit KI-Assistenten unter Verwendung von bidirektionalem Audio-Streaming. Das adk-realtime crate bietet eine einheitliche Schnittstelle zum Erstellen von sprachfähigen Agents, die mit OpenAI's Realtime API und Google's Gemini Live API funktionieren.
Übersicht
Realtime agents unterscheiden sich in mehreren wesentlichen Punkten von textbasierten LlmAgents:
| Merkmal | LlmAgent | RealtimeAgent |
|---|---|---|
| Eingabe | Text | Audio/Text |
| Ausgabe | Text | Audio/Text |
| Verbindung | HTTP requests | WebSocket |
| Latenz | Anfrage/Antwort | Echtzeit-Streaming |
| VAD | N/A | Serverseitige Spracherkennung |
Architektur
┌─────────────────────────────────────────┐
│ Agent Trait │
│ (name, description, run, sub_agents) │
└────────────────┬────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
┌──────▼──────┐ ┌─────────▼─────────┐ ┌─────────▼─────────┐
│ LlmAgent │ │ RealtimeAgent │ │ SequentialAgent │
│ (text-based)│ │ (voice-based) │ │ (workflow) │
└─────────────┘ └───────────────────┘ └───────────────────┘
RealtimeAgent implementiert dasselbe Agent trait wie LlmAgent, wobei Folgendes geteilt wird:
- Anweisungen (statisch und dynamisch)
- Tool-Registrierung und -Ausführung
- Callbacks (before_agent, after_agent, before_tool, after_tool)
- Sub-Agent-Übergaben
Schnellstart
Installation
Fügen Sie Ihrem Cargo.toml hinzu:
[dependencies]
adk-realtime = { version = "0.2.0", features = ["openai"] }
Grundlegende Verwendung
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")?;
// Erstellen des Echtzeit-Modells
let model: Arc<dyn RealtimeModel> = Arc::new(
OpenAIRealtimeModel::new(&api_key, "gpt-4o-realtime-preview-2024-12-17")
);
// Erstellen des Echtzeit-Agents
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()?;
// Oder verwenden Sie die Low-Level-Session-API direkt
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?;
// Text senden und Antwort erhalten
session.send_text("Hello!").await?;
session.create_response().await?;
// Ereignisse verarbeiten
while let Some(event) = session.next_event().await {
match event? {
ServerEvent::TextDelta { delta, .. } => print!("{}", delta),
ServerEvent::AudioDelta { delta, .. } => {
// Audio abspielen (delta ist base64-kodiertes PCM)
}
ServerEvent::ResponseDone { .. } => break,
_ => {}
}
}
Ok(())
}
Unterstützte Anbieter
| Anbieter | Modell | Feature-Flag | Audioformat |
|---|---|---|---|
| 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 |
Hinweis:
gpt-realtimeist OpenAI's neuestes Echtzeitmodell mit verbesserter Sprachqualität, Emotionen und Function Calling-Fähigkeiten.
RealtimeAgent Builder
Der RealtimeAgentBuilder bietet eine fließende API zur Konfiguration von Agents:
let agent = RealtimeAgent::builder("assistant")
// Erforderlich
.model(model)
// Anweisungen (wie bei LlmAgent)
.instruction("You are helpful.")
.instruction_provider(|ctx| format!("User: {}", ctx.user_name()))
// Spracheinstellungen
.voice("alloy") // Optionen: alloy, coral, sage, shimmer, etc.
// Spracherkennung (VAD)
.server_vad() // Standardwerte verwenden
.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 (wie bei LlmAgent)
.tool(Arc::new(weather_tool))
.tool(Arc::new(search_tool))
// Sub-Agents für Übergaben
.sub_agent(booking_agent)
.sub_agent(support_agent)
// Callbacks (wie bei 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-spezifische Callbacks
.on_audio(|audio_chunk| { /* Audio abspielen */ })
.on_transcript(|text| { /* Transkript anzeigen */ })
.build()?;
Spracherkennung (VAD)
VAD ermöglicht einen natürlichen Gesprächsfluss, indem es erkennt, wann der Benutzer zu sprechen beginnt und aufhört.
Server-VAD (Empfohlen)
let agent = RealtimeAgent::builder("assistant")
.model(model)
.server_vad() // Verwendet sinnvolle Standardwerte
.build()?;
Benutzerdefinierte VAD-Konfiguration
use adk_realtime::{VadConfig, VadMode};
let vad = VadConfig {
mode: VadMode::ServerVad,
threshold: Some(0.5), // Empfindlichkeit der Spracherkennung (0.0-1.0)
prefix_padding_ms: Some(300), // Audio, das vor der Sprache eingeschlossen werden soll
silence_duration_ms: Some(500), // Stille, bevor die Sprechphase beendet wird
interrupt_response: Some(true), // Assistenten unterbrechen erlauben
eagerness: None, // Für den SemanticVad-Modus
};
let agent = RealtimeAgent::builder("assistant")
.model(model)
.vad(vad)
.build()?;
Semantische VAD (Gemini)
Für Gemini-Modelle können Sie semantische VAD verwenden, die die Bedeutung berücksichtigt:
let vad = VadConfig {
mode: VadMode::SemanticVad,
eagerness: Some("high".to_string()), // niedrig, mittel, hoch
..Default::default()
};
Tool-Aufrufe
adk-realtime-Agenten unterstützen Tool-Aufrufe während Sprachkonversationen:
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?;
}
_ => {}
}
}
Multi-Agenten-Übergaben
Übertragen Sie Konversationen zwischen spezialisierten Agenten:
// 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()?;
Wenn das Modell transfer_to_agent aufruft, übernimmt der RealtimeRunner die Übergabe automatisch.
Audioformate
| Format | Abtastrate | Bits | Kanäle | Anwendungsfall |
|---|---|---|---|---|
| PCM16 | 24000 Hz | 16 | Mono | OpenAI (Standard) |
| PCM16 | 16000 Hz | 16 | Mono | Gemini-Eingabe |
| G711 u-law | 8000 Hz | 8 | Mono | Telefonie |
| G711 A-law | 8000 Hz | 8 | Mono | Telefonie |
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)?;
Ereignistypen
Server-Ereignisse
| Ereignis | Beschreibung |
|---|---|
SessionCreated | Verbindung hergestellt |
AudioDelta | Audio-Chunk (base64 PCM) |
TextDelta | Textantwort-Chunk |
TranscriptDelta | Transkript der Audioeingabe |
FunctionCallDone | Tool-Aufrufanfrage |
ResponseDone | Antwort abgeschlossen |
SpeechStarted | VAD hat Sprachbeginn erkannt |
SpeechStopped | VAD hat Sprach_ende_ erkannt |
Error | Fehler aufgetreten |
Client-Ereignisse
| Ereignis | Beschreibung |
|---|---|
AudioInput | Audio-Chunk senden |
AudioCommit | Audio-Puffer committen |
ItemCreate | Text- oder Tool-Antwort senden |
CreateResponse | Antwort anfordern |
CancelResponse | Aktuelle Antwort abbrechen |
SessionUpdate | Konfiguration aktualisieren |
Beispiele
Führen Sie die enthaltenen Beispiele aus:
# Basic text-only session
cargo run --example realtime_basic --features realtime-openai
# Voice assistant with VAD
cargo run --example realtime_vad --features realtime-openai
# Tool calling
cargo run --example realtime_tools --features realtime-openai
# Multi-agent handoffs
cargo run --example realtime_handoff --features realtime-openai
Best Practices
- Server VAD verwenden: Lassen Sie den Server die Spracherkennung für geringere Latenz handhaben
- Unterbrechungen handhaben: Aktivieren Sie
interrupt_responsefür natürliche Gespräche - Anweisungen prägnant halten: Sprachantworten sollten kurz sein
- Zuerst mit Text testen: Debuggen Sie Ihre Agent-Logik mit Text, bevor Sie Audio hinzufügen
- Fehler elegant behandeln: Netzwerkprobleme sind bei WebSocket-Verbindungen üblich
Vergleich mit dem OpenAI Agents SDK
Die Echtzeit-Implementierung von adk-rust folgt dem OpenAI Agents SDK-Muster:
| Funktion | OpenAI SDK | ADK-Rust |
|---|---|---|
| Agent-Basisklasse | Agent | Agent trait |
| Echtzeit-Agent | RealtimeAgent | RealtimeAgent |
| Tools | Funktionsdefinitionen | Tool trait + ToolDefinition |
| Übergaben | transfer_to_agent | sub_agents + automatisch generierte Tool |
| Callbacks | Hooks | before_* / after_* Callbacks |
Vorherige: ← Graph Agents | Nächste: Modell-Anbieter →