Skip to main content

تسليمات أم وكلاء فرعيون؟

البدء السريع

أعطِ كل هدف name وdescription (يقرأ النموذج الوصف ليقرر متى يسلّم)، ثم مرّرها إلى وكيل الفرز في handoffs. تختار بادئة النموذج vendor/ المزوّد؛ ومع OpenRouter استخدم openrouter/<vendor>/<model> (مثل openrouter/openai/gpt-4o-mini):
يُعرض كل هدف على النموذج أداةً واحدة اسمها transfer_to_<name> (transfer_to_billing وtransfer_to_tech-support). حين يستدعيها النموذج، يتابع التشغيل بصفة الهدف ضمن استدعاء send() / stream() نفسه. وresult.agentName هو اسم الوكيل الذي أنتج الرد النهائي. يجب أن يأتي الهدف من createAgent() وأن يكون له name (فريد بين التسليمات) وdescription (أو description في handoff())؛ وإلا يرمي createAgent() الخطأ LOUSHO_CONFIG_INVALID. ولا يجوز أن يشارك اسم أداة التسليم اسمَ إحدى أدوات الوكيل.

خيارات handoff()

غلّف الهدف بـ handoff() لضبطه:

مرشحات الإدخال

يرى الهدف المحادثة كما يعيدها inputFilter، تحت موجّه النظام الخاص به (موجّه النظام للوكيل الذي سلّم يُستبدل ولا يُحتفظ به أبدًا). يتلقى المرشح { messages, from, to, args }؛ وmessages هي السجل حتى تلك اللحظة بلا موجّه النظام، وتنتهي باستدعاء التسليم ونتيجته. يوجد مرشحان مضمَّنان:
  • handoffFilters.removeToolCalls: يُبقي نص المستخدم والمساعد، ويحذف استدعاءات الأدوات ونتائجها.
  • handoffFilters.lastUserMessage: يُبقي آخر رسالة للمستخدم فقط.
ما يعيده المرشح يصبح سجل التشغيل: ويستمر كل من result.messages وسجل الجلسة منه. ويجب أن يُبقي المرشح رسالة واحدة على الأقل. أما الموافقات التي جرى تذكّرها بـ once() في الجزء الأسبق من السجل فتُسقَط عند التسليم، فتعود أدوات الهدف إلى طلب الموافقة.

ما الذي يتبدل وما الذي يبقى

الوكيل الذي بدأ به التشغيل هو الوكيل الرئيسي. لا يحصل الهدف على أي من أدوات الوكيل الرئيسي أو وكلائه الفرعيين أو خانات الذاكرة الخاصة به؛ ولا تُستخدم خانات الذاكرة الخاصة بالهدف أيضًا (كما في الوكيل الفرعي). وتُضاف تعليمات output الخاصة بالوكيل الرئيسي إلى موجّه النظام لكل هدف.

الجلسات

في الجلسة، الوكيل النشط هو الذي سلّم إليه السجل آخر مرة (قيمة to في آخر علامة metadata.handoff)، فيشغّل الاستدعاء التالي session.send() / session.stream() ذلك الوكيل:
أما agent.send() بلا جلسة فيبدأ دائمًا من الوكيل الرئيسي. يعيد الهدف التسليم عبر handoffs الخاصة به. ولأن الوكيل الرئيسي يُنشأ بعد أهدافه، أعطِ الهدف مصفوفة ثم أضف إليها الوكيل الرئيسي لاحقًا (تُقرأ المصفوفة عند كل تشغيل):
الأسماء هي التي تحدد الوكلاء: يجب أن يكون لكل وكيل يمكن الوصول إليه عبر handoffs اسمه الخاص. وإذا لم يعد الوكيل الذي يذكره السجل قابلًا للوصول، يعمل الوكيل الرئيسي.

الموافقات والاستئناف بعد التسليم

أداة الهدف التي تحتاج إلى موافقة توقف التشغيل في مخزن الموافقات الخاص بالوكيل الرئيسي؛ ويتابعه agent.approvals.resolve() على الوكيل الرئيسي بصفة الهدف. والتشغيل ذو نقاط الحفظ (send(message, { sessionId }) أو جلسة لها مخزن) الذي تعطّل بعد تسليم يُستأنف بصفة الهدف عبر agent.resume(id) أو session.resume(). ويقارن فحص الانجراف عند الاستئناف (onAgentDrift، انظر التنفيذ المتين) ببصمة الهدف المحفوظة. وحين تحتوي خطوة على استدعاء تسليم بجانب استدعاء يتوقف انتظارًا لموافقة، ينتظر التسليم: يتوقف التشغيل بصفة الوكيل الذي سلّم، ويحدث التسليم بعد البتّ في الموافقة وتنفيذ الاستدعاءات الأخرى في الخطوة.

الأحداث

يُبلَّغ عن التسليم بين tool.start / tool.done الخاصين باستدعاء التسليم وأول step.start للهدف:
يحمل handoff الحقول from وto وtoolCallId. وللتشغيل run.start واحد وrun.done واحد مهما بلغ عدد التسليمات. انظر مخطط الأحداث.

القيود

  • تسليم واحد فقط في الدورة الواحدة للنموذج: حين تستدعي الدورة عدة أدوات تسليم، يُنفَّذ الأول وتحصل الباقية على خطأ أداة.
  • maxHandoffs (خيار في createAgent()، وقيمته الافتراضية 5) يحدّ عدد تسليمات التشغيل الواحد، لمنع الوكلاء من تمرير المحادثة ذهابًا وإيابًا. أي استدعاء تسليم يتجاوز الحد يحصل على خطأ أداة ويجيب الوكيل بنفسه. والتشغيل الذي يُستأنف بعد موافقة أو بعد تعطل يبدأ العدّ من الصفر مجددًا.
  • لا يمكن أن تكون الوكلاء البعيدة (remoteAgent()) أهدافًا للتسليم؛ استخدمها وكلاء فرعيين.
  • لا يعيد الهدف التسليم من تلقاء نفسه في نهاية دورته؛ أعطِه تسليمًا إلى الوكيل الرئيسي (انظر الجلسات).

واجهة المنفِّذ البرمجية

يقبل AgentExecutor.execute() الخيارين handoffs (ResolvedHandoff[]: name وtoolName وdescription وinput وspec(input) الذي يحدد إعداد تشغيل الهدف وتسليماته الخاصة، وinputFilter وonHandoff) وmaxHandoffs. يبنيها createAgent()؛ ولا تمرّرها بنفسك إلا حين تشغّل المنفِّذ مباشرة.