1. סקירה כללית
הכותרת של ADK 2 היא שלושה דפוסי תזמור. ב-Codelab הזה נלמד את שלושת השלבים האלה באמצעות יצירת אפליקציה אחת – מאמן ליום המרתון – שלב אחר שלב. כל רמה עונה על שאלה אחת, מוסיפה רעיון אחד ופועלת באופן עצמאי.
מה תלמדו
- תהליכי עבודה של גרפים (Pillar 1) – כשאתם יכולים לצייר את התהליך לפני שהקלט מגיע.
- סוכנים שפועלים בשיתוף פעולה (עמוד 2) – כשאתם יודעים את הצוות אבל הבקשה בוחרת את קבוצת המשנה – וכל שלושת מצבי שיתוף הפעולה (
chat/task/single_turn), כל אחד פועל בזמן אמת. - תהליכי עבודה דינמיים (עמוד 3) – כשהצורה של העבודה עצמה תלויה בקלט.
- איך בוחרים – עץ החלטות עם שאלה אחת, והסבר על דפוסי ההתנהגות.
הקו המרכזי
מבנה מוכר ← צוות מוכר / קבוצת משנה של משתנים ← צורה לא מוכרת ← בחירת הצורה הנכונה

מה תפַתחו
אפליקציה אחת – Marathon Race Day Coach – הרכיבה שלב אחד שניתן להרצה בכל פעם. כל רמה היא מודול פשוט של Python שמריצים מהטרמינל. החל מרמה 5, כל החלקים שבהמשך הם שלכם.
התמונה נוצרת מהקוד הפועל: כל קו מלא נקרא מתוך Workflow.graph.edges. השיעור הראשון הוא שאת החלקים שאפשר לצייר מראש אפשר לראות בדיוק בעמודה 1, והחלקים שאי אפשר לצייר מראש הם הסיבה לקיומן של עמודות 2 ו-3.

הדרישות
- חשבון Google (ל-Colab) – אין צורך בהגדרה מקומית.
- ~50 דקות (שתי הרמות L4 הן הארוכות ביותר – כדאי להקצות להן זמן).
- אחת משתי הדרכים להגיע למודל Gemini. בוחרים את הדרך – מריצים שלב הגדרה אחד ומדלגים על השאר:
🎓 סדנה | 🏠 Take-home | |
מי | אתם משתתפים בסדנה בזמן אמת והמדריך נתן לכם קישור למימוש קרדיט | כל השאר – כולל משתתפים בסדנה, לאחר מכן |
מה צריך | קישור למימוש ההטבה וחשבון Google שיש לו הרשאה ליצור פרויקט בענן | מפתח API של AI Studio בחינם |
פועל במהירות | Vertex AI, בפרויקט שמתבצע בו חיוב על הקרדיט שקיבלתם לסדנה | Google AI Studio |
עלות | השובר תקף למוצר הזה | תוכנית בחינם |
שלב ההגדרה | הגדרת הסדנה (השלב הבא) | הגדרה בבית (השלב הבא) |
החל מההקדמה ואילך, הכול זהה בשני המקרים – הנתיב רק קובע לאיזה נקודת קצה של מודל מחברת ה-Notebook מתקשרת.
שתי דרכים לעקוב אחרי השיחה
כל שלב שמופיע בהמשך מתאים לתא אחד ב-נוטבוק של Colab ולתיקייה אחת במאגר GitHub. בוחרים באחת מהאפשרויות הבאות:
- ▶ Colab (מומלץ): פתיחת הנוטבוק → הפעלת התאים מלמעלה למטה.
- 💻 מקומי:
git cloneמאגר,./setup_venv.sh, ואז מריצים כל רמה כמודול (python -m ...) או מעיינים בכל הרמות באמצעות./run.sh(adk web).
2. הגדרת סדנה · מימוש הקרדיט ומעבר ל-Vertex AI
בסדנה תקבלו קרדיט ל-Google Cloud. תתבעו את הבעלות על החשבון, תיצרו פרויקט שיחויב דרכו ותגדירו את ה-notebook כך שיפנה אל Vertex AI במקום אל AI Studio. תא אחד עושה את כל הפעולות אחרי התביעה.
1 · מימוש הקרדיט (כדקה אחת)
- פותחים את הקישור למימוש ההטבה שהמורה שיתף או שיתפה. נראה ש
https://me.developers.google.com/benefits/claim/your-workshop-name. - נכנסים לחשבון וממשיכים לדף כדי לאשר את הזיכוי.
- שימו לב באיזה חשבון Google השתמשתם. כל שלב שמופיע בהמשך צריך להתבצע באותו חשבון.
2 · פותחים את ה-notebook ומתקינים את ADK 2 (~1 min)
לוחצים על פתיחה ב-Colab ▶ ואז מריצים את תא הקוד הראשון. הוא מצמיד את הגרסה המדויקת של ADK 2 שבה בוצע האימות של ה-Codelab הזה ומדפיס ✓ installed.
3. מריצים את התא 'Workshop setup' (כ-3 דקות)
זה התא עם הכותרת 🎓 נתיב א' · סדנה. מריצים את התא, ומערכת Colab תבקש מכם לאשר – בוחרים את אותו חשבון Google שדרכו מימשתם את הקרדיט ומאשרים את הגישה.
התא עושה ארבעה דברים: הוא יוצר פרויקט בשם adk-2-tutorial-XXXX על הקרדיט שלכם, מפעיל את Vertex AI API בפרויקט, מגדיר את ארבעת משתני הסביבה שכל תא מאוחר יותר קורא, ואז מבצע שיחת ניסיון ל-Vertex וממתין עד שהיא נענית – כך שההגדרה מסתיימת או שמקבלים הסבר למה היא לא הסתיימה, במקום שהיא תיכשל בהמשך בתוך רמה.
הפלט המצופה – השורה האחרונה היא החשובה:
Signed in as: you@example.com
...
Successfully created GCP project 'adk-2-tutorial-4817'.
Successfully linked 'adk-2-tutorial-4817' to billing account '01ABCD-...'.
waiting for Vertex AI to come up on the new project... (10s)
waiting for Vertex AI to come up on the new project... (20s)
✅ Vertex AI on adk-2-tutorial-4817 · us-central1 · gemini-2.5-flash — answered a test call
4. מדלגים על השלב 'הגדרה בבית'.
אל תפעילו את תא המפתח של AI Studio – הפעלה כזו תחזיר את המחברת ל-AI Studio ותבטל את מה שעשיתם. (התא מגן מפני זה ולא יפעל, אבל הפעולה הנכונה יותר היא פשוט לדלג עליו). אפשר לעבור מכאן ישירות לתא Shared building blocks.
5 · מריצים את התא 'אבני בניין משותפות'
מפעילים פתרונות חכמים פעם אחת. הוא מגדיר את סכימות Pydantic + תרחישי מרתון מוכנים מראש שכל רמה מ-L2 ואילך עושה בהם שימוש חוזר. יוצג לכם ✓ schemas + scenarios ready.
אחרי הסדנה
הקרדיט והפרויקט שנוצר לא יחזיקו מעמד לנצח. כדי להמשיך להריץ את הרמות האלה בחינם אחרי הסדנה, צריך להריץ את השלב הגדרת שימוש בבית במקום – מפתח AI Studio בחינם, ללא פרויקט בענן וללא חיוב. רק התא הזה משתנה.
כדי לנקות את החשבון מוקדם יותר: פותחים את מסוף Cloud, בוחרים את adk-2-tutorial-XXXX ומוחקים אותו. שום דבר אחר ב-codelab הזה לא יוצר משאבים שניתנים לחיוב.
3. הגדרה בבית · מפתח API של AI Studio
כל מה שמופיע בנתיב הזה מופעל באמצעות מפתח API חינמי של Google AI Studio – בלי פרויקט בענן ב-Google Cloud, בלי חיוב ובלי התקנה מקומית. השלב הזה נמשך כ-3 דקות.
1 · פותחים את הנוטבוק
לוחצים על פתיחה ב-Colab ▶. תועברו אל ה-notebook – מבוא בפורמט Markdown, ואז תא אחד שניתן להרצה לכל רמה. מריצים תאים מלמעלה למטה, וכל אחד מהם מדפיס את הפלט שלו מיד מתחתיו.
2 · התקנת ADK 2 (~1 min)
מריצים את תא הקוד הראשון. הוא מצמיד את הגרסה המדויקת שבה בוצע האימות של ה-Codelab:
%pip install -q "google-adk==2.3.0" python-dotenv pydantic nest_asyncio
מחכים עד שהפעולה תסתיים – יופיע ✓ installed. (ההתקנה אורכת כ-30 עד 60 שניות בפעם הראשונה, ולאחר מכן היא נשמרת במטמון).
3 · קבלת מפתח Gemini API מ-AI Studio (~דקה)
- פותחים את aistudio.google.com/app/apikey בכרטיסייה חדשה בדפדפן.
- נכנסים באמצעות חשבון Google.
- לוחצים על Create API key (יצירת מפתח API) בפינה השמאלית העליונה.
- בוחרים פרויקט קיים ב-Google או מאפשרים למערכת ליצור פרויקט חדש.
- מעתיקים את המפתח – הוא מתחיל ב-
AIza...ומכיל כ-40 תווים.
4 · הוספת המפתח ל-Colab (~1 min)
אפשרות א' – Colab Secrets (מומלצת; המפתח נשאר מוסתר):
- לוחצים על סמל המפתח 🔑 בסרגל הצד השמאלי של Colab.
- לוחצים על + הוספת סוד חדש.
- מגדירים את Name בדיוק לערך
GOOGLE_API_KEY. - מדביקים את המפתח בשדה Value (ערך).
- מעבירים את המתג גישה ל-Notebook למצב מופעל.
אפשרות ב' – הדבקה כשמופיעה בקשה (מהירה): מדלגים על הסוד. כשמריצים את התא הבא, מופיעה בקשה מוסתרת 🔑 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 · מריצים את התא 'אבני בניין משותפות'
מריצים את התא Shared building blocks פעם אחת. הוא מגדיר את סכימות Pydantic + תרחישי מרתון מוכנים מראש שכל רמה מ-L2 ואילך עושה בהם שימוש חוזר. יוצג לכם ✓ schemas + scenarios ready.
ההגדרה הושלמה. 🎽 לפני L0 – הגרסה שכולם יוצרים קודם – יש עוד נושא אחד שחשוב להכיר.
4. הקדמה · למה לא הנחיה גדולה אחת?
⚡ לפני שמפעילים פתרונות חכמים, חשוב להבין את הדבר האחד שצריך לשים לב אליו: מאיפה מגיע כל מספר ספציפי? זה כל התרגיל – כל השאר הוא קישוט.
לפני השימוש ב-ladder, מריצים את מה שה-ladder מחליף: סוכן אחד שההנחיה שלו מבטיחה הכול – שליפת נתוני מזג האוויר, ניתוח הקורס, קריאת יומן האימונים, ניתוב לפי תנאים, פלט של התוכנית.
מה שתראו: אסטרטגיה ספציפית, מנוסחת היטב ומשכנעת... שהמספרים שלה מומצאים. באחד הניסיונות, הוא פתח עם "I have pulled today's weather metrics" ודיווח על טמפרטורה של 11.1°C, רוח של 14.5 קמ"ש וניתוח של יומן אימונים שהוא מעולם לא ראה. אין כאן API של מזג אוויר, אין נתונים של קורסים, אין יומן – קריאה אטומה אחת למודל או שממציאה את הקלט שלה או שמגדרת אותו כך שהוא חסר תועלת.
זו המחלה, ויש לה ארבעה תסמינים שכדאי לציין:
- אי אפשר לסמוך עליו – הנתונים מומצאים, בצורה שוטפת.
- אי אפשר לבדוק את זה – הניתוב של שלב 4 נמצא בתוך הטקסט, ואין
ifשאפשר לבדוק. - אי אפשר להחליף שלב – אין נקודת חיבור שבה אפשר לחבר API אמיתי של מזג אוויר.
- אתם משלמים על כל דבר, בכל פעם – חמישה שלבים, קריאה אחת גדולה, ללא שמירה במטמון של חלק דטרמיניסטי.
שירים שיעוררו בכם רגש. ב-9 הרמות הבאות, השלבים האלה מוצאים מההנחיה, אחד בכל פעם: פונקציות אחזור (L1–L2a), ניתוב של הצהרת if (L2b), חלוקת העבודה בין מומחים (L3a–L3b) וקביעת גבולות הצורה באמצעות קוד (L4a–L4b).

💻 מקומי: python -m shared.prologue
5. רמה 0 · הסוכן הראשון שלכם ב-ADK 2

⚡ בקצרה: סוכן הוא מודל + הוראה + כלים שהוא יכול להפעיל; Runner מבצע את הפעולה. כל מה שמעבר לרמה הזו הוא פשוט עוד סוכנים, שמסודרים בצורות טובות יותר.
השאלה: האם אפשר לגרום למודל לענות על שאלה – ולהשתמש בקוד אמיתי כשמדובר באריתמטיקה?
הרעיון האחד – שלושה חלקים:
-
Agent– הגורם שמבצע את ההיגיון (מודל Gemini + הוראה). -
Runner– הרכיב שמריץ סוכן בתוך סשן ומזרים אירועים. - כלי – פונקציית Python פשוטה (
pace_splits) שהמודל מחליט להפעיל. ה-ADK קורא את החתימה + docstring ומעביר למודל הצהרה; אין כתיבת סכימה.
אחרי ההקדמה, הנה התיקון הראשון: מודל LLM שמבצע חישובים של קצב בראש שלו ישמח לטעות – pace_splits הוא קוד פייתון דטרמיניסטי, ולכן המספרים בתשובה מחושבים ולא מאולתרים.
▶ Colab: מריצים את התא L0 · 📁 GitHub: L0_first_agent/ · 💻 Local: python -m L0_first_agent.agent

def pace_splits(target_finish: str) -> dict:
"""Convert a goal time like '3:30:00' into exact per-mile / per-km paces."""
... # deterministic Python — no LLM
pace_coach = Agent(
name="pace_coach", model=MODEL,
tools=[pace_splits], # the model may call it; ADK reads the signature
instruction="You are a friendly, concise marathon coach. ... If the runner "
"mentions a goal time, call pace_splits — never do arithmetic yourself.",
)
runner = Runner(node=pace_coach, session_service=InMemorySessionService(), auto_create_session=True)
async for event in runner.run_async(user_id="u1", session_id="s1", new_message=msg):
... # events carry the model's text
🔍 הסמנים: Agent(...) · tools=[pace_splits] · Runner(...). ובפלט, השורה 🔧 – זה המודל שמחליט, באמצע התשובה, לקרוא לקוד שלכם.
מה יוצג לכם:
🔧 model called tool → pace_splits({'target_finish': '3:30:00'})
🔧 tool returned → {'per_mile': '8:00', 'per_km': '4:58', ...}
🧠 Coach: To finish in 3:30:00, you need an average pace of 8:00 per mile...
השורות עם הסמל 🔧 הן השיעור: באמצע התשובה, המודל בחר לקרוא לפונקציה שלכם, והערך המדויק 8:00/mile בתשובה שלו הגיע מהקוד שלכם – לא מסטטיסטיקות של טוקנים.
❓ אולי תרצו לדעת: האם המודל תמיד קורא לכלי? לא – ההחלטה מתקבלת לגבי כל שאלה בנפרד. אם שואלים שאלה בלי מספרים, הקווים 🔧 נעלמים (בארגז החול אפשר לנסות בדיוק את זה).
👀 קריאה: pace_splits (פונקציה פשוטה) והשורה tools=[pace_splits]. · לוחצים על ▶ הפעלה. · ✏️ שינוי: שואלים את השאלה הכללית (ללא זמן יעד) – שימו לב שהקווים 🔧 נעלמים: המודל מחליט מתי כדאי להפעיל כלי. אחר כך כותבים מחדש את instruction ומריצים מחדש – ההוראה היא שאר התוכנית.
6. רמה 1 · תהליך העבודה הראשון שלכם

⚡ בקצרה: פונקציה רגילה וסוכן LLM הם אותו סוג של צומת. עבודה צפויה → פונקציה (0 LLM, דטרמיניסטית); חשיבה רציונלית → סוכן.
השאלה: איך אפשר לשלב קוד רגיל ו-LLM בתהליך אחד, בלי לשלם על קריאה למודל בחלקים שהם רק קוד?
הרעיון המרכזי: ב-Workflow, פונקציית Python רגילה וסוכן LLM הם רק צמתים באותה רשימת edges.
START ──► fetch_conditions (function, 0 LLM) ──► advise (agent, 1 LLM)
▶ Colab: מריצים את התא L1 · 📁 GitHub: L1_graph_basics/ · 💻 Local: 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 בפונקציה ומריצים אותה מחדש – ההמלצה משתנה והפונקציה עדיין לא כרוכה בעלויות של קריאות ל-LLM.
7. L2a · Parallel fan-out + JoinNode (Pillar 1a)

⚡ אמ;לק: פיצול מקביל (בחינם), המתנה להכול, איגוד, העברת התמונה המלאה לסוכן אחד.
השאלה: אפשר לשרטט את התרשים לפני שהקלט מגיע. מתחילים עם המבנה הבסיסי: אוספים נתונים במקביל, מאגדים אותם ומעבירים אותם לסוכן אחד.
הצורה:
START ──► fetch_weather ──┐
START ──► analyze_course ─┼─► JoinNode ─► strategy (1 agent)
START ──► pull_fitness ───┘ (bundles)
▶ Colab: מריצים את התא L2a · 📁 GitHub: L2a_parallel_join/ · 💻 Local: python -m L2a_parallel_join.workflow

🔍 הסמנים: שלוש קצוות שמתחילים ב-START – זה ה-fan-out – וב-JoinNode, נקודת המפגש.
- שלושת האחזורים הם פונקציות – הם פועלים במקביל, 0 קריאות ל-LLM.
-
JoinNodeמחכה לשלושתם ומאגדת אותם למטען ייעודי (payload) אחד עם הקלדה (BundledRunData), שמקבל מפתח לפי שם הפונקציה. - סוכן
strategyקורא את החבילה וכותבRaceStrategy.
מה שרואים: בכל אחזור מודפסת חותמת זמן של started / finished. שלושתם מתחילים ב-0.0s וה-fan-out מסתיים ב-2.0s – האחזור הכי איטי, ולא ב-4.5s שמתקבלים מסיכום משך הזמן שלהם. החפיפה הזו היא המקביליות. (הזמן הכולל שחלף מההתחלה ועד הסוף total שמוצג בסוף הוא בערך 8 שניות, כי הוא כולל גם את הקריאה ל-LLM של סוכן האסטרטגיה – צריך לקרוא את חותמות הזמן של האחזור של הטענה המקבילה, ולא את הסכום הכולל).
💡 הקדמה: הפרומפט הענק המציא את מזג האוויר. הטמפרטורה כאן מגיעה מפונקציה של אחזור נתונים – קוד אמיתי, נקודת חיבור אמיתית. מחליפים את הדיבור המוקלט ב-API של מזג אוויר אמיתי, ושום דבר אחר לא משתנה.
❓ אולי תרצו לדעת: כמה
JoinNode
מה חשוב לדעת? משפט אחד: הפונקציה מחכה עד שכל ענף מקביל מסתיים, אורזת את התוצאות במילון אחד עם מפתח שהוא השם של הפונקציה במעלה הזרם, ולא מבצעת חישוב בעצמה. בגלל ההכתבה הזו, הנתב של L2b יכול לכתוב node_input["fetch_weather"]["temp_f"].
👀 קריאה: שלושה קצוות יוצאים מ-START; JoinNode מאגד אותם לסוכן אחד. · ▶ מריצים את הפקודה וקוראים את חותמות הזמן, לא את הסכום הכולל. · ✏️ שינוי: גורמים להשהיית אחזור אחד 3.0 – קודם חוזים את שעת הסיום החדשה של ה-fan-out, ואז מאמתים.
8. L2b · הוספת הנתב הדטרמיניסטי (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/ · 💻 Local: 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=...) – צומת פונקציה שנותן שם לנתיב – והקצה של המילון {"HOT": ..., "NORMAL": ..., "COLD": ...} שממפה שמות לצמתים.
המסר העיקרי – שלושה סוגי עבודה, שלושה בתים:
- עבודה צפויה → פונקציות (3 האחזורים המקבילים)
- כלל ברור → ניתוב מפורש (
route_by_weatherהיא הצהרתif, לא החלטה של מודל) - חשיבה רציונלית → המודל (סוכן אסטרטגיה אחד פועל בדיוק)
מה שיוצג: temp=78F -> route=HOT, ואז RaceStrategy מובנה. עלות נטו: קריאה אחת ל-LLM.
⚠️ אם מוסיפים ענף רביעי, צריך להוסיף גם רשומה של DEFAULT_ROUTE למילון הנתיבים. אם המסלול לא תואם למילון, זו לא שגיאה – הענף פשוט מסתיים, והתוכנית יוצאת 0 ללא פלט, וזהו מצב מבולבל לניפוי באגים.
❓ אולי תהיתם: אז L2b הוא פשוט L2a בתוספת נתב? כן – הפעולות של שליפת הנתונים וההצטרפות לא משתנות, ועדיין מדובר בדיוק בקריאה אחת של LLM. מה השתנה: האפשרות 'תמיד אותו סוכן' הפכה ל'אחד משלושה, שנבחר על סמך נתונים'.
👀 קריאה: route_by_weather – הנתב הוא הצהרת if, לא סוכן. · ▶ Run run("COLD") גם כן. · ✏️ שינוי: הוספת הסתעפות WINDY עם סוכן רביעי – וחשוב לקרוא את האזהרה DEFAULT_ROUTE למעלה לפני שעושים את זה.
9. L3a · Collaborative agents: one flag, two worlds — Pillar 2

⚡ אמ;לק: אותו צוות, flag אחד. chat מעביר את כל השיחה למומחה אחד ולא חוזר; single_turn הופך כל מומחה לכלי – קבוצת משנה מקבילה, חזרה אוטומטית, סינתזה אחת.
השאלה: אתם מכירים את הצוות, אבל הבקשה קובעת אילו חברים צריכים לענות. איך מאפשרים למודל שפה גדול לבחור את קבוצת המשנה ולהריץ אותם במקביל?
הצורה: רכז מעל שישה מומחים (רפואי, מזג אוויר, קצב, ציוד, תזונה, נפשי). ברמה הזו, אותו צוות מריץ את אותו קמפיין פעמיים – אותה הנחיה לרכז ואותם שישה מומחים. ההבדל היחיד הוא דגל אחד בסוכני המשנה. הניגודיות היא השיעור.
▶ Colab: מריצים את התא L3a · 📁 GitHub: L3a_collaborative/ · 💻 Local: python -m L3a_collaborative.concierge --mode chat "What about fueling?"

🔍 הסמנים: mode="single_turn" במפעל – ובפלט, TRANSFER → (פעימה 1) לעומת רצף של DISPATCH → שורות עם חותמת זמן אחת (פעימה 2).
Beat 1 · מריצים את ברירת המחדל קודם – ורואים שהיא לא מצליחה לבצע את העבודה
לא נכתב mode= → ברירת המחדל של סוכני המשנה היא chat. הפרטים שיוצגו הם:
TRANSFER → nutrition_specialist (transfer_to_agent — the only tool chat subagents provide)
Final speaker: nutrition_specialist
למתאם אין כלי העברה – סוכני המשנה של הצ'אט מעבירים לו רק את transfer_to_agent, העברה סדרתית של השיחה כולה למומחה אחד. המומחה עונה למשתמש ישירות, והריצה מסתיימת. אין שליחה מקבילה. אין אפשרות להחזיר מוצרים. אין סינתזה. אם שואלים שאלה כללית, המצב מחמיר: שישה מומחים, העברה אחת.
זו לא תקלה – זה מצב הצ'אט עושה את העבודה שלו. השיחה שייכת למי שמנהל אותה, עד שמישהו מעביר אותה באופן מפורש. נכון לגבי עוזר וירטואלי עם יכולות בלתי מוגבלות, אבל לא נכון לגבי שלב בצינור.
Beat 2 · One flag, two worlds
ההבדל היחיד: 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 מריץ אותן במקביל, כל אחת מחזירה אוטומטית את התוצאה שלה, והמתאם מבצע סינתזה.
שאלה | מומחים שפוטרו |
"What about fueling?" | תזונה בלבד |
"My knee hurts at mile 18" | רפואי בלבד |
"כדאי לי לרוץ היום?" | רפואי + מזג אוויר + קצב |
"יש משהו שצריך להדאיג אותי?" | all 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 נעלם.
👀 Read: the _specialist factory — the mode parameter is the whole level. · ▶ Run (הפעלה) של שני המקצבים. · ✏️ שינוי: שואלים "my knee hurts at mile 18" (הברך שלי כואבת בקילומטר ה-29) – קודם חוזים את קבוצת המשנה, ואז בודקים את שורות ה-DISPATCH.
# The factory's mode parameter is THE variable this level teaches:
def _specialist(name, domain, focus, mode):
kwargs = {}
if mode == "single_turn": # the structured contract only makes sense for a TOOL
kwargs = dict(mode="single_turn",
input_schema=SpecialistInput, output_schema=SpecialistResponse)
return Agent(name=name, model=MODEL,
description=f"Marathon {domain} specialist. Consult for: {focus}.",
instruction=..., **kwargs)
race_concierge = Agent(name="race_concierge", model=MODEL,
sub_agents=[...six specialists...], # NOTE: no `mode` on the coordinator
instruction="...DECIDE which specialists are relevant... call them IN PARALLEL... SYNTHESIZE...")
10. L3b · מצב משימה: שיחה עם קו סיום – עמוד 2

⚡ בקצרה: המצב האמצעי – מתקשרים עם המשתמש עד לאיסוף השדות, ואז חוזרים אוטומטית עם אובייקט מאומת.
השאלה: L3a left a gap. chat הוא הבעלים של כל השיחה, ו-single_turn אף פעם לא מדבר עם המשתמש. אבל יש עבודת קליטה אמיתית באמצע: "תדבר עם המשתמש עד שתאסוף X – ואז תחזור עם אובייקט מאומת". איזה מצב זה?
הצורה:
race_desk (coordinator)
└─ gear_fitter (mode="task", output_schema=GearOrder)
▶ Colab: מריצים את התא L3b · 📁 GitHub: L3b_task_desk/ · 💻 Local: 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פשוט מקלידים את התשובה, והסקריפטים של ה-harness מתייחסים אליה כהודעה שנייה באותה סשן). - ההודעה הבאה הפעילה מחדש את אותו סוכן משימות – לא בוצעה הפניה מחדש ולא הוקצתה מחדש משימה. בסשן יודעים מי חיכה.
-
finish_taskהסתיים – כלי ADK הוזרק בגללmode="task". הנציג חייב להתקשר אליו כדי לסיים את הפעולה, והמטען הייעודי (payload) שלו חייב לעבור אימות מולoutput_schema. שיחה עם קו סיום מוקלד – ואז השליטה חוזרת אוטומטית לתיאום, התוצאה מצורפת.
הכלל של שאלה אחת לבחירת מצב
💡 "האם המשתמש צריך לדבר עם ה-Agent – ועד מתי?" chat = indefinitely · task = until the fields are collected · single_turn = never.
מצב | האדם שבתהליך | מקביל? | חזרה להורה |
| שיחה מלאה | לא | ידני (דרך העברה) |
| שאלות הבהרה בלבד | לא | אוטומטי (דרך |
| אין | yes | אוטומטי (עם התוצאה שלו) |
mode מופיע בסוכנים משניים בלבד – אף פעם לא בסוכן הראשי. צמתים בתהליך העבודה מוגדרים כברירת מחדל ל-single_turn (ולכן L1–L2b אף פעם לא כתבו אותו), ואילו סוכני משנה מוגדרים כברירת מחדל ל-chat (ולכן L3a היה צריך).
⚠️ שתי הערות לגבי הגרסה לפני שמתחילים לבנות על בסיס הגרסה הזו: (1) task
כצומת גרף סטטי תלוי בגרסה – בגרסאות 2.0.0b1 עד 2.3.0 (הגרסה שמוצמדת בשיעור Codelab הזה), 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
לקנות לי את זה, ששני האחרים לא יכולים? שלושה דברים: חזרה אוטומטית (הצ'אט ממשיך את השיחה במקום) · קו סיום מוקלד (המטען הייעודי (payload) של finish_task צריך לעבור אימות מול הסכימה – מקבלים נתונים בחזרה, לא תמליל) · השהיה/הפעלה מחדש (הסמל ⏸ הוא משימה בהמתנה שממתינה לאדם, ולא ניתוק).
👀 קריאה: gear_fitter – mode="task" + output_schema הוא החוזה המלא. · לוחצים על ▶ הפעלה. · ✏️ שינוי: run_desk("I need a hydration vest", "2 liters, medium") — שאלת ההבהרה משתנה, קו הסיום נשאר מוקלד.
11. L4a · fan-out מקבילי בגודל זמן ריצה (Pillar 3a)

⚡ בקצרה: השלד עדיין מורכב משלושה שלבים סטטיים – ההסתרה הדינמית מתבצעת בתוך השלב האמצעי, שבו הרוחב נקבע על ידי הנתונים בזמן הריצה.
⚠️ חשוב לדעת: זה השלב הכי תלול בסולם. ברמה הקודמת היו 44 שורות, ברמה הזו יש בערך 120 שורות – שלושה סוכנים ושני צמתי תהליך עבודה, ואין שורות ריקות. כדאי להקדיש לזה כ-15 דקות, ולהסתמך על השורה Read/Run/Change בסוף: לא צריך להבין כל שורה בקריאה הראשונה.
השאלה: הצורה של העבודה תלויה בקלט. אי אפשר לצייר את הגרף מראש. מתחילים עם רוחב זמן הריצה: מאפשרים ל-LLM להחליט כמה שאלות משנה.
הצורה (רמה אחת לעומק):
START ─► decompose ─► research_topic (parallel_worker) ─► synthesize
│ │ │
└──┴──┴─ (flat: no children yet)
שאלה פתוחה מפורקת ל-N שאלות משנה – המספר N נבחר על ידי מודל שפה גדול בזמן הריצה (3-7) – כל אחת מהן נחקרת במקביל, ואז מסונתזת לתדרוך אחד.
▶ Colab: מריצים את התא L4a · 📁 GitHub: L4a_flat_research/ · 💻 Local: python -m L4a_flat_research.deep_research

🔍 הסמנים – אין
dynamic=True
החלפה. דינמי הוא דרך לכתוב, לא הגדרה. שני סמנים בלבד: @node(parallel_worker=True) (מקבל רשימה בגודל זמן ריצה, מפעיל worker אחד לכל פריט) ו-ctx.run_node(...) (מתזמן ישירות צמתי תזמון של קוד). אם רואים את אחת מהאפשרויות האלה → אתם משתמשים בשיטה הדינמית.
מה שתראו: הכלי לפירוק השאלה מדפיס למשל 5 שאלות משנה, הוא מבצע מחקר במקביל ואז יוצר תדרוך מסכם. המספר שונה בכל הפעלה – דבר שלא היה אפשרי בתרשים הקבוע.
שני דגלים שחשוב להבין לגבי העובד:
rerun_on_resume=Trueחובה בכל צומת שמבצע קריאה ל-ctx.run_node– אם לא מציינים אותו, ADK מעלהValueError. כשממשיכים את ההפעלה, הצומת של השליחה צריך להפעיל מחדש את השליחה כדי לבנות מחדש את הצמתים הצאצאים שהוא יצר, כי הם לא נמצאים בתרשים הסטטי.retry_config=bounds how this FAILS. עובד מקביל מבטל כל אח ומעלה מחדש את המיידי אם אחד מהצאצאים נכשל – כך שבלי ניסיון חוזר, שגיאת 429 זמנית אחת מבטלת את כל הריצה, כולל כל שיחה שכבר שולמה. הניסיון החוזר מגיע לצומת הפנימי של כל פריט, כך שכל ענף מנסה שוב באופן עצמאי.
❓ אולי תרצו לדעת: איך ADK יודע שזה דינמי? אין צורך בכך – שום דבר לא מוצהר בשום מקום. הכלי לפירוק יוצר רשימה בזמן הריצה, והגודל של העובד המקביל מותאם למה שמגיע. הדינמיות היא מאפיין של זרימת הנתונים שכתבתם, ולא מצב שהפעלתם.
👀 קריאה: שני הדגלים ב-research_topic – parallel_worker ו-rerun_on_resume. · לוחצים על ▶ הפעלה. · ✏️ שינוי: החלפה בשאלה פתוחה משלכם – N משתנה כי הקלט קובע את הרוחב.
12. L4b · Add recursive spawning (Pillar 3b)

⚡ תקציר: רקורסיה נכתבת, לא ניתנת – העובד קורא לעצמו דרך ctx.run_node, פייתון רגיל – ולכן צריך לכתוב גם את הבלם. זה אומר שנשארו 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/ · 💻 Local: 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 עצמו – ההפניה העצמית is היא הרקורסיה – והשומר 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 בוחר לכתוב איתה רקורסיה. ומכיוון שאתם כתבתם את הרקורסיה, אתם צריכים לכתוב את הגבול שלה – כאן הסיסמה "תנו ל-LLM לעצב את העבודה, שמרו על הגבולות בקוד" מפסיקה להיות סיסמה.
👀 קריאה: השומר: if finding.needs_deeper and depth < MAX_DEPTH. · לוחצים על ▶ הפעלה. · ✏️ שינוי: הגדרה של MAX_DEPTH = 1 והרצה מחדש – העץ משוטח (וההרצה הופכת לזולה יותר). הגבול הוא שלכם, בקוד.
13. L5 · באיזה דפוס כדאי להשתמש?

⚡ סיכום: ציר אחד קובע הכול – מי בוחר את השלב הבא: התרשים שציירתם, ה-LLM או הקוד שלכם.
בנית את כל שלושת המבנים. המודל הזה מסביר למה התבניות שימושיות: התבנית צריכה להתאים לבעיה שרוצים לפתור.
הציר: מי מחליט מה יפעל בהמשך?
עמוד | מי מחליט מה יפעל בהמשך | מובנה |
1 · Graph | הגרף שציירתם | L2a / L2b |
2 · שיתופי | ה-LLM | L3a / L3b |
3 · דינמית | קוד Python, בזמן הריצה | L4a / L4b |
שלב 0: האם בכלל צריך גרף?
חבילת ADK כוללת סוכני תהליכי עבודה מוכנים מראש – SequentialAgent, ParallelAgent ו-LoopAgent. בשרשרת פשוטה של סוכנים, אלה התשובות הנכונות הכי זולות ואין גרף להרכבה. אפשר להשתמש בהם כשצריך ניתוב מפורש (הנתב של L2b), צומת איחוד (JoinNode של L2a) או צמתים שהם לא סוכנים (פונקציה רגילה, ללא קריאות ל-LLM) – בדרך כלל זו הסיבה.
Would a prebuilt SequentialAgent / ParallelAgent / LoopAgent do?
│
├─ YES ──────────────────────────────► use it; stop here
│
└─ NO — I need routing, a join, or non-agent nodes
│
Can you draw the workflow before the input arrives?
│
├─ YES ───────────────────────────► Pillar 1 · Graph workflow (L2a/L2b)
│
└─ NO
├─ Known team, request picks the subset? ─► Pillar 2 · Collaborative (L3a/L3b)
└─ Does the shape depend on the input? ──► Pillar 3 · Dynamic (L4a/L4b)

המסגרת האמינה של 1.x לעומת 2
זו לא גרסה 2.0 שיכולה לעשות דברים שגרסה 1.x לא יכולה לעשות – גרסה 1.x יכולה לבנות את הכול. השינוי הוא שבגרסה 2.0 לכל צורה יש בית ישיר יותר, כך שזרימת הבקרה המוכרת יוצאת מההנחיה והופכת למבנה שאפשר לראות ולבדוק.
דוגמת קוד | העלות בגרסה 1.x | הדף הראשי של ADK 2 |
תרשים | 4 קריאות ל-LLM בגרסה הנפוצה; ההפניה מוסתרת בהנחיה | פונקציה + צמתי סוכן כעמיתים → שיחה אחת, נתב של משפטי |
שיתופי | ניתן להגדרה באמצעות | צוות מוצהר: |
Dynamic | recursion drops you out of the framework | |
האפליקציה כולה, ומה שלא רואים בגרף
סיימתם לבנות את כל החלקים שבהמשך. המבנה של Workflow מוצג ב-graph.edges, ולכן התמונה הזו נוצרת מהקוד ולא מצוירת ידנית. מה שמתקבל מהאינטרוספקציה הוא הסיכום של שיעור ה-Lab הזה:
עמוד | מה כלול ב- | סיבה |
1 · Graph (רמה 2b) | 10 קצוות, מסלולים והכול | ציירתם אותו לפני שהגיעו נתונים |
2 · שיתוף פעולה (L3a) | 0 קצוות – רק | ה-LLM בוחר את קבוצת המשנה לכל בקשה |
3 · דינמי (L4a/L4b) | 3 קצוות – זהים בשני הצדדים | הרקרוסיה כתובה ב-Python, ולא מחוברת בתרשים |
השורה האחרונה היא ההוכחה לתשובה לשאלה L4b: ל-L4a ול-L4b יש גרף זהה, ורק אחד מהם חוזר על עצמו.
מה אפשר לפתח עכשיו
כל דוגמה שהרצתם היא צורה של מוצר אמיתי:
תרגלת | בטבע, | התחל מ- |
גרף + נתב (L2a/L2b) | document pipelines, ETL-with-LLM-steps, review/approval chains, eval harnesses | L2b של המאגר הזה |
רכז + צוות | טייס משנה לתמיכה עם צוותים מומחים, עמדות מיון, בדיקה מרובת היבטים | מצב marathon demo 2 |
| טפסים לקבלת פרטים, תהליכי הזמנה, צירוף משתמשים, אימות זהות (KYC) – כל תהליך של "איסוף ואז פעולה" | |
רוחב/עומק דינמי (L4a/L4b) | סוכני מחקר, כלי ליצירת דוחות, סריקות ביקורת על קלט בגודל לא ידוע | מצב 3 של הדגמה של ריצת מרתון |
הם יוצרים
שלושת הדפוסים לא בלעדיים. צומת בגרף יכול לקרוא לתיאום שיתופי, ומומחה יכול להפעיל תהליך עבודה דינמי. כדי להימנע ממצב שבו כל מערכת של סוכן הופכת להנחיה ענקית אחת, צריך לבחור את התבנית הנכונה לכל חלק בבעיה.

💡 כדאי לנסות את זה בתהליך העבודה שלכם: הסקריפט ששימש ליצירת התמונה הזו הוא scripts/graph_dump.py. מצמידים אותו לכל Workflow והוא ידפיס את הקצוות האמיתיים – דיאגרמה מבנית חינמית של כל מה שתבנו.
14. מזל טוב

בניתם מאמן ליום המרתון, ובמהלך התהליך השתמשתם בכל שלושת דפוסי התזמור של ADK 2.
מה למדתם
- הקדמה – הנחיה מגה שהמציאה מזג אוויר משלה: למה בכלל קיים מבנה.
- L0–L1 —
Agent,Runner, כלי אמיתי שהמודל בוחר להפעיל, ו-Workflowהראשון (צמתי פונקציות + צמתי סוכן כעמיתים). - L2a / L2b — graph workflows: parallel fan-out +
JoinNode, then deterministic routing — one LLM call. - L3a – סוכנים שפועלים בשיתוף פעולה: אותו צוות פועל ב-
chat(stranded) ואז ב-single_turn(parallel subset + synthesis) – דגל אחד, שני עולמות. - L3b — מצב
task: שאלה להבהרה בהשהיה, חידוש מתוסרט,finish_taskהחזרת אובייקט מאומת. - L4a / L4b – Workflows דינמיים: רוחב זמן ריצה (fan-out), ואז עומק זמן ריצה (רקורסיה) עם גבולות בקוד.
- L5 – עץ ההחלטה, והאופן שבו הדפוסים מורכבים.
שורות שכדאי לשמור
הפונקציות מכינות את ההקשר. הקצוות מגדירים את תהליך העבודה. הנתב בוחר את הנתיב. המודל כותב את התשובה.
מאפשרים ל-LLM לעצב את העבודה, אבל שומרים על הגבולות בקוד.
מתאימים את התבנית לצורה של הבעיה.
השלבים הבאים
- כדאי להריץ את האפליקציה המלאה שממנה נלקחו הרמות האלה – Marathon Race Day Coach, גרסת FastAPI + SSE עם ממשק משתמש בדפדפן שמציג את כל שלושת המצבים בשידור חי: github.com/cuppibla/adk-2-marathon-demo.
- הרחבה: adk-workflows-compared – כל 23 הדוגמאות הרשמיות של תהליכי עבודה ב-ADK 2, כל אחת עם יציאה מגרסה 1.x והנחיות מתי להשתמש. מומלץ להתחיל עם
docs/three-pillars.md, ואז לעבור לנושאים שלא נכללו ב-Codelab הזה:07_loop,17_request_input,22_agent_in_workflow. - העברת בעיה משלכם: אילו חלקים הם בעלי מבנה מוכר (רמה 2), צוות מוכר (רמה 3א/רמה 3ב) וצורה לא מוכרת (רמה 4)?
- אפשר לעיין בקוד בכתובת github.com/cuppibla/adk2-tutorial.
- השתתפת בסדנה? הקרדיט שלכם – והפרויקט שנוצר בעזרתו – לא יישארו לתמיד. כדי להמשיך להריץ את הרמות האלה בחינם, צריך לבצע את השלב הגדרה לשימוש ביתי במקום: מפתח AI Studio בחינם, ללא פרויקט בענן וללא חיוב. השינוי היחיד הוא החלפת התא הזה.