1. نظرة عامة
لتلبية طلب سفر يتضمّن قيودًا متعددة (مثل التخطيط لرحلة يومية في كيوتو بقيمة 100 دولار أمريكي تشمل زيارة المعابد التاريخية وتناول الرامن المحلي وعدم زيارة متاحف الفن الحديث)، يجب استخراج التفضيلات المنظَّمة والبحث عن الأماكن في الوقت نفسه وتجميع مسودة مفصّلة ومراجعة التكلفة الإجمالية قبل الردّ. في الإصدار 1.x من ADK، كان تنظيم هذه المراحل يتطلّب دمج برامج تضمين SequentialAgent وParallelAgent وLoopAgent، وحفظ كل ناتج وسيط في حالة الجلسة، واستدعاء أداة LLM إضافية للخروج من حلقة التحسين.
في هذا الدرس التطبيقي حول الترميز، يمكنك إنشاء مخطِّط رحلات متعدّد الوكلاء على Agent Platform باستخدام مهام سير عمل الرسم البياني (Workflow) في Agent Development Kit (ADK) 2. على مدار ثلاث مراحل متقدّمة، يمكنك ربط عُقد Agent متخصّصة (مستندة إلى gemini-3.8-flash) في سلسلة حواف متسلسلة (node_input)، وتوزيع باحثي google_search متزامنين مع JoinNode، وفرض قواعد الميزانية والاستبعاد باستخدام موجّه Python حتمي (Event(route=...)) يتخطّى التحسين عندما تجتاز المسودة الأولية عملية التدقيق.
المتطلبات الأساسية
- إتقان أساسي للبرمجة بلغة Python
- الإلمام بمفاهيم الذكاء الاصطناعي التوليدي وأساسيات وكيل الذكاء الاصطناعي
ما ستتعرّف عليه
- كيفية تعريف مسار متعدد الوكلاء في ADK 2 باستخدام صفوف حواف
Workflow - كيفية تمرير ADK 2 للمخرجات مباشرةً على طول الحواف كـ
node_inputوربط مفاتيح حالة الجلسة كمَعلمات دالة - كيفية توزيع فروع البحث المتزامنة ودمج نتائجها باستخدام
JoinNode - كيفية توجيه دورات صانع-مدقّق محدودة بشكل حتمي في Python باستخدام
Event(route=...) - كيفية فحص الرسوم البيانية لسير العمل المجمّع والمخططات الزمنية للتنفيذ الموازي وفروق الحالة في واجهة مستخدم الويب الخاصة بـ ADK
ما تحتاج إليه
- حساب Google (يُرجى استخدام حساب
@gmail.comشخصي في حال المطالبة برصيد ورشة العمل) - رابط رصيد ورشة العمل من المدرّب (بالإضافة إلى كاميرا الهاتف لمسح رمز الاستجابة السريعة ضوئيًا) أو حساب فوترة نشط على Cloud
- Google Chrome (ننصح باستخدام نافذة تصفّح متخفٍّ لتجنُّب الخلط بين الحسابات الشخصية وحسابات العمل)
2. طلب الحصول على أرصدة Google Cloud (اختياري)
إذا كنت تحضر ورشة عمل تتضمّن رابطًا لرصيد الحدث، يمكنك الحصول على رصيد Google Developer Program لتوفير حساب فوترة بدون بطاقة ائتمان.
طلب رصيد الفعالية
- افتح رابط رصيد ورشة العمل في نافذة التصفّح المتخفي وسجِّل الدخول باستخدام حسابك على "
@gmail.com". - في صفحة طلب الاستفادة من الميزة، انقر على طلب الرصيد:

- إذا طُلب منك إنشاء ملف شخصي في Google Developer Program، أكمِل النموذج.
- عند ظهور رسالة يُرجى مسح الرمز ضوئيًا لإثبات أنّك شخص حقيقي، امسح رمز الاستجابة السريعة ضوئيًا باستخدام هاتفك وأكمِل عملية التحقّق (أعِد تحميل الصفحة وانقر على طلب الرصيد مرة أخرى إذا لم يظهر رمز الاستجابة السريعة):

- تأكَّد من ظهور الرسالة تمت المطالبة برصيد الحدث بنجاح، ثم انقر على فتح حساب الفوترة:

🔍 التحقّق من عملك
يستغرق إعداد حساب الفوترة مدة تصل إلى 3 دقائق:
- افتح Google Cloud Billing (أو انسخ عنوان URL في نافذة التصفّح المتخفي) واختَر حسابات الفوترة:
https://console.cloud.google.com/billing
- أعِد تحميل الصفحة إلى أن تظهر حالة حسابك على
GDP Creditعلى أنّها نشط:

3- إنشاء مشروع على Google Cloud (اختياري)
أنشئ مشروعًا مخصّصًا على Google Cloud لتبقى جميع الموارد من هذا الدرس التطبيقي حول الترميز معزولة ويسهل حذفها.
- افتح إنشاء مشروع (أو انسخ عنوان URL في نافذة التصفّح المتخفي):
https://console.cloud.google.com/projectcreate
- أدخِل تفاصيل مشروعك:
- اسم المشروع: على سبيل المثال،
google-cloud-workshop - حساب الفوترة (إذا ظهر): اختَر
GDP Credit(أو حساب الفوترة النشط) - المورد الرئيسي: بدون مؤسسة (أو اختَر مؤسستك إذا لزم الأمر)
- اسم المشروع: على سبيل المثال،
- دوِّن رقم تعريف المشروع الذي تم إنشاؤه أسفل اسم المشروع، ثم انقر على إنشاء:

🔍 التحقّق من عملك
انقر على الإشعارات في شريط الأدوات في أعلى يسار الصفحة، ثم انقر على اختيار مشروع بعد الانتهاء من إنشاء المشروع:

4. إعداد البيئة
اضبط Google Cloud Shell وفعِّل Agent Platform API وأنشئ بيئة افتراضية معزولة في Python 3.12 باستخدام uv.
إعداد Cloud Shell
- انقر على تفعيل Cloud Shell (
>_) في شريط أدوات Google Cloud Console، أو افتح Google Cloud Shell مباشرةً (أو انسخ عنوان URL في نافذة التصفّح المتخفي):
https://shell.cloud.google.com/?show=ide,terminal

- انقر على تفويض إذا طُلب منك ذلك:

- اختَر رقم تعريف مشروع Google Cloud النشط من القائمة المرقّمة في وحدة التحكّم:
unset CLOUDSDK_CORE_PROJECT
PS3="Select your project (e.g. 1): "
select PROJECT_ID in $(gcloud projects list --format="value(projectId)"); do
[ -n "$PROJECT_ID" ] && gcloud config set project "$PROJECT_ID" && break
done
من المفترض أن تظهر لك نتيجة مشابهة لما يلي (تطبع المشاريع غير المُصنَّفة أيضًا سطرًا إعلاميًا [environment: untagged]):
1) google-cloud-workshop-4210 2) my-cloud-project-8812 Select your project (e.g. 1): 1 Updated property [core/project].
تأكَّد من ظهور رقم تعريف المشروع الذي اخترته مميّزًا باللون الأصفر في طلب Cloud Shell:

تفعيل واجهات برمجة التطبيقات المطلوبة
فعِّل Agent Platform API لتتمكّن وكلاء ADK من استدعاء نماذج Gemini:
gcloud services enable aiplatform.googleapis.com
من المفترَض أن تظهر لك نتيجة مثل:
Operation "operations/acat.p2-..." finished successfully.
إنشاء بيئة Python افتراضية وتثبيت ADK
أنشِئ مساحة عمل ~/adk-graph-agents وفعِّل بيئة Python 3.12 افتراضية:
cd ~
mkdir -p adk-graph-agents && cd ~/adk-graph-agents
which uv >/dev/null 2>&1 || curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv venv .venv --python 3.12
source .venv/bin/activate
تأكَّد من ظهور البادئة (.venv) في بداية طلب Terminal:

ثبِّت ADK 2 داخل البيئة الافتراضية النشطة:
uv pip install --no-cache "google-adk==2.14.0"
🔍 التحقّق من عملك
تحقَّق من إصدار واجهة سطر الأوامر (CLI) المثبَّت في adk:
adk --version
من المفترَض أن تظهر لك نتيجة مثل:
adk, version 2.14.0
5- توفير الدعم في أداة تخطيط الرحلات
أنشِئ حزمة travel_planner الأساسية باستخدام adk create واختبِر أداء الوكيل الواحد التلقائي في adk web.
إنشاء الحزمة الأساسية
تشغيل "adk create" من "~/adk-graph-agents":
cd ~/adk-graph-agents
adk create travel_planner
حدِّد الخيارات التالية عندما يُطلب منك ذلك (إذا طُلب منك إدخال Enable telemetry? [Y/n]: عند التشغيل لأول مرة، اضغط على مفتاح Enter أو اكتب n واضغط على مفتاح Enter):
- اختيار نموذج للوكيل الجذر: اكتب
2لاختيارgemini-3.8-flash(يؤدي الخيار1إلى اختيارgemini-3.5-flash) واضغط على مفتاح Enter. - اختيار الخلفية: اكتب
2لاختيار خلفية Agent Platform في Google Cloud (الخيار2في قائمة واجهة سطر الأوامر أدناه) واضغط على مفتاح Enter. - إدخال رقم تعريف مشروع Google Cloud: اضغط على مفتاح Enter لقبول رقم تعريف المشروع الذي تم رصده بين قوسين.
- أدخِل منطقة Google Cloud: اكتب
global(لاستخدام نقطة نهاية Gemini العالمية) واضغط على مفتاح Enter.
يكتب adk create السمة GOOGLE_GENAI_USE_ENTERPRISE=1 ورقم تعريف مشروعك والسمة GOOGLE_CLOUD_LOCATION=global في travel_planner/.env، وبذلك تظل بيانات الاعتماد سليمة عند استبدال agent.py لاحقًا.
من المفترَض أن تظهر لك نتيجة مثل:
Choose a model for the root agent: 1. gemini-3.5-flash 2. gemini-3.8-flash 3. Other models (fill later) Choose model (1, 2, 3): 2 1. Google AI 2. Vertex AI 3. Login with Google Choose a backend (1, 2, 3): 2 You need an existing Google Cloud account and project, check out this link for details: https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-cloud-vertex-ai Enter Google Cloud project ID [google-cloud-workshop-4210]: Enter Google Cloud region [us-central1]: global Agent created in /home/your_username/adk-graph-agents/travel_planner: - .env - .gitignore - __init__.py - agent.py ⚠️ WARNING: Secrets (like GOOGLE_API_KEY) are stored in .env. Next steps: - Chat with your agent in the terminal: adk run travel_planner - Or in the browser: adk web . - Have your coding agent evaluate and deploy it: uvx google-agents-cli setup (other install options: https://adk.dev/get-started/agents-cli/)
افتح ~/adk-graph-agents في أداة تعديل الرموز في Cloud Shell:
which cloudshell >/dev/null 2>&1 && cloudshell workspace ~/adk-graph-agents || true
أعِد تفعيل البيئة الافتراضية في الوحدة الطرفية التي تمت إعادة تحميلها:
cd ~/adk-graph-agents
source .venv/bin/activate
اختبار الوكيل الفردي المبدئي
ابدأ واجهة مستخدم الويب الخاصة بـ ADK لملاحظة كيف يجيب وكيل مبتدئ واحد غير منسَّق عن طلب سفر:
cd ~/adk-graph-agents
adk web --allow_origins "*"
انقر على رمز معاينة الويب في شريط أدوات Cloud Shell في أعلى يسار الصفحة، ثم اختَر تغيير المنفذ، وأدخِل 8000، وانقر على تغيير ومعاينة:

🔍 التحقّق من عملك
اختَر travel_planner في القائمة المنسدلة أعلى يمين "adk web" وأرسِل "Help me plan a trip to Japan":

من المفترض أن يظهر لك ردّ حواري من خطوة واحدة في لوحة المحادثة (مع استدعاء واحد لـ root_agent في الأحداث):
root_agent -> responds in one pass without structured preference extraction, live search, or budget verification
اضغط على Ctrl + C في وحدة طرفية Cloud Shell لإيقاف adk web قبل تعديل الملفات في الخطوة التالية.
6. إنشاء سير عمل رسم بياني خطي
أنشئ أول ADK 2 Workflow: سلسلة متتابعة تربط نقطة الدخول المحجوزة "START" بـ user_profiler_agent وitinerary_synthesizer_agent (أي عقدة ليس لها حواف صادرة تعمل كعقدة طرفية). تُشغّل كل حافة (a, b) تلقائيًا عُقد Agent (اسم بديل لـ LlmAgent) في وضع single_turn المعزول وتُرسل مخرجات العقدة a كـ node_input (رسالة المستخدم الواردة) إلى العقدة b، بينما يُدرج {user_preferences} في سلسلة تعليمات مفتاح حالة الجلسة المطابق الذي تم حفظه عبر output_key.

إنشاء المتخصّصين الأوّليين
تأكَّد من إيقاف adk web (Ctrl + C)، ثم افتح ملفًا جديدًا باسم travel_planner/specialists.py:
cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py
الصِق الرمز التالي في travel_planner/specialists.py لتحديد user_profiler_agent وitinerary_synthesizer_agent (استيراد google_search مسبقًا للخطوة التالية):
from google.adk import Agent
from google.adk.tools import google_search
MODEL = "gemini-3.8-flash"
# --- Specialist 1: The User Profiler ---
user_profiler_agent = Agent(
model=MODEL,
name="user_profiler_agent",
description="Extracts travel preferences and constraints from user input.",
instruction="""
Extract destination, duration (default 1 day), budget, interests, and exclusions.
Return a single JSON object with keys: "destination", "duration", "budget", "interests", "exclusions".
""",
output_key="user_preferences", # Saved for multi-hop constraints downstream
)
# --- Specialist 2: The Synthesizer ---
itinerary_synthesizer_agent = Agent(
model=MODEL,
name="itinerary_synthesizer_agent",
description="Compiles preferences and research into a final Markdown itinerary.",
instruction="""
You are an elite Travel Concierge. Using the incoming input and
User Preferences ({user_preferences}), write a Markdown itinerary
with an itemized USD and local currency cost breakdown.
""",
output_key="final_itinerary",
)
تحديد سلسلة الحواف المتسلسلة
افتح ملفًا جديدًا باسم travel_planner/workflows.py:
cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py
ألصِق تعريف Workflow التالي (حيث يتم تجميع صف من 3 عُقد أو أكثر في سلسلة متسلسلة من "START"):
from google.adk import Workflow
from .specialists import (
itinerary_synthesizer_agent,
user_profiler_agent,
)
# 1. SEQUENTIAL GRAPH: START -> user_profiler_agent -> itinerary_synthesizer_agent
travel_workflow = Workflow(
name="travel_workflow",
description="Orchestrates the end-to-end travel planning process as a graph workflow.",
edges=[
("START", user_profiler_agent, itinerary_synthesizer_agent),
],
)
عرض سير العمل كـ root_agent
افتح travel_planner/agent.py:
cloudshell edit ~/adk-graph-agents/travel_planner/agent.py
استبدِل محتوى travel_planner/agent.py بالكامل بهذين السطرَين:
from .workflows import travel_workflow
root_agent = travel_workflow
🔍 التحقّق من عملك
بدء adk web من ~/adk-graph-agents:
cd ~/adk-graph-agents
adk web --allow_origins "*"
افتح "معاينة الويب" (Web Preview) على المنفذ 8000، وانقر على + جلسة جديدة (+ New Session)، ثم أرسِل:
Help me plan a trip to Kyoto
في عرض الأحداث، من المفترض أن يظهر لك تسلسل أحداث مشابه لما يلي:
1. user_profiler_agent -> outputs JSON {"destination": "Kyoto", "duration": "1 day", ...} and writes state["user_preferences"]
2. itinerary_synthesizer_agent -> receives preferences via node_input and outputs the Markdown itinerary

انقر على أي حدث في الأحداث، ثم انقر على رمز الرسم البياني (account_tree في شريط أدوات تفاصيل الحدث) لفحص بنية START -> user_profiler_agent -> itinerary_synthesizer_agent المجمّعة، ثم راجِع علامة التبويب الحالة للتأكّد من تعبئة user_preferences وfinal_itinerary.
اضغط على Ctrl + C في الوحدة الطرفية لإيقاف adk web قبل المتابعة.
7. التوزيع والانضمام باستخدام JoinNode
يمكنك ربط برنامج الرحلة ببيانات الويب المباشرة من خلال إضافة خبيرَين متخصصَين في google_search (activity_finder_agent وrestaurant_finder_agent) ومزامنتهما مع JoinNode:
- مجموعة البيانات المتعدّدة المخرجات: يؤدي وضع
(activity_finder_agent, restaurant_finder_agent)داخل مجموعة بيانات الحافة إلى إرسال مخرجاتuser_profiler_agentعلى شكلnode_inputإلى كلا الباحثَين في الوقت نفسه. - حاجز Fan-in (
JoinNode): يؤدي وضعJoinNode(name="research_join")مباشرةً بعد الصف إلى الانتظار حتى يكتمل كل فرع وارد ويمرّرdict({"activity_finder_agent": ..., "restaurant_finder_agent": ...}) مدمجًا واحدًا كـnode_inputإلىitinerary_synthesizer_agentبدلاً من تشغيل عملية التركيب مرتين.

إضافة المتخصّصين في الأبحاث
تأكَّد من إيقاف adk web (Ctrl + C)، ثم افتح travel_planner/specialists.py:
cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py
أضِف activity_finder_agent وrestaurant_finder_agent إلى أسفل travel_planner/specialists.py (لا يحتاج أي منهما إلى output_key لأنّ research_join يعيد توجيه كلا الناتجَين مباشرةً عبر node_input):
# --- Specialist 3: The Activity Finder ---
activity_finder_agent = Agent(
model=MODEL,
name="activity_finder_agent",
description="Finds 3 attractions matching the user's destination and interests.",
instruction="""
Using the travel preferences in the input, call google_search to find 3 specific attractions
(including budget-friendly options).
Return a JSON list with keys: "attraction_name", "estimated_cost_local", "estimated_cost_usd", "notes".
""",
tools=[google_search],
)
# --- Specialist 4: The Restaurant Finder ---
restaurant_finder_agent = Agent(
model=MODEL,
name="restaurant_finder_agent",
description="Finds 3 restaurants matching the destination and budget.",
instruction="""
Using the travel preferences in the input, call google_search to find 3 highly-rated restaurants
across price points.
Return a JSON list with keys: "restaurant_name", "cuisine", "estimated_cost_local", "estimated_cost_usd".
""",
tools=[google_search],
)
إضافة fan-out وJoinNode إلى workflows.py
افتح travel_planner/workflows.py:
cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py
استبدِل محتوى travel_planner/workflows.py بالكامل بالرسم البياني لعملية التوزيع وJoinNode:
from google.adk import Workflow
from google.adk.workflow import JoinNode
from .specialists import (
activity_finder_agent,
itinerary_synthesizer_agent,
restaurant_finder_agent,
user_profiler_agent,
)
research_join = JoinNode(name="research_join")
# 2. FAN-OUT / FAN-IN GRAPH: Profile -> (Activities || Restaurants) -> Join -> Synthesize
travel_workflow = Workflow(
name="travel_workflow",
description="Orchestrates the end-to-end travel planning process as a graph workflow.",
edges=[
(
"START",
user_profiler_agent,
(activity_finder_agent, restaurant_finder_agent),
research_join,
itinerary_synthesizer_agent,
),
],
)
🔍 التحقّق من عملك
ابدأ adk web لاختبار البحث المتزامن ومزامنة JoinNode:
cd ~/adk-graph-agents
adk web --allow_origins "*"
افتح "معاينة الويب" (Web Preview) على المنفذ 8000، وانقر على + جلسة جديدة (+ New Session)، ثم أرسِل:
Help me plan a trip to Kyoto focused on historic temples and ramen
في عرض الأحداث، من المفترض أن يظهر لك تسلسل أحداث مشابه لما يلي:
1. user_profiler_agent -> emits JSON preferences via node_input
2. activity_finder_agent & restaurant_finder_agent -> invoke google_search concurrently
3. research_join -> merges both researcher outputs into one dict node_input
4. itinerary_synthesizer_agent -> drafts final_itinerary from the merged dict + {user_preferences}
اضغط على Ctrl + C في الوحدة الطرفية لإيقاف adk web قبل المتابعة.
8. دورات مراجعة المسارات
يمكنك فرض قيود الميزانية والقيود السلبية من خلال إضافة itinerary_critic_agent وitinerary_refiner_agent وعقدتَي دالة Python حتميتَين (route_critique وfinalize_itinerary) تُرجعان عناصر Event في ADK:
-
route: يختار مفتاح الفرع المُعنوَن في حافة قاموس ({"revise": ..., "approved": ...}) الذي سيتم تشغيله بعد ذلك. -
output: يمرّر قيمة أو سلسلة Python مكتوبة على طول الحافة كـnode_inputإلى العقدة التالية بدون عرض رسالة محادثة. -
messageوstate: تُصدر السمةmessageنصًا مرئيًا للمستخدم في نص المحادثة، بينما تُنفّذ السمةstateتعديلات على أزواج المفتاح والقيمة (stateDelta) في حالة الجلسة.

إضافة المتخصّصين في النقد والتحسين
تأكَّد من إيقاف adk web (Ctrl + C)، ثم افتح travel_planner/specialists.py:
cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py
أضِف itinerary_critic_agent وitinerary_refiner_agent إلى أسفل travel_planner/specialists.py (لا يحتاج المنقّح إلى أداة google_search أو exit_loop لأنّه يبدّل العناصر التي تم جمعها في {final_itinerary} ولا يعمل إلا عندما يختار route_critique "revise"):
# --- Specialist 5: The Budget & Constraint Critic ---
itinerary_critic_agent = Agent(
model=MODEL,
name="itinerary_critic_agent",
description="Audits the itinerary draft against budget and negative constraints.",
instruction="""
Audit the itinerary in the input against User Preferences ({user_preferences}).
Verify that the USD total stays within the user's budget and no excluded venue types appear.
If all checks pass, respond EXACTLY with the single word "APPROVED".
Otherwise, output 1-2 concise revision instructions explaining what to swap or adjust.
""",
)
# --- Specialist 6: The Itinerary Refiner ---
itinerary_refiner_agent = Agent(
model=MODEL,
name="itinerary_refiner_agent",
description="Revises the itinerary draft using the critic's feedback.",
instruction="""
Revise Current Itinerary ({final_itinerary}) using the auditor critique in the input
so all USD budget and exclusion rules in {user_preferences} pass.
Output ONLY the updated Markdown itinerary.
""",
output_key="final_itinerary",
)
إضافة route_critique والدورة
افتح travel_planner/workflows.py:
cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py
استبدِل محتوى travel_planner/workflows.py بالكامل بسير عمل الرسم البياني الكامل:
from google.adk import Event, Workflow
from google.adk.workflow import JoinNode
from .specialists import (
activity_finder_agent, itinerary_critic_agent, itinerary_refiner_agent,
itinerary_synthesizer_agent, restaurant_finder_agent, user_profiler_agent,
)
MAX_REVISIONS = 2
research_join = JoinNode(name="research_join")
def route_critique(node_input: str, revision_count: int = 0):
"""Routes to 'approved' when constraints pass, or 'revise' up to MAX_REVISIONS."""
approved = node_input.strip().rstrip(".").upper() == "APPROVED"
if approved or revision_count >= MAX_REVISIONS:
return Event(route="approved", output=approved)
return Event(
route="revise", output=node_input, state={"revision_count": revision_count + 1}
)
def finalize_itinerary(node_input: bool, final_itinerary: str, revision_count: int = 0):
"""Emits the verified itinerary and resets revision_count for the next turn."""
status = (
f"Itinerary approved after {revision_count} revision(s)."
if node_input
else f"Max revisions ({revision_count}) reached; returning best-effort draft."
)
return Event(
message=f"{status}\n\n{final_itinerary}",
output=final_itinerary,
state={"revision_count": 0},
)
travel_workflow = Workflow(
name="travel_workflow",
description="Orchestrates the end-to-end travel planning process as a graph workflow.",
edges=[
(
"START",
user_profiler_agent,
(activity_finder_agent, restaurant_finder_agent),
research_join,
itinerary_synthesizer_agent,
itinerary_critic_agent,
route_critique,
),
(route_critique, {"revise": itinerary_refiner_agent, "approved": finalize_itinerary}),
(itinerary_refiner_agent, itinerary_critic_agent),
],
)
🔍 التحقّق من عملك
تأكَّد من أنّ travel_planner/workflows.py يتم تجميعه بشكل صحيح ويطبع حواف الرسم البياني الموجَّه:
cd ~/adk-graph-agents && source .venv/bin/activate
python3 -c "from travel_planner.agent import root_agent; print('\n'.join(f'{e.from_node.name} -> {e.to_node.name} (route={e.route})' for e in root_agent.graph.edges))"
من المفترَض أن تظهر لك نتيجة مثل:
__START__ -> user_profiler_agent (route=None) user_profiler_agent -> activity_finder_agent (route=None) user_profiler_agent -> restaurant_finder_agent (route=None) activity_finder_agent -> research_join (route=None) restaurant_finder_agent -> research_join (route=None) research_join -> itinerary_synthesizer_agent (route=None) itinerary_synthesizer_agent -> itinerary_critic_agent (route=None) itinerary_critic_agent -> route_critique (route=None) route_critique -> itinerary_refiner_agent (route=revise) route_critique -> finalize_itinerary (route=approved) itinerary_refiner_agent -> itinerary_critic_agent (route=None)
بعد ذلك، ابدأ adk web لاختبار كل من الموافقة الفورية والمراجعات التي يتم إجراؤها استنادًا إلى الميزانية:
adk web --allow_origins "*"
افتح "معاينة الويب" (Web Preview) على المنفذ 8000، وانقر على + جلسة جديدة (+ New Session)، وأرسِل الطلب المتعدّد الشروط حول كيوتو:
Design a full-day itinerary for Kyoto with a total budget of $100. My main interests are historical landmarks, temples, and authentic local cuisine. Please do not include any modern art museums or galleries.
لمشاهدة حلقة route="revise" أثناء عملها، أرسِل طلب متابعة بميزانية محدودة تبلغ 15 دولار أمريكي:
Now design a full-day Kyoto itinerary with paid temple admissions, lunch, and dinner on a strict total budget of $15 USD.
في عرض الأحداث، من المفترض أن يظهر لك تسلسل تنفيذ مشابه لما يلي:
1. user_profiler_agent -> writes JSON constraints to state["user_preferences"] 2. (activity_finder_agent, restaurant_finder_agent) -> run google_search concurrently -> research_join 3. itinerary_synthesizer_agent -> writes initial draft to state["final_itinerary"] 4. itinerary_critic_agent -> outputs "APPROVED" (or revision instructions when over budget) 5. route_critique -> emits route="approved" (skipping refiner) or route="revise" -> itinerary_refiner_agent -> itinerary_critic_agent 6. finalize_itinerary -> emits "Itinerary approved after N revision(s)." (or max-revisions notice) and resets revision_count=0
اضغط على Ctrl + C في الوحدة الطرفية لإيقاف adk web.
9. تحديد المشاكل وحلّها
القائمة المنسدلة للوكيل فارغة في adk web
- السبب: تم بدء
adk webداخلtravel_planner/بدلاً من الدليل الرئيسي~/adk-graph-agents، أو تمت إعادة تشغيل جلسة Cloud Shell. - الحلّ: اضغط على
Ctrl + C، ثم ارجع إلى الدليل الرئيسي، وأعِد التشغيل باستخدامcd ~/adk-graph-agents && source .venv/bin/activate && adk web --allow_origins "*".
خطأ في نموذج "404 NOT_FOUND"
- السبب: ضغطت على مفتاح Enter لقبول منطقة
us-central1التلقائية أثناءadk createبدلاً من كتابةglobal. - الحلّ: افتح
~/adk-graph-agents/travel_planner/.envوتأكَّد من ضبطGOOGLE_CLOUD_LOCATION=global.
ERROR: [Errno 98] address already in use على المنفذ 8000
- السبب: لا يزال خادم
adk webالسابق قيد التشغيل في Cloud Shell. - الحلّ: اضغط على
Ctrl + Cفي الوحدة الطرفية النشطة أو أوقِف العملية الحالية باستخدامpkill -f "adk web"قبل بدءadk webمرة أخرى.
10. تَنظيم
أزِل مساحة العمل المحلية وأوقِف واجهة برمجة التطبيقات أو احذف مشروع ورشة عمل مخصّصًا، إذا أردت.
حذف ملفات المشروع على جهاز المستخدم
أزِل دليل ~/adk-graph-agents والبيئة الافتراضية:
cd ~
rm -rf ~/adk-graph-agents
إيقاف Agent Platform API (اختياري)
أوقِف Agent Platform API إذا لم تعُد بحاجة إليها في هذا المشروع:
gcloud services disable aiplatform.googleapis.com --quiet
🔍 التحقّق من عملك
تأكيد إزالة "~/adk-graph-agents":
test ! -d ~/adk-graph-agents && echo "Workspace ~/adk-graph-agents removed"
من المفترَض أن تظهر لك نتيجة مثل:
Workspace ~/adk-graph-agents removed
11. تهانينا
لقد أنشأت مخطِّط سفر متعدّد الوكلاء باستخدام ADK 2 Workflow، ووحّدت السلاسل المتسلسلة، والتوزيع المتزامن google_search باستخدام JoinNode، ودورات صانع-مدقّق شرطية في رسم بياني حافة تعريفي واحد.
إنجازاتك
- تم الإعلان عن مسار متعدد الوكلاء باستخدام ADK 2
Workflow(edges=[...]) - تم تمرير البيانات مباشرةً بين عُقد الدوال
AgentوJoinNodeوPython من خلالnode_inputوالمَعلمات المرتبطة بالحالة مع الحفاظ على الحد الأدنى من حالة الجلسة - تم توزيع
google_searchفرع متزامن ومزامنتها معJoinNode - تم استبدال
LoopAgentوالتصعيد المتكرر المستند إلى الأدوات بجهاز توجيهEvent(route=...)حتمي يتخطّى طلبات النماذج اللغوية الكبيرة غير الضرورية في المسودات الموافَق عليها
الخطوات التالية
- استكشاف الأنظمة المتعددة الوكلاء في ADK
- انضم إلى برنامج GEAR (Gemini Enterprise Agent Ready) وبرنامج الحصول على شهادة للمشاركة في ورش عمل تطبيقية ومسارات تعلُّم