ADK-এর মাধ্যমে AI এজেন্ট তৈরি করা: গ্রাফ ওয়ার্কফ্লো অর্কেস্ট্রেট করা

১. এক নজরে

একাধিক শর্তযুক্ত ভ্রমণের অনুরোধ (যেমন, ঐতিহাসিক মন্দির, স্থানীয় রামেন এবং কোনও আধুনিক আর্ট মিউজিয়াম নেই এমন কিয়োটোতে $১০০-এর এক দিনের ট্রিপের প্ল্যান করা) পূরণ করার জন্য স্ট্রাকচার্ড পছন্দ বের করা, একই সাথে ভেনু রিসার্চ করা, আইটেম অনুযায়ী ড্রাফ্ট তৈরি করা এবং উত্তর দেওয়ার আগে মোট খরচ অডিট করা প্রয়োজন। ADK 1.x-এ, সেইসব ধাপ সাজানোর জন্য SequentialAgent, ParallelAgent ও LoopAgent র‍্যাপার নেস্ট করা, সেশন স্টেটে প্রতিটি ইন্টারমিডিয়েট আউটপুট সেভ করা এবং রিফাইনমেন্ট লুপ থেকে বেরিয়ে আসার জন্য অতিরিক্ত LLM টুল কল করার প্রয়োজন হয়।

এই কোডল্যাবে, আপনি Agent Development Kit (ADK) 2 গ্রাফ ওয়ার্কফ্লো (Workflow) ব্যবহার করে Agent Platform-এ একটি মাল্টি-এজেন্ট ট্রাভেল প্ল্যানার তৈরি করবেন। তিনটি প্রগতিশীল পর্যায় জুড়ে, আপনি একটি সিকোয়েন্সিয়াল এজ চেনে (node_input) বিশেষজ্ঞ Agent নোড (gemini-3.8-flash দ্বারা পরিচালিত) কানেক্ট করবেন, JoinNode-এর সাথে সিঙ্ক করা সমবর্তী google_search রিসার্চারদের ফ্যান আউট করবেন এবং একটি নির্ধারক Python রাউটার (Event(route=...)) সহ বাজেট এবং বাদ দেওয়ার নিয়ম এনফোর্স করবেন যা প্রাথমিক ড্রাফ্ট অডিটে পাস করলেই রিফাইনমেন্ট এড়িয়ে যায়।

পূর্বশর্ত

আপনি কী শিখবেন

  • Workflow এজ টাপল ব্যবহার করে ADK 2-তে কীভাবে মাল্টি-এজেন্ট পাইপলাইন ঘোষণা করতে হয়
  • ADK 2 কীভাবে node_input হিসেবে এজ বরাবর সরাসরি আউটপুট পাস করে এবং ফাংশন প্যারামিটার হিসেবে সেশন স্টেট কী বাইন্ড করে
  • কীভাবে একই সাথে চলা রিসার্চ ব্রাঞ্চ ফ্যান-আউট করতে হয় এবং JoinNode-এর সাথে তাদের আউটপুট মার্জ করতে হয়
  • Event(route=...)-এর সাহায্যে Python-এ কীভাবে বাউন্ডেড মেকার-চেকার সাইকেল নির্ধারক হিসেবে রুট করবেন
  • ADK ওয়েব UI-তে কম্পাইল করা ওয়ার্কফ্লো গ্রাফ, প্যারালাল এক্সিকিউশন টাইমলাইন ও স্টেট ডেল্টা কীভাবে চেক করবেন

আপনার যা প্রয়োজন

  • Google অ্যাকাউন্ট (ওয়ার্কশপ ক্রেডিট দাবি করলে ব্যক্তিগত @gmail.com অ্যাকাউন্ট ব্যবহার করুন)
  • আপনার ইনস্ট্রাক্টরের থেকে পাওয়া ওয়ার্কশপ ক্রেডিট লিঙ্ক (সাথে QR কোড স্ক্যান করার জন্য ফোনের ক্যামেরা) অথবা একটি অ্যাক্টিভ Cloud Billing অ্যাকাউন্ট
  • Google Chrome (ব্যক্তিগত ও অফিসের অ্যাকাউন্ট যাতে মিশে না যায়, তার জন্য ছদ্মবেশী উইন্ডো ব্যবহার করার সাজেশন দেওয়া হয়)

২. Google Cloud ক্রেডিট দাবি করুন (ঐচ্ছিক)

আপনি যদি ইভেন্ট ক্রেডিট লিঙ্ক সহ কোনও ওয়ার্কশপে যোগ দেন, তাহলে ক্রেডিট কার্ড ছাড়াই বিলিং অ্যাকাউন্ট প্রোভিশন করতে আপনার Google Developer Program ক্রেডিট দাবি করুন।

আপনার ইভেন্ট ক্রেডিট দাবি করুন

  1. ছদ্মবেশী উইন্ডোতে ওয়ার্কশপ ক্রেডিট লিঙ্ক খুলুন এবং আপনার @gmail.com অ্যাকাউন্ট দিয়ে সাইন-ইন করুন।
  2. আপনার সুবিধা দাবি করুন বিকল্পে গিয়ে ক্রেডিট দাবি করুন বিকল্পে ক্লিক করুন:

Google Builders Hub-এর 'আপনার সুবিধা দাবি করুন' কার্ডে 'ক্রেডিট দাবি করুন' বোতাম দেখানো হচ্ছে

  1. Google Developer Program প্রোফাইল তৈরি করার জন্য প্রম্পট করা হলে, ফর্মটি পূরণ করুন।
  2. আপনি যে মানুষ তা যাচাই করতে স্ক্যান করুন বিকল্পটি দেখা গেলে, আপনার ফোন দিয়ে QR কোড স্ক্যান করুন এবং যাচাইকরণ সম্পূর্ণ করুন (QR কোড দেখা না গেলে, রিফ্রেশ করে আবার ক্রেডিট দাবি করুন বিকল্পে ক্লিক করুন):

Google Developer Program-এ আপনি যে মানুষ (বট নন) তা যাচাই করাতে QR কোড স্ক্যান করার ডায়ালগ

  1. আপনার ইভেন্ট ক্রেডিট দাবি করা হয়েছে! মেসেজটি দেখতে পাবেন, তারপর বিলিং অ্যাকাউন্ট খুলুন বিকল্পে ক্লিক করুন:

Google Builders Hub-এ 'আপনার ইভেন্ট ক্রেডিট দাবি করা হয়েছে' এবং 'বিলিং অ্যাকাউন্ট খুলুন' বোতাম দেখানো হচ্ছে

🔍 আপনার কাজ চেক করুন

বিলিং অ্যাকাউন্ট সেট-আপ করতে সর্বাধিক ৩ মিনিট সময় লাগে:

  1. Google Cloud Billing খুলুন (অথবা URL কপি করে আপনার ছদ্মবেশী উইন্ডোতে পেস্ট করুন) এবং আপনার বিলিং অ্যাকাউন্ট বেছে নিন:
https://console.cloud.google.com/billing
  1. আপনার GDP Credit অ্যাকাউন্টে স্ট্যাটাস অ্যাক্টিভ না দেখানো পর্যন্ত রিফ্রেশ করুন:

Google Cloud বিলিং অ্যাকাউন্ট ম্যানেজমেন্টে একটি অ্যাক্টিভ GDP ক্রেডিট বিলিং অ্যাকাউন্ট দেখানো হচ্ছে

৩. Google Cloud প্রোজেক্ট তৈরি করা (ঐচ্ছিক)

একটি ডেডিকেটেড Google Cloud প্রোজেক্ট তৈরি করুন যাতে এই কোডল্যাবের সব রিসোর্স আলাদা থাকে এবং সহজেই মুছে ফেলা যায়।

  1. প্রোজেক্ট তৈরি করুন বিকল্প খুলুন (অথবা আপনার ছদ্মবেশী উইন্ডোতে URL কপি করুন):
https://console.cloud.google.com/projectcreate
  1. আপনার প্রোজেক্টের বিবরণ লিখুন:
    • প্রোজেক্টের নাম: যেমন, google-cloud-workshop
    • বিলিং অ্যাকাউন্ট (যদি দেখানো হয়): GDP Credit (অথবা আপনার অ্যাক্টিভ বিলিং অ্যাকাউন্ট) বেছে নিন
    • মূল রিসোর্স: কোনও সংস্থা নেই (অথবা প্রয়োজন হলে আপনার সংস্থা বেছে নিন)
  2. প্রোজেক্টের নামের নিচে জেনারেট করা প্রোজেক্ট আইডি নোট করুন, তারপর তৈরি করুন বিকল্পে ক্লিক করুন:

Google Cloud প্রোজেক্ট তৈরি করার স্ক্রিন যেখানে প্রোজেক্টের নাম, প্রোজেক্ট আইডি, পেরেন্ট রিসোর্স এবং 'তৈরি করুন' বোতাম দেখানো হচ্ছে

🔍 আপনার কাজ চেক করুন

প্রজেক্ট তৈরি করা হয়ে গেলে, উপরে ডানদিকের টুলবারে বিজ্ঞপ্তি বিকল্পে ক্লিক করুন এবং প্রজেক্ট বেছে নিন বিকল্পে ক্লিক করুন:

Google Cloud Console-এর বিজ্ঞপ্তি মেনুতে 'প্রোজেক্ট তৈরি করুন' এবং 'প্রোজেক্ট বেছে নিন' লিঙ্ক দেখানো হচ্ছে

৪. আপনার পরিবেশ সেট-আপ করুন

Google Cloud Shell কনফিগার করুন, Agent Platform API চালু করুন এবং uv-এর মাধ্যমে একটি আইসোলেটেড Python 3.12 ভার্চুয়াল এনভায়রনমেন্ট তৈরি করুন।

Cloud Shell কনফিগার করুন

  1. Google Cloud কনসোল টুলবারে Cloud Shell চালু করুন (>_) বিকল্পে ক্লিক করুন অথবা সরাসরি Google Cloud Shell খুলুন (অথবা আপনার ছদ্মবেশী উইন্ডোতে URL কপি করুন):
https://shell.cloud.google.com/?show=ide,terminal

Google Cloud Console টুলবারে Cloud Shell চালু করার বোতাম

  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 টার্মিনালে বেছে নেওয়া প্রোজেক্ট আইডি হলুদ রঙে হাইলাইট করে দেখানো হচ্ছে

প্রয়োজনীয় API চালু করুন

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 টার্মিনাল অ্যাক্টিভ Python ভার্চুয়াল এনভায়রনমেন্টে .venv প্রিফিক্স দেখাচ্ছে

অ্যাক্টিভ ভার্চুয়াল এনভায়রনমেন্টের মধ্যে ADK 2 ইনস্টল করুন:

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

🔍 আপনার কাজ চেক করুন

ইনস্টল করা adk CLI ভার্সন যাচাই করুন:

adk --version

আপনি এই ধরনের আউটপুট দেখতে পাবেন:

adk, version 2.14.0

৫. ট্রাভেল প্ল্যানার স্ক্যাফোল্ড করো

adk create-এর সাহায্যে স্টার্টার travel_planner প্যাকেজ জেনারেট করুন এবং adk web-এ ডিফল্ট সিঙ্গল-এজেন্ট বেসলাইন পরীক্ষা করুন।

স্টার্টার প্যাকেজ তৈরি করুন

~/adk-graph-agents থেকে adk create রান করুন:

cd ~/adk-graph-agents
adk create travel_planner

প্রম্পট করা হলে নিম্নলিখিত বিকল্পগুলি বেছে নিন (প্রথমবার চালানোর সময় Enable telemetry? [Y/n]: সহ প্রম্পট করা হলে, Enter প্রেস করুন অথবা n টাইপ করে Enter প্রেস করুন):

  1. রুট এজেন্টের জন্য একটি মডেল বেছে নিন: gemini-3.8-flash বেছে নিতে 2 টাইপ করুন (1 বিকল্প gemini-3.5-flash বেছে নেয়) এবং Enter প্রেস করুন।
  2. ব্যাকএন্ড বেছে নিন: Google Cloud এজেন্ট প্ল্যাটফর্ম ব্যাকএন্ড (নিচের CLI মেনুতে 2 বিকল্প) বেছে নিতে 2 টাইপ করুন এবং 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/)

Cloud Shell কোড এডিটরে ~/adk-graph-agents খুলুন:

which cloudshell >/dev/null 2>&1 && cloudshell workspace ~/adk-graph-agents || true

রিলোড করা টার্মিনালে আপনার ভার্চুয়াল এনভায়রনমেন্ট আবার অ্যাক্টিভেট করুন:

cd ~/adk-graph-agents
source .venv/bin/activate

স্টার্টার সিঙ্গেল এজেন্ট টেস্ট করুন

একটি আনঅরকেস্ট্রেটেড স্টার্টার এজেন্ট কীভাবে ট্রাভেল প্রম্পটের উত্তর দেয় তা দেখতে ADK Web UI চালু করুন:

cd ~/adk-graph-agents
adk web --allow_origins "*"

উপরের ডানদিকে Cloud Shell টুলবারে ওয়েব প্রিভিউ আইকনে ক্লিক করুন, পোর্ট পরিবর্তন করুন বিকল্প বেছে নিন, 8000 লিখুন এবং পরিবর্তন ও প্রিভিউ করুন বিকল্পে ক্লিক করুন:

Cloud Shell ওয়েব প্রিভিউ পোর্ট কনফিগারেশন ডায়ালগ ৮০০০-এ সেট করা হয়েছে

🔍 আপনার কাজ চেক করুন

adk web-এর উপরে বাঁদিকের ড্রপডাউন থেকে travel_planner বেছে নিন এবং "Help me plan a trip to Japan" পাঠান:

ADK ডেভেলপমেন্ট ওয়েব UI-তে একটি প্রাথমিক সিঙ্গেল-এজেন্ট কথোপকথন দেখানো হচ্ছে

চ্যাট প্যানে আপনি একটি সিঙ্গেল-পাস কথোপকথনমূলক উত্তর দেখতে পাবেন (ইভেন্ট-এ একটি root_agent ইনভোকেশন সহ):

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

পরবর্তী ধাপে ফাইল এডিট করার আগে adk web বন্ধ করতে আপনার Cloud Shell টার্মিনালে Ctrl + C প্রেস করুন।

৬. একটি লিনিয়ার গ্রাফ ওয়ার্কফ্লো তৈরি করুন

আপনার প্রথম 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 (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

user_profiler_agent ও itinerary_synthesizer_agent (পরবর্তী ধাপের জন্য google_search আগে থেকে ইমপোর্ট করা) নির্ধারণ করতে travel_planner/specialists.py-এ নিম্নলিখিত কোড পেস্ট করুন:

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-graph-agents থেকে adk web শুরু করুন:

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 ওয়েব UI, START থেকে user_profiler_agent হয়ে itinerary_synthesizer_agent গ্রাফ এক্সিকিউশন এবং জেনারেট করা Kyoto ভ্রমণসূচী দেখাচ্ছে

ইভেন্ট-এ যেকোনও ইভেন্টে ক্লিক করুন এবং কম্পাইল করা START -> user_profiler_agent -> itinerary_synthesizer_agent টোপোলজি পরীক্ষা করতে গ্রাফ আইকনে (ইভেন্টের বিবরণ টুলবারে account_tree) ক্লিক করুন, তারপর user_preferences এবং final_itinerary পপুলেট করা হয়েছে কিনা তা যাচাই করতে স্টেট ট্যাব চেক করুন।

চালিয়ে যাওয়ার আগে adk web বন্ধ করতে আপনার টার্মিনালে Ctrl + C প্রেস করুন।

৭. ফ্যান আউট করুন এবং JoinNode-এর সাথে যোগ দিন

দুটি সমবর্তী google_search বিশেষজ্ঞ (activity_finder_agent এবং restaurant_finder_agent) যোগ করে এবং তাদের JoinNode-এর সাথে সিঙ্ক্রোনাইজ করে লাইভ ওয়েব ডেটাতে ভ্রমণসূচী গ্রাউন্ড করুন:

  • ফ্যান-আউট টাপল: এজ টাপলের মধ্যে (activity_finder_agent, restaurant_finder_agent) রাখলে, user_profiler_agent-এর আউটপুট node_input হিসেবে একই সাথে দুই গবেষকের কাছে পৌঁছে যায়।
  • ফ্যান-ইন ব্যারিয়ার (JoinNode): টিউপলের ঠিক পরে JoinNode(name="research_join") রাখলে, প্রতিটি ইনকামিং ব্রাঞ্চ সম্পূর্ণ না হওয়া পর্যন্ত অপেক্ষা করে এবং দুবার সিন্থেসিস ট্রিগার করার পরিবর্তে itinerary_synthesizer_agent-এ node_input হিসেবে একটি মার্জ করা dict ({"activity_finder_agent": ..., "restaurant_finder_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

travel_planner/specialists.py-এর নিচে activity_finder_agent ও restaurant_finder_agent যোগ করুন (কোনওটির জন্যই 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],
)

workflows.py-এ ফ্যান-আউট ও JoinNode যোগ করুন

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,
        ),
    ],
)

🔍 আপনার কাজ চেক করুন

একইসাথে সার্চ ও JoinNode সিঙ্ক্রোনাইজেশন পরীক্ষা করতে adk web শুরু করুন:

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: ডিক্ট এজে ({"revise": ..., "approved": ...}) কোন নামযুক্ত ব্রাঞ্চ কী পরবর্তী ধাপে রান করবে তা বেছে নেয়।
  • output: চ্যাট মেসেজ রেন্ডার না করে পরবর্তী নোডে node_input হিসেবে এজ বরাবর টাইপ করা Python ভ্যালু বা স্ট্রিং পাস করে।
  • message এবং state: message চ্যাট ট্রান্সক্রিপ্টে ব্যবহারকারীকে টেক্সট দেখায়, যেখানে state সেশন স্টেটে কী-ভ্যালু আপডেট (stateDelta) করে।

আর্কিটেকচার ডায়াগ্রাম, যেখানে travel_workflow-এর সাথে itinerary_critic_agent-এর মাধ্যমে route_critique ফিড করা হচ্ছে, যা 'সংশোধন' করার জন্য itinerary_refiner_agent-এ (itinerary_critic_agent-এ লুপ ব্যাক করে) অথবা 'অনুমোদিত' করার জন্য finalize_itinerary-তে রুট করে

সমালোচক এবং রিফাইনার বিশেষজ্ঞদের যোগ করুন

adk web বন্ধ করা হয়েছে কিনা তা কনফার্ম করুন (Ctrl + C), তারপর travel_planner/specialists.py খুলুন:

cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py

travel_planner/specialists.py-এর নিচে itinerary_critic_agent এবং itinerary_refiner_agent যোগ করুন (রিফাইনারের কোনও 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 পোর্টে ওয়েব প্রিভিউ খুলুন, + নতুন সেশন বিকল্পে ক্লিক করুন এবং Kyoto-র মাল্টি-কনস্ট্রেন্ট প্রম্পট পাঠান:

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-graph-agents পেরেন্ট ডিরেক্টরির পরিবর্তে travel_planner/-এর মধ্যে adk web শুরু করা হয়েছে অথবা Cloud Shell সেশন রিস্টার্ট করা হয়েছে।
  • সমাধান: Ctrl + C প্রেস করে পেরেন্ট ডিরেক্টরিতে ফিরে যান এবং cd ~/adk-graph-agents && source .venv/bin/activate && adk web --allow_origins "*" দিয়ে রিস্টার্ট করুন।

404 NOT_FOUND মডেল সংক্রান্ত সমস্যা

  • কারণ: আপনি global টাইপ করার পরিবর্তে adk create-এর সময় ডিফল্ট us-central1 অঞ্চল গ্রহণ করতে Enter প্রেস করেছেন।
  • সমাধান: ~/adk-graph-agents/travel_planner/.env খুলুন এবং GOOGLE_CLOUD_LOCATION=global সেট করা আছে কিনা তা নিশ্চিত করুন।

8000 পোর্টে ERROR: [Errno 98] address already in use

  • কারণ: Cloud Shell-এ আগের একটি adk web সার্ভার এখনও চলছে।
  • সমাধান: অ্যাক্টিভ টার্মিনালে Ctrl + C প্রেস করুন অথবা adk web আবার শুরু করার আগে pkill -f "adk web"-এর মাধ্যমে আগে থেকে চলা প্রসেস বন্ধ করুন।

১০. অপ্রয়োজনীয়গুলি মুছুন

লোকাল ওয়ার্কস্পেস সরিয়ে দিন এবং বিকল্প হিসেবে API বন্ধ করুন অথবা কোনও নির্দিষ্ট ওয়ার্কশপ প্রোজেক্ট মুছে দিন।

স্থানীয় প্রোজেক্ট ফাইল মুছে দিন

~/adk-graph-agents ডিরেক্টরি ও ভার্চুয়াল এনভায়রনমেন্ট সরিয়ে দিন:

cd ~
rm -rf ~/adk-graph-agents

এজেন্ট প্ল্যাটফর্ম API বন্ধ করুন (ঐচ্ছিক)

এই প্রোজেক্টে এজেন্ট প্ল্যাটফর্ম 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 ব্যবহার করে একটি মাল্টি-এজেন্ট ট্রাভেল প্ল্যানার তৈরি করেছেন, যা একটি ডিক্লারেটিভ এজ গ্রাফে সিকোয়েন্সিয়াল চেইন, JoinNode-এর সাথে কনকারেন্ট google_search ফ্যান-আউট এবং কন্ডিশনাল মেকার-চেকার সাইকেলকে একত্রিত করে।

আপনি কী কী অর্জন করেছেন

  • ADK 2 ব্যবহার করে মাল্টি-এজেন্ট পাইপলাইন ঘোষণা করা Workflow(edges=[...])
  • node_input এবং স্টেট-বাউন্ড প্যারামিটারের মাধ্যমে Agent, JoinNode এবং Python ফাংশন নোডের মধ্যে সরাসরি ডেটা পাস করা হয়েছে, সেশন স্টেট ন্যূনতম রাখা হয়েছে
  • একইসাথে google_search ব্রাঞ্চ ফ্যান-আউট করা হয়েছে এবং JoinNode-এর সাথে সিঙ্ক করা হয়েছে
  • LoopAgent এবং টুল-ভিত্তিক লুপ এসকেলেশনকে নির্ধারক Event(route=...) রাউটার দিয়ে পরিবর্তন করা হয়েছে যা অনুমোদিত ড্রাফ্টে অপ্রয়োজনীয় LLM কল এড়িয়ে যায়

পরবর্তী ধাপ