1. نظرة عامة
عنوان ADK 2 هو ثلاثة أنماط تنسيق. يعلّمك هذا الدرس التطبيقي حول الترميز كيفية استخدام هذه الأدوات الثلاث من خلال إنشاء تطبيق واحد، وهو مدرب يوم سباق الماراثون، وذلك من خلال إنشاء حلقة قابلة للتنفيذ في كل مرة. يجيب كل مستوى على سؤال واحد، ويضيف فكرة واحدة، ويعمل بشكل مستقل.
أهداف الدورة التعليمية
- مخططات سير العمل (الركيزة 1): عندما يمكنك رسم المسار قبل وصول الإدخال
- الوكلاء التعاونيون (الركيزة 2): عندما تعرف الفريق ولكن الطلب يختار المجموعة الفرعية، وأوضاع التعاون الثلاثة (
chat/task/single_turn) تعمل جميعها مباشرةً. - سير العمل الديناميكي (الركيزة 3): عندما يعتمد شكل العمل نفسه على الإدخال.
- كيفية الاختيار: شجرة قرارات تتضمّن سؤالاً واحدًا، وكيفية تكوين الأنماط
الرابط المشترك
بنية معروفة → فريق معروف / مجموعة فرعية من المتغيرات → شكل غير معروف → اختيار الشكل الصحيح

ما ستنشئه
جمّع أحد التطبيقات، وهو Marathon Race Day Coach، مستوى واحدًا قابلاً للتشغيل في كل مرة. كل مستوى هو وحدة Python عادية يمكنك تشغيلها من الجهاز. وبحلول المستوى 5، ستكون جميع الأجزاء أدناه ملكًا لك.
تم رسم الصورة من الرمز البرمجي الذي يتم تنفيذه: تم قراءة كل خط متصل من Workflow.graph.edges. وهذا هو الدرس الأول: الأجزاء التي يمكن رسمها مسبقًا هي بالضبط العمود 1، والأجزاء التي لا يمكن رسمها مسبقًا هي سبب وجود العمودين 2 و3.

المتطلبات
- حساب Google (لـ Colab) — لا يلزم إجراء أي إعدادات محلية
- 50 دقيقة تقريبًا (المستويان 4 هما الأطول، لذا يجب تخصيص وقت كافٍ لهما).
- إحدى طريقتَين للوصول إلى نموذج Gemini اختيار مسار: يمكنك تنفيذ خطوة واحدة من خطوات الإعداد وتخطّي الخطوة الأخرى:
🎓 ورشة عمل | 🏠 التقييم المنزلي | |
الحضور | أنت تشارك في ورشة عمل مباشرة وقد قدّم لك المعلّم رابطًا للمطالبة برصيد | أي شخص آخر، بما في ذلك المشاركون في ورشة العمل، بعد ذلك |
المتطلبات | رابط المطالبة وحساب Google يمكنه إنشاء مشروع على السحابة الإلكترونية | مفتاح AI Studio API مجاني |
تعمل على | Vertex AI، في مشروع يتم تحصيل رسومه من رصيد ورشة العمل | Google AI Studio |
التكلفة | الخدمات التي يغطيها الرصيد | الفئة المجانية |
خطوة الإعداد | إعداد ورشة العمل (الخطوة التالية) | الإعداد في المنزل (الخطوة التالية) |
إنّ كل شيء بدءًا من "المقدمة" فصاعدًا متطابق في كلتا الحالتين، ولا يحدّد المسار سوى نقطة نهاية النموذج التي يتواصل معها دفتر الملاحظات.
طريقتان للمتابعة
تتطابق كل خطوة أدناه مع ورقة ملاحظات Colab واحدة ومجلد واحد في مستودع GitHub. اختَر أحد الخيارين التاليين:
- ▶ Colab (يُنصح به): افتح ورقة الملاحظات → شغِّل الخلايا من الأعلى إلى الأسفل.
- 💻 على الجهاز:
git cloneمستودع، ثم./setup_venv.sh، ثم شغِّل كل مستوى كوحدة (python -m ...) أو تصفّحها كلها باستخدام./run.sh(adk web).
2. إعداد ورشة العمل · المطالبة برصيدك والتبديل إلى Vertex AI
يتم منحك رصيد Google Cloud في ورشة العمل. عليك المطالبة به وإنشاء مشروع تتم فوترته، وتوجيه دفتر الملاحظات إلى Vertex AI بدلاً من AI Studio. تتولّى خلية واحدة تنفيذ كل الإجراءات بعد تقديم المطالبة.
1 · طلب الرصيد (حوالي دقيقة واحدة)
- افتح رابط المطالبة الذي شاركه معك المعلّم. يبدو أنّها
https://me.developers.google.com/benefits/claim/your-workshop-name. - سجِّل الدخول واتّبِع التعليمات الواردة في الصفحة لقبول الرصيد.
- دوِّن حساب Google الذي استخدمته. يجب تنفيذ كل خطوة من الخطوات أدناه باستخدام الحساب نفسه.
2 · افتح دفتر الملاحظات وثبِّت حزمة تطوير التطبيقات (ADK) 2 (حوالي دقيقة واحدة)
انقر على الفتح في Colab ▶، ثم شغِّل خلية الرمز الأولى. يتم تثبيت إصدار ADK 2 الدقيق الذي تم التحقّق من صحة هذا الدرس العملي عليه وطباعة ✓ installed.
3 · شغِّل الخلية "إعداد ورشة العمل" (حوالي 3 دقائق)
هذه هي الخلية التي تحمل العنوان 🎓 المسار أ · ورشة عمل. نفِّذ الأمر وسيطلب منك Colab منح الإذن. اختَر حساب Google نفسه الذي استخدمته للتوّ للحصول على الرصيد، ثم اسمح بالوصول.
ويقوم بأربعة أشياء: إنشاء مشروع باسم adk-2-tutorial-XXXX على رصيدك، وتفعيل Vertex AI API عليه، وضبط متغيرات البيئة الأربعة التي تقرأها كل خلية لاحقة، ثم إجراء اختبار اتصال بـ Vertex والانتظار إلى أن يرد، وبالتالي ينتهي الإعداد من العمل أو يخبرك بالسبب، بدلاً من حدوث خطأ لاحقًا داخل مستوى.
الناتج المتوقّع — السطر الأخير هو المهم:
Signed in as: you@example.com
...
Successfully created GCP project 'adk-2-tutorial-4817'.
Successfully linked 'adk-2-tutorial-4817' to billing account '01ABCD-...'.
waiting for Vertex AI to come up on the new project... (10s)
waiting for Vertex AI to come up on the new project... (20s)
✅ Vertex AI on adk-2-tutorial-4817 · us-central1 · gemini-2.5-flash — answered a test call
4 · تخطّي خطوة "الإعداد في المنزل"
لا تشغّل خلية مفتاح AI Studio، لأنّ ذلك سيؤدي إلى إعادة دفتر الملاحظات إلى AI Studio وإلغاء ما فعلته للتو. (تمنع الخلية حدوث ذلك وترفض التشغيل، ولكن من الأفضل تخطّيها). انتقِل مباشرةً من هنا إلى خلية عناصر الإنشاء المشترَكة.
5 · نفِّذ خلية "الوحدات الأساسية المشترَكة"
نفِّذها مرة واحدة. يحدّد هذا الملف مخططات Pydantic بالإضافة إلى سيناريوهات الماراثون الجاهزة التي يعيد استخدامها كل مستوى بدءًا من المستوى 2. سيظهر لك ✓ schemas + scenarios ready.
بعد ورشة العمل
لن يدوم رصيدك والمشروع الذي أنشأته إلى الأبد. لإعادة تشغيل هذه المستويات مجانًا بعد انتهاء ورشة العمل، نفِّذ خطوة الإعداد في المنزل بدلاً من ذلك، وهي تتضمّن مفتاحًا مجانيًا في AI Studio بدون مشروع على السحابة الإلكترونية وبدون فوترة. وهذه الخلية الواحدة هي الشيء الوحيد الذي يتغير.
لتنظيفها في وقت أقرب، افتح Cloud Console، وانقر على adk-2-tutorial-XXXX، ثم احذفها. لا ينشئ أي شيء آخر في هذا الدرس التطبيقي موارد قابلة للفوترة.
3- الإعداد في المنزل · مفتاح واجهة برمجة التطبيقات في AI Studio
يتم تشغيل كل ما هو متاح في هذا المسار باستخدام مفتاح واجهة برمجة تطبيقات مجاني من Google AI Studio، بدون الحاجة إلى مشروع على Google Cloud أو فوترة أو تثبيت محلي. تستغرق هذه الخطوة بأكملها حوالي 3 دقائق.
1 · فتح دفتر الملاحظات
انقر على الفتح في Colab ▶. سيتم نقلك إلى دفتر الملاحظات الذي يتضمّن مقدمة بتنسيق Markdown، ثم خلية قابلة للتنفيذ لكل مستوى. يمكنك تشغيل الخلايا من الأعلى إلى الأسفل، ويتم عرض ناتج كل خلية أسفلها مباشرةً.
2 · تثبيت حزمة تطوير البرامج (ADK) 2 (حوالى دقيقة واحدة)
نفِّذ خلية الرمز البرمجي الأولى. يتم تثبيت الإصدار الدقيق الذي تم التحقّق من صحة هذا الدرس التطبيقي حول الترميز عليه:
%pip install -q "google-adk==2.3.0" python-dotenv pydantic nest_asyncio
انتظِر ريثما تكتمل العملية، وسيظهر لك الرمز ✓ installed. (تستغرق عملية التثبيت من 30 إلى 60 ثانية تقريبًا في المرة الأولى، ويتم تخزينها مؤقتًا بعد ذلك).
3 · الحصول على مفتاح Gemini API من AI Studio (دقيقة واحدة تقريبًا)
- افتح aistudio.google.com/app/apikey في علامة تبويب متصفّح جديدة.
- سجِّل الدخول باستخدام حسابك على Google.
- انقر على إنشاء مفتاح واجهة برمجة تطبيقات (في أعلى يسار الصفحة).
- اختَر مشروعًا حاليًا على Google أو اسمح له بإنشاء مشروع.
- انسخ المفتاح الذي يبدأ بـ
AIza...ويتألف من 40 حرفًا تقريبًا.
4 · إضافة مفتاحك إلى Colab (دقيقة واحدة تقريبًا)
الخيار أ: Colab Secrets (يُنصح به، ويبقى المفتاح مخفيًا):
- انقر على رمز المفتاح 🔑 في الشريط الجانبي الأيمن في Colab.
- انقر على + إضافة سر جديد.
- اضبط الاسم على
GOOGLE_API_KEYبالضبط. - ألصِق المفتاح في حقل القيمة.
- فعِّل إذن الوصول إلى دفتر الملاحظات.
الخيار ب: اللصق عند الطلب (سريع): تخطَّ كلمة المرور السرية، وعند تشغيل الخلية التالية، ستظهر لك رسالة طلب مخفية 🔑 Enter your Google AI Studio API key:، ما عليك سوى لصق كلمة المرور والضغط على Enter.
5 · تنفيذ الخلية الرئيسية
يقرأ السر (أو يعود إلى طلب اللصق)، ثم يوجّه ADK إلى AI Studio (وليس Vertex AI):
import os
# 🏠 TAKE-HOME ONLY — if you ran the Workshop setup cell, skip this one.
if os.environ.get("GOOGLE_GENAI_USE_VERTEXAI") == "True":
raise SystemExit("✋ You're set up on the workshop path (Vertex AI). Skip this cell.")
# Google AI Studio API key — add GOOGLE_API_KEY in the 🔑 Secrets panel (or paste when prompted).
try:
from google.colab import userdata
key = userdata.get("GOOGLE_API_KEY")
except Exception:
import getpass
key = getpass.getpass("Enter your Google AI Studio API key: ")
os.environ["GOOGLE_API_KEY"] = "".join(key.split()) # drop any stray whitespace/newlines
os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "False" # use AI Studio, not Vertex AI
print("✅ API key set — using Google AI Studio.")
الناتج المتوقّع: ✅ API key set — using Google AI Studio.
6 · نفِّذ خلية "الوحدات الأساسية المشتركة"
نفِّذ خلية الوحدات الأساسية المشتركة مرة واحدة. يحدّد هذا الملف مخططات Pydantic بالإضافة إلى سيناريوهات الماراثون الجاهزة التي يعيد استخدامها كل مستوى بدءًا من المستوى 2. سيظهر لك ✓ schemas + scenarios ready.
اكتملت عملية الإعداد. 🎽 قبل الانتقال إلى L0، وهو الإصدار الذي يبدأ الجميع بإنشائه، إليك بعض المعلومات السريعة.
4. المقدّمة · لماذا لا نستخدم طلبًا واحدًا كبيرًا؟
⚡ قبل تشغيلها، حدِّد الأمر الوحيد الذي تريد مراقبته: من أين يأتي كل رقم محدّد؟ هذا هو التمرين بأكمله، وكل ما عدا ذلك هو مجرد تفاصيل.
قبل استخدام السلّم، شغِّل العنصر الذي يحلّ محلّه: وكيل واحد يعدك بكل شيء — الحصول على معلومات الطقس، وتحليل الدورة التدريبية، وقراءة سجلّ التدريب، والتوجيه حسب الشروط، وإخراج الخطة.
ما ستراه: استراتيجية واثقة ومحدّدة ومنسّقة بشكل جيد... ولكن أرقامها مختلَقة. في إحدى التجارب المباشرة، بدأ بالعبارة "لقد حصلتُ على مقاييس الطقس اليوم" وقدّم معلومات عن درجة الحرارة التي بلغت 52 درجة فهرنهايت وسرعة الرياح التي بلغت 9 أميال في الساعة، بالإضافة إلى تحليل لسجلّ تدريب لم يسبق له أن رآه. لا تتوفّر هنا واجهة برمجة تطبيقات خاصة بالطقس، ولا بيانات دورات تدريبية، ولا سجلّ. إنّ طلبًا واحدًا من نموذج مبهم إما أن يزوّر مدخلاته أو يحوّلها إلى بيانات غير مفيدة.
هذا هو المرض، وله أربعة أعراض تستحق التسمية:
- لا يمكن الوثوق بها، فالبيانات من تأليفها، وبطريقة سلسة.
- لا يمكنك اختبارها: يتم توجيه الخطوة 4 داخل النص، ولا يوجد
ifلاختبار الوحدة. - لا يمكنك استبدال خطوة، إذ لا يوجد موضع يمكن فيه إدخال واجهة برمجة تطبيقات حقيقية خاصة بالطقس.
- تدفع مقابل كل شيء في كل مرة: خمس خطوات، وطلب واحد كبير، وبدون تخزين مؤقت لجزء محدّد.
احتفظ بهذا الشعور. تتجاهل المستويات التسعة التالية هذه الخطوات في الطلب، واحدة تلو الأخرى: تسترجع الدوال (L1–L2a)، وتوجّه عبارة if (L2b)، ويقسّم المتخصصون العمل (L3a–L3b)، ويحدّد الرمز البرمجي الشكل (L4a–L4b).

💻 محلي: python -m shared.prologue
5- المستوى 0: أول وكيل ADK 2

⚡ خلاصة: الوكيل هو نموذج + تعليمات + أدوات يمكنه استخدامها، ويتم تنفيذه من خلال Runner. كل ما يأتي بعد هذا المستوى هو المزيد من العملاء، مرتّبين بأشكال أفضل.
السؤال: هل يمكن أن يجيب النموذج عن السؤال، وأن يستعين بالرمز البرمجي الحقيقي عند الحاجة إلى إجراء عمليات حسابية؟
الفكرة الواحدة — ثلاثة أجزاء:
Agent: هو العنصر الذي يقدّم الاستنتاجات (نموذج Gemini + تعليمات).Runner: هو العنصر الذي ينفّذ وكيلاً داخل جلسة ويبث الأحداث.- أداة: هي دالة Python عادية (
pace_splits) يقرّر النموذج استدعاءها. يقرأ ADK التوقيع وسلسلة المستندات ويسلّم النموذج بيانًا، بدون كتابة مخطط.
بعد المقدمة، إليك الإصلاح الأول: إنّ نموذجًا لغويًا كبيرًا يجري عمليات حسابية بسيطة في ذهنه سيخطئ على الأرجح، لأنّ pace_splits هي لغة Python حتمية، وبالتالي يتم احتساب الأرقام في الإجابة وليس ارتجالها.
▶ Colab: تشغيل الخلية L0 · 📁 GitHub: L0_first_agent/ · 💻 الجهاز المحلي: python -m L0_first_agent.agent

def pace_splits(target_finish: str) -> dict:
"""Convert a goal time like '3:30:00' into exact per-mile / per-km paces."""
... # deterministic Python — no LLM
pace_coach = Agent(
name="pace_coach", model=MODEL,
tools=[pace_splits], # the model may call it; ADK reads the signature
instruction="You are a friendly, concise marathon coach. ... If the runner "
"mentions a goal time, call pace_splits — never do arithmetic yourself.",
)
runner = Runner(node=pace_coach, session_service=InMemorySessionService(), auto_create_session=True)
async for event in runner.run_async(user_id="u1", session_id="s1", new_message=msg):
... # events carry the model's text
🔍 العلامات: Agent(...) · tools=[pace_splits] · Runner(...) وفي الناتج، يمثّل السطر 🔧 قرار النموذج، في منتصف الإجابة، باستدعاء الرمز.
البيانات التي ستظهر لك:
🔧 model called tool → pace_splits({'target_finish': '3:30:00'})
🔧 tool returned → {'per_mile': '8:00', 'per_km': '4:58', ...}
🧠 Coach: To finish in 3:30:00, you need an average pace of 8:00 per mile...
تشكّل أسطر 🔧 الدرس: في منتصف الإجابة، اختار النموذج استدعاء الدالة، وجاءت 8:00/mile في رده من الرمز البرمجي وليس من إحصاءات الرموز المميزة.
❓ قد تتساءل: هل يستدعي النموذج الأداة دائمًا؟ لا، بل يحدّد ذلك لكل سؤال. اطرح سؤالاً لا يتضمّن أرقامًا وستختفي خطوط 🔧 (تتيح لك ساحة اللعب تجربة ذلك بالضبط).
👀 قراءة: pace_splits (دالة عادية) والسطر tools=[pace_splits] · ▶ تشغيل · ✏️ التغيير: اطرح السؤال العام (بدون وقت محدد) — لاحظ اختفاء خطوط 🔧: يقرّر النموذج الوقت المناسب لاستخدام أداة. بعد ذلك، أعِد كتابة instruction وأعِد التشغيل، فالتعليمات هي بقية البرنامج.
6. المستوى 1 · سير العمل الأول

⚡ خلاصة: الدالة العادية وبرنامج LLM هما نوع العقدة نفسه. المهام التي يمكن التنبؤ بها → دالة (0 نموذج لغوي كبير، حتمية)؛ الاستدلال المنطقي → وكيل
السؤال: كيف يمكن دمج رموز برمجية عادية مع نموذج لغوي كبير في مسار واحد، بدون دفع رسوم مقابل طلب النموذج في الأجزاء التي تتضمّن رموزًا برمجية فقط؟
الفكرة الأساسية: في Workflow، تكون دالة Python عادية وعامل نموذج لغوي كبير مجرد عقد في قائمة edges نفسها.
START ──► fetch_conditions (function, 0 LLM) ──► advise (agent, 1 LLM)
▶ Colab: تشغيل الخلية L1 · 📁 GitHub: L1_graph_basics/ · 💻 الجهاز المحلي: python -m L1_graph_basics.workflow

تعرض عقدة الدالة البيانات التي أنتجتها (بدون استدعاء نموذج)، ثم يقدّم الوكيل نصيحة تشير إلى درجة الحرارة والرياح الفعليتين اللتين تلقّاهما:
def fetch_conditions(node_input): # function node — 0 LLM
return Event(output=Conditions(temp_f=78, wind_mph=12, conditions="sunny").model_dump())
advise = Agent(name="advise", model=MODEL, mode="single_turn",
input_schema=Conditions, instruction="...give pacing + gear advice...")
workflow = Workflow(edges=[(START, fetch_conditions, advise)])
🔍 العلامات: صف واحد من الحواف — (START, fetch_conditions, advise) — مع دالة Python مجردة في المنتصف، وinput_schema= للتحقّق من عملية التسليم.
الجديد مقارنةً بالمستوى 0: Workflow(edges=[...]) وSTART (حيث يتم إدخال البيانات)، وعقدة دالة تعرض Event(output=...)، وinput_schema=Conditions حتى يتم التحقّق من صحة ناتج الدالة استنادًا إلى هذا المخطط قبل أن يراه الوكيل (كنص JSON — يتحقّق input_schema من الحدود، ولا يقدّم للوكيل عنصر Python).
❓ قد تتساءل: هل الترتيب المطلوب هو استخدام الدالة ثمّ الأداة؟ لا، يمكن استخدام أي ترتيب وأي مزيج وأي عدد. يتم تنفيذ advise ثانيًا فقط لأنّه يحتاج إلى بيانات fetch_conditions. العبرة هي في التكافؤ، وليس في التسلسل.
👀 قراءة: تعرض fetch_conditions بيانات بدون طلب نموذج، بينما تتضمّن advise input_schema=Conditions. · ▶ تشغيل · ✏️ التغيير: اضبط temp_f=30 في الدالة وأعِد تشغيلها، وستتغير النصيحة، وستظل الدالة لا تتطلب أي مكالمات إلى نموذج اللغة الكبير.
7. L2a · توزيع موسَّع متوازٍ + JoinNode (الركيزة 1a)

⚡ ملخّص: يمكنك تنفيذ عمليات التوزيع بالتوازي (بدون تكلفة)، والانتظار إلى حين اكتمال كل العمليات، ثم تجميع النتائج، وتسليم الصورة الكاملة إلى وكيل واحد.
السؤال: يمكنك رسم المسار قبل وصول الإدخال. ابدأ بالهيكل الأساسي: اجمع البيانات بالتوازي، ثم حزِّمها، وقدِّمها إلى وكيل واحد.
الشكل:
START ──► fetch_weather ──┐
START ──► analyze_course ─┼─► JoinNode ─► strategy (1 agent)
START ──► pull_fitness ───┘ (bundles)
▶ Colab: تشغيل الخلية L2a · 📁 GitHub: L2a_parallel_join/ · 💻 الجهاز المحلي: python -m L2a_parallel_join.workflow

🔍 العلامات: ثلاث حواف تبدأ جميعها عند START، أي التوزيع الموسَّع، وJoinNode، أي نقطة الالتقاء.
- عمليات الجلب الثلاث هي دوال، ويتم تنفيذها بالتوازي، بدون أي طلبات إلى نموذج اللغة الكبير.
- تنتظر
JoinNodeجميع النتائج الثلاث وتجمعها في حمولة واحدة مكتوبة (BundledRunData)، ويتم تحديد مفتاحها حسب اسم الدالة. - يقرأ أحد وكلاء
strategyالحزمة ويكتبRaceStrategy.
ما سيظهر لك: في كل عملية جلب، سيتم عرض طابع زمني started / finished. تبدأ جميعها عند 0.0 ثانية وينتهي التوزيع الموسَّع عند 2.0 ثانية، أي أبطأ عملية جلب، وليس عند 4.5 ثانية التي سيبلغها مجموع مدتها. وهذا التداخل هو التوازي. (يبلغ إجمالي وقت التشغيل الفعلي الذي يتم عرضه في النهاية حوالي 8 ثوانٍ لأنّه يتضمّن أيضًا طلب LLM من وكيل الاستراتيجية. لذا، يُرجى قراءة الطوابع الزمنية لجلب المطالبة المتوازية، وليس الإجمالي).
💡 استدعاء المشهد الافتتاحي: اخترع الطلب الضخم الطقس. في هذا المثال، يتم الحصول على درجة الحرارة من دالة جلب، أي رمز حقيقي، ووصلة حقيقية. استبدِل القاموس المُعدّ مسبقًا بواجهة برمجة تطبيقات فعلية خاصة بالطقس، ولن يتغيّر أي شيء آخر.
❓ قد تتساءل: ما هو
JoinNode
هل يجب أن أفهم ذلك؟ في جملة واحدة: ينتظر حتى تنتهي كل فروع التنفيذ المتوازية، ويجمع النتائج في قاموس واحد مفتاحه اسم الدالة السابقة، ولا يحتسب أي شيء بنفسه. هذا القاموس هو السبب تحديدًا الذي يتيح لجهاز التوجيه L2b كتابة node_input["fetch_weather"]["temp_f"].
👀 قراءة: تتفرّع ثلاث حواف من START، وتجمعها JoinNode في حزمة واحدة لوكيل واحد. · ▶ تشغيل الفيديو وقراءة الطوابع الزمنية، وليس الإجمالي · ✏️ تغيير: جعل عملية جلب واحدة في وضع السكون 3.0 — يتم أولاً توقّع وقت انتهاء التوزيع الموسَّع الجديد، ثم يتم التحقّق من ذلك.
8. L2b · إضافة جهاز التوجيه الحتمي (الركيزة 1b)

⚡ الخلاصة: يتم تشغيل أحد الوكيلَين، إما L2a بدون تعديل أو if عادي. التفرّع بدون سؤال النموذج
السؤال: يجب أن تختلف الخطة باختلاف الطقس الحار والبارد. كيف يمكنك إنشاء فروع بدون أن تطلب من النموذج اتخاذ القرار؟
الشكل (L2a + جهاز توجيه):
... JoinNode ─► route_by_weather ─► hot_strategy
(if-statement) ─► normal_strategy
─► cold_strategy
▶ Colab: تشغيل الخلية L2b — جرِّب run("NORMAL") / run("COLD") · 📁 GitHub: L2b_router/ · 💻 الجهاز المحلي: python -m L2b_router.workflow COLD

def route_by_weather(node_input): # an if-statement, 0 LLM
temp = node_input["fetch_weather"]["temp_f"]
route = "HOT" if temp >= 70 else "COLD" if temp <= 40 else "NORMAL"
return Event(output=node_input, route=route)
(route_by_weather, {"HOT": hot_strategy, "NORMAL": normal_strategy, "COLD": cold_strategy})
🔍 العلامات: Event(output=..., route=...) — عقدة دالة تسمّي المسار — وdict-edge {"HOT": ..., "NORMAL": ..., "COLD": ...} التي تربط الأسماء بالعُقد.
الخلاصة: ثلاثة أنواع من العمل، وثلاثة أنواع من المنازل:
- العمل المتوقّع → الدوال (عمليات الجلب الثلاث المتوازية)
- قاعدة واضحة → توجيه صريح (
route_by_weatherهي عبارةif، وليست قرارًا نموذجيًا) - الاستدلال → النموذج (يتم تنفيذ استراتيجية واحدة فقط)
ما سيظهر لك: temp=78F -> route=HOT، ثم RaceStrategy منظَّم. صافي التكلفة: مكالمة واحدة مع نموذج لغوي كبير.
⚠️ في حال إضافة فرع رابع، يجب أيضًا إضافة إدخال DEFAULT_ROUTE إلى route-dict. إنّ عدم تطابق المسار مع القاموس ليس خطأ، بل ينتهي الفرع ببساطة، ويخرج البرنامج 0 بدون أي ناتج، ما يشكّل طريقًا مسدودًا يصعب تصحيحه.
❓ قد تتساءل: هل L2b هي في الواقع L2a بالإضافة إلى جهاز توجيه؟ نعم، لا يتم تعديل عمليات الجلب وعمليات الربط، ويبقى عدد طلبات LLM 1. التغيير: أصبحت عبارة "دائمًا الوكيل نفسه" "واحد من ثلاثة، يتم اختياره حسب البيانات".
👀 قراءة: route_by_weather — جهاز التوجيه هو عبارة if، وليس وكيلًا. · ▶ الركض run("COLD") أيضًا · ✏️ التغيير: أضِف فرع WINDY مع وكيل رابع، واقرأ تحذير DEFAULT_ROUTE أعلاه قبل إجراء ذلك.
9. L3a · Collaborative agents: one flag, two worlds — Pillar 2

⚡ ملخّص: الفريق نفسه، إشارة واحدة. تُسلّم chat المحادثة بأكملها إلى أحد الخبراء ولا تعود أبدًا، بينما تحوّل single_turn كل خبير إلى أداة، أي مجموعة فرعية متوازية، وعودة تلقائية، وتوليف واحد.
السؤال: أنت تعرف الفريق، ولكن الطلب يحدّد الأعضاء الذين يجب أن يجيبوا. كيف يمكن السماح لنموذج لغوي كبير باختيار المجموعة الفرعية وتشغيلها بشكل متزامن؟
الشكل: منسّق يشرف على ستة أخصائيين (طبي، وأحوال جوية، وتحديد السرعة، ومعدات، وتغذية، وصحة عقلية). في هذا المستوى، يتم تنفيذ الفريق نفسه مرتين، أي يتم استخدام طلب المنسّق نفسه وستة خبراء أنفسهم. الفرق الوحيد هو علامة واحدة على الوكلاء الفرعيين. التباين هو الدرس.
▶ Colab: تشغيل الخلية L3a · 📁 GitHub: L3a_collaborative/ · 💻 الجهاز المحلي: python -m L3a_collaborative.concierge --mode chat "What about fueling?"

🔍 العلامات: mode="single_turn" في المصنع — وفي الناتج، TRANSFER → (الضربة الأولى) مقابل مجموعة من أسطر DISPATCH → تشترك في طابع زمني واحد (الضربة الثانية).
الخطوة 1: تشغيل الإعدادات التلقائية أولاً، ومراقبة عدم نجاحها في تنفيذ المهمة
لم تتم كتابة mode= → يتم تلقائيًا ضبط الوكلاء الفرعيين على chat. ستظهر لك المعلومات التالية:
TRANSFER → nutrition_specialist (transfer_to_agent — the only tool chat subagents provide)
Final speaker: nutrition_specialist
لم يحصل المنسّق على أدوات تفويض، إذ يمنحه وكلاء المحادثة الفرعيون transfer_to_agent فقط، وهو عبارة عن عملية تسليم متسلسلة للمحادثة بأكملها إلى خبير مختص واحد. يجيب هذا الاختصاصي المستخدم مباشرةً، وينتهي التشغيل عند هذا الحد. لا يتم إرسال البيانات بشكلٍ متوازٍ. لا يمكن إرجاع المشتريات. ما مِن تركيب. طرح السؤال العام يؤدي إلى تفاقم المشكلة: ستة متخصصين، عملية تحويل واحدة.
هذا ليس خطأ، بل هو وضع المحادثة الذي يؤدي وظيفته. يملك المحادثة الشخص الذي يجريها إلى أن ينقلها شخص آخر صراحةً. صحيح بالنسبة إلى مساعد مفتوح النهاية، وغير صحيح بالنسبة إلى خطوة في مسار.
الموضوع 2 · علم واحد، عالمان
الاختلاف الوحيد هو mode="single_turn" لكل أخصائي. السؤال نفسه، إعادة التشغيل:
[t= 7.8s] DISPATCH → medical_specialist ← same timestamp =
[t= 7.8s] DISPATCH → weather_specialist one turn, many calls
[t=14.5s] ↩ medical_specialist replied ← replies land inside
[t=14.5s] ↩ weather_specialist replied one short window
🧠 Concierge (synthesized): <one answer>
يُدرج ADK الآن أداة تفويض واحدة لكلّ أخصائي، ويتم تسميتها باسم الوكيل الفرعي، ويتم وصفها بواسطة description= (هذا النص هو ما يقرأه المنسّق عند اختيار المجموعة الفرعية، ويمكنك تخطّيه وتوجيه الطلبات استنادًا إلى الأسماء فقط). يصدر المنسّق عدة طلبات في دورة واحدة، ويشغّلها "حزمة تطوير التطبيقات" بالتوازي، وتعرض كل منها نتيجتها تلقائيًا، ثم يجمع المنسّق النتائج.
السؤال | المتخصصون الذين يتم إطلاق النار عليهم |
"ماذا عن التزوّد بالوقود؟" | المعلومات الغذائية فقط |
"أشعر بألم في ركبتي عند الكيلومتر 29" | الطبية فقط |
"هل يجب أن أشارك في السباق اليوم؟" | medical + weather + pacing |
"هل هناك أي شيء يدعو للقلق؟" | كل 6 |
سبب حصول كل أخصائي على الموجز الكامل: يعمل كل وكيل فرعي single_turn في فرع جلسة معزول خاص به، ولا يمكنه الاطّلاع على المحادثة أو الوكلاء الفرعيين الآخرين. لا يوجد أي شيء محيطي: يجب أن يرسل المنسّق SpecialistInput بأكمله (السؤال + الاستراتيجية + بيانات التنفيذ) بشكل منفصل إلى كل عملية استدعاء متوازية.
💡 المكان الذي يوفّر فيه الإصدار 2 من "مجموعة أدوات المطوّرين الإعلانية" هذا الخيار مباشرةً: تختار نماذج اللغات الكبيرة مجموعة فرعية لكل طلب وتنفّذها بالتوازي، ويتم تحديدها من خلال sub_agents + mode="single_turn". يمكنك تجميع الشكل نفسه في الإصدار 1.x من خلال تضمين كل معالج في AgentTool، والتغيير هو أنّه أصبح الآن تعريفًا بدلاً من أن يكون مجرد رمز. (ParallelAgent هي دائمًا "الكل" وtransfer_to_agent هي "متسلسل".)
⚠️ ملاحظتان مهمّتان: (1) يختار النموذج المجموعة الفرعية، لذا فهو أقل تحديدًا من الموجّه المبرمَج في L2، ويمكن أن تختلف المجموعة الفرعية الدقيقة من عملية إلى أخرى. (2) في بعض الأحيان، سيظهر لك سطر Error validating input: ... لموظف دعم واحد. لا يكون الناتج من اختصاص المتخصص أبدًا، بل تتولّى output_schema فرض ذلك من جهة الخادم. هذا هو الإدخال: على المنسّق إعادة إنتاج SpecialistInput المتداخل بالكامل حرفيًا لكل مكالمة متوازية، وفي بعض الأحيان يخطئ في إحداها. تعرض حزمة تطوير التطبيقات (ADK) الخطأ كنتيجة لهذه الأداة، ويتم استرداد البيانات من خلال المنسّق، ويتم عرض عملية التجميع.
❓ قد تتساءل: هل
chat
هل يمكن استخدام تفويض واحد فقط بنمط 1.x، أي وكيل واحد في كل مرة؟ نعم، هذا هو السلوك التلقائي للإصدار 1.x، ولكن مع اسم. تتألف الفجوة إلى single_turn من ثلاثة جوانب: ما يحتفظ به المنسّق (transfer_to_agent واحد مقابل أداة واحدة لكل متخصص) · عدد الأشخاص الذين يمكنهم العمل (شخص واحد يملك المحادثة مقابل N بالتوازي) · ما إذا كان يتم استعادة عناصر التحكّم (أبدًا مقابل تلقائيًا، مع النتائج). في ما يتعلق بالرمز: يتوفّر فرع if mode == في المصنع فقط حتى يتمكّن فريق واحد من إنشاء التطبيق بطريقتَين مختلفتَين، إذ يثبّت تطبيق حقيقي وضعًا واحدًا ويختفي if.
👀 قراءة: _specialist المصنع — المَعلمة mode هي المستوى بأكمله. · ▶ تشغيل كلا الإيقاعين · ✏️ تغيير: اطرح السؤال "أشعر بألم في ركبتي عند الكيلومتر 29" — توقّع المجموعة الفرعية أولاً، ثم تحقّق من أسطر DISPATCH.
# The factory's mode parameter is THE variable this level teaches:
def _specialist(name, domain, focus, mode):
kwargs = {}
if mode == "single_turn": # the structured contract only makes sense for a TOOL
kwargs = dict(mode="single_turn",
input_schema=SpecialistInput, output_schema=SpecialistResponse)
return Agent(name=name, model=MODEL,
description=f"Marathon {domain} specialist. Consult for: {focus}.",
instruction=..., **kwargs)
race_concierge = Agent(name="race_concierge", model=MODEL,
sub_agents=[...six specialists...], # NOTE: no `mode` on the coordinator
instruction="...DECIDE which specialists are relevant... call them IN PARALLEL... SYNTHESIZE...")
10. L3b · وضع المهام: محادثة لها نهاية محددة — العمود 2

⚡ الخلاصة: الوضع المتوسط — التحدّث مع المستخدم إلى أن يتم جمع الحقول، ثم العودة تلقائيًا مع كائن تم التحقّق من صحته.
السؤال: ترك L3a فجوة. chat يملك المحادثة بأكملها، بينما لا يتحدث single_turn مع المستخدم على الإطلاق. لكنّ عملية جمع البيانات الحقيقية تقع بينهما: "تحدّث إلى المستخدم إلى أن تجمع X، ثم ارجع إليّ بعنصر تم التحقّق من صحته". ما هو هذا الوضع؟
الشكل:
race_desk (coordinator)
└─ gear_fitter (mode="task", output_schema=GearOrder)
▶ Colab: تشغيل الخلية L3b · 📁 GitHub: L3b_task_desk/ · 💻 الجهاز المحلي: python -m L3b_task_desk.desk


🔍 العلامات: mode="task" + output_schema= على العميل نفسه، وفي الناتج، الإيقاف المؤقت ⏸ والاتصال finish_task.
البيانات التي ستظهر لك:
━━ TURN 1 ━━ user: 'I need shoes for the marathon.'
race_desk → delegate: gear_fitter
gear_fitter: What is your shoe size?
⏸ The run ENDED — but nothing failed. This is a PAUSED task.
━━ TURN 2 ━━ user: 'Size 9, wide.' (same session → resumes the task)
gear_fitter → finish_task (payload validates as GearOrder)
race_desk: Your order ... in size 9 Wide has been confirmed.
حدثت ثلاثة أمور لا يمكن أن يحدثها وضع L3a:
- توقّف عملية التشغيل في منتصف المهمة: مهمة متوقّفة مؤقتًا، وليس تعليقًا أو خطأً. طرح الوكيل سؤالاً توضيحيًا وأبقى المهمة مفتوحة. (في
adk web، ما عليك سوى كتابة الإجابة، وستسجِّل النصوص البرمجية للإطار الإجابة كرسالة ثانية في الجلسة نفسها). - استأنفت الرسالة التالية مهمة وكيل المهام نفسه، بدون إعادة توجيه أو إعادة تفويض. تعرف الجلسة المستخدمين الذين كانوا ينتظرون.
finish_taskأنهى العملية — أدرجت حزمة تطوير البرامج (ADK) الخاصة بالأداة لأنّmode="task". يجب أن يستدعي الوكيل هذه السمة لإكمال العملية، ويجب أن يتم التحقّق من صحة حمولتها باستخدامoutput_schema. محادثة تتضمّن خط نهاية مكتوبًا، ثمّ يتم تلقائيًا إعادة التحكّم إلى المنسّق مع إرفاق النتيجة
قاعدة السؤال الواحد لاختيار وضع
💡 "هل يحتاج المستخدم إلى التحدث معها؟ وإلى متى؟" chat = إلى أجل غير مسمى · task = إلى أن يتم جمع الحقول · single_turn = أبدًا.
الوضع | المشاركة البشرية | هل هي متوازية؟ | الرجوع إلى الصف الرئيسي |
| محادثة كاملة | لا | يدوي (عبر النقل) |
| الأسئلة التوضيحية فقط | لا | تلقائي (عبر |
| لا ينطبق | yes | تلقائي (مع نتيجته) |
يتم تفعيل mode على الوكلاء الفرعيين فقط، وليس على المنسّق. وتكون عُقد سير العمل تلقائيًا single_turn (وهذا هو السبب في أنّ مستويات L1 إلى L2b لم تكتبها مطلقًا)، بينما تكون الوكلاء الفرعيون تلقائيًا chat (وهذا هو السبب في أنّ مستوى L3a كان عليه كتابتها).
⚠️ ملاحظتان حول الإصدار قبل البناء على هذا: (1) task
كعقدة رسم بياني ثابتة تعتمد على الإصدار: في الإصدارات 2.0.0b1–2.3.0 (الإصدار الذي تم تثبيته في هذا الدرس التطبيقي حول الترميز)، يتم إنشاء Workflow(...) عند الإنشاء. استخدِم ما يفعله هذا المستوى بالضبط (منسّق محادثة مع وكلاء فرعيين للمهام) أو أرسِل عبر ctx.run_node. تمت إزالة هذه القيود في الإصدار 2.5.0. (2) "يجب أن تكون وكلاء المهام وكلاء فرعيين" (أي ليس لديهم وكلاء فرعيون خاصون بهم) هو قيد موثّق في "حزمة تطوير التطبيقات"، ولكنه عقد وليس حماية وقت التشغيل: لن يمنعك الإصداران 2.3.0 و2.5.0 من ذلك. لا تعتبر عدم ظهور خطأ بمثابة إذن.
💡 مزيد من التفاصيل: وكيل task مضمّن في مهمة سير عمل بيانية (الشكل 2.5.0 والإصدارات الأحدث)، مع توجيه يمكنه إعادة توجيه المحادثة لتجربة أخرى: مستودع الرمز المصدر المرافق 22_agent_in_workflow · دليل الوضع الكامل: docs/agent-modes.md.
❓ قد تتساءل: ماذا يعني
task
شراء ما لا يمكن للطفلين الآخرين شراؤه؟ ثلاثة أشياء: الرجوع التلقائي (تتولى المحادثة نقل الحوار بدلاً من ذلك) وخط النهاية المكتوب (يجب أن يتم التحقق من صحة حمولة finish_task وفقًا للمخطط، وستتلقى البيانات وليس نصًا) والإيقاف المؤقت/الاستئناف (يشير رمز ⏸ إلى مهمة معلّقة تنتظر ردًا من المستخدم، وليس إلى تعليق).
👀 القراءة: gear_fitter — mode="task" + output_schema هو العقد الكامل. · ▶ تشغيل · ✏️ تغيير: run_desk("I need a hydration vest", "2 liters, medium") — يتكيّف السؤال التوضيحي، ويبقى خط النهاية مكتوبًا.
11. L4a · توزيع موسَّع متوازٍ بحجم وقت التشغيل (الركيزة 3a)

⚡ الخلاصة: لا يزال الهيكل يتضمّن ثلاث خطوات ثابتة، ويتم إخفاء المحتوى الديناميكي داخل الخطوة الوسطى، حيث يتم تحديد العرض حسب البيانات في وقت التشغيل.
⚠️ تنبيه: هذه هي الخطوة الأصعب في السلم. كان المستوى السابق يتضمّن 44 سطرًا، أما هذا المستوى فيتضمّن حوالي 120 سطرًا، أي ثلاثة عناصر ووكيلَين من عقد سير العمل، ولا يتضمّن أي مساحة متروكة. خصِّص حوالي 15 دقيقة، وركِّز على سطر القراءة/التشغيل/التغيير في النهاية: لا تحتاج إلى استيعاب كل سطر في المرة الأولى.
السؤال: يعتمد شكل العمل على المدخلات. لا يمكنك رسم الرسم البياني مسبقًا. ابدأ بالعرض في وقت التشغيل: دع النموذج اللغوي الكبير يقرّر عدد الأسئلة الفرعية.
الشكل (مستوى واحد):
START ─► decompose ─► research_topic (parallel_worker) ─► synthesize
│ │ │
└──┴──┴─ (flat: no children yet)
يتم تقسيم السؤال المفتوح إلى N سؤال فرعي — يختار النموذج اللغوي الكبير قيمة N في وقت التشغيل (من 3 إلى 7) — ويتم البحث عن كل سؤال فرعي بالتوازي، ثم يتم تجميع النتائج في موجز واحد.
▶ Colab: تشغيل الخلية L4a · 📁 GitHub: L4a_flat_research/ · 💻 الجهاز المحلي: python -m L4a_flat_research.deep_research

🔍 العلامات — لا يوجد
dynamic=True
مفتاح التبديل السمة "ديناميكي" هي طريقة كتابة، وليست إعدادًا. علامتان فقط: @node(parallel_worker=True) (تأخذ قائمة بحجم وقت التشغيل، وتشغّل عاملًا واحدًا لكل عنصر) وctx.run_node(...) (تجدول عقد الرمز البرمجي مباشرةً). إذا ظهرت إحدى هاتين العلامتين، يعني ذلك أنّك تستخدم ميزة "السطح الديناميكي".
ما سيظهر لك: يطبع المحلّل مثلاً 5 أسئلة فرعية، ويبحث عنها بالتوازي، ثم يعرض موجزًا مركّبًا. يختلف الرقم في كل عملية تنفيذ، وهو ما لا يمكن أن يفعله الرسم البياني الثابت.
هناك علامتان على العامل يجب فهمهما:
rerun_on_resume=Trueإلزامي على أي عقدة تستدعيctx.run_node، وإلا ستعرض حزمة تطوير البرامج (ADK) الخطأValueError. عند استئناف العملية، يجب إعادة تنفيذ عقدة الإرسال لإعادة إنشاء العناصر الفرعية التي تم إنشاؤها، لأنّ هذه العناصر غير مضمّنة في الرسم البياني الثابت.- تحدّد
retry_config=حدود هذا الفشل. يلغي العامل المتوازي كل العمليات المتزامنة ويعيد إطلاق العملية الفورية إذا تعذّر تنفيذ إحدى العمليات المتزامنة. وبالتالي، بدون إعادة المحاولة، يؤدي الخطأ المؤقت 429 إلى إلغاء عملية التشغيل بأكملها، بما في ذلك كل المكالمات التي تم الدفع مقابلها. تتم إعادة المحاولة على العقدة الداخلية لكل عنصر، لذا تتم إعادة محاولة كل فرع بشكل مستقل.
❓ قد تتساءل: كيف تعرف حزمة تطوير التطبيقات (ADK) أنّ هذا المحتوى ديناميكي؟ ليس من الضروري ذلك، إذ لم يتم تعريف أي شيء في أي مكان. ينتج المحلّل قائمة في وقت التشغيل، ويضبط العامل المتوازي حجمه حسب ما يصل إليه. الديناميكية هي إحدى خصائص تدفّق البيانات الذي كتبته، وليست وضعًا فعّلته.
👀 قراءة: العلامتان على research_topic — parallel_worker وrerun_on_resume · ▶ تشغيل · ✏️ تغيير: استبدِل السؤال المفتوح بسؤالك الخاص، ويتغير N لأنّ الإدخال يحدّد العرض.
12. L4b · Add recursive spawning (Pillar 3b)

⚡ الخلاصة: يتم كتابة التكرار العودي، وليس تقديمه. يستدعي العامل نفسه من خلال ctx.run_node، أي Python العادي، لذا يجب كتابة الفرامل أيضًا. هذا هو MAX_DEPTH.
السؤال: في بعض الأحيان، يؤدي أحد نتائج البحث إلى ظهور موضوع فرعي ضيق يستحق التحقيق فيه بشكل منفصل. كيف يمكنك السماح لفرع بإنشاء المزيد من العمل المتوازي مع الحفاظ على حدوده؟
الشكل (تكراري الآن):
START ─► decompose ─► research_topic (parallel_worker, recursive) ─► synthesize
│ │ │
│ │ └─ research(q3) ─► maybe spawn children
│ └─── research(q2) ─► maybe spawn children
└────── research(q1) ─► maybe spawn children
▶ Colab: تشغيل الخلية L4b · 📁 GitHub: L4b_recursion/ · 💻 الجهاز المحلي: python -m L4b_recursion.deep_research

@node(parallel_worker=True, rerun_on_resume=True)
async def research_topic(ctx, node_input):
finding = coerce(await ctx.run_node(research_agent, node_input=...), ResearchFinding)
if finding.needs_deeper and finding.deeper_questions and depth < MAX_DEPTH: # boundary in CODE
children = await ctx.run_node(research_topic, node_input=deeper) # recursive fan-out
yield Event(output={..., "children": children})
🔍 العلامات: ctx.run_node(research_topic, ...) داخل research_topic نفسها — الإشارة الذاتية هي التكرار — والحارس depth < MAX_DEPTH سطر واحد فوقها.
ما ستراه: ستظهر عُقد البحث وهي تطبع spawning N deeper، أي أنّ عملية التكرار تحدث مباشرةً، ثم سيظهر شكل شجرة وقت التشغيل (مثل 5 top-level + 10 recursive children). وتختلف الشجرة في كل عملية تشغيل.
⚠️ قبل رفع الحدّ الأقصى: يرتفع الحدّ الأقصى بسرعة، إذ ينتقل MAX_DEPTH=3 من أسوأ حالة من حوالي 30 مكالمة إلى حوالي 93 مكالمة. وفي نهاية عملية التنفيذ، قد يظهر سطر سجل cancelling N leftover tasks: هذا يعني أنّ حزمة تطوير التطبيقات (ADK) تعمل على إيقاف مجموعة المهام المتوازية بعد اكتمال النتيجة. وهي غير ضارة، وقد لا تظهر لك أبدًا حسب إعدادات التسجيل.
❓ قد تتساءل: أليس التكرار الديناميكي مفعَّلاً تلقائيًا؟ لا، فالمستوى 4a ديناميكي بالكامل مع عدم تكرار. لا يمنحك Dynamic سوى تدفق تحكّم عادي في Python، بينما يختار L4b كتابة تكرار متداخل معه. وبما أنّ المطوّر هو من كتب التعليمات البرمجية المتكرّرة، عليه أيضًا كتابة حدودها، وهنا يتوقف شعار "دع النموذج اللغوي الكبير يحدّد شكل العمل، واحتفظ بالحدود في التعليمات البرمجية" عن كونه مجرد شعار.
👀 قراءة: الحارس: if finding.needs_deeper and depth < MAX_DEPTH · ▶ تشغيل · ✏️ التغيير: اضبط MAX_DEPTH = 1 وأعِد التشغيل، وسيتم تسوية الشجرة (وستصبح عملية التشغيل أقل تكلفة). الحدود هي حدودك، في الرمز.
13. L5 · Which pattern should you use?

⚡ الخلاصة: يحدّد أحد المحاور كل شيء، وهو من يختار الخطوة التالية: الرسم البياني الذي رسمته أو النموذج اللغوي الكبير أو الرمز البرمجي.
لقد أنشأت جميعها. وهذا هو النموذج الذي يجعلها مفيدة: مطابقة النمط مع شكل مشكلتك.
المحور: من يقرّر ما سيتم تشغيله بعد ذلك؟
عمود | من يقرّر ما سيتم تشغيله بعد ذلك؟ | مدمَج |
1 · الرسم البياني | الرسم البياني الذي رسمته | L2a / L2b |
2 · تعاوني | النموذج اللغوي الكبير | L3a / L3b |
3 · ديناميكية | رمز Python أثناء وقت التشغيل | L4a / L4b |
الخطوة 0: هل تحتاج إلى رسم بياني؟
تتضمّن حزمة تطوير التطبيقات (ADK) وكلاء سير عمل مُنشأين مسبقًا، وهم SequentialAgent وParallelAgent وLoopAgent. بالنسبة إلى سلسلة بسيطة من الوكلاء، هذه هي الإجابة الصحيحة الأرخص ولا يوجد رسم بياني لتجميعه. يمكنك تجاوزها عندما تحتاج إلى توجيه صريح (جهاز توجيه L2b) أو دمج (JoinNode في L2a) أو عُقد ليست وكلاء (دالة عادية، بدون طلبات من النموذج اللغوي الكبير) — وهذا هو السبب عادةً.
Would a prebuilt SequentialAgent / ParallelAgent / LoopAgent do?
│
├─ YES ──────────────────────────────► use it; stop here
│
└─ NO — I need routing, a join, or non-agent nodes
│
Can you draw the workflow before the input arrives?
│
├─ YES ───────────────────────────► Pillar 1 · Graph workflow (L2a/L2b)
│
└─ NO
├─ Known team, request picks the subset? ─► Pillar 2 · Collaborative (L3a/L3b)
└─ Does the shape depend on the input? ──► Pillar 3 · Dynamic (L4a/L4b)

الفرق بين الإصدار 1.x والإصدار 2
هذا لا يعني أنّ "الإصدار 2.0" يمكنه تنفيذ إجراءات لم يكن بإمكان "الإصدار 1.x" تنفيذها، بل كان بإمكان "الإصدار 1.x" إنشاء كل ذلك. التغيير هو أنّ الإصدار 2.0 يمنح كل شكل مساحة مخصّصة أكثر مباشرةً، لذا يغادر مسار التحكّم المعروف الطلب ويصبح بنية يمكنك رؤيتها واختبارها.
نمط | تكلفة الإصدار 1.x | الصفحة الرئيسية لـ ADK 2 |
الرسم البياني | 4 طلبات من النموذج اللغوي الكبير في الإصدار الشائع، ويتم إخفاء التوجيه في الطلب | العقدة الوظيفية + عقدة الوكيل كعقدتَين متساويتَين → مكالمة واحدة، موجّه عبارة |
تعاوني | يمكن إنشاؤها من خلال | فريق معرَّف: |
ديناميكية | يؤدي التكرار إلى إخراجك من إطار العمل |
|
التطبيق بأكمله، وما لا يمكن أن يعرضه لك الرسم البياني
لقد أنشأت الآن كل جزء أدناه. تعرض Workflow بنيتها في graph.edges، لذا يتم إنشاء هذه الصورة من الرمز بدلاً من رسمها يدويًا، وهذا هو ملخّص هذا المختبر الذي يتم العثور عليه من خلال الاستبطان:
عمود | المحتوى الذي يتضمّنه | السبب |
1 · الرسم البياني (L2b) | 10 حواف ومسارات وكل شيء | أنّك رسمت الشكل قبل وصول أي إدخال |
2 · تعاوني (L3a) | 0 حواف: | يختار النموذج اللغوي الكبير المجموعة الفرعية لكل طلب |
3 · ديناميكي (L4a/L4b) | 3 حواف — متطابقة في كلتا الصورتَين | يتم كتابة التكرار العودي بلغة Python، وليس في الرسم البياني |
الصف الأخير هو دليل على إجابة السؤال L4b: يحتوي كل من L4a وL4b على الرسم البياني نفسه، ويتكرر أحدهما فقط.
ما يمكنك إنشاؤه الآن
كل نمط نفّذته للتو هو شكل منتج حقيقي:
لقد تدربت على | في البرية، | بدء من |
الرسم البياني + الموجّه (المستوى 2أ/المستوى 2ب) | مسارات المستندات، وخطوات استخراج البيانات وتحويلها وتحميلها باستخدام نماذج اللغات الكبيرة، وسلاسل المراجعة/الموافقة، وأدوات التقييم | L2b لهذا المستودع |
المنسِّق + فريق | مساعد دعم آلي مزوّد بفِرق متخصّصة ومكاتب فرز ومراجعة متعددة الجوانب | الوضع 2 للعرض التوضيحي لماراثون |
وكلاء | نماذج جمع المعلومات، ومسارات الحجز، وعمليات الإعداد، وعمليات "اعرف عميلك"، وأي عملية "جمع المعلومات ثم اتّخاذ إجراء" | |
العرض/العمق الديناميكي (L4a/L4b) | وكلاء البحث، وأدوات إنشاء التقارير، وعمليات التدقيق الشاملة على المدخلات غير المعروفة الحجم | الوضع 3 للعرض التوضيحي للماراثون |
تأليف
لا يستبعد أحد الأنماط الثلاثة الآخر. يمكن لعقدة الرسم البياني استدعاء منسّق تعاوني، ويمكن لأحد المختصين إطلاق سير عمل ديناميكي. اختَر النمط المناسب لكل جزء من المشكلة، فهذه هي الطريقة التي تتجنّب بها تحويل كل نظام وكيل إلى طلب ضخم واحد.

💡 جرِّب ذلك في سير عملك: النص البرمجي الذي رسم هذا الشكل هو scripts/graph_dump.py. وجّهها إلى أي Workflow وستطبع الحواف الحقيقية، أي مخططًا هيكليًا مجانيًا لأي شيء تبنيه.
14. تهانينا

لقد أنشأت تطبيق Marathon Race Day Coach، واستخدمت خلال ذلك جميع أنماط التنسيق الثلاثة في ADK 2.
ما تعلّمته
- المقدمة: هي الطلب الضخم الذي ابتكر طقسه الخاص، أي سبب وجود البنية في الأساس.
- المستوى 0 إلى المستوى 1:
AgentوRunnerوأداة حقيقية يختار النموذج استخدامها، وWorkflowالأول (عُقد الدوال + عُقد الوكيل كعُقد متساوية). - L2a / L2b: مسارات العمل الرسومية: توسيع نطاق متوازٍ +
JoinNode، ثم توجيه قطعي: طلب واحد من نموذج اللغة الكبير. - المستوى 3أ: عملاء تعاونيون: يعمل الفريق نفسه في
chat(مقطوع) ثمsingle_turn(مجموعة فرعية متوازية + توليف) — علامة واحدة، عالمان مختلفان. - L3b — وضع
task: سؤال توضيحي متوقف مؤقتًا، واستئناف مبرمَج، وfinish_taskلعرض كائن تم التحقّق من صحته. - L4a / L4b: مهام سير العمل الديناميكية: العرض في وقت التشغيل (توزيع موسَّع)، ثم العمق في وقت التشغيل (التكرار) مع حدود في الرمز البرمجي
- L5: شجرة القرارات وكيفية إنشاء الأنماط
عبارات تستحق الاحتفاظ بها
تُعدّ الدوال السياق. تحدّد الحواف سير العمل. يختار الموجه المسار. يكتب النموذج الإجابة.
السماح للنموذج اللغوي الكبير بتحديد شكل العمل، ولكن مع الحفاظ على الحدود في الرمز البرمجي:
مطابقة النمط مع شكل المشكلة:
الخطوات التالية
- يمكنك تشغيل التطبيق الكامل الذي تم استخلاص هذه المستويات منه، وهو Marathon Race Day Coach، وهو إصدار FastAPI + SSE مع واجهة مستخدم في المتصفّح تعرض جميع الأوضاع الثلاثة مباشرةً: github.com/cuppibla/adk-2-marathon-demo.
- توسيع نطاق الاستخدام: adk-workflows-compared: جميع نماذج سير العمل الرسمية البالغ عددها 23 في "حزمة تطوير تطبيقات Android" 2، ويتضمّن كل نموذج منفذًا متوافقًا مع الإصدار 1.x وإرشادات حول حالات الاستخدام. ابدأ بـ
docs/three-pillars.md، ثمّ العناصر التي تم تخطّيها في هذا الدرس التطبيقي حول الترميز:07_loopو17_request_inputو22_agent_in_workflow. - حدِّد المشكلة الخاصة بك: ما هي الأجزاء المعروفة البنية (المستوى 2) والمعروفة الفريق (المستوى 3أ/المستوى 3ب) وغير المعروفة الشكل (المستوى 4)؟
- استكشاف الرمز البرمجي: github.com/cuppibla/adk2-tutorial
- هل شاركت في ورشة العمل؟ لن يدوم رصيدك والمشروع الذي أنشأته إلى الأبد. لمواصلة إعادة تشغيل هذه المستويات مجانًا، عليك اتّباع خطوة الإعداد في المنزل بدلاً من ذلك: مفتاح مجاني في AI Studio، وبدون مشروع على السحابة الإلكترونية أو فوترة. ويكون التغيير الوحيد هو تبديل تلك الخلية.