ساختن «عامل‌های هوشواره» با ADK: سازمان‌دهی گردش کار نمودار

۱. نمای کلی

برآورده کردن درخواست سفر با چند محدودیت (مانند برنامه‌ریزی یک سفر یک‌روزه ۱۰۰ دلاری در کیوتو با معابد تاریخی، رامن محلی، و بدون موزه‌های هنر مدرن) مستلزم استخراج اولویت‌های ساختاریافته، تحقیق هم‌زمان درباره مکان‌ها، ترکیب پیش‌نویس تفکیک‌شده، و حسابرسی هزینه کل قبل‌از پاسخ دادن است. در ADK 1.x، سازمان‌دهی این مراحل مستلزم تودرتو کردن پوشاننده‌های SequentialAgent، ParallelAgent، و LoopAgent، ذخیره کردن هر برونداد واسطه در وضعیت جلسه، و فراخوانی یک فراخوان ابزار LLM اضافی فقط برای خروج از حلقه پالایش بود.

در این codelab، بااستفاده از گردش‌های کاری نموداری (Workflow) Agent Development Kit (ADK) 2، یک برنامه‌ریز سفر چندعاملی در Agent Platform می‌سازید. در سه مرحله پیش‌رونده، گره‌های تخصصی Agent (با پشتیبانی gemini-3.8-flash) را در یک زنجیره لبه متوالی (node_input) متصل می‌کنید، پژوهشگران همزمان google_search را که با JoinNode همگام‌سازی شده‌اند پخش می‌کنید، و قوانین بودجه و استثنا را با یک رهیاب قطعی Python (Event(route=...)) اعمال می‌کنید که هرگاه پیش‌نویس اولیه از ممیزی عبور کند، پالایش را نادیده می‌گیرد.

پیش‌نیازها

آنچه می‌آموزید

  • نحوه اعلام کردن خط لوله چندعاملی در ADK 2 بااستفاده از چندتایی‌های لبه Workflow
  • ‫ADK 2 چگونه بروندادها را مستقیماً درطول لبه‌ها به‌عنوان node_input ارسال می‌کند و کلیدهای وضعیت جلسه را به‌عنوان پارامترهای تابع مقید می‌کند
  • نحوه گسترش دادن شاخه‌های پژوهش هم‌زمان و ادغام کردن خروجی‌های آن‌ها با JoinNode
  • نحوه مسیریابی قطعی چرخه‌های محدود سازنده-بررسی‌کننده در Python با Event(route=...)
  • نحوه بازرسی نمودارهای گردش کار کامپایل‌شده، خطوط زمان اجرای موازی، و دلتاهای وضعیت در ADK Web UI

آنچه نیاز دارید

  • حساب Google (اگر اعتبار کارگاه را مطالبه می‌کنید، از حساب شخصی @gmail.com استفاده کنید)
  • پیوند اعتبار کارگاه از مربی (به‌علاوه دوربین تلفن برای اسکن کردن رمزینه پاسخ‌سریع) یا حساب Cloud Billing فعال
  • Google Chrome (توصیه می‌شود از پنجره «ناشناس» استفاده کنید تا حساب‌های شخصی و کاری باهم تداخل پیدا نکنند)

۲. مطالبه کردن اعتبارهای Google Cloud (اختیاری)

اگر در کارگاهی با پیوند اعتبار رویداد شرکت می‌کنید، اعتبار Google Developer Program خود را مطالبه کنید تا حساب صورت‌حساب را بدون کارت اعتباری تأمین کنید.

اعتبار رویدادتان را مطالبه کنید

  1. پیوند اعتبار کارگاه را در پنجره ناشناس باز کنید و با حساب @gmail.com خود به سیستم وارد شوید.
  2. در مطالبه مزایا، روی مطالبه اعتبار کلیک کنید:

کارت «مطالبه مزایا» در Google Builders Hub که دکمه «مطالبه اعتبار» را نشان می‌دهد

  1. اگر از شما خواسته شد نمایه Google Developer Program ایجاد کنید، فرم را تکمیل کنید.
  2. وقتی اسکن برای درستی‌سنجی انسان بودن ظاهر شد، رمزینه پاسخ‌سریع را با تلفنتان اسکن کنید و درستی‌سنجی را تکمیل کنید (اگر رمزینه پاسخ‌سریع ظاهر نشد، صفحه را بازآورید و دوباره روی مطالبه اعتبار کلیک کنید):

کادر گفتگوی رمزینه پاسخ‌سریع «برای درستی‌سنجی انسان بودن خود، اسکن کنید» در Google Developer Program

  1. مطمئن شوید اعتبار رویداد شما باموفقیت مطالبه شد! نشان داده شود، سپس روی باز کردن حساب صورت‌حساب کلیک کنید:

Google Builders Hub که «اعتبار رویداد باموفقیت مطالبه شد» و دکمه «باز کردن حساب صورت‌حساب» را نشان می‌دهد

🔍 بررسی کردن کارتان

راه‌اندازی حساب صورت‌حساب تا ۳ دقیقه طول می‌کشد:

  1. Google Cloud Billing را باز کنید (یا نشانی وب را در پنجره «ناشناس» کپی کنید) و حساب‌های صورت‌حساب خود را انتخاب کنید:
https://console.cloud.google.com/billing
  1. بازآوری کنید تا حساب GDP Credit شما وضعیت فعال را نشان دهد:

مدیریت حساب «صورت‌حساب Google Cloud» که حساب صورت‌حساب «اعتبار GDP» فعال را نشان می‌دهد

۳. ایجاد پروژه Google Cloud (اختیاری)

یک پروژه Google Cloud اختصاصی ایجاد کنید تا همه منابع این codelab مجزا بمانند و به‌راحتی پاک شوند.

  1. ایجاد پروژه را باز کنید (یا نشانی وب را در پنجره «ناشناس» کپی کنید):
https://console.cloud.google.com/projectcreate
  1. جزئیات پروژه را وارد کنید:
    • نام پروژه: برای مثال، google-cloud-workshop
    • حساب صورت‌حساب (اگر نشان داده شده است): GDP Credit (یا حساب صورت‌حساب فعال خود) را انتخاب کنید
    • منبع اصلی: بدون سازمان (یا درصورت نیاز، سازمانتان را انتخاب کنید)
  2. شناسه پروژه تولیدشده را در زیر نام پروژه یادداشت کنید، سپس روی ایجاد کلیک کنید:

صفحه «ایجاد پروژه Google Cloud» که «نام پروژه»، «شناسه پروژه»، «منبع والد»، و دکمه «ایجاد» را نشان می‌دهد

🔍 بررسی کردن کارتان

روی اعلان‌ها در نوار ابزار بالا سمت چپ کلیک کنید و پس‌از اتمام ایجاد پروژه، روی انتخاب پروژه کلیک کنید:

منو اعلان‌های کنسول Google Cloud که «ایجاد پروژه» و پیوند «انتخاب پروژه» را نشان می‌دهد

۴. راه‌اندازی محیط

Google Cloud Shell را پیکربندی کنید، Agent Platform API را فعال کنید، و محیط مجازی Python 3.12 مجزایی با uv ایجاد کنید.

پیکربندی Cloud Shell

  1. روی فعال کردن Cloud Shell (>_) در نوارابزار کنسول Google Cloud کلیک کنید، یا Google Cloud Shell را مستقیماً باز کنید (یا نشانی وب را در پنجره «ناشناس» خود کپی کنید):
https://shell.cloud.google.com/?show=ide,terminal

دکمه «فعال کردن Cloud Shell» در نوارابزار کنسول Google Cloud

  1. درصورت درخواست، روی مجاز کردن کلیک کنید:

کادر گفتگوی «مجاز کردن Cloud Shell»

  1. شناسه پروژه فعال 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 با رنگ زرد برجسته شده باشد:

پایانه 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) در ابتدای پیام‌واره پایانه شما ظاهر می‌شود:

ترمینال Cloud Shell که پیشوند .venv را در محیط مجازی فعال Python نشان می‌دهد

‫ADK 2 را در محیط مجازی فعال نصب کنید:

uv pip install --no-cache "google-adk==2.14.0"

🔍 بررسی کردن کارتان

نسخه adk CLI نصب‌شده را درستی‌سنجی کنید:

adk --version

باید بروندادی مشابه زیر ببینید:

adk, version 2.14.0

۵. طراحی سفر را داربست‌بندی کن

بسته شروع travel_planner را با adk create تولید کنید و خط مبنای تک‌عامل پیش‌فرض را در adk web آزمایش کنید.

تولید بسته آغازگر

اجرای adk create از ~/adk-graph-agents:

cd ~/adk-graph-agents
adk create travel_planner

وقتی از شما خواسته شد، گزینه‌های زیر را انتخاب کنید (اگر در اولین اجرا از شما خواسته شد Enable telemetry? [Y/n]: را انتخاب کنید، کلید ورود را فشار دهید یا n را تایپ کنید و کلید ورود را فشار دهید):

  1. مدلی برای عامل ریشه انتخاب کنید: 2 را تایپ کنید تا gemini-3.8-flash را انتخاب کنید (گزینه 1 gemini-3.5-flash را انتخاب می‌کند) و Enter را فشار دهید.
  2. انتخاب پس‌رانه: 2 را تایپ کنید تا پس‌رانه Agent Platform در Google Cloud را انتخاب کنید (گزینه 2 در منو CLI زیر) و Enter را فشار دهید.
  3. شناسه پروژه Google Cloud را وارد کنید: کلید Enter را فشار دهید تا شناسه پروژه شناسایی‌شده در پرانتز را بپذیرید.
  4. منطقه 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 را وارد کنید، و روی تغییر و پیش‌نمایش کلیک کنید:

کادر گفتگوی پیکربندی درگاه «پیش‌نمایش وب Cloud Shell» روی ۸۰۰۰ تنظیم شده است

🔍 بررسی کردن کارتان

travel_planner را در منو کرکره‌ای بالا سمت راست adk web انتخاب کنید و "Help me plan a trip to Japan" را ارسال کنید:

میانای کاربری وب توسعه ADK که مکالمه تک‌عاملی پایه را نشان می‌دهد

باید پاسخ مکالمه‌ای تک‌گذری را در قاب گپ ببینید (با یک فراخوانی root_agent در رویدادها):

root_agent -> responds in one pass without structured preference extraction, live search, or budget verification

قبل‌از ویرایش فایل‌ها در مرحله بعد، Ctrl + C را در پایانه Cloud Shell فشار دهید تا adk web متوقف شود.

‫۶. ساختن گردش کار نمودار خطی

اولین ADK 2 خود را بسازید Workflow: یک زنجیره متوالی که نقطه ورودی رزروشده "START" را به user_profiler_agent و itinerary_synthesizer_agent متصل می‌کند (هر گره‌ای که لبه خروجی نداشته باشد به‌عنوان گره پایانی عمل می‌کند). هر لبه (a, b) به‌طور خودکار گره‌های Agent (نام مستعار برای LlmAgent) را در حالت مجزای single_turn اجرا می‌کند و برونداد گره a را به‌عنوان node_input (پیام ورودی کاربر) به گره b تحویل می‌دهد، درحالی‌که {user_preferences} در رشته دستورالعمل، کلید حالت جلسه منطبق را که ازطریق output_key ذخیره شده است درون‌یابی می‌کند.

نمودار معماری که travel_workflow (گردش کار) را نشان می‌دهد که START را به user_profiler_agent و itinerary_synthesizer_agent متصل می‌کند

ایجاد متخصصان اولیه

مطمئن شوید 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 زیر را جای‌گذاری کنید (که در آن چندتایی ۳ گره یا بیشتر در زنجیره‌ای متوالی از "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 "*"

«پیش‌نمایش وب» را در درگاه 8000 باز کنید، روی + جلسه جدید کلیک کنید، و این را ارسال کنید:

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

میانای کاربر وب ADK 2.14.0 که اجرای نمودار START به user_profiler_agent به itinerary_synthesizer_agent و برنامه سفر تولیدشده کیوتو را نشان می‌دهد

روی هر رویدادی در رویدادها کلیک کنید و روی نماد نمودار (account_tree در نوارابزار جزئیات رویداد) کلیک کنید تا توپولوژی START -> user_profiler_agent -> itinerary_synthesizer_agent کامپایل‌شده را بررسی کنید، سپس برگه وضعیت را بررسی کنید تا مطمئن شوید user_preferences و final_itinerary پر شده‌اند.

برای توقف adk web قبل‌از ادامه دادن، Ctrl + C را در پایانه فشار دهید.

‫۷. Fan out and join with 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 ارسال می‌کند، به‌جای اینکه ترکیب را دو بار راه‌اندازی کند.

نمودار معماری که نشان می‌دهد travel_workflow از user_profiler_agent ازطریق node_input به‌طور موازی به activity_finder_agent و restaurant_finder_agent منشعب می‌شود، در research_join (JoinNode) ادغام می‌شود، و node_input (dict) را به 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 "*"

«پیش‌نمایش وب» را در درگاه 8000 باز کنید، روی + جلسه جدید کلیک کنید، و این را ارسال کنید:

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}

برای توقف adk web قبل‌از ادامه دادن، Ctrl + C را در پایانه فشار دهید.

‫۸. چرخه‌های بازبینی مسیر

با افزودن یک itinerary_critic_agent، یک itinerary_refiner_agent، و دو گره تابع Python قطعی (route_critique و finalize_itinerary) که اشیاء ADK Event را برمی‌گردانند، محدودیت‌های بودجه و منفی را اعمال کنید:

  • route: انتخاب می‌کند که کدام کلید شاخه نام‌گذاری‌شده در لبه dict‏ ({"revise": ..., "approved": ...}) در مرحله بعد اجرا شود.
  • output: یک مقدار یا رشته تایپ‌شده Python را در امتداد لبه به‌عنوان node_input به گره بعدی منتقل می‌کند بدون اینکه پیام گپ را رندر کند.
  • ‫message و state: message نوشتار قابل‌مشاهده برای کاربر را در ترانویسی گپ منتشر می‌کند، درحالی‌که state به‌روزرسانی‌های مقدار کلید (stateDelta) را به وضعیت جلسه ارسال می‌کند.

نمودار معماری که travel_workflow را با itinerary_critic_agent نشان می‌دهد که route_critique را تغذیه می‌کند، که «revise» را به itinerary_refiner_agent (با برگشت به itinerary_critic_agent) یا «approved» را به finalize_itinerary هدایت می‌کند

افزودن متخصصان منتقد و پالایشگر

مطمئن شوید 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 "*"

«پیش‌نمایش وب» را در درگاه 8000 باز کنید، روی + جلسه جدید کلیک کنید، و پیام‌واره چندمحدودیتی کیوتو را ارسال کنید:

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"، پیام‌واره پیگیری با بودجه محدود $۱۵ ارسال کنید:

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

برای توقف adk web، Ctrl + C را در پایانه فشار دهید.

‫۹. عیب‌یابی

منو کرکره‌ای عامل در adk web خالی است

  • علت: adk web به‌جای دایرکتوری والد ~/adk-graph-agents در travel_planner/ شروع شده است، یا جلسه 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 را دوباره شروع کنید.

‫۱۰. مرتب‌سازی

فضای کاری محلی را بردارید و به‌طور اختیاری API را غیرفعال کنید یا پروژه کارگاهی اختصاصی را حذف کنید.

حذف کردن فایل‌های پروژه محلی

فهرست راهنمای ~/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

‫۱۱. تبریک می‌گوییم

شما بااستفاده از ADK 2 Workflow، یک برنامه‌ریز سفر چندعاملی ساختید که زنجیره‌های متوالی، توزیع هم‌زمان google_search با JoinNode، و چرخه‌های سازنده-بررسی‌کننده شرطی را در یک گراف لبه‌ای اعلانی واحد متحد می‌کند.

آنچه انجام داده‌اید

  • خط لوله چندعاملی بااستفاده از ADK 2 اعلام شد Workflow(edges=[...])
  • داده‌ها را مستقیماً بین Agent، JoinNode، و گره‌های تابع Python ازطریق node_input و پارامترهای محدود به حالت منتقل کرد و درعین‌حال حالت جلسه را در حداقل نگه داشت
  • google_search شاخه هم‌زمان را گسترش داد و آن‌ها را با JoinNode همگام‌سازی کرد
  • LoopAgent و ارتقای حلقه مبتنی بر ابزار را با یک مسیریاب قطعی Event(route=...) جایگزین کردیم که از تماس‌های غیرضروری LLM در پیش‌نویس‌های تأییدشده صرف‌نظر می‌کند

مراحل بعدی