1. מבוא
סקירה כללית
בשיעור ה-Lab הזה תלמדו איך ליצור מערכת מרובת סוכנים מבוזרת, ולא רק צ'אטבוטים פשוטים.
מודל LLM יחיד יכול לענות על שאלות, אבל המורכבות של העולם האמיתי דורשת לעיתים קרובות תפקידים מיוחדים. אתם לא מבקשים ממהנדס ה-Backend לעצב את ממשק המשתמש, ואתם לא מבקשים מהמעצב לבצע אופטימיזציה של שאילתות במסד הנתונים. באופן דומה, אנחנו יכולים ליצור סוכני AI ייעודיים שמתמקדים במשימה אחת ומתואמים ביניהם כדי לפתור בעיות מורכבות.
תבנו מערכת ליצירת קורסים שתכלול:
- סוכן מחקר: שימוש ב-
google_searchכדי למצוא מידע עדכני. - סוכן שופט: מבקר את המחקר כדי לבדוק את האיכות והשלמות שלו.
- סוכן ליצירת תוכן: הופך את המחקר לקורס מובנה.
- סוכן Orchestrator: ניהול תהליך העבודה והתקשורת בין המומחים האלה.
דרישות מוקדמות
- ידע בסיסי ב-Python.
- היכרות עם מסוף Google Cloud.
הפעולות שתבצעו:
- הגדרת סוכן לשימוש בכלי (
researcher) שיכול לחפש באינטרנט. - הטמעת פלט מובנה באמצעות Pydantic עבור
judge. - התחברות לסוכנים מרוחקים באמצעות פרוטוקול Agent-to-Agent (A2A).
- כדאי ליצור
LoopAgentכדי ליצור לולאת משוב בין החוקר לבין השופט. - מריצים את המערכת המבוזרת באופן מקומי באמצעות ADK.
- פורסים את המערכת מרובת הסוכנים ב-Google Cloud Run.
עקרונות של ארכיטקטורה ותזמור
לפני שכותבים קוד, כדאי להבין איך הסוכנים האלה פועלים יחד. אנחנו מפתחים צינור ליצירת קורסים.
עיצוב המערכת

תזמור באמצעות סוכנים
סוכנים רגילים (כמו חוקר) מבצעים עבודה. סוכני תזמור (כמו LoopAgent או SequentialAgent) מנהלים סוכנים אחרים. אין להם כלים משלהם, והכלי שלהם הוא העברת הרשאה.
-
LoopAgent: הפעולה הזו דומה ללולאתwhileבקוד. הוא מריץ רצף של סוכנים שוב ושוב עד שתנאי מסוים מתקיים (או עד שמגיעים למספר המקסימלי של איטרציות). אנחנו משתמשים בזה בשביל לולאת המחקר:- חוקר מוצא מידע.
- שופט נותן ביקורת על התשובה.
- אם Judge אומר 'Fail', EscalationChecker מאפשר להמשיך את הלולאה.
- אם Judge אומר 'Pass', EscalationChecker יוצא מהלולאה.
-
SequentialAgent: הפעולה הזו דומה להרצת סקריפט רגילה. הוא מריץ סוכנים אחד אחרי השני. אנחנו משתמשים בזה בצינור עיבוד הנתונים ברמה גבוהה:- קודם מריצים את Research Loop (עד שהוא מסתיים עם נתונים טובים).
- לאחר מכן, מפעילים את כלי יצירת התוכן (כדי לכתוב את הקורס).
השילוב של כל אלה מאפשר לנו ליצור מערכת חזקה שיכולה לתקן את עצמה לפני יצירת הפלט הסופי.
2. הגדרה
הגדרת הסביבה
- פותחים את Cloud Shell: לוחצים על הסמל Activate Cloud Shell (הפעלת Cloud Shell) בפינה הימנית העליונה של מסוף Google Cloud.
קבלת קוד לתחילת הדרך
- משכפלים את מאגר הקוד ההתחלתי לספריית הבית:
cd ~ git clone --depth 1 --filter=blob:none --sparse https://github.com/GoogleCloudPlatform/devrel-demos.git temp-repo && cd temp-repo && git sparse-checkout set agents/build-with-ai/production-ready-ai/prai-roadshow-lab-1-starter && cd .. && mv temp-repo/agents/build-with-ai/production-ready-ai/prai-roadshow-lab-1-starter . && rm -rf temp-repo cd prai-roadshow-lab-1-starter - מפעילים ממשקי API: מריצים את הפקודה הבאה כדי להפעיל את שירותי Google Cloud הנדרשים:
gcloud services enable \ run.googleapis.com \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ aiplatform.googleapis.com \ compute.googleapis.com - פותחים את התיקייה הזו בכלי העריכה.
התקנת יחסי תלות
אנחנו משתמשים ב-uv לניהול מהיר של יחסי תלות.
- מתקינים את יחסי התלות של הפרויקט:
# Ensure you have uv installed: pip install uv uv sync - מגדירים משתני סביבה.
- טיפ: אפשר למצוא את מזהה הפרויקט בלוח הבקרה של Cloud Console או על ידי הפעלת הפקודה
gcloud config get-value project.
.envכדי לאחסן את המשתנים האלה, כך שתוכלו לטעון אותם מחדש בקלות אם הסשן יתנתק.cat <<EOF > .env export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) export GOOGLE_CLOUD_LOCATION=global export GOOGLE_GENAI_USE_VERTEXAI=true EOF - טיפ: אפשר למצוא את מזהה הפרויקט בלוח הבקרה של Cloud Console או על ידי הפעלת הפקודה
- מקור משתני הסביבה:
אזהרה: משתני סביבה לא נשמרים בין הפעלות חדשות של הטרמינל. אם פותחים כרטיסיית טרמינל חדשה, מריצים את הפקודהsource .envsource .envכדי לשחזר אותן.
3. 🕵️ סוכן המחקר

החוקר הוא מומחה. התפקיד היחיד שלו הוא למצוא מידע. כדי לעשות את זה, היא צריכה גישה לכלי: חיפוש Google.
למה כדאי להפריד את הכלי 'מחקר'?
ניתוח מעמיק: למה לא להשתמש רק בסוכן אחד שיעשה הכול?
קל יותר להעריך ולנפות באגים בסוכנים קטנים וממוקדים. אם המחקר לא טוב, משפרים את ההנחיה לחוקר. אם הפורמט של הקורס לא טוב, אפשר לחזור על התהליך ב-Content Builder. בהנחיה מונוליטית שכוללת את כל הפעולות, תיקון של דבר אחד גורם לעיתים קרובות לבעיה בדבר אחר.
- אם אתם עובדים ב-Cloud Shell, מריצים את הפקודה הבאה כדי לפתוח את Cloud Shell Editor:
אם אתם עובדים בסביבה המקומית, פותחים את סביבת הפיתוח המשולבת המועדפת עליכם.cloudshell workspace . - פתיחת
agents/researcher/agent.py. - יוצג שלד עם הערה מסוג TODO.
- מוסיפים את הקוד הבא כדי להגדיר את סוכן
researcher:# ... existing imports ... # Define the Researcher Agent researcher = Agent( name="researcher", model=MODEL, description="Gathers information on a topic using Google Search.", instruction=""" You are an expert researcher. Your goal is to find comprehensive and accurate information on the user's topic. Summarize your findings clearly. If you receive feedback that your research is insufficient, use the feedback to refine your next search. DO NOT output any function calls. Provide your research directly as text. """, ) root_agent = researcher
מושג מפתח: שימוש בכלי
כשמשתמשים ב-Gemini 3, כלי חיפוש Google זמין באופן אוטומטי. אם השתמשתם במודל אחר, למשל Gemini 2.5, תצטרכו להעביר את tools=[google_search] כפרמטר נוסף לבונה Agent(). ערכת ה-ADK מטפלת במורכבות של תיאור הכלי הזה למודל שפה גדול (LLM). כשהמודל מחליט שהוא צריך מידע, הוא יוצר קריאה מובנית לכלי, ה-ADK מפעיל את פונקציית Python google_search ומחזיר את התוצאה למודל.
4. ⚖️ סוכן השופט

החוקר עובד קשה, אבל מודלים גדולים של שפה יכולים להיות עצלנים. אנחנו צריכים ששופט יבדוק את העבודה. השופט מקבל את המחקר ומחזיר הערכה מובנית של עובר/נכשל.
פלט מובנה
מידע נוסף: כדי להפוך תהליכי עבודה לאוטומטיים, אנחנו צריכים פלט צפוי. קשה לנתח ביקורת טקסט ארוכה ומבולבלת באופן אוטומטי. על ידי אכיפה של סכימת JSON (באמצעות Pydantic), אנחנו מוודאים שהשופט מחזיר ערך בוליאני pass או fail שהקוד שלנו יכול לפעול על פיו בצורה מהימנה.
- פתיחת
agents/judge/agent.py. - הגדרת סכימת
JudgeFeedbackוהסוכןjudge.# 1. Define the Schema class JudgeFeedback(BaseModel): """Structured feedback from the Judge agent.""" status: Literal["pass", "fail"] = Field( description="Whether the research is sufficient ('pass') or needs more work ('fail')." ) feedback: str = Field( description="Detailed feedback on what is missing. If 'pass', a brief confirmation." ) # 2. Define the Agent judge = Agent( name="judge", model=MODEL, description="Evaluates research findings for completeness and accuracy.", instruction=""" You are a strict editor. Evaluate the 'research_findings' against the user's original request. If the findings are missing key info, return status='fail'. If they are comprehensive, return status='pass'. """, output_schema=JudgeFeedback, # Disallow delegation because it should only output the schema disallow_transfer_to_parent=True, disallow_transfer_to_peers=True, ) root_agent = judge
מושג מפתח: הגבלת התנהגות של סוכנים
הגדרנו את disallow_transfer_to_parent=True ואת disallow_transfer_to_peers=True. הפעולה הזו גורמת ל-Judge להחזיר רק את הנתונים המובנים JudgeFeedback. הוא לא יכול להחליט להתכתב בצ'אט עם המשתמש או להעביר את הטיפול לסוכן אחר. כך הוא הופך לרכיב דטרמיניסטי בתהליך הלוגי שלנו.
5. 🧪 בדיקה בבידוד
לפני שמקשרים אותם, אפשר לוודא שכל נציג עובד. ה-ADK מאפשר להפעיל סוכנים בנפרד.
מושג מרכזי: סביבת זמן הריצה האינטראקטיבית
adk run מפעיל סביבה קלה שבה אתם ה "משתמשים". כך תוכלו לבדוק את ההוראות של הסוכן ואת השימוש בכלי בנפרד. אם הסוכן נכשל כאן (לדוגמה, אם הוא לא יכול להשתמש בחיפוש Google), הוא ייכשל בוודאות בתיאום.
- מריצים את הכלי 'חוקר' באופן אינטראקטיבי. שימו לב שאנחנו מציינים את ספריית הסוכן הספציפית:
# This runs the researcher agent in interactive mode uv run adk run agents/researcher - בהנחיה בצ'אט, מקלידים:
הוא צריך להשתמש בכלי של חיפוש Google ולהחזיר את התשובה.הערה: אם מוצגת שגיאה שמציינת שהפרויקט, המיקום והשימוש ב-Vertex לא מוגדרים, צריך לוודא שמזהה הפרויקט מוגדר ולהריץ את הפקודה הבאה:Find the population of Tokyo in 2020export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) export GOOGLE_CLOUD_LOCATION=global export GOOGLE_GENAI_USE_VERTEXAI=true - יוצאים מהצ'אט (Ctrl+C).
- מריצים את Judge באופן אינטראקטיבי:
uv run adk run agents/judge - בפרומפט של הצ'אט, מדמים את הקלט:
התשובה צריכה להיותTopic: Tokyo. Findings: Tokyo is a city.status='fail'כי הממצאים קצרים מדי.
6. ✍️ סוכן ליצירת תוכן

כלי יצירת התוכן הוא הכותב היצירתי. הוא לוקח את המחקר שאושר והופך אותו לקורס.
- פתיחת
agents/content_builder/agent.py. - מגדירים את הסוכן
content_builder.content_builder = Agent( name="content_builder", model=MODEL, description="Transforms research findings into a structured course.", instruction=""" You are an expert course creator. Take the approved 'research_findings' and transform them into a well-structured, engaging course module. **Formatting Rules:** 1. Start with a main title using a single `#` (H1). 2. Use `##` (H2) for main section headings. 3. Use bullet points and clear paragraphs. 4. Maintain a professional but engaging tone. Ensure the content directly addresses the user's original request. """, ) root_agent = content_builder
מושג מרכזי: העברת הקשר
יכול להיות שתשאלו: "איך כלי יצירת התוכן יודע מה כלי המחקר מצא?" ב-ADK, סוכנים בצינור משתפים session.state. בהמשך, ב-Orchestrator, נגדיר את Researcher ואת Judge כך שהפלט שלהם יישמר במצב המשותף הזה. ההיסטוריה הזו נגישה להנחיה של הכלי ליצירת תוכן.
7. 🎻 כלי התזמור

המתזמר הוא המנהל של צוות המולטי-אייג'נט שלנו. בניגוד לסוכנים המומחים (חוקר, שופט, יוצר תוכן) שמבצעים משימות ספציפיות, התפקיד של המנהל הוא לתאם את תהליך העבודה ולוודא שהמידע זורם ביניהם בצורה נכונה.
🌐 הארכיטקטורה: סוכן לסוכן (A2A)

בשיעור ה-Lab הזה נבנה מערכת מבוזרת. במקום להפעיל את כל הסוכנים בתהליך Python יחיד, אנחנו פורסים אותם כמיקרו-שירותים עצמאיים. כך כל סוכן יכול להתרחב באופן עצמאי ולהיכשל בלי לגרום לקריסה של המערכת כולה.
כדי לאפשר את זה, אנחנו משתמשים בפרוטוקול Agent-to-Agent (A2A).
פרוטוקול A2A
הסבר מפורט: במערכת ייצור, סוכנים פועלים בשרתים שונים (או אפילו בעננים שונים). פרוטוקול A2A יוצר דרך סטנדרטית לחיפוש ולתקשורת ביניהם באמצעות HTTP. RemoteA2aAgent הוא לקוח ה-ADK של הפרוטוקול הזה.
- פתיחת
agents/orchestrator/agent.py. - מאתרים את התגובה
# TODO: Define connections to remote agentsאו את הקטע של הגדרות הסוכן המרוחק. - מוסיפים את הקוד הבא כדי להגדיר את החיבורים. חשוב להציב את הקוד הזה אחרי הייבוא ולפני הגדרות אחרות של סוכנים.
# ... existing code ... # Connect to the Researcher (Localhost port 8001) researcher_url = os.environ.get("RESEARCHER_AGENT_CARD_URL", "http://localhost:8001/a2a/agent/.well-known/agent-card.json") researcher = RemoteA2aAgent( name="researcher", agent_card=researcher_url, description="Gathers information using Google Search.", # IMPORTANT: Save the output to state for the Judge to see after_agent_callback=create_save_output_callback("research_findings"), # IMPORTANT: Use authenticated client for communication httpx_client=create_authenticated_client(researcher_url) ) # Connect to the Judge (Localhost port 8002) judge_url = os.environ.get("JUDGE_AGENT_CARD_URL", "http://localhost:8002/a2a/agent/.well-known/agent-card.json") judge = RemoteA2aAgent( name="judge", agent_card=judge_url, description="Evaluates research.", after_agent_callback=create_save_output_callback("judge_feedback"), httpx_client=create_authenticated_client(judge_url) ) # Content Builder (Localhost port 8003) content_builder_url = os.environ.get("CONTENT_BUILDER_AGENT_CARD_URL", "http://localhost:8003/a2a/agent/.well-known/agent-card.json") content_builder = RemoteA2aAgent( name="content_builder", agent_card=content_builder_url, description="Builds the course.", httpx_client=create_authenticated_client(content_builder_url) )
8. 🛑 הכלי לבדיקת העברה לטיפול ברמה גבוהה יותר
צריך שתהיה דרך לעצור לולאה. אם השופט אומר 'עבר', אנחנו רוצים לצאת מהלולאה באופן מיידי ולעבור לכלי ליצירת תוכן.
לוגיקה מותאמת אישית באמצעות BaseAgent
הסבר מפורט: לא כל הנציגים משתמשים ב-LLM. לפעמים צריך לוגיקה פשוטה של Python. BaseAgent מאפשרת להגדיר סוכן שמריץ רק קוד. במקרה כזה, אנחנו בודקים את מצב הסשן ומשתמשים ב-EventActions(escalate=True) כדי לסמן ל-LoopAgent להפסיק.
- עדיין ב-
agents/orchestrator/agent.py. - מחפשים את הפלייסהולדר
EscalationCheckerTODO. - מחליפים אותו בהטמעה הבאה:
class EscalationChecker(BaseAgent): """Checks the judge's feedback and escalates (breaks the loop) if it passed.""" async def _run_async_impl( self, ctx: InvocationContext ) -> AsyncGenerator[Event, None]: # Retrieve the feedback saved by the Judge feedback = ctx.session.state.get("judge_feedback") print(f"[EscalationChecker] Feedback: {feedback}") # Check for 'pass' status is_pass = False if isinstance(feedback, dict) and feedback.get("status") == "pass": is_pass = True # Handle string fallback if JSON parsing failed elif isinstance(feedback, str) and '"status": "pass"' in feedback: is_pass = True if is_pass: # 'escalate=True' tells the parent LoopAgent to stop looping yield Event(author=self.name, actions=EventActions(escalate=True)) else: # Continue the loop yield Event(author=self.name) escalation_checker = EscalationChecker(name="escalation_checker")
מושג מרכזי: בקרה על זרימת נתונים באמצעות אירועים
הסוכנים מתקשרים לא רק באמצעות טקסט, אלא גם באמצעות אירועים. על ידי הפקת אירוע באמצעות escalate=True, הסוכן הזה שולח אות אל ההורה שלו (LoopAgent). ה-LoopAgent מתוכנת לזהות את האות הזה ולסיים את הלולאה.
9. 🔁 מחזור המחקר

אנחנו צריכים לולאת משוב: מחקר -> שיפוט -> (כישלון) -> מחקר -> ...
- עדיין ב-
agents/orchestrator/agent.py. - מוסיפים את ההגדרה
research_loop. ממקמים את זה אחרי הכיתהEscalationCheckerוהמופעescalation_checker.research_loop = LoopAgent( name="research_loop", description="Iteratively researches and judges until quality standards are met.", sub_agents=[researcher, judge, escalation_checker], max_iterations=3, )
מושג מרכזי: LoopAgent
האפשרות LoopAgent עוברת בין sub_agents לפי הסדר.
-
researcher: חיפוש נתונים. -
judge: הערכת נתונים. escalation_checker: קובע אםyield Event(escalate=True). אם מתרחשescalate=True, הלולאה נשברת מוקדם. אחרת, הוא יופעל מחדש אצל החוקר (עדmax_iterations).
10. 🔗 צינור עיבוד הנתונים הסופי

לבסוף, מחברים את כל החלקים.
- עדיין ב-
agents/orchestrator/agent.py. - מגדירים את
root_agentבתחתית הקובץ. מוודאים שהפלייסולדר הזה מחליף פלייסולדר קיים שלroot_agent = None.root_agent = SequentialAgent( name="course_creation_pipeline", description="A pipeline that researches a topic and then builds a course from it.", sub_agents=[research_loop, content_builder], )
מושג מרכזי: קומפוזיציה היררכית
שימו לב ש-research_loop הוא סוכן בעצמו (LoopAgent). אנחנו מתייחסים אליו כמו לכל סוכן משנה אחר ב-SequentialAgent. האפשרות הזו מאפשרת לכם לבנות לוגיקה מורכבת על ידי קינון של דפוסים פשוטים (לולאות בתוך רצפים, רצפים בתוך נתבים וכו').
11. 💻 הרצה מקומית
לפני שמריצים הכול, נבדוק איך ה-ADK מדמה את הסביבה המבוזרת באופן מקומי.
ניתוח מעמיק: איך פועל פיתוח מקומי
בארכיטקטורת מיקרו-שירותים, כל סוכן פועל כשרת משלו. כשפורסים, מקבלים 4 שירותים שונים של Cloud Run. אם צריך לפתוח 4 כרטיסיות של טרמינל ולהריץ 4 פקודות, הסימולציה המקומית יכולה להיות מייגעת.
הסקריפט הזה מתחיל uvicorn תהליכים עבור Researcher (יציאה 8001), Judge (יציאה 8002) ו-Content Builder (יציאה 8003). הוא מגדיר משתני סביבה כמו RESEARCHER_AGENT_CARD_URL ומעביר אותם ל-Orchestrator (יציאה 8004). כך בדיוק נגדיר את זה בענן בהמשך!

- מריצים את סקריפט התזמור:
הפקודה הזו מפעילה 4 תהליכים נפרדים.perl -pi -e 's/us-central1/global/g' run_local.sh ./run_local.sh - בדיקה:
- אם משתמשים ב-Cloud Shell: לוחצים על הלחצן תצוגה מקדימה באינטרנט (בפינה השמאלית העליונה של הטרמינל) -> תצוגה מקדימה ביציאה 8080 -> שינוי היציאה ל-
8000. - אם מריצים באופן מקומי: פותחים את
http://localhost:8000בדפדפן. - הנחיה: "צור קורס על ההיסטוריה של הקפה".
- התבוננות: כלי התזמור יתקשר אל החוקר. הפלט מועבר לשופט. אם השופט לא מצליח, הלולאה ממשיכה!
- "שגיאת שרת פנימית" / שגיאות אימות: אם מוצגות שגיאות אימות (למשל, שגיאות שקשורות ל-
google-auth), צריך לוודא שהפעלתם אתgcloud auth application-default loginאם אתם מריצים את הפקודה במחשב מקומי. ב-Cloud Shell, מוודאים שמשתנה הסביבהGOOGLE_CLOUD_PROJECTמוגדר בצורה נכונה. - שגיאות בטרמינל: אם הפקודה נכשלת בחלון טרמינל חדש, צריך לייצא מחדש את משתני הסביבה (
GOOGLE_CLOUD_PROJECTוכו').
- אם משתמשים ב-Cloud Shell: לוחצים על הלחצן תצוגה מקדימה באינטרנט (בפינה השמאלית העליונה של הטרמינל) -> תצוגה מקדימה ביציאה 8080 -> שינוי היציאה ל-
- בדיקת סוכנים בבידוד: גם כשהמערכת פועלת באופן מלא, אפשר לבדוק סוכנים ספציפיים על ידי טירגוט ישיר של היציאות שלהם. האפשרות הזו שימושית לניפוי באגים ברכיב ספציפי בלי להפעיל את כל השרשרת.הערה: אלה נקודות קצה של API, לא דפי אינטרנט. אי אפשר לגשת אליהם דרך דפדפן. במקום זאת, משתמשים ב-
curlכדי לוודא שהם פועלים (למשל, על ידי אחזור כרטיס הסוכן שלהם).- חוקר בלבד (יציאה 8001):
- בודקים את הסטטוס (ומחפשים את נקודת הקצה
url):curl http://localhost:8001/a2a/agent/.well-known/agent-card.json - שולחים שאילתה (באמצעות פרוטוקול A2A JSON-RPC):
curl -X POST http://localhost:8001/a2a/agent \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "message/send", "id": 1, "params": { "message": { "message_id": "test-1", "role": "user", "parts": [ { "text": "What is the capital of France?", "kind": "text" } ] } } }'
- בודקים את הסטטוס (ומחפשים את נקודת הקצה
- Judge Only (Port 8002):
- בדיקת הסטטוס:
curl http://localhost:8002/a2a/agent/.well-known/agent-card.json - שליחת שאילתה:
curl -X POST http://localhost:8002/a2a/agent \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "message/send", "id": 1, "params": { "message": { "message_id": "test-2", "role": "user", "parts": [ { "text": "Topic: Tokyo. Findings: Tokyo is the capital of Japan.", "kind": "text" } ] } } }'
- בדיקת הסטטוס:
- Content Builder Only (Port 8003):
curl http://localhost:8003/a2a/agent/.well-known/agent-card.json - Orchestrator (יציאה 8004):
curl http://localhost:8004/a2a/agent/.well-known/agent-card.json
- חוקר בלבד (יציאה 8001):
12. 🚀 פריסה ב-Cloud Run
האימות הסופי מתבצע בענן. אנחנו נפריד בין הסוכנים ונפרוס כל אחד מהם כשירות נפרד.
הסבר על הגדרת הפריסה
כשפורסים סוכנים ב-Cloud Run, אנחנו מעבירים כמה משתני סביבה כדי להגדיר את ההתנהגות והקישוריות שלהם:
-
GOOGLE_CLOUD_PROJECT: מוודא שהנציג משתמש בפרויקט הנכון ב-Google Cloud לרישום ביומן ולקריאות ל-Vertex AI. -
GOOGLE_GENAI_USE_VERTEXAI: מציין ל-Agent Development Kit (ADK) להשתמש ב-Vertex AI להסקת מסקנות ממודלים במקום להפעיל ישירות את Gemini API. -
GOOGLE_CLOUD_LOCATION: מציין למסגרת הסוכן (ADK) באיזו נקודת קצה להשתמש. -
[AGENT]_AGENT_CARD_URL: זהו נתון חיוני עבור כלי התזמור. הוא מציין ל-Orchestrator איפה נמצאים הסוכנים המרוחקים. הגדרת הערך הזה לכתובת ה-URL של Cloud Run שנפרסה (בספציפיות, הנתיב של כרטיס הסוכן) מאפשרת ל-Orchestrator לגלות את Researcher, Judge ו-Content Builder ולתקשר איתם באינטרנט.
- פריסת הסוכנים המשניים (במקביל): כדי לחסוך זמן, נבצע פריסה של החוקר, השופט ובונה התוכן בו-זמנית.פותחים שלוש כרטיסיות חדשות במסוף. בכל כרטיסייה חדשה, מריצים את הפקודה הבאה כדי להגדיר את הסביבה:
כרטיסייה 1: מריצים את הפריסה של כלי המחקר:cd ~/prai-roadshow-lab-1-starter source .env כרטיסייה 2: מריצים את הפריסה של Judge:gcloud run deploy researcher \ --source agents/researcher/ \ --region us-west1 \ --allow-unauthenticated \ --labels dev-tutorial=prod-ready-1 \ --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \ --set-env-vars GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION \ --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true" כרטיסייה 3: הפעלת הפריסה של הכלי ליצירת תוכן:gcloud run deploy judge \ --source agents/judge/ \ --region us-west1 \ --allow-unauthenticated \ --labels dev-tutorial=prod-ready-1 \ --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \ --set-env-vars GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION \ --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true"gcloud run deploy content-builder \ --source agents/content_builder/ \ --region us-west1 \ --allow-unauthenticated \ --labels dev-tutorial=prod-ready-1 \ --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \ --set-env-vars GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION \ --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true" - תיעוד כתובות ה-URL: אחרי שכל שלושת הפריסות מסתיימות, חוזרים אל הטרמינל המקורי (שבו תבצעו את הפריסה של Orchestrator). מריצים את הפקודות הבאות כדי לתעד את כתובות ה-URL של השירות:
RESEARCHER_URL=$(gcloud run services describe researcher --region us-west1 --format='value(status.url)') JUDGE_URL=$(gcloud run services describe judge --region us-west1 --format='value(status.url)') CONTENT_BUILDER_URL=$(gcloud run services describe content-builder --region us-west1 --format='value(status.url)') echo "Researcher: $RESEARCHER_URL" echo "Judge: $JUDGE_URL" echo "Content Builder: $CONTENT_BUILDER_URL" - פריסת ה-Orchestrator: משתמשים במשתני הסביבה שתועדו כדי להגדיר את ה-Orchestrator.
מצלמים את כתובת ה-URL:gcloud run deploy orchestrator \ --source agents/orchestrator/ \ --region us-west1 \ --allow-unauthenticated \ --labels dev-tutorial=prod-ready-1 \ --set-env-vars RESEARCHER_AGENT_CARD_URL=$RESEARCHER_URL/a2a/agent/.well-known/agent-card.json \ --set-env-vars JUDGE_AGENT_CARD_URL=$JUDGE_URL/a2a/agent/.well-known/agent-card.json \ --set-env-vars CONTENT_BUILDER_AGENT_CARD_URL=$CONTENT_BUILDER_URL/a2a/agent/.well-known/agent-card.json \ --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT \ --set-env-vars GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION \ --set-env-vars GOOGLE_GENAI_USE_VERTEXAI="true"ORCHESTRATOR_URL=$(gcloud run services describe orchestrator --region us-west1 --format='value(status.url)') echo $ORCHESTRATOR_URL - פריסת חזית האתר:
gcloud run deploy course-creator \ --source app \ --region us-west1 \ --allow-unauthenticated \ --labels dev-tutorial=prod-ready-1 \ --set-env-vars AGENT_SERVER_URL=$ORCHESTRATOR_URL \ --set-env-vars GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT - בדיקת פריסה מרחוק: פותחים את כתובת ה-URL של Orchestrator שנפרס. היא פועלת עכשיו באופן מלא בענן, ומשתמשת בתשתית בלי שרת (serverless) של Google כדי להתאים את הסוכנים לעומס!טיפ: כל המיקרו-שירותים וכתובות ה-URL שלהם נמצאים בממשק Cloud Run
13. סיכום
מעולה! יצרתם ופרסתם בהצלחה מערכת מרובת סוכנים מבוזרת שמוכנה לייצור.
מה השגנו
- פירוק משימה מורכבת: במקום הנחיה אחת גדולה, פיצלנו את העבודה לתפקידים מיוחדים (חוקר, שופט, יוצר תוכן).
- הטמענו בקרת איכות: השתמשנו ב
LoopAgentובJudgeמובנה כדי להבטיח שרק מידע באיכות גבוהה יגיע לשלב הסופי. - מיועד לשימוש בסביבת ייצור: באמצעות פרוטוקול Agent-to-Agent (A2A) ו-Cloud Run, יצרנו מערכת שבה כל סוכן הוא מיקרו-שירות עצמאי שניתן להתאמה. השיטה הזו אמינה הרבה יותר מאשר הפעלה של הכול בסקריפט Python יחיד.
- תזמור: השתמשנו ב-
SequentialAgentוב-LoopAgentכדי להגדיר דפוסי זרימת בקרה ברורים.
השלבים הבאים
עכשיו, אחרי שיש לכם את הבסיס, אתם יכולים להרחיב את המערכת הזו:
- הוספת כלים נוספים: נותנים לחוקר גישה למסמכים פנימיים או לממשקי API.
- שיפור השופט: מוסיפים קריטריונים ספציפיים יותר או אפילו שלב של "התערבות אנושית".
- החלפת מודלים: אפשר לנסות להשתמש במודלים שונים לסוכנים שונים (למשל, מודל מהיר יותר לשופט ומודל חזק יותר לכותב התוכן).
עכשיו אתם מוכנים לבנות תהליכי עבודה מורכבים ואמינים מבוססי-סוכנים ב-Google Cloud!