وكلاء الصوت في الوقت الفعلي
تُمكّن وكلاء الصوت في الوقت الفعلي التفاعلات الصوتية مع مساعدي الذكاء الاصطناعي باستخدام تدفق الصوت ثنائي الاتجاه. يوفر adk-realtime crate واجهة موحدة لبناء وكلاء يدعمون الصوت ويعملون مع OpenAI's Realtime API و Google's Gemini Live API.
نظرة عامة
يختلف وكلاء الصوت في الوقت الفعلي عن LlmAgents المستندة إلى النصوص بعدة طرق رئيسية:
| الميزة | LlmAgent | RealtimeAgent |
|---|---|---|
| الإدخال | نص | صوت/نص |
| الإخراج | نص | صوت/نص |
| الاتصال | طلبات HTTP | WebSocket |
| الكمون | طلب/استجابة | بث مباشر في الوقت الفعلي |
| VAD | لا ينطبق | اكتشاف الصوت من جانب الخادم |
البنية
┌─────────────────────────────────────────┐
│ Agent Trait │
│ (name, description, run, sub_agents) │
└────────────────┬────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
┌──────▼──────┐ ┌─────────▼─────────┐ ┌─────────▼─────────┐
│ LlmAgent │ │ RealtimeAgent │ │ SequentialAgent │
│ (text-based)│ │ (voice-based) │ │ (workflow) │
└─────────────┘ └───────────────────┘ └───────────────────┘
RealtimeAgent يطبق نفس Agent السمة مثل LlmAgent، مشاركًا في:
- التعليمات (الثابتة والديناميكية)
- تسجيل الأدوات وتنفيذها
- دوال الاستدعاء العكسي (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(())
}
الموفرون المدعومون
| مزود | نموذج | النقل | علامة الميزة | تنسيق الصوت |
|---|---|---|---|---|
| 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 عبر Vertex AI | WebSocket + OAuth2 | vertex-live | PCM16 16kHz/24kHz | |
| LiveKit | أي (جسر إلى Gemini/OpenAI) | WebRTC | livekit | PCM16 |
ملاحظة:
gpt-realtimeهو أحدث نموذج في الوقت الفعلي من OpenAI مع جودة كلام محسنة وعواطف وقدرات استدعاء الوظائف.
خيارات النقل
يدعم ADK-Realtime طبقات نقل متعددة:
- WebSocket (افتراضي): اتصال مباشر بـ OpenAI أو Gemini. بسيط، زمن انتقال منخفض، يعمل في كل مكان.
- Vertex AI Live: يتصل بـ Gemini عبر Google Cloud مع مصادقة OAuth2 (بيانات اعتماد التطبيق الافتراضية). استخدمه عندما تحتاج إلى مصادقة مؤسسية وتكامل GCP.
- LiveKit WebRTC: جسر WebRTC بجودة إنتاجية. يوجه الصوت عبر خادم LiveKit لسيناريوهات قابلة للتطوير ومتعددة المشاركين.
- OpenAI WebRTC: اتصال WebRTC مباشر بـ OpenAI مع برنامج ترميز Opus وقنوات البيانات. يتطلب cmake لبناء مكتبة Opus C.
RealtimeAgent Builder
يوفر 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 تدفق المحادثة الطبيعي من خلال اكتشاف متى يبدأ المستخدم ويتوقف عن الكلام.
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()
};
استدعاء الأدوات
تدعم وكلاء Realtime استدعاء الأدوات أثناء المحادثات الصوتية:
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?;
}
_ => {}
}
}
تسليم المهام بين وكلاء متعددين
نقل المحادثات بين وكلاء متخصصين:
// 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 مع التسليم تلقائيًا.
تنسيقات الصوت
| التنسيق | معدل العينة | البتات | القنوات | حالة الاستخدام |
|---|---|---|---|---|
| PCM16 | 24000 Hz | 16 | أحادي | OpenAI (افتراضي) |
| PCM16 | 16000 Hz | 16 | أحادي | مدخلات Gemini |
| G711 u-law | 8000 Hz | 8 | أحادي | الاتصالات الهاتفية |
| G711 A-law | 8000 Hz | 8 | أحادي | الاتصالات الهاتفية |
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 | جزء صوتي (PCM base64) |
TextDelta | جزء استجابة نصي |
TranscriptDelta | نسخة صوتية للمدخلات |
FunctionCallDone | طلب استدعاء أداة |
ResponseDone | اكتملت الاستجابة |
SpeechStarted | بداية الكلام المكتشف بواسطة VAD |
SpeechStopped | نهاية الكلام المكتشف بواسطة VAD |
Error | حدث خطأ |
أحداث العميل
| الحدث | الوصف |
|---|---|
AudioInput | إرسال جزء صوتي |
AudioCommit | تثبيت مخزن الصوت المؤقت |
ItemCreate | إرسال نص أو استجابة أداة |
CreateResponse | طلب استجابة |
CancelResponse | إلغاء الاستجابة الحالية |
SessionUpdate | تحديث التكوين |
Vertex AI Live (جوجل كلاود)
اتصل بـ Gemini Live عبر Vertex AI باستخدام مصادقة المؤسسة (ADC، حسابات الخدمة، 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 مع استدعاء الأدوات
يوضح المثال vertex_live_tools استدعاء الدوال عبر جلسة 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,
_ => {}
}
}
علامات الميزات
| ميزة | التبعيات | حالة الاستخدام |
|---|---|---|
vertex-live | gemini + google-cloud-auth | Vertex AI Live مع مصادقة ADC/حساب الخدمة |
livekit | livekit + livekit-api | LiveKit WebRTC جسر |
openai-webrtc | openai + str0m + audiopus | OpenAI WebRTC مع Opus (يتطلب cmake) |
full | openai + gemini + vertex-live + livekit | جميع وسائل النقل باستثناء WebRTC |
full-webrtc | full + openai-webrtc | كل شيء (يتطلب cmake) |
LiveKit WebRTC جسر
لتطبيقات الصوت الإنتاجية، يوجه جسر LiveKit الصوت عبر خادم LiveKit لسيناريوهات قابلة للتطوير ومتعددة المشاركين.
LiveKitConfig
قم بتكوين بيانات اعتماد LiveKit بشكل آمن. يتم تخزين مفاتيح وأسرار API باستخدام secrecy::SecretString ويتم إخفاؤها في مخرجات Debug:
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
منشئ حالة نوع (typestate builder) للاتصال بغرف 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
أفضل الممارسات
- استخدم VAD الخادم: دع الخادم يتعامل مع اكتشاف الكلام لتقليل زمن الاستجابة
- تعامل مع المقاطعات: قم بتمكين
interrupt_responseللمحادثات الطبيعية - اجعل التعليمات موجزة: يجب أن تكون الاستجابات الصوتية موجزة
- اختبر بالنص أولاً: قم بتصحيح منطق وكيلك بالنص قبل إضافة الصوت
- تعامل مع الأخطاء بلطف: مشكلات الشبكة شائعة مع اتصالات WebSocket
مقارنة مع OpenAI Agents SDK
تطبيق ADK-Rust في الوقت الفعلي يتبع نمط OpenAI Agents SDK:
| الميزة | OpenAI SDK | ADK-Rust |
|---|---|---|
| فئة Agent الأساسية | Agent | Agent trait |
| Agent في الوقت الفعلي | RealtimeAgent | RealtimeAgent |
| الأدوات | تعريفات الدوال | Tool trait + ToolDefinition |
| التسليمات | transfer_to_agent | sub_agents + أداة تم إنشاؤها تلقائيًا |
| وظائف الاستدعاء | الخطافات | before_* / after_* callbacks |
السابق: ← Graph Agents | التالي: موفرو النماذج →