1. खास जानकारी
ADK 2 की हेडलाइन तीन ऑर्केस्ट्रेशन पैटर्न है. इस कोडलैब में, एक ऐप्लिकेशन — मैराथन रेस डे कोच — बनाकर इन तीनों के बारे में बताया गया है. इसे एक-एक करके रन किया जा सकता है. हर लेवल में एक सवाल का जवाब दिया जाता है, एक आइडिया जोड़ा जाता है, और यह अपने-आप चलता है.
आपको क्या सीखने को मिलेगा
- ग्राफ़ वर्कफ़्लो (पहला पिलर) — जब इनपुट मिलने से पहले फ़्लो बनाया जा सकता है.
- मिलकर काम करने वाले एजेंट (दूसरा पिलर) — जब आपको टीम के बारे में पता हो, लेकिन अनुरोध सबसेट चुनता हो. साथ ही, मिलकर काम करने के तीनों मोड (
chat/task/single_turn) लाइव हों. - डाइनैमिक वर्कफ़्लो (तीसरा पिलर) — जब काम का तरीका इनपुट पर निर्भर करता है.
- कैसे चुनें — एक सवाल वाला फ़ैसला लेने वाला ट्री और पैटर्न कैसे बनाए जाते हैं.
थ्रू-लाइन
पहचाना गया स्ट्रक्चर → जानी-पहचानी टीम / वैरिएबल का सबसेट → अज्ञात शेप → सही शेप चुनें

आपको क्या बनाना है
एक ऐप्लिकेशन — मैराथन रेस डे कोच — ने एक बार में एक लेवल तैयार किया. हर लेवल एक सामान्य Python मॉड्यूल है, जिसे टर्मिनल से चलाया जाता है. L5 तक, यहां दी गई सभी चीज़ें आपकी हो जाती हैं.
यह इमेज, चल रहे कोड से बनाई गई है: हर सॉलिड लाइन को Workflow.graph.edges से पढ़ा गया था. पहला सबक यह है कि जिन हिस्सों को पहले से तैयार किया जा सकता है वे पिलर 1 के तहत आते हैं. वहीं, जिन हिस्सों को पहले से तैयार नहीं किया जा सकता वे पिलर 2 और 3 के तहत आते हैं.

आपको किन चीज़ों की ज़रूरत होगी
- Colab के लिए Google खाता — लोकल सेटअप की ज़रूरत नहीं है.
- ~50 मिनट (L4 के दोनों लेवल लंबे हैं — इनके लिए बजट तय करें).
- Gemini के किसी मॉडल तक पहुंचने के दो तरीकों में से एक. अपनी ज़रूरत के हिसाब से विकल्प चुनें — सेटअप के एक चरण को पूरा करें और दूसरे को छोड़ दें:
🎓 वर्कशॉप | 🏠 घर ले जाने के लिए | |
नाम | आप किसी लाइव वर्कशॉप में शामिल हैं और शिक्षक ने आपको क्रेडिट का दावा करने वाला लिंक दिया है | बाकी सभी लोग — इसमें वर्कशॉप में शामिल होने वाले लोग भी शामिल हैं |
आपको इनकी ज़रूरत होगी | दावा लिंक करने के लिए, एक Google खाता होना चाहिए. साथ ही, उस खाते से क्लाउड प्रोजेक्ट बनाया जा सकता हो | मुफ़्त AI Studio API पासकोड |
इस पर चलता है | Vertex AI, आपके वर्कशॉप क्रेडिट के लिए बिल किया गया प्रोजेक्ट | Google AI Studio |
लागत | क्रेडिट के दायरे में आने वाले | फ़्री टियर |
सेटअप करने का चरण | वर्कशॉप का सेटअप (अगला चरण) | घर ले जाकर सेटअप करना (इसके बाद का चरण) |
प्रोलॉग के बाद से, दोनों नोटबुक में सब कुछ एक जैसा होता है. लेन सिर्फ़ यह तय करती है कि नोटबुक किस मॉडल एंडपॉइंट से कम्यूनिकेट करेगी.
साथ-साथ करने के दो तरीके
यहां दिया गया हर चरण, Colab notebook में मौजूद एक सेल और GitHub repo में मौजूद एक फ़ोल्डर से जुड़ा है. इनमें से कोई एक चुनें:
- ▶ Colab (सुझाया गया): नोटबुक खोलें → सेल को ऊपर से नीचे की ओर चलाएं.
- 💻 लोकल:
git clonerepo,./setup_venv.shपर जाएं. इसके बाद, हर लेवल को मॉड्यूल (python -m ...) के तौर पर चलाएं या./run.sh(adk web) का इस्तेमाल करके उन सभी को ब्राउज़ करें.
2. वर्कशॉप का सेटअप · क्रेडिट क्लेम करना और Vertex AI पर स्विच करना
वर्कशॉप में आपको Google Cloud क्रेडिट दिया जाता है. इसके बाद, आपको उस खाते पर दावा करना होगा. साथ ही, उससे जुड़ा एक प्रोजेक्ट बनाना होगा. इसके बाद, नोटबुक को AI Studio के बजाय Vertex AI पर पॉइंट करना होगा. एक सेल, दावा करने के बाद सभी कार्रवाइयां करता है.
1 · क्रेडिट पर दावा करें (~1 मिनट)
- अपने प्रशिक्षक की ओर से शेयर किया गया दावा करने का लिंक खोलें. यह
https://me.developers.google.com/benefits/claim/your-workshop-nameजैसा दिखता है. - साइन इन करें और पेज पर दिए गए निर्देशों का पालन करके क्रेडिट स्वीकार करें.
- ध्यान दें कि आपने किस Google खाते का इस्तेमाल किया था. नीचे दिए गए हर चरण को उसी खाते से पूरा करना होगा.
2 · नोटबुक खोलें और ADK 2 इंस्टॉल करें (~1 मिनट)
Colab में खोलें ▶ पर क्लिक करें. इसके बाद, पहले कोड सेल को चलाएं. यह उस ADK 2 वर्शन को पिन करता है जिस पर इस कोडलैब की पुष्टि की गई थी और ✓ installed प्रिंट करता है.
3 · "वर्कशॉप सेटअप" सेल चलाएं (~3 मिनट)
यह 🎓 पाथ A · वर्कशॉप नाम की सेल है. इसे चलाएं. इसके बाद, 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 स्कीमा और पहले से तैयार मैराथन के ऐसे उदाहरण तय करता है जिन्हें L2 और इससे ऊपर के हर लेवल में फिर से इस्तेमाल किया जाता है. आपको ✓ schemas + scenarios ready दिखेगा.
वर्कशॉप के बाद
आपको मिला क्रेडिट और उससे बनाया गया प्रोजेक्ट हमेशा के लिए नहीं रहेगा. वर्कशॉप खत्म होने के बाद, इन लेवल को बिना किसी शुल्क के फिर से चलाने के लिए, घर पर सेटअप करें चरण को पूरा करें. इसमें आपको AI Studio का एक पासकोड बिना किसी शुल्क के मिलेगा. इसके लिए, आपको क्लाउड प्रोजेक्ट की ज़रूरत नहीं होगी और न ही कोई शुल्क देना होगा. सिर्फ़ एक सेल में बदलाव होता है.
डेटा को तुरंत हटाने के लिए: Cloud Console खोलें, adk-2-tutorial-XXXX को चुनें, और उसे मिटाएं. इस कोडलैब में, बिल किए जा सकने वाले संसाधनों को बनाने के लिए और कुछ नहीं है.
3. घर पर सेटअप करने की सुविधा · AI Studio API पासकोड
इस पाथ पर मौजूद सभी सुविधाएं, बिना किसी शुल्क वाले Google AI Studio एपीआई पासकोड पर काम करती हैं. इसके लिए, न तो Google Cloud प्रोजेक्ट की ज़रूरत होती है, न ही बिलिंग की और न ही लोकल इंस्टॉलेशन की. इस पूरे चरण में करीब तीन मिनट लगते हैं.
1 · नोटबुक खोलें
Colab में खोलें ▶ पर क्लिक करें. इसके बाद, आपको नोटबुक पर रीडायरेक्ट कर दिया जाएगा. इसमें मार्कडाउन की जानकारी दी गई है. साथ ही, हर लेवल के लिए एक सेल दी गई है. सेल को ऊपर से नीचे की ओर चलाया जाता है. हर सेल का आउटपुट, उसके ठीक नीचे प्रिंट होता है.
2 · ADK 2 इंस्टॉल करें (~1 मिनट)
पहली कोड सेल को चलाएं. यह उस वर्शन को पिन करता है जिस पर इस कोडलैब की पुष्टि की गई थी:
%pip install -q "google-adk==2.3.0" python-dotenv pydantic nest_asyncio
प्रोसेस पूरी होने तक इंतज़ार करें. इसके बाद, आपको ✓ installed दिखेगा. (पहली बार इंस्टॉल करने में ~30–60 सेकंड लगते हैं; इसके बाद, इसे कैश मेमोरी में सेव कर लिया जाता है.)
3 · AI Studio से Gemini API पासकोड पाएं (~1 मिनट)
- नए ब्राउज़र टैब में aistudio.google.com/app/apikey खोलें.
- अपने Google खाते से साइन इन करें.
- सबसे ऊपर दाईं ओर मौजूद, एपीआई पासकोड बनाएं पर क्लिक करें.
- कोई मौजूदा Google प्रोजेक्ट चुनें या उसे एक प्रोजेक्ट बनाने दें.
- कॉपी करें — यह
AIza...से शुरू होती है और इसमें ~40 वर्ण होते हैं.
4 · Colab में अपना पासकोड जोड़ें (~1 मिनट)
विकल्प A — Colab के सीक्रेट (सुझाया गया; इसमें कुंजी छिपी रहती है):
- Colab के बाईं ओर मौजूद साइडबार में, 🔑 कुंजी वाले आइकॉन पर क्लिक करें.
- + नया सीक्रेट जोड़ें पर क्लिक करें.
- नाम को
GOOGLE_API_KEYपर सेट करें. - अपनी कुंजी को वैल्यू में चिपकाएं.
- नोटबुक का ऐक्सेस को चालू करें पर टॉगल करें.
विकल्प B — प्रॉम्प्ट मिलने पर चिपकाएं (जल्दी): सीक्रेट को छोड़ दें; अगली सेल चलाने पर, यह एक छिपा हुआ प्रॉम्प्ट 🔑 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 स्कीमा और पहले से तैयार मैराथन के ऐसे उदाहरण तय करता है जिन्हें L2 और इससे ऊपर के हर लेवल में फिर से इस्तेमाल किया जाता है. आपको ✓ schemas + scenarios ready दिखेगा.
आपका खाता सेट अप हो गया है! 🎽 L0 पर जाने से पहले, एक और वर्शन के बारे में जान लें. यह ऐसा वर्शन है जिसे हर कोई सबसे पहले बनाता है.
4. प्रोलॉग · एक बड़ा प्रॉम्प्ट क्यों नहीं?
⚡ इसे चलाने से पहले, यह तय करें कि आपको किस एक चीज़ पर ध्यान देना है: हर खास संख्या कहां से आई है? बस इतनी ही कसरत है. बाकी सब सजावट है.
लैडर से पहले, लैडर की जगह इस्तेमाल की जाने वाली चीज़ को चलाएं: एक ऐसा एजेंट जिसका प्रॉम्प्ट हर काम करने का वादा करता है — मौसम की जानकारी पाना, कोर्स का विश्लेषण करना, ट्रेनिंग लॉग पढ़ना, शर्तों के हिसाब से रूट करना, और प्लान का आउटपुट देना.
आपको क्या दिखेगा: एक भरोसेमंद, खास, और अच्छी तरह से फ़ॉर्मैट की गई रणनीति... जिसके आंकड़े मनगढ़ंत हैं. एक लाइव रन में, यह "मैंने आज के मौसम की मेट्रिक हासिल कर ली हैं" के साथ खुला. इसमें 11 डिग्री सेल्सियस तापमान, 14.4 किलोमीटर प्रति घंटे की हवा की रफ़्तार, और ट्रेनिंग लॉग का विश्लेषण दिखाया गया था. हालांकि, इस लॉग को कभी नहीं देखा गया था. यहां कोई मौसम का एपीआई नहीं है, न ही कोई कोर्स का डेटा है और न ही कोई लॉग है. एक ओपेक मॉडल कॉल या तो अपने इनपुट बनाता है या उन्हें बेकार बना देता है.
यह रोग है और इसके चार मुख्य लक्षण हैं:
- इस पर भरोसा नहीं किया जा सकता — डेटा को फ़्लुएंट तरीके से बनाया गया है.
- इसकी जांच नहीं की जा सकती — चौथे चरण की राउटिंग, टेक्स्ट में मौजूद होती है. यूनिट-टेस्ट के लिए कोई
ifनहीं है. - किसी चरण को बदला नहीं जा सकता — इसमें कोई ऐसी जगह नहीं होती जहां मौसम की जानकारी देने वाले एपीआई को प्लग इन किया जा सके.
- आपको हर बार हर चीज़ के लिए पेमेंट करना होता है — पांच चरण, एक बड़ी कॉल, और डिटरमिनिस्टिक हिस्से को कैश मेमोरी में सेव नहीं किया जाता.
इस खुशी को संजोए रखें. अगले नौ लेवल में, एक-एक करके प्रॉम्प्ट से उन चरणों को हटा दिया जाता है: फ़ंक्शन फ़ेच (L1–L2a), if-स्टेटमेंट रूट (L2b), विशेषज्ञ काम को बांटते हैं (L3a–L3b), और कोड शेप को बाउंड करता है (L4a–L4b).

💻 लोकल: python -m shared.prologue
5. L0 · आपका पहला 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. L1 · आपका पहला वर्कफ़्लो

⚡ खास जानकारी: एक सामान्य फ़ंक्शन और एलएलएम एजेंट, एक ही तरह के नोड होते हैं. अनुमान लगाया जा सकने वाला काम → फ़ंक्शन (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= हैंड-ऑफ़ की पुष्टि कर रहा है.
नया क्या है बनाम L0: 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 (Pillar 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 सेकंड है, क्योंकि इसमें रणनीति एजेंट का एलएलएम कॉल भी शामिल है — पैरलल दावे के लिए फ़ेच किए गए टाइमस्टैंप पढ़ें, कुल नहीं.)
💡 प्रोलॉग कॉलबैक: मेगा-प्रॉम्प्ट ने मौसम की जानकारी बनाई. यहां तापमान, फ़ेच फ़ंक्शन से मिलता है. यह असली कोड है और असली सीम है. कैन किए गए डिक्ट को मौसम की जानकारी देने वाले एपीआई से बदलें. इसके अलावा, कोई और बदलाव न करें.
❓ आपके मन में यह सवाल हो सकता है कि: कितना
JoinNode
क्या मुझे समझना होगा? एक वाक्य में: यह तब तक इंतज़ार करता है, जब तक हर पैरलल ब्रांच पूरी नहीं हो जाती. इसके बाद, यह आउटपुट को अपस्ट्रीम फ़ंक्शन के नाम के हिसाब से कुंजी वाले एक डिक्शनरी में पैक करता है. यह खुद कोई भी कंप्यूटेशन नहीं करता. इसी वजह से, L2b का राऊटर node_input["fetch_weather"]["temp_f"] लिख सकता है.
👀 पढ़ें: तीन किनारे START से बाहर की ओर जाते हैं; JoinNode उन्हें एक एजेंट के लिए बंडल करता है. · ▶ इसे चलाएं और कुल संख्या के बजाय टाइमस्टैंप पढ़ें. · ✏️ बदलाव: एक फ़ेच को स्लीप 3.0 पर सेट करें — सबसे पहले, फ़ैन-आउट के खत्म होने का नया समय अनुमानित करें. इसके बाद, इसकी पुष्टि करें.
8. L2b · Add the deterministic router (Pillar 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. कुल लागत: एक एलएलएम कॉल.
⚠️ अगर आपको चौथा ब्रांच जोड़ना है, तो route-dict में DEFAULT_ROUTE एंट्री भी जोड़ें. अगर डिक्शनरी में कोई ऐसा रूट है जो मैच नहीं करता, तो यह कोई गड़बड़ी नहीं है. इस मामले में, ब्रांच खत्म हो जाती है और प्रोग्राम बिना किसी आउटपुट के 0 से बाहर निकल जाता है. यह डीबग करने के लिए एक उलझन भरा डेड एंड है.
❓ आपके मन में यह सवाल आ सकता है कि क्या L2b, L2a और राउटर का कॉम्बिनेशन है? हाँ — फ़ेच और जॉइन में कोई बदलाव नहीं किया गया है. साथ ही, यह अब भी एलएलएम को एक बार कॉल करने का उदाहरण है. क्या बदलाव हुआ: "हमेशा एक ही एजेंट" को बदलकर "तीन में से एक एजेंट, जिसे डेटा के आधार पर चुना जाता है" कर दिया गया है.
👀 पढ़ें: route_by_weather — राऊटर एक if-स्टेटमेंट है, एजेंट नहीं. · ▶ Run 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 → (बीट 1) बनाम एक टाइमस्टैंप (बीट 2) शेयर करने वाली 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= में बताया गया है. कोऑर्डिनेटर, सबसेट चुनते समय इस टेक्स्ट को पढ़ता है. इसे छोड़ें और सिर्फ़ नामों के आधार पर रूटिंग करें. कोऑर्डिनेटर एक बार में कई कॉल करता है. ADK उन्हें एक साथ चलाता है. हर कॉल का नतीजा अपने-आप वापस आ जाता है. इसके बाद, कोऑर्डिनेटर उन्हें जोड़ता है.
सवाल | आग लगने की जानकारी देने वाले विशेषज्ञ |
"ईंधन भरने के बारे में क्या जानकारी है?" | सिर्फ़ पोषण |
"18 मील पर मेरे घुटने में दर्द हो रहा है" | सिर्फ़ मेडिकल के लिए |
"क्या मुझे आज रेस में हिस्सा लेना चाहिए?" | मेडिकल + मौसम + पेसिंग |
"क्या मुझे किसी बात की चिंता करनी चाहिए?" | सभी 6 |
हर विशेषज्ञ को पूरी जानकारी क्यों दी जाती है: हर single_turn सब-एजेंट, अपने अलग सेशन ब्रांच में काम करता है. वह बातचीत या अपने साथियों को नहीं देख सकता. कोई भी जानकारी एंबियंट नहीं है: कोऑर्डिनेटर को पूरी SpecialistInput जानकारी (सवाल + रणनीति + रनर डेटा) को हर पैरलल कॉल में अलग-अलग फ़ॉरवर्ड करना होगा.
💡 ADK 2 में यह सुविधा सीधे तौर पर उपलब्ध है: एलएलएम, हर अनुरोध के लिए सबसेट चुनता है और उसे साथ-साथ चलाता है. इसे sub_agents + mode="single_turn" के ज़रिए डिक्लेयर किया जाता है. 1.x वर्शन में, हर स्पेशलिस्ट को AgentTool में रैप करके एक ही शेप में असेंबल किया जा सकता था. हालांकि, अब यह प्लंबिंग के बजाय एक डेक्लेरेशन है. (ParallelAgent हमेशा-सभी होता है और transfer_to_agent सीरियल होता है.)
⚠️ दो ज़रूरी बातें: (1) मॉडल, सबसेट चुनता है. इसलिए, यह L2 के हार्ड-कोड किए गए राउटर की तुलना में कम भरोसेमंद है. सबसेट, रन के हिसाब से अलग-अलग हो सकता है. (2) कभी-कभी आपको किसी विशेषज्ञ के लिए Error validating input: ... लाइन दिखेगी. यह आउटपुट, विशेषज्ञ का नहीं होता. output_schema, Gemini को सर्वर-साइड पर इसे लागू करने के लिए कहता है. यह इनपुट है: कोऑर्डिनेटर को हर पैरलल कॉल के लिए, पूरे नेस्ट किए गए SpecialistInput को दोहराना होता है. कभी-कभी वह एक को दोहराना भूल जाता है. ADK, टूल के नतीजे के तौर पर गड़बड़ी दिखाता है. इसके बाद, कोऑर्डिनेटर ठीक हो जाता है और सिंथेसिस अब भी काम करता है.
❓ आपके मन में यह सवाल हो सकता है कि क्या
chat
सिर्फ़ 1.x-स्टाइल का डेलिगेशन — एक बार में एक एजेंट? हाँ, यह 1.x का डिफ़ॉल्ट व्यवहार है. अब इसे नाम दिया गया है. single_turn और टूल के बीच तीन तरह का अंतर होता है: कोऑर्डिनेटर के पास क्या होता है (एक transfer_to_agent बनाम हर विशेषज्ञ के लिए एक टूल) · कितने लोग काम कर सकते हैं (एक, बातचीत का मालिक बनाम समानांतर में N) · कंट्रोल वापस मिलता है या नहीं (कभी नहीं बनाम अपने-आप, नतीजों के साथ). कोड के बारे में जानकारी: फ़ैक्ट्री की if mode == ब्रांच सिर्फ़ इसलिए मौजूद है, ताकि इस अंतर के लिए एक टीम को दोनों तरह से बनाया जा सके. एक असली ऐप्लिकेशन में एक मोड को हार्डकोड किया जाता है और if गायब हो जाता है.
👀 पढ़ें: _specialist फ़ैक्ट्री — mode पैरामीटर पूरा लेवल है. · ▶ Run दोनों बीट. · ✏️ बदलाव: "मेरी दौड़ के 18वें मील पर मेरे घुटने में दर्द हो रहा है" के बारे में पूछें — सबसे पहले सबसेट का अनुमान लगाएं. इसके बाद, 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के हिसाब से होनी चाहिए. टाइप की गई फ़िनिश लाइन के साथ बातचीत — इसके बाद, कंट्रोल अपने-आप कोऑर्डिनेटर को वापस मिल जाता है और नतीजे अटैच हो जाते हैं.
मोड चुनने के लिए, एक सवाल पूछने का नियम
💡 "क्या उपयोगकर्ता को इससे बात करने की ज़रूरत है — और कब तक?" चैट = हमेशा · टास्क = फ़ील्ड इकट्ठा होने तक · सिंगल_टर्न = कभी नहीं.
मोड | मैन्युअल प्रक्रिया वाला चरण | पैरलल है? | पेरंट पर वापस जाता है |
| पूरी बातचीत | नहीं | मैन्युअल (ट्रांसफ़र के ज़रिए) |
| सिर्फ़ अतिरिक्त जानकारी के लिए सवाल | नहीं | अपने-आप ( |
| कोई नहीं | हाँ | ऑटोमैटिक (नतीजे के साथ) |
mode सिर्फ़ सब-एजेंट को मिलता है, कोऑर्डिनेटर को कभी नहीं मिलता. साथ ही, वर्कफ़्लो नोड डिफ़ॉल्ट रूप से single_turn पर सेट होते हैं. यही वजह है कि L1–L2b ने इसे कभी नहीं लिखा. वहीं, सब-एजेंट डिफ़ॉल्ट रूप से chat पर सेट होते हैं. यही वजह है कि L3a को इसे लिखना पड़ा.
⚠️ इस पर काम करने से पहले, वर्शन के बारे में दो नोट: (1) task
स्टैटिक ग्राफ़ नोड के तौर परवर्शन पर निर्भर करता है — 2.0.0b1–2.3.0 (इस कोडलैब का पिन) पर, Workflow(...) कंस्ट्रक्शन के दौरान बढ़ता है; इस लेवल के हिसाब से ही इस्तेमाल करें (टास्क सब-एजेंट के साथ चैट कोऑर्डिनेटर) या ctx.run_node के ज़रिए भेजें. 2.5.0 में हटा दिया गया. (2) "टास्क एजेंट, लीफ़ एजेंट होने चाहिए" (उनके कोई सब-एजेंट नहीं होने चाहिए) एक दस्तावेज़ में बताई गई ADK की सीमा है. हालांकि, यह एक अनुबंध है, न कि रनटाइम गार्ड: 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 · रनटाइम के हिसाब से पैरलल फ़ैन-आउट (Pillar 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(...) (यह सीधे तौर पर कोड शेड्यूलिंग नोड करता है). इनमें से कोई एक विकल्प दिखे, तो इसका मतलब है कि आप डाइनैमिक मोड में हैं.
आपको क्या दिखेगा: डीकंपोज़र, उदाहरण के लिए पांच उप-सवाल प्रिंट करता है.इसके बाद, उन पर एक साथ रिसर्च की जाती है. फिर, जवाब को छोटे शब्दों में तैयार किया जाता है. हर बार रन करने पर, संख्या अलग-अलग होती है. हालांकि, फ़िक्स्ड ग्राफ़ ऐसा नहीं कर सकता.
कर्मचारी के लिए दो फ़्लैग, जिनके बारे में जानना ज़रूरी है:
rerun_on_resume=True,ctx.run_nodeको कॉल करने वाले किसी भी नोड पर ज़रूरी है. इसके बिना, ADKValueErrorको बढ़ाता है. फिर से शुरू करने पर, इसे डिसपैचिंग नोड को फिर से एक्ज़ीक्यूट करना होगा, ताकि यह उन चाइल्ड नोड को फिर से बना सके जिन्हें इसने बनाया था. ऐसा इसलिए, क्योंकि वे स्टैटिक ग्राफ़ में नहीं हैं.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 अपने पैरलल टास्क ग्रुप को बंद कर रहा है. इससे कोई नुकसान नहीं होता. साथ ही, लॉगिंग कॉन्फ़िगरेशन के आधार पर, हो सकता है कि आपको यह कभी न दिखे.
❓ आपके मन में यह सवाल आ सकता है कि क्या डाइनैमिक रीमार्केटिंग डिफ़ॉल्ट रूप से काम नहीं करती? नहीं — L4a पूरी तरह से डाइनैमिक है और इसमें शून्य रिकर्सन है. डाइनैमिक सिर्फ़ आपको सामान्य Python कंट्रोल फ़्लो देता है. L4b, इसके साथ रिकर्सन लिखने का विकल्प चुनता है. आपने रिकर्सन लिखा है, इसलिए आपको इसकी सीमा तय करनी होगी. यहीं पर "एलएलएम को काम करने दें, सीमाओं को कोड में रखें" का सिद्धांत लागू होता है.
👀 पढ़ें: गार्ड: if finding.needs_deeper and depth < MAX_DEPTH. · ▶ इसे चलाएं. · ✏️ बदलें: MAX_DEPTH = 1 सेट करें और फिर से चलाएं — ट्री फ़्लैट हो जाता है (और रन सस्ता हो जाता है). कोड में सीमा तय करने का अधिकार आपका है.
13. L5 · आपको किस पैटर्न का इस्तेमाल करना चाहिए?

⚡ कम शब्दों में जानकारी: एक ऐक्सिस से यह तय होता है कि अगला चरण कौन तय करेगा: आपने जो ग्राफ़ बनाया है, एलएलएम या आपका कोड.
आपने तीनों बना लिए हैं. यह मॉडल, पैटर्न को आपकी समस्या के हिसाब से मैच करता है. इसलिए, यह आपके लिए मददगार है: पैटर्न को अपनी समस्या के हिसाब से मैच करें.
ऐक्सिस: यह कौन तय करता है कि अगला विज्ञापन कौन सा होगा?
Pillar | यह कौन तय करता है कि अगला विज्ञापन कौन-सा दिखाया जाएगा | पहले से मौजूद |
1 · ग्राफ़ | आपके बनाए गए ग्राफ़ | L2a / L2b |
2 · साथ मिलकर काम करना | एलएलएम | L3a / L3b |
3 · डाइनैमिक | आपका Python कोड, रनटाइम पर | L4a / L4b |
सबसे पहले: क्या आपको वाकई किसी ग्राफ़ की ज़रूरत है?
ADK, पहले से बनाए गए वर्कफ़्लो एजेंट उपलब्ध कराता है — SequentialAgent, ParallelAgent, LoopAgent. एजेंट की सामान्य चेन के लिए, ये सबसे सस्ते और सही जवाब हैं. साथ ही, इन्हें इकट्ठा करने के लिए कोई ग्राफ़ नहीं है. जब आपको एक्सप्लिसिट राउटिंग (L2b का राउटर), जॉइन (L2a का JoinNode) या ऐसे नोड जो एजेंट नहीं हैं (एक सामान्य फ़ंक्शन, ज़ीरो एलएलएम कॉल) की ज़रूरत हो, तो इन नोड तक पहुंचें. आम तौर पर, इसकी वजह आखिरी वाला नोड होता है.
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 का होम पेज |
ग्राफ़ | कॉमन बिल्ड में एलएलएम के चार कॉल; प्रॉम्प्ट में राउटिंग छिपी हुई है | फ़ंक्शन + एजेंट नोड, पीयर के तौर पर → 1 कॉल, |
सहयोग |
| डिक्लेयर की गई टीम: |
डाइनैमिक | रिकर्सन की वजह से, आपको फ़्रेमवर्क से बाहर कर दिया जाता है | फ़्रेमवर्क के अंदर |
पूरा ऐप्लिकेशन और वह जानकारी जो ग्राफ़ में नहीं दिखती
अब आपने नीचे दिए गए हर हिस्से को बना लिया है. Workflow अपने स्ट्रक्चर को graph.edges पर दिखाता है. इसलिए, यह तस्वीर हाथ से नहीं बनाई गई है, बल्कि कोड से जनरेट की गई है. साथ ही, इस लैब के बारे में यह जानकारी मिलती है:
Pillar |
| क्यों |
1 · ग्राफ़ (L2b) | 10 किनारे, रास्ते वगैरह | आपने इनपुट मिलने से पहले ही उसे बना लिया हो |
2 · सहयोगी (L3a) | 0 किनारे — सिर्फ़ | एलएलएम, हर अनुरोध के हिसाब से सबसेट चुनता है |
3 · डाइनैमिक (L4a/L4b) | तीन किनारे — दोनों में एक जैसे हैं | रिकर्सन को Python में लिखा गया है, न कि ग्राफ़ में |
आखिरी लाइन में, L4b के जवाब का सबूत दिया गया है: L4a और L4b का ग्राफ़ एक जैसा है. साथ ही, इनमें से सिर्फ़ एक ही बार-बार दोहराता है.
अब क्या-क्या बनाया जा सकता है
आपने अभी जो पैटर्न चलाया है वह एक असली प्रॉडक्ट का आकार है:
आपने प्रैक्टिस की | जंगल में, यह | से आरंभ |
ग्राफ़ + राऊटर (L2a/L2b) | दस्तावेज़ पाइपलाइन, ETL-with-LLM-steps, समीक्षा/अनुमोदन चेन, eval harnesses | इस repo का L2b |
कोऑर्डिनेटर + | विशेषज्ञ टीमों, ट्राइएज डेस्क, और मल्टी-लेंस रिव्यू के साथ सहायता करने वाला एक कोपायलट | मैराथन डेमो मोड 2 |
| इनटेक फ़ॉर्म, बुकिंग फ़्लो, ऑनबोर्डिंग, केवाईसी — "जानकारी इकट्ठा करने के बाद कार्रवाई करने" से जुड़ी कोई भी सुविधा | |
डाइनैमिक चौड़ाई/गहराई (L4a/L4b) | रिसर्च एजेंट, रिपोर्ट जनरेटर, और अनजान साइज़ के इनपुट पर ऑडिट स्वीप | मैराथन डेमो मोड 3 |
वे
ये तीनों पैटर्न म्युचुअली एक्सक्लूसिव नहीं हैं. ग्राफ़ नोड, कोलैबोरेटिव कोऑर्डिनेटर को कॉल कर सकता है. साथ ही, कोई विशेषज्ञ डाइनैमिक वर्कफ़्लो लॉन्च कर सकता है. समस्या के हर भाग के लिए सही पैटर्न चुनें. इससे हर एजेंट सिस्टम को एक बड़े प्रॉम्प्ट में बदलने से बचा जा सकता है.

💡 इसे अपने वर्कफ़्लो में आज़माएं: इस स्क्रिप्ट को scripts/graph_dump.py से बनाया गया है. इसे किसी भी Workflow पर पॉइंट करें. यह उसके असली किनारों को प्रिंट करेगा. साथ ही, आपके बनाए गए किसी भी स्ट्रक्चर का मुफ़्त में स्ट्रक्चरल डायग्राम देगा.
14. बधाई हो

आपने मैराथन रेस डे कोच बनाया है. साथ ही, ADK 2 के तीनों ऑर्केस्ट्रेशन पैटर्न का इस्तेमाल किया है.
आपने क्या सीखा
- प्रोलॉग — यह एक मेगा-प्रॉम्प्ट है, जिसने अपना मौसम खुद बनाया: स्ट्रक्चर क्यों मौजूद है.
- L0–L1 —
Agent,Runner, एक असली टूल जिसे मॉडल कॉल करने के लिए चुनता है, और आपका पहलाWorkflow(फ़ंक्शन नोड + एजेंट नोड). - L2a / L2b — ग्राफ़ वर्कफ़्लो: पैरलल फ़ैन-आउट +
JoinNode, फिर डिटरमिनिस्टिक राउटिंग — एक एलएलएम कॉल. - L3a — साथ मिलकर काम करने वाले एजेंट: एक ही टीम, पहले
chat(स्ट्रैंडेड) और फिरsingle_turn(पैरलल सबसेट + सिंथेसिस) में काम करती है — एक फ़्लैग, दो दुनिया. - L3b —
taskमोड: जवाब को बेहतर बनाने के लिए पूछा गया सवाल, स्क्रिप्ट किया गया जवाब फिर से शुरू करना,finish_taskपुष्टि किया गया ऑब्जेक्ट वापस लाना. - L4a / L4b — डाइनैमिक वर्कफ़्लो: रनटाइम चौड़ाई (फ़ैन-आउट), फिर कोड में सीमाओं के साथ रनटाइम डेप्थ (रिकर्सन).
- L5 — डिसिज़न ट्री और पैटर्न कैसे बनते हैं.
काम की लाइनें
फ़ंक्शन, कॉन्टेक्स्ट तैयार करते हैं. किनारों से वर्कफ़्लो तय होता है. राउटर, पाथ चुनता है. मॉडल जवाब लिखता है.
एलएलएम को काम करने दें, लेकिन कोड में सीमाएं तय करें.
समस्या के पैटर्न को उसके टाइप से मैच करें.
अगले चरण
- उस पूरे ऐप्लिकेशन को चलाएं जिससे ये लेवल बनाए गए हैं. यह मैराथन रेस डे कोच है. इसे FastAPI + SSE की मदद से बनाया गया है. इसमें ब्राउज़र यूज़र इंटरफ़ेस (यूआई) है, जो तीनों मोड को लाइव दिखाता है: github.com/cuppibla/adk-2-marathon-demo.
- ज़्यादा जानकारी: adk-workflows-compared — इसमें ADK 2 के वर्कफ़्लो के 23 आधिकारिक सैंपल दिए गए हैं. इनमें से हर एक में 1.x पोर्ट और इस्तेमाल करने के बारे में दिशा-निर्देश दिए गए हैं. सबसे पहले
docs/three-pillars.mdसे शुरू करें. इसके बाद, इस कोडलैब में शामिल नहीं की गई चीज़ें देखें:07_loop,17_request_input,22_agent_in_workflow. - अपनी खुद की समस्या को पोर्ट करें: समस्या के कौनसे हिस्से, जानी-पहचानी संरचना (एल2), जानी-पहचानी टीम (एल3a/एल3b), और अनजानी संरचना (एल4) वाले हैं?
- कोड एक्सप्लोर करें: github.com/cuppibla/adk2-tutorial.
- क्या आपको वर्कशॉप के ज़रिए यह जानकारी मिली? आपको मिला क्रेडिट और उससे बनाया गया प्रोजेक्ट हमेशा के लिए नहीं रहेगा. इन लेवल को बिना किसी शुल्क के फिर से चलाने के लिए, टेक-होम सेटअप वाला चरण पूरा करें. इसमें आपको AI Studio की एक मुफ़्त कुंजी मिलेगी. साथ ही, इसमें कोई क्लाउड प्रोजेक्ट और बिलिंग शामिल नहीं है. सिर्फ़ उस सेल को बदला गया है.