وكلاء الصوت في الوقت الفعلي
تُمكّن وكلاء الوقت الفعلي التفاعلات الصوتية مع المساعدين المدعومين بالذكاء الاصطناعي باستخدام تدفق الصوت ثنائي الاتجاه. يوفر adk-realtime crate واجهة موحدة لبناء وكلاء يدعمون الصوت ويعملون مع OpenAI's Realtime API و Google's Gemini Live API.
نظرة عامة
يختلف وكلاء الوقت الفعلي عن LlmAgent النصيين بعدة طرق رئيسية:
| الميزة | LlmAgent | RealtimeAgent |
|---|---|---|
| المدخلات | Text | Audio/Text |
| المخرجات | Text | Audio/Text |
| الاتصال | HTTP requests | WebSocket |
| الاستجابة | Request/response | Real-time streaming |
| VAD | N/A | اكتشاف الصوت من جانب الخادم |
البنية
┌─────────────────────────────────────────┐
│ Agent Trait │
│ (name, description, run, sub_agents) │
└────────────────┬────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
┌──────▼──────┐ ┌─────────▼─────────┐ ┌─────────▼─────────┐
│ LlmAgent │ │ RealtimeAgent │ │ SequentialAgent │
│ (text-based)│ │ (voice-based) │ │ (workflow) │
└─────────────┘ └───────────────────┘ └───────────────────┘
يطبق RealtimeAgent نفس Agent trait مثل LlmAgent، ويتشاركان في:
- التعليمات (ثابتة وديناميكية)
- تسجيل الأدوات وتنفيذها
- استدعاءات الرد (before_agent, after_agent, before_tool, after_tool)
- تسليم وكلاء فرعيين
البدء السريع
التثبيت
أضف إلى Cargo.toml الخاص بك:
[dependencies]
adk-realtime = { version = "0.2.0", features = ["openai"] }
الاستخدام الأساسي
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")?;
// أنشئ نموذج الوقت الفعلي
let model: Arc<dyn RealtimeModel> = Arc::new(
OpenAIRealtimeModel::new(&api_key, "gpt-4o-realtime-preview-2024-12-17")
);
// ابنِ وكيل الوقت الفعلي
let agent = RealtimeAgent::builder("voice_assistant")
.model(model.clone())
.instruction("You are a helpful voice assistant. Be concise.")
.voice("alloy")
.server_vad() // تفعيل اكتشاف النشاط الصوتي
.build()?;
// أو استخدم واجهة برمجة تطبيقات الجلسة ذات المستوى المنخفض مباشرةً
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?;
// أرسل نصًا واحصل على استجابة
session.send_text("Hello!").await?;
session.create_response().await?;
// عالج الأحداث
while let Some(event) = session.next_event().await {
match event? {
ServerEvent::TextDelta { delta, .. } => print!("{}", delta),
ServerEvent::AudioDelta { delta, .. } => {
// شغل الصوت (دلتا هي PCM مشفرة بـ base64)
}
ServerEvent::ResponseDone { .. } => break,
_ => {}
}
}
Ok(())
}
موفرو الخدمة المدعومون
| الموفر | النموذج | علامة الميزة | تنسيق الصوت |
|---|---|---|---|
| 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 |
ملاحظة:
gpt-realtimeهو أحدث نموذج في الوقت الفعلي من OpenAI مع جودة كلام محسنة، وعواطف، وقدرات استدعاء الوظائف.
بناء RealtimeAgent
يوفر RealtimeAgentBuilder واجهة برمجة تطبيقات سلسة لتكوين العملاء (agents):
let agent = RealtimeAgent::builder("assistant")
// مطلوب
.model(model)
// التعليمات (نفس LlmAgent)
.instruction("You are helpful.")
.instruction_provider(|ctx| format!("User: {}", ctx.user_name()))
// إعدادات الصوت
.voice("alloy") // الخيارات: alloy, coral, sage, shimmer, إلخ.
// كشف نشاط الصوت (Voice Activity Detection)
.server_vad() // استخدم الإعدادات الافتراضية
.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,
})
// الأدوات (نفس LlmAgent)
.tool(Arc::new(weather_tool))
.tool(Arc::new(search_tool))
// العملاء الفرعيون للتسليم
.sub_agent(booking_agent)
.sub_agent(support_agent)
// ردود الاتصال (نفس 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) })
// ردود الاتصال الخاصة بالوقت الفعلي
.on_audio(|audio_chunk| { /* تشغيل الصوت */ })
.on_transcript(|text| { /* عرض النص */ })
.build()?;
كشف نشاط الصوت (VAD)
يمكّن VAD تدفق المحادثة الطبيعي من خلال الكشف عن متى يبدأ المستخدم ويتوقف عن التحدث.
Server VAD (موصى به)
let agent = RealtimeAgent::builder("assistant")
.model(model)
.server_vad() // يستخدم إعدادات افتراضية معقولة
.build()?;
تكوين VAD مخصص
use adk_realtime::{VadConfig, VadMode};
let vad = VadConfig {
mode: VadMode::ServerVad,
threshold: Some(0.5), // حساسية كشف الكلام (0.0-1.0)
prefix_padding_ms: Some(300), // الصوت المراد تضمينه قبل الكلام
silence_duration_ms: Some(500), // الصمت قبل إنهاء الدور
interrupt_response: Some(true), // السماح بمقاطعة المساعد
eagerness: None, // لوضع SemanticVad
};
let agent = RealtimeAgent::builder("assistant")
.model(model)
.vad(vad)
.build()?;
Semantic VAD (Gemini)
بالنسبة لنماذج Gemini، يمكنك استخدام Semantic VAD الذي يأخذ المعنى في الاعتبار:
let vad = VadConfig {
mode: VadMode::SemanticVad,
eagerness: Some("high".to_string()), // منخفض، متوسط، مرتفع
..Default::default()
};
استدعاء الأدوات
تدعم Agents في الوقت الفعلي استدعاء الأدوات أثناء المحادثات الصوتية:
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()?;
عندما يقوم Model باستدعاء transfer_to_agent، يتعامل RealtimeRunner مع التسليم تلقائيًا.
تنسيقات الصوت
| التنسيق | معدل العينة | البتات | القنوات | حالة الاستخدام |
|---|---|---|---|---|
| PCM16 | 24000 Hz | 16 | أحادي | OpenAI (افتراضي) |
| PCM16 | 16000 Hz | 16 | أحادي | Gemini input |
| 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 | جزء صوتي (base64 PCM) |
TextDelta | جزء استجابة نصية |
TranscriptDelta | نص الصوت المدخل |
FunctionCallDone | طلب استدعاء الأداة |
ResponseDone | اكتملت الاستجابة |
SpeechStarted | VAD كشف بداية الكلام |
SpeechStopped | VAD كشف نهاية الكلام |
Error | حدث خطأ |
أحداث العميل
| الحدث | الوصف |
|---|---|
AudioInput | إرسال جزء صوتي |
AudioCommit | تأكيد مخزن الصوت المؤقت |
ItemCreate | إرسال نص أو استجابة أداة |
CreateResponse | طلب استجابة |
CancelResponse | إلغاء الاستجابة الحالية |
SessionUpdate | تحديث التكوين |
أمثلة
قم بتشغيل الأمثلة المضمنة:
# 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
أفضل الممارسات
- استخدام Server VAD: دع الخادم يتعامل مع اكتشاف الكلام للحصول على زمن وصول أقل
- التعامل مع الانقطاعات: قم بتمكين
interrupt_responseللمحادثات الطبيعية - الحفاظ على التعليمات موجزة: يجب أن تكون الردود الصوتية قصيرة
- الاختبار بالنص أولاً: قم بتصحيح منطق الوكيل الخاص بك بالنص قبل إضافة الصوت
- التعامل مع الأخطاء بسلاسة: مشاكل الشبكة شائعة مع اتصالات WebSocket
مقارنة مع OpenAI Agents SDK
يتبع التنفيذ في الوقت الفعلي في adk-rust نمط OpenAI Agents SDK:
| الميزة | OpenAI SDK | adk-rust |
|---|---|---|
| Agent base class | Agent | Agent trait |
| Realtime agent | RealtimeAgent | RealtimeAgent |
| Tools | تعريفات الوظائف | Tool trait + ToolDefinition |
| Handoffs | transfer_to_agent | sub_agents + أداة يتم إنشاؤها تلقائياً |
| Callbacks | Hooks | before_* / after_* callbacks |
السابق: ← Graph Agents | التالي: Model Providers →