Runner

وقت تشغيل التنفيذ من adk-runner الذي يقوم بتنسيق تنفيذ Agent.

نظرة عامة

يدير Runner دورة الحياة الكاملة لتنفيذ Agent:

  • إدارة Session (إنشاء/استرداد Sessions)
  • حقن Memory (البحث عن Memories ذات الصلة وحقنها)
  • التعامل مع Artifact (وصول Artifact محدد النطاق)
  • تدفق Event (معالجة وإعادة توجيه Events)
  • عمليات نقل Agent (التعامل مع التسليمات المتعددة بين Agent)

التثبيت

[dependencies]
adk-runner = "0.2.0"

RunnerConfig

قم بتكوين Runner بالخدمات المطلوبة:

use adk_runner::{Runner, RunnerConfig};
use adk_session::InMemorySessionService;
use adk_artifact::InMemoryArtifactService;
use std::sync::Arc;

let config = RunnerConfig {
    app_name: "my_app".to_string(),
    agent: Arc::new(my_agent),
    session_service: Arc::new(InMemorySessionService::new()),
    artifact_service: Some(Arc::new(InMemoryArtifactService::new())),
    memory_service: None,
    run_config: None,
};

let runner = Runner::new(config)?;

حقول التكوين

الحقلالنوعمطلوبالوصف
app_nameStringنعممعرّف التطبيق
agentArc<dyn Agent>نعمAgent الجذر المراد تنفيذه
session_serviceArc<dyn SessionService>نعمواجهة تخزين Session
artifact_serviceOption<Arc<dyn ArtifactService>>لاتخزين Artifact
memory_serviceOption<Arc<dyn Memory>>لاذاكرة طويلة المدى
run_configOption<RunConfig>لاخيارات التنفيذ

تشغيل Agents

نفّذ Agent بمدخلات المستخدم:

use adk_core::Content;
use futures::StreamExt;

let user_content = Content::new("user").with_text("Hello!");

let mut stream = runner.run(
    "user-123".to_string(),
    "session-456".to_string(),
    user_content,
).await?;

while let Some(event) = stream.next().await {
    match event {
        Ok(e) => {
            if let Some(content) = e.content() {
                for part in &content.parts {
                    if let Some(text) = part.text() {
                        print!("{}", text);
                    }
                }
            }
        }
        Err(e) => eprintln!("Error: {}", e),
    }
}

تدفق التنفيذ

┌─────────────────────────────────────────────────────────────┐
│                     Runner.run()                            │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  1. استرجاع الجلسة                           │
│                                                             │
│   SessionService.get(app_name, user_id, session_id)        │
│   → ينشئ جلسة جديدة إذا لم تكن موجودة                        │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  2. اختيار Agent                            │
│                                                             │
│   التحقق من حالة الجلسة لوجود Agent نشط                     │
│   → استخدام root agent أو transferred agent                 │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                3. إنشاء السياق                               │
│                                                             │
│   InvocationContext مع:                                     │
│   - Session (قابل للتعديل)                                  │
│   - Artifacts (محددة بالنطاق للجلسة)                        │
│   - Memory (إذا تم تكوينها)                                 │
│   - Run config                                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  4. تنفيذ Agent                            │
│                                                             │
│   agent.run(ctx) → EventStream                             │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                 5. معالجة الأحداث                           │
│                                                             │
│   لكل حدث:                                                  │
│   - تحديث حالة الجلسة                                        │
│   - التعامل مع عمليات النقل                                 │
│   - إعادة التوجيه إلى المتصل                                │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  6. حفظ الجلسة                               │
│                                                             │
│   SessionService.append_event(session, events)             │
└─────────────────────────────────────────────────────────────┘

InvocationContext

السياق المقدم للوكلاء أثناء التنفيذ:

pub trait InvocationContext: CallbackContext {
    /// الوكيل الذي يتم تنفيذه
    fn agent(&self) -> Arc<dyn Agent>;
    
    /// خدمة الذاكرة (إذا تم تهيئتها)
    fn memory(&self) -> Option<Arc<dyn Memory>>;
    
    /// الجلسة الحالية
    fn session(&self) -> &dyn Session;
    
    /// تهيئة التنفيذ
    fn run_config(&self) -> &RunConfig;
    
    /// إشارة نهاية الاستدعاء
    fn end_invocation(&self);
    
    /// التحقق مما إذا كان الاستدعاء قد انتهى
    fn ended(&self) -> bool;
}

RunConfig

خيارات التنفيذ:

pub struct RunConfig {
    /// وضع البث للاستجابات
    pub streaming_mode: StreamingMode,
}

pub enum StreamingMode {
    /// لا يوجد بث، إرجاع استجابة كاملة
    None,
    /// أحداث مرسلة من الخادم (افتراضي)
    SSE,
    /// بث ثنائي الاتجاه (في الوقت الفعلي)
    Bidi,
}

ملاحظة: من المخطط إضافة حقول إضافية مثل max_turns و include_history في الإصدارات المستقبلية.

عمليات نقل Agent

يتعامل Runner مع عمليات نقل multi-agent تلقائيًا:

// في أداة agent أو وظيفة رد الاتصال
if should_transfer {
    // تعيين النقل في EventActions
    ctx.set_actions(EventActions {
        transfer_to_agent: Some("specialist_agent".to_string()),
        ..Default::default()
    });
}

سيقوم Runner بما يلي:

  1. اكتشاف طلب النقل في الحدث
  2. البحث عن agent الهدف في sub_agents
  3. تحديث حالة session باستخدام active agent الجديد
  4. متابعة التنفيذ باستخدام الـ agent الجديد

التكامل مع Launcher

يستخدم Launcher الـ Runner داخليًا:

// Launcher ينشئ Runner باستخدام الخدمات الافتراضية
Launcher::new(agent)
    .app_name("my_app")
    .run()
    .await?;

// ما يعادله:
let runner = Runner::new(RunnerConfig {
    app_name: "my_app".to_string(),
    agent,
    session_service: Arc::new(InMemorySessionService::new()),
    artifact_service: Some(Arc::new(FileArtifactService::new("./artifacts")?)),
    memory_service: None,
    run_config: None,
})?;

الاستخدام المخصص لـ Runner

للسيناريوهات المتقدمة، استخدم Runner مباشرة:

use adk_runner::{Runner, RunnerConfig};
use adk_session::DatabaseSessionService;
use adk_artifact::S3ArtifactService;
use adk_memory::QdrantMemoryService;

// تهيئة الإنتاج
let config = RunnerConfig {
    app_name: "production_app".to_string(),
    agent: my_agent,
    session_service: Arc::new(DatabaseSessionService::new(db_pool)),
    artifact_service: Some(Arc::new(S3ArtifactService::new(s3_client))),
    memory_service: Some(Arc::new(QdrantMemoryService::new(qdrant_client))),
    run_config: None,  // يستخدم بث SSE الافتراضي
};

let runner = Runner::new(config)?;

// يُستخدم في معالج HTTP
async fn chat_handler(runner: &Runner, request: ChatRequest) -> Response {
    let stream = runner.run(
        request.user_id,
        request.session_id,
        request.content,
    ).await?;
    
    // بث الأحداث إلى العميل
    Response::sse(stream)
}

السابق: ← Core Types | التالي: Launcher →