الوكلاء الصوتيون الآنيون
يتيح الوكلاء الآنيون تفاعلات قائمة على الصوت مع المساعدين الذكيين باستخدام بث صوتي ثنائي الاتجاه. توفر حزمة adk-realtime واجهة موحدة لبناء وكلاء مُمكّنين صوتيًا يعملون مع OpenAI Realtime API وGemini Live API من Google.
نظرة عامة
يختلف الوكلاء الآنيون عن 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.1.0", features = ["openai"] }
# For Vertex AI Live (Google Cloud with ADC auth)
# adk-realtime = { version = "2.1.0", features = ["vertex-live"] }
# For LiveKit WebRTC bridge
# adk-realtime = { version = "2.1.0", features = ["livekit"] }
# For all transports (except WebRTC which needs cmake)
# adk-realtime = { version = "2.1.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-2.1")
);
// 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-2.1 | WebSocket | openai | PCM16 24kHz |
| OpenAI | gpt-realtime-2.1 | WebRTC | openai-webrtc | Opus |
gemini-3.1-flash-live-preview | WebSocket | gemini | PCM16 16kHz/24kHz | |
| Gemini عبر Vertex AI | WebSocket + OAuth2 | vertex-live | PCM16 16kHz/24kHz | |
| LiveKit | أي (جسر إلى Gemini/OpenAI) | WebRTC | livekit | PCM16 |
ملاحظة: يُعدّ
gpt-realtime-2.1الإعداد الافتراضي الحالي لـ ADK-Rust للوقت الفعلي 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
يوفّر 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()
};
استدعاء الأدوات
تدعم الوكلاء الآنيون استدعاء الأدوات أثناء المحادثات الصوتية:
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 هرتز | 8 | أحادي | الاتصالات الهاتفية |
| G711 A-law | 8000 هرتز | 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 (Google Cloud)
اتصل بـ 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-3.1-flash-live-preview");
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-3.1-flash-live-preview",
).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، وتُحجَب في مخرجات التصحيح:
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 للاتصال بغرف 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 SDK
يتبع التنفيذ الآني في ADK-Rust نمط وكلاء OpenAI SDK:
| الميزة | OpenAI SDK | ADK-Rust |
|---|---|---|
| الفئة الأساسية للوكيل | Agent | سمة Agent |
| وكيل في الوقت الفعلي | RealtimeAgent | RealtimeAgent |
| الأدوات | تعريفات الدوال | Tool trait + ToolDefinition |
| التسليمات | transfer_to_agent | sub_agents + أداة مولدة تلقائيًا |
| عمليات الاستدعاء | الخطافات | عمليات استدعاء before_* / after_* |
السابق: ← وكلاء الرسم البياني | التالي: موفرو النماذج →