1. 1. סקירה כללית
ב-Codelab הזה תבנו מערכת מרובת סוכנים שמתכננת מסלול רחוב של פורמולה E ומקבלת אישור בהתאם לכללים פשוטים של FIA.
תשתמשו ב-agents-cli כדי ליצור שני פרויקטים רגילים של ערכה לפיתוח סוכנים (ADK), ואז תכתבו את החלקים החשובים: מיומנות של סוכן, שלושה סוכנים והערכה. כל השאר (פריסת הפרויקט, השרת, יחסי התלות, הגדרת הפריסה) מגיע מה-CLI.
חדשים בפורמולה E?
אתם לא צריכים להכיר את עולם הספורט המוטורי. חמשת המונחים האלה מספיקים:
- פורמולה E: אליפות המרוצים של FIA למכוניות חשמליות. רוב המרוצים מתקיימים במסלולי רחוב זמניים במרכזי ערים.
- אישור רשמי: האישור הרשמי של ה-FIA לכך שמסלול מסוים בטוח למרוצים. בלי הומולוגציה, אין מרוץ.
- בלימה רגנרטיבית: כשהרכב בולם, המנועים שלו טוענים את הסוללה. בלימה חזקה יותר מחזירה יותר אנרגיה, ולכן הכללים של ה-codelab הזה דורשים לפחות אזור אחד של בלימה חזקה.
- שכבות CAD: שכבות עם שמות בשרטוטי התכנון של המסלול, כמו קו המרוץ, רחבת הטיפולים והמחסומים. ה-FIA בודק שהשדות הנדרשים קיימים.
- מצב התקפה: הנהגים מקבלים תוספת כוח זמנית כשהם עוברים באזור הפעלה שנמצא מחוץ למסלול המרוצים.
הסוכנים שלכם משחקים בשני הצדדים: אחד מתכנן את המסלול, ושניים בודקים אותו עבור ה-FIA.
מה תפַתחו
התיבות הירוקות הן נציגים והתיבות המקווקוות הן הכלים שלהם, באותו אופן שבו הם מוצגים ב-ADK Playground. שניים מהכלים כוללים סוכנים אחרים: fia_assessor הוא סוכן FIA Assessor עם מיומנות הציות ל-FIA, ו-remote_gatekeeper קורא לסוכן Gatekeeper בפרויקט השני דרך A2A.
סוכן | פרויקט | משרה |
|
Lead Architect |
| קורא את המקום, שואל את המעריך, פותר בעיות, מבקש אישור מהשומר |
|
מעריך FIA |
| בודק את הפריסה באמצעות המיומנות של FIA וכלי ניקוד |
|
שומר הסף של התאום הדיגיטלי |
| מריץ את רשימת המשימות הסופית לאישור |
|
מה תלמדו
- איך
agents-cli scaffold createמסדר פרויקט ADK, ואילו קבצים אתם עורכים. - איך לארוז ידע בתחום מסוים בתור מיומנות של סוכן (
SKILL.md,references/,scripts/) ולטעון אותו באמצעותSkillToolsetשל ADK. - איך להתאים את
thinking_levelלתפקיד של כל נציג. - איך מעריכים סוכנים באמצעות
agents-cli eval run. - איך פורסים נציג ב-Agent Runtime, מה ההבדל בין זהות הנציג לחשבון שירות ואיך קוראים לנציג שנפרס באמצעות פרוטוקול A2A.
2. 2. הגדרת הסביבה
לפני שמתחילים
צריך פרויקט בענן ב-Google Cloud עם חיוב מופעל. אם אתם משתתפים ב-Codelab הזה באירוע, השתמשו בחשבון ובפרויקט שקיבלתם.
פתיחת Cloud Shell והגדרת הפרויקט
פותחים את Cloud Shell ומריצים את הפקודה:
# Cloud Shell sometimes opens without a project set. If so, this sets it to
# the first project on your account.
if [ -z "$(gcloud config get-value project 2>/dev/null)" ]; then
gcloud config set project "$(gcloud projects list --format='value(projectId)' --limit=1)"
fi
export GOOGLE_CLOUD_PROJECT="$(gcloud config get-value project)"
export REGION="us-central1"
export ASSETS="$HOME/devrel-demos/codelabs/formula-e-track-planner"
echo "Project: $GOOGLE_CLOUD_PROJECT Region: $REGION"
יצירת פרטי כניסה לנציגים
כבר נכנסת לחשבון gcloud, אבל קוד Python שהנציגים שלך מריצים משתמש בApplication Default Credentials (ADC), שדורשים כניסה נפרדת:
gcloud auth application-default login
פותחים את הקישור שמוצג, נכנסים עם אותו חשבון, מעתיקים את הקוד ומדביקים אותו בחזרה ב-Cloud Shell. ואז מגדירים את הפרויקט שהמכסה מחויבת בו:
gcloud auth application-default set-quota-project "$GOOGLE_CLOUD_PROJECT"
הפעלת ממשקי ה-API
gcloud services enable \
aiplatform.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
storage.googleapis.com \
cloudresourcemanager.googleapis.com \
serviceusage.googleapis.com \
compute.googleapis.com \
iam.googleapis.com \
logging.googleapis.com \
cloudtrace.googleapis.com
מה המטרה של כל API:
ממשקי API | משמשת עבור: |
| מודלי Gemini ו-Agent Runtime |
| בדיקות הפרויקטים וההרשאות שמופעלות על ידי |
| יוצר את חשבון השירות שמוגדר כברירת מחדל ב-Compute Engine, שבו משתמשים לפריסה בשלב 7. |
| אחסון, יומנים ומעקבים, כמו שמומלץ במדריך להגדרת Agent Runtime |
| קובצי אימג' ו-builds של קונטיינרים, שנכללים כאמצעי זהירות לפריסה בשלב 7 |
בחלק מהפרויקטים כבר מופעלים חלק מהשירותים האלה. אם מפעילים API שכבר פועל, לא קורה כלום.
התקנה של uv ו-agents-cli
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv tool install google-agents-cli==1.10.0
agents-cli --version
ה-Codelab הזה נבדק עם agents-cli בגרסה 1.10.0, אז כדאי להתקין את הגרסה הזו כדי לקבל את אותם קבצים שנוצרו.
3. 3. הגדרת הפרויקטים והוספת הנכסים
יצירת שני הפרויקטים
agents-cli scaffold create יוצר פרויקט ADK מלא שאפשר לפרוס. מריצים אותו פעמיים, פעם אחת לכל מערכת של נציג.
קודם כל, מתכנן המסלולים:
cd ~
agents-cli scaffold create track-planner \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
ואז מסנן השיחות:
cd ~
agents-cli scaffold create gatekeeper \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
דגל | משמעות |
| התחלה מתבנית Python ADK |
| יצירת השרת וההגדרה של Agent Runtime |
| דילוג על CI/CD; שמירה על פרויקט מינימלי |
| אישור ברירות המחדל בלי להציג בקשה |
היכרות עם הפריסה
הפרויקט שנוצר נראה כך. אתם עורכים רק את הקבצים שמסומנים ב-✍️:
track-planner/
├── agents-cli-manifest.yaml # Records the template, deployment target and root agent name
├── pyproject.toml # Dependencies (google-adk, a2a-sdk, ...)
├── .env # Your project and model location, filled in for you
├── Dockerfile # Used by `agents-cli deploy`; copies app/ into the image
├── app/
│ ├── agent.py # ✍️ Your agents
│ ├── fast_api_app.py # Generated server: ADK API, A2A routes, Agent Runtime routes
│ └── app_utils/ # Generated helpers (A2A, sessions)
└── tests/
├── unit/ # Fast tests with no model calls
├── integration/ # Generated server tests
└── eval/ # ✍️ eval_config.yaml and datasets for `agents-cli eval`
תיאור של כל קובץ שנוצר מופיע בקטע מבנה הפרויקט במדריך של Agents CLI.
איך בודקים את הסוכן שנוצר
לפני שמשנים משהו, מריצים את הנציג של התבנית כדי לראות מה מקבלים מהתבנית. מתקינים את יחסי התלות ומפעילים את סביבת הניסויים המקומית ביציאה 8080:
cd ~/track-planner
agents-cli install
agents-cli playground --port 8080
כדי לפתוח אותו, לוחצים על הלחצן Web Preview בסרגל הכלים של Cloud Shell (סמל העין בפינה הימנית העליונה) ובוחרים באפשרות Preview on port 8080.
ב-Playground, שואלים את הסוכן שאלה שהכלים שלו יכולים לענות עליה, לדוגמה:
What's the weather in San Francisco?
בחלונית הצדדית מוצג כל אירוע, כולל הקריאה לכלי get_weather והתוצאה שלה. בהמשך תשתמשו באותה תצוגה כדי לעקוב אחרי הנציגים שלכם.
בסיום, חוזרים לטרמינל ולוחצים על Ctrl+C כדי לעצור את ה-playground.
הוספת הנכסים של Formula E
נתוני המקום, כללי ה-FIA, סקריפט הפיזיקה, הכלים וקבוצות הנתונים להערכה הם לא חלק מהשיעור, אז אתם מעתיקים אותם מ-GitHub במקום להקליד אותם:
cd ~
git clone --depth 1 --filter=blob:none --sparse \
--branch formula-e-lab-v1 \
https://github.com/tdsymonds/devrel-demos.git
git -C devrel-demos sparse-checkout set codelabs/formula-e-track-planner
cp -r "$ASSETS/track-planner/." ~/track-planner/
cp -r "$ASSETS/gatekeeper/." ~/gatekeeper/
formula-e-lab-v1 הוא תג גרסה קבוע, כך שכולם מקבלים את אותם קבצים. $ASSETS הוגדר בשלב 2 ומצביע על התיקייה ששכפלתם.
הפעולה הזו מוסיפה את הקבצים הבאים:
track-planner/
├── app/
│ ├── tools.py # get_track_topology, evaluate_track_layout
│ ├── auth.py # A2A client with per-request token refresh
│ ├── data/circuits.json # Five candidate venues
│ └── skills/fia-compliance-skill/
│ ├── references/track_regulations.md # The FIA rules
│ └── scripts/calculate_regen_zones.py # Braking-energy calculator
└── tests/
├── unit/test_tools.py
└── eval/datasets/track_eval.json, track_eval_quick.json
gatekeeper/
├── app/tools.py # verify_infrastructure_checklist
└── tests/unit/test_tools.py
התקנה ובדיקה
(cd ~/track-planner && agents-cli install && uv run pytest tests/unit)
(cd ~/gatekeeper && agents-cli install && uv run pytest tests/unit)
agents-cli install מריץ את uv sync כדי ליצור סביבה וירטואלית לכל פרויקט. כל בדיקות היחידה צריכות לעבור בהצלחה.
4. 4. כתיבת המיומנות של תאימות ל-FIA
מיומנות של Agent כוללת הוראות, מסמכי עזר וסקריפטים בתיקייה אחת. ה-SkillToolset של ADK טוען את הנתונים בשלוש רמות, כך שהסוכן קורא רק את מה שהוא צריך:
רמה | קובץ | מתי נציג התמיכה רואה את זה |
1 |
| תמיד (כמה עשרות טוקנים) |
2 | גוף | כשהוא מתקשר אל |
3 |
| כשהוא מתקשר אל |
היכולת נמצאת ב-app/skills/ כי ה-Dockerfile שנוצר מעתיק רק את app/ לתמונה שנפרסה.
עיון בקבצים ברמה 3
העתקתם את הקבצים של רמה 3 של הסקיל בשלב 3:
- ב-
references/track_regulations.mdנמצאים הכללים שה-Assessor בודק: מגבלות האורך והרוחב, המחסום שנדרש בכל אזור בלימה, שכבות ה-CAD שחובה להוסיף (בנוסף לשכבות הרפואיות של מסלולי בתי החולים), יעד ההתחדשות וכללי מצב ההתקפה. -
scripts/calculate_regen_zones.pyהוא מחשבון. הוא מקבל את מהירות הכניסה, מהירות היציאה ומרחק הבלימה של אזור הבלימה, ומחשב את האנרגיה שמוחזרת ואת המחסום שהפנייה צריכה, כך שהסוכן אף פעם לא צריך לנחש את הפיזיקה.
מריצים את הסקריפט לפנייה 10 בלונדון, שבה מכוניות בולמות מ-215 ל-55 קמ"ש לאורך 82 מטרים:
cd ~/track-planner
uv run python app/skills/fia-compliance-skill/scripts/calculate_regen_zones.py \
--entry-kph 215 --exit-kph 55 --brake-dist-m 82
הרכב מחזיר כאן כ-508 קילוואט, מעל היעד של 250 קילוואט. הוא מאט ביותר מ-2G, ולכן צריך מחסומי Tecpro בפינה (F1_TEC3):
{"entry_kph": 215.0, "exit_kph": 55.0, "brake_dist_m": 82.0, "deceleration_g": 2.07, "estimated_regen_kw": 507.7, "meets_250kw_target": true, "required_barrier_layer": "F1_TEC3"}
כתיבה של SKILL.md
יוצרים את הקובץ שמקשר בין כל חלקי המיומנות:
cloudshell edit app/skills/fia-compliance-skill/SKILL.md
מוסיפים את התוכן הבא:
---
name: fia-compliance-skill
description: >
FIA Formula E street circuit rules: length and width limits, mandatory CAD
layers, barrier selection, and Gen3 regenerative braking estimates. Use when
designing, checking or fixing a Formula E circuit layout.
---
# FIA Formula E Compliance
Follow these steps for every circuit you check.
1. **Read the rules.** Call `load_skill_resource` with
`file_path="references/track_regulations.md"`.
2. **Estimate regeneration for every heavy braking zone.** Call
`run_skill_script` with `file_path="scripts/calculate_regen_zones.py"` and
`args={"entry-kph": <entry>, "exit-kph": <exit>, "brake-dist-m": <distance>}`.
Never guess kW values. Use the highest `estimated_regen_kw` as the
circuit's peak regeneration.
3. **Check barriers.** Any zone whose `required_barrier_layer` is `F1_TEC3`
needs the `F1_TEC3` CAD layer.
4. **Report.** List every rule the layout fails and a concrete fix for each
one.
description הוא מה שהמודל קורא כדי להחליט מתי להשתמש במיומנות, אז הוא אומר גם מה המיומנות מכסה וגם מתי להשתמש בה.
איך המיומנות מחוברת
פותחים את app/tools.py ב-Cloud Shell Editor:
cloudshell edit app/tools.py
מוצאים את הפונקציה build_fia_skill_toolset:
def build_fia_skill_toolset() -> SkillToolset:
return SkillToolset(
skills=[load_skill_from_dir(SKILL_DIR)],
code_executor=UnsafeLocalCodeExecutor(),
)
-
load_skill_from_dirקורא את תיקיית הסקיל:SKILL.md,references/ו-scripts/. -
SkillToolsetהופך אותן לכלים שהסוכן יכול להפעיל:list_skills, load_skill, load_skill_resourceו-run_skill_script. -
UnsafeLocalCodeExecutorמאפשר ל-run_skill_scriptלהריץ את סקריפט Python במכונה הזו. זה בסדר למעבדה, אבל בסביבת ייצור צריך להשתמש ב-executor בארגז חול.
בשלב הבא תצרפו את ערכת הכלים הזו ל-Assessor.
5. 5. כתיבת הסוכנים
מודלים של Gemini 3 שולטים בהסקת מסקנות באמצעות thinking_level (LOW, MEDIUM או HIGH) במקום תקציב טוקנים. ב-ADK מגדירים את זה באמצעות types.ThinkingConfig(thinking_level=types.ThinkingLevel.HIGH). התאימו את המודל למשימה של כל נציג: מודל שחושב יותר מתכנן טוב יותר, אבל הוא גם יקר יותר וזמן האחזור שלו ארוך יותר.
שומר הסף (LOW)
ה-Gatekeeper מריץ רק רשימת משימות דטרמיניסטית, ולכן הוא לא צריך הרבה יכולות חשיבה. מחליפים את סוכן התבנית:
cloudshell edit ~/gatekeeper/app/agent.py
"""FIA Digital Twin Gatekeeper agent.
This agent runs in its own project and is deployed to Agent Runtime. The track
planner calls it over the A2A protocol.
"""
from google.adk.agents import Agent
from google.adk.apps import App
from google.adk.models import Gemini
from google.genai import types
from app.tools import verify_infrastructure_checklist
# Tested with Gemini 3.8 Flash. To try Gemini 4 Argon, change this to
# "gemini-4-argon", delete the `temperature` settings below (Argon ignores
# them) and run `uv add "google-genai>=2.30.1"` in this project first.
MODEL = "gemini-3.8-flash"
root_agent = Agent(
# Must match `root_agent_name` in agents-cli-manifest.yaml.
name="gatekeeper",
model=Gemini(
model=MODEL,
retry_options=types.HttpRetryOptions(attempts=3),
),
description=(
"FIA Digital Twin Gatekeeper. Runs the final homologation checklist "
"for a Formula E circuit blueprint."
),
instruction=(
"You are the FIA Digital Twin Gatekeeper. For every circuit blueprint "
"you receive, call `verify_infrastructure_checklist` with its circuit "
"ID, CAD layers, minimum width and peak regeneration. Reply with the "
"status and any missing CAD layers. Never approve a blueprint the "
"checklist rejects."
),
# A deterministic checklist needs little reasoning: keep it fast and cheap.
generate_content_config=types.GenerateContentConfig(
temperature=0.0,
thinking_config=types.ThinkingConfig(
thinking_level=types.ThinkingLevel.LOW,
),
),
tools=[verify_infrastructure_checklist],
)
app = App(
root_agent=root_agent,
name="app",
)
הפעלת Gatekeeper באופן מקומי
פותחים כרטיסייה שנייה ב-Cloud Shell ומפעילים את השרת שנוצר על ידי Gatekeeper ביציאה 8001:
cd ~/gatekeeper
APP_URL=http://localhost:8001 uv run uvicorn app.fast_api_app:app --port 8001
חוזרים לכרטיסייה הראשונה ומסתכלים על כרטיס הסוכן של Gatekeeper. ככה סוכנים אחרים מגלים מהו ה-Gatekeeper ומה הוא יכול לעשות:
curl -s http://localhost:8001/a2a/app/.well-known/agent-card.json | jq .
אמור להופיע קובץ JSON שנראה כך (מקוצר):
{
"name": "gatekeeper",
"description": "FIA Digital Twin Gatekeeper. Runs the final homologation checklist for a Formula E circuit blueprint.",
"supportedInterfaces": [
{"url": "http://localhost:8001/a2a/app", "protocolBinding": "JSONRPC", "protocolVersion": "1.0"}
],
"skills": [
{"id": "gatekeeper", "name": "model", "description": "FIA Digital Twin Gatekeeper. ..."},
{"id": "gatekeeper-verify_infrastructure_checklist", "name": "verify_infrastructure_checklist", "description": "Runs the final homologation checklist ..."}
]
}
- הערכים
nameו-descriptionמגיעים ישירות מההגדרה שלAgent(...). skillsמפרט את הפעולות שהסוכן יכול לבצע. כלי ה-ADK הוסיף אתverify_infrastructure_checklistבאופן אוטומטי, באמצעות ה-docstring של הכלי.supportedInterfacesמציין למתקשרים לאן לשלוח בקשות A2A. לכן הפעלתם את השרת עםAPP_URL=http://localhost:8001: המתקשר קורא קודם את הכרטיס, ואז שולח את הבקשות שלו לכלurlשהכרטיס מפרסם.
שום דבר כאן לא נכתב ידנית: השרת שנוצר מהתבנית בונה את הכרטיס מהסוכן שלכם. המתכנן של המסלול יקרא את הקלף הזה כדי למצוא את השומר ולקרוא לו.
המעריך (MEDIUM) והאדריכל הראשי (HIGH)
לכלי לתכנון מסלולים יש שני סוכנים:
- המעריך שוקל כמה כללים, ולכן הוא מקבל
MEDIUM. היא עטופה ב-AgentTool, כך שהאדריכל הראשי קורא לה כמו פונקציה ומקבל את התוצאה. - האדריכל הראשי מתכנן, מתקן ומתאם, כדי שהפרויקט יקבל
HIGH. הוא מגיע אל Gatekeeper דרךRemoteA2aAgent, שנוצר על ידיcreate_remote_gatekeeper_agent()ב-app/auth.py, וגם עוטף אותו ב-AgentTool.
למה לעטוף את שני הכלים? AgentTool מחזיר את התשובה שלו לפונקציית הקריאה החוזרת (caller), כך שהאדריכל הראשי נשאר אחראי וכותב את התוכנית הסופית. אם ה-Gatekeeper היה sub_agent, ה-Lead Architect היה מעביר אליו את השיחה, והסטטוס הקצר של ה-Gatekeeper היה התשובה הסופית.
פותחים את הקובץ app/agent.py של הכלי לתכנון מסלולים:
cloudshell edit ~/track-planner/app/agent.py
מעתיקים את הקוד הבא ומחליפים את כל התוכן של ~/track-planner/app/agent.py בקוד הזה:
"""Formula E track planner: Lead Architect, FIA Assessor and remote Gatekeeper.
- The Lead Architect (root agent) designs the circuit and stays in charge.
- The FIA Assessor checks the layout and is called as a tool (`AgentTool`).
- The Gatekeeper runs in a separate project. It is also called as a tool, over
A2A, so its verdict comes back to the Lead Architect.
"""
from google.adk.agents import Agent
from google.adk.apps import App
from google.adk.models import Gemini
from google.adk.tools.agent_tool import AgentTool
from google.genai import types
from app.auth import create_remote_gatekeeper_agent
from app.tools import build_fia_skill_toolset
from app.tools import evaluate_track_layout
from app.tools import get_track_topology
# Tested with Gemini 3.8 Flash. To try Gemini 4 Argon, change this to
# "gemini-4-argon", delete the `temperature` settings below (Argon ignores
# them) and run `uv add "google-genai>=2.30.1"` in this project first.
MODEL = "gemini-3.8-flash"
fia_skill_toolset = build_fia_skill_toolset()
# 1. FIA Assessor: MEDIUM thinking to weigh several rules without much latency.
assessor_agent = Agent(
name="fia_assessor",
model=Gemini(
model=MODEL,
retry_options=types.HttpRetryOptions(attempts=3),
),
description=(
"FIA safety and energy assessor. Audits a proposed circuit against "
"the geometry, regeneration and CAD layer rules."
),
instruction=(
"You are the FIA Assessor. Load the `fia-compliance-skill` and follow "
"it. Estimate regeneration for each braking zone with "
"`calculate_regen_zones.py`, then call `evaluate_track_layout` with "
"the highest value. Reply with the verdict, the score and every "
"remediation note."
),
generate_content_config=types.GenerateContentConfig(
temperature=0.1,
thinking_config=types.ThinkingConfig(
thinking_level=types.ThinkingLevel.MEDIUM,
),
),
tools=[fia_skill_toolset, evaluate_track_layout],
)
# 2. Remote Gatekeeper, reached over A2A (see app/auth.py).
remote_gatekeeper = create_remote_gatekeeper_agent()
# 3. Lead Architect: HIGH thinking for multi-step planning and trade-offs.
root_agent = Agent(
# Must match `root_agent_name` in agents-cli-manifest.yaml.
name="track_planner",
model=Gemini(
model=MODEL,
retry_options=types.HttpRetryOptions(attempts=3),
),
description=(
"Lead Formula E circuit architect. Designs FIA-compliant street "
"circuits and gets them homologated."
),
instruction=(
"You are the Lead Formula E Circuit Architect. For every request:\n"
"1. Call `get_track_topology` for the venue.\n"
"2. Call the `fia_assessor` tool with the full topology.\n"
"3. If the Assessor rejects the layout, propose concrete fixes (for "
"example widen a sector to 10.0m or add missing CAD layers) and "
"re-assess the fixed layout.\n"
"4. Once the Assessor passes it, call the `remote_gatekeeper` tool "
"with the circuit ID, CAD layers, minimum width and peak "
"regeneration for final approval.\n"
"5. Finish with a short blueprint: circuit ID, length, minimum width, "
"peak regeneration, every CAD layer by name, and the Gatekeeper's "
"status."
),
generate_content_config=types.GenerateContentConfig(
temperature=0.2,
thinking_config=types.ThinkingConfig(
thinking_level=types.ThinkingLevel.HIGH,
),
),
# Both helpers are tools, so their answers come back to the Lead Architect
# and it writes the final blueprint.
tools=[
get_track_topology,
AgentTool(agent=assessor_agent),
AgentTool(agent=remote_gatekeeper),
],
)
app = App(
root_agent=root_agent,
name="app",
)
הפעלת המערכת כולה ב-Playground
מוודאים שה-Gatekeeper עדיין פועל בכרטיסייה השנייה. בכרטיסייה הראשונה, מפעילים את סביבת הניסויים של מתכנן המסלולים:
cd ~/track-planner
agents-cli playground --port 8080
לוחצים על Web Preview > Preview on port 8080, כמו שעשיתם בשלב 3.
בקשו לולאת השראה במקום שעומד בכללים:
Design and homologate a Formula E circuit at Tokyo Bay.
צפו בחלונית האירועים בזמן שהסוכנים עובדים. השלבים הבאים אמורים להופיע לפי הסדר:
get_track_topology: האדריכל הראשי טוען את הנתונים של מפרץ טוקיו.-
fia_assessor: האדריכל הראשי מעביר את הפריסה למעריך, שקורא ל-load_skill, ל-load_skill_resourceול-run_skill_script(פעם אחת לכל אזור בלימה), ואז ל-evaluate_track_layout. -
remote_gatekeeper: האדריכל הראשי מתקשר למסנן השיחה באמצעות A2A. הבקשה תופיע בכרטיסייה השנייה. - תוכנית סופית מהאדריכל הראשי, שבה מפורטות כל שכבות ה-CAD וסטטוס APPROVED (מאושר) של Gatekeeper.
לוחצים על אירוע כלשהו כדי לראות את הקלט והפלט המדויקים שלו.
עכשיו מתחילים סשן חדש ומנסים מקום שמפר את הכללים:
Can the Monaco Harbour layout be homologated? If not, fix it and try again.
הפעם המעריך דוחה את העיקול של 6.8 מטרים, האדריכל הראשי מציע עיקול רחב יותר, והפריסה המתוקנת חוזרת למעריך לפני שהיא מגיעה לשומר הסף.
בסיום, לוחצים על Ctrl+C בכרטיסייה הראשונה כדי לעצור את ה-playground. משאירים את Gatekeeper פועל בכרטיסייה השנייה: תצטרכו אותו בשלב הבא.
6. 6. הערכת הסוכנים
agents-cli eval run מריץ את הסוכן על קבוצת נתונים, מתעד כל פנייה וקריאה לכלי ומדרג את התוצאות. אתם מחליטים מה למדוד ב-tests/eval/eval_config.yaml.
עיון במערך הנתונים
פותחים את מערך הנתונים ב-Cloud Shell Editor:
cd ~/track-planner
cloudshell edit tests/eval/datasets/track_eval.json
הקובץ מכיל רשימה של eval_cases. לכל מקרה יש eval_case_id, prompt (מה שהמשתמש שואל) וreference (איך נראית תשובה טובה). השופט של ה-LLM משווה בין התשובה של הנציג לבין חומר העזר.
| מה נבדק |
| מקום שעומד בכל הכללים ומאושר |
| העיקול הכפול באורך 6.8 מטרים לא עומד בכלל הרוחב |
| המסלול באורך 4,350 מטרים לא עומד בכלל האורך |
| בפריסה חסרות שכבות CAD חובה |
| אזור בלימה מתחת ליעד של 250 קילוואט |
| גישה לבית חולים שדורשת שכבות CAD רפואיות |
| אזור Attack Mode במסלול המרוצים |
| שיחה מרובת שלבים: מונקו נדחית, המשתמש מבקש תיקון, והפריסה המתוקנת צריכה לקבל אישור |
במקרה האחרון משתמשים ב-agent_data במקום ב-prompt. הוא מפעיל מחדש את החלקים הקודמים של השיחה, כדי שתוכלו לבדוק איך הסוכן מטפל בבקשת המשך, ולא רק בשאלה אחת.
הקובץ track_eval_quick.json באותה תיקייה מכיל רק שני מקרים: מקרה 1 (שאלה אחת) ומקרה 8 (שיחה). תריצו את השאילתה הזו כי היא מהירה יותר ומשתמשת בפחות מכסה.
כתיבת המדדים
מערך הנתונים מציין מה לשאול את הסוכן. eval_config.yaml מסביר איך לתת ציון לתשובות. agents-cli eval run קורא אותו אחרי שהנציג ענה על כל מקרה, ומריץ כל מדד על כל תשובה.
פותחים את הקובץ שנוצר על ידי הפיגום:
cloudshell edit tests/eval/eval_config.yaml
הוא כבר מכיל שופט LLM כללי (custom_response_quality) ומדד agent_turn_count שסופר רק את מספר הפעמים שהמשתמש והמודל הגיבו. זו התחלה טובה לכל סוכן, אבל היא לא אומרת שום דבר על פורמולה E. אתם תשאירו את השופט ותוסיפו מדד שבודק כלל ספציפי לדומיין הזה.
הערכות טובות בדרך כלל משלבות שני סוגים של מדדים:
סוג | איך הציון נקבע | למה היעד מתאים | פשרה |
LLM-as-a-judge | המודל קורא את התשובה ואת | איכויות מעורפלות: האם התשובה נכונה, מלאה וברורה? | עלות של קריאה למודל לכל מקרה; הציונים יכולים להשתנות מעט בין הרצות שונות |
מדד קוד | פונקציית Python קטנה בודקת את התשובה | עובדות מדויקות שניתן לבדוק: האם התשובה כללה משהו שחייב להיות שם? | בודק רק את מה שאפשר לבטא בקוד |
מחליפים את תוכן הקובץ בתוכן הבא:
metrics_to_run:
- custom_response_quality
- fia_cad_layer_compliance
custom_metrics:
# LLM-as-a-judge. response_quality.py is generated by `agents-cli scaffold
# create`; it grades the final answer against the case's `reference`.
- name: custom_response_quality
custom_function_file: response_quality.py
# Deterministic code metric: an approved blueprint must name every
# mandatory FIA CAD layer.
- name: fia_cad_layer_compliance
custom_function: |
def evaluate(instance):
response = str(instance.get("response") or "")
reference = str(instance.get("reference") or "")
# Only approvals must list every layer. Rejections and other
# questions (such as Attack Mode) don't, so skip them.
if "APPROVED" not in reference:
return {"score": 1.0, "explanation": "Not an approval case."}
required = [
"F1_TRACK_CENTRELINE",
"F1_PIT_ENTRY_SPEED_LIMIT_LANE",
"F1_WALL_TEMP",
"F1_TEC3",
]
missing = [layer for layer in required if layer not in response]
return {
"score": round(1 - len(missing) / len(required), 2),
"explanation": "Missing: " + (", ".join(missing) or "none"),
}
מה כל חלק עושה:
metrics_to_runמפרט את המדדים להרצה, לפי שם. אם מסירים שם של מדד, המדד מושבת אבל לא נמחק.-
custom_response_qualityהוא השופט ב-LLM. custom_function_fileמפנה אלtests/eval/response_quality.py, שנוצר על ידי הפיגום. כדי לראות את ההנחיה לשיפוט, פותחים את הקובץ. -
fia_cad_layer_complianceהוא מדד הקוד, שכתוב בשורה מתחת ל-custom_function. בכל מקרה, הוא מקבלinstance(ההנחיה,responseהסופי של הנציג וreference). במקרים שבהם התשובה הצפויה היא אישור, הוא בודק אם התשובה מציינת את כל ארבע שכבות ה-CAD הנדרשות ומפרט את השכבות החסרות. לדוגמה, תוכנית שלא כוללת אתF1_TEC3תקבל ציון של 0.75. במקרים אחרים הציון הוא 1.0, כי בתשובה של דחייה או של מצב התקפה לא צריך לפרט כל שכבה.
למה כדאי לבדוק את שכבות ה-CAD? תוכנית מאושרת שחסרה בה שכבה חיונית היא שגויה, גם אם היא נראית טוב, ושופט LLM עלול לפספס את זה. בדיקת קוד מחילה את אותו כלל באותו אופן בכל הפעלה.
הרצת ההערכה
משאירים את Gatekeeper המקומי פועל בכרטיסייה השנייה, ואז מריצים את הפקודה:
agents-cli eval run \
--dataset tests/eval/datasets/track_eval_quick.json \
--config tests/eval/eval_config.yaml \
--concurrency 1
ls artifacts/grade_results/
הבדיקה נמשכת כמה דקות. כל מקרה מפעיל את כל התהליך של מספר הסוכנים, כעשר קריאות למודל עם האדריכל הראשי שחושב ב-HIGH, כך ש-Step 1/2: eval generate הוא החלק האיטי. הוא לא תקוע.
בסיום, פותחים את דוח ה-HTML ב-artifacts/grade_results/ באמצעות Cloud Shell Editor. ציוני fia_cad_layer_compliance נמוכים מצביעים על כך שהתשובה הסופית של האדריכל הראשי לא כוללת שכבות. כדאי לנסות לנסח את ההוראה בצורה מדויקת יותר ולהפעיל את ההערכה שוב.
7. 7. פריסת Gatekeeper ב-Agent Runtime
אתם פורסים רק את Gatekeeper. הכלי לתכנון המסלול ממשיך לפעול ב-Cloud Shell וקורא לו.
פותחים כרטיסייה חדשה ב-Cloud Shell.
הפריסה נמשכת 5 עד 8 דקות, אז כדאי לבצע אותה בכרטיסייה חדשה בזמן שההערכה משלב 6 מסתיימת:
- בסרגל הכלים של Cloud Shell, לוחצים על Open a new tab (+).
- בכרטיסייה החדשה לא נשמרים המשתנים משלב 2, אז צריך להגדיר אותם שוב:
export GOOGLE_CLOUD_PROJECT="$(gcloud config get-value project)" export REGION="us-central1" export ASSETS="$HOME/devrel-demos/codelabs/formula-e-track-planner" export PATH="$HOME/.local/bin:$PATH" echo "Project: $GOOGLE_CLOUD_PROJECT Region: $REGION"
משאירים את Gatekeeper המקומי פועל בכרטיסייה השנייה: ההערכה עדיין משתמשת בו, ואין צורך לעצור אותו בשביל הפריסה.
פריסה
בכרטיסייה החדשה, פורסים את Gatekeeper. הוא פועל כחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine של הפרויקט:
cd ~/gatekeeper
PROJECT_NUMBER=$(gcloud projects describe "$GOOGLE_CLOUD_PROJECT" --format="value(projectNumber)")
agents-cli deploy \
--no-agent-identity \
--service-account "${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--project "$GOOGLE_CLOUD_PROJECT" \
--region "$REGION" \
--no-confirm-project
הפריסה נמשכת כ-5 עד 8 דקות. אל תסגרו את הכרטיסייה של Cloud Shell בזמן שהיא פועלת. אם החיבור לזרם היומנים מתנתק, אפשר לבדוק את ההתקדמות באמצעות agents-cli deploy --status. בזמן ההמתנה, חוזרים לשלב 6 וקוראים את דוח ההערכה.
בדיקת הזהות של הסוכן
agents-cli מתעד את המשאב שנפרס ב-deployment_metadata.json:
export RUNTIME_ID=$(jq -r .remote_agent_runtime_id ~/gatekeeper/deployment_metadata.json)
echo "$RUNTIME_ID"
curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${RUNTIME_ID}" \
| jq -r .spec.effectiveIdentity
השורה השנייה של הפלט היא הזהות שבה פועל Gatekeeper:
נפרס באמצעות | פלט לדוגמה |
חשבון השירות (ברירת המחדל) |
|
Agent Identity |
|
חשבון השירות משותף לכל מה שמשתמש בו בפרויקט. לכל סוכן יש זהות משלו, כך שאתם יכולים להקצות לו בדיוק את התפקידים שהוא צריך ולראות את הפעולות שלו בנפרד ביומני הביקורת.
8. 8. התחברות ל-Gatekeeper שנפרס דרך A2A
Agent Runtime מציג את נתיבי ה-A2A שנוצרו על ידי Gatekeeper מאחורי נתיב /api מאומת.
מוודאים שההערכה משלב 6 הסתיימה, ואז עוצרים את Gatekeeper המקומי בכרטיסייה השנייה (Ctrl+C). מעכשיו, מתכנן המסלולים יקרא למודל שנפרס. בכרטיסייה הראשונה, מכוונים את מתכנן המסלולים אל הכתובת:
export RUNTIME_ID=$(jq -r .remote_agent_runtime_id ~/gatekeeper/deployment_metadata.json)
: "${RUNTIME_ID:?No deployed Gatekeeper found. Complete Step 7 first.}"
cd ~/track-planner
echo "GATEKEEPER_A2A_URL=https://${REGION}-aiplatform.googleapis.com/reasoningEngines/v1/${RUNTIME_ID}/api/a2a/app" >> .env
למה הלקוח מרענן את הטוקן שלו
פתיחת app/auth.py. התוקף של אסימוני הגישה של Google Cloud פג אחרי שעה, ולכן לקוח שמגדיר כותרת Authorization קבועה בזמן ההפעלה מתחיל להיכשל עם 401 Unauthorized אחרי שעה. GoogleAuthRefresh יוצר מחלקת משנה של httpx.Auth ובודק את פרטי הכניסה בכל בקשה, ומרענן אותם לפי הצורך. הפרמטר create_remote_gatekeeper_agent() מצרף אותו רק לכתובות URL של https://.
הפעלה מקצה לקצה
מפעילים שוב את סביבת ה-Playground כדי שהיא תזהה את ה-GATEKEEPER_A2A_URL החדש:
agents-cli playground --port 8080
לוחצים על Web Preview (תצוגה מקדימה באינטרנט) > Preview on port 8080 (תצוגה מקדימה ביציאה 8080), מתחילים סשן חדש ושואלים:
Assess the Monaco Harbour layout, widen the chicane to 11m, and get Gatekeeper approval.
האירועים נראים כמו בשלב 5, אבל הקריאה ל-remote_gatekeeper עוברת עכשיו ל-Gatekeeper ב-Agent Runtime במקום לכרטיסייה השנייה.
איך רואים את השיחה ב-Agent Runtime
מוכיחים שהבקשה באמת הגיעה ל-Gatekeeper שנפרס דרך A2A:
- במסוף Cloud, מחפשים את Agent Platform ופותחים את Deployments בתפריט שמימין.
- בוחרים באפשרות gatekeeper.
- פותחים את הכרטיסייה סשנים.
יופיע סשן חדש שבו מזהה המשתמש מתחיל ב-A2A_USER_. שרת ה-A2A של Gatekeeper יצר אותו כשמתכנן המסלולים שלכם קרא לו. פותחים את הכרטיסייה Traces באותו דף כדי לראות את הקריאה למודל של Gatekeeper ואת הקריאה לכלי verify_infrastructure_checklist של אותה בקשה.
אופציונלי: פריסה גם של מתכנן המסלולים
עד עכשיו, מתכנן המסלולים פעל ב-Cloud Shell, ולכן הקריאות שלו מ-A2A ל-Gatekeeper השתמשו בפרטי הכניסה שלכם. פורסים גם את הסוכן לתכנון, ושני הסוכנים פועלים ב-Agent Runtime וקוראים אחד לשני באמצעות הזהויות שנפרסו.
מקישים על Ctrl+C כדי לעצור את ה-Playground, ואז פורסים את המתכנן באותו אופן כמו ה-Gatekeeper:
cd ~/track-planner
PROJECT_NUMBER=$(gcloud projects describe "$GOOGLE_CLOUD_PROJECT" --format="value(projectNumber)")
agents-cli deploy \
--no-agent-identity \
--service-account "${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--project "$GOOGLE_CLOUD_PROJECT" \
--region "$REGION" \
--no-confirm-project
שני הסוכנים פועלים באותו חשבון שירות של Compute Engine. חשוב להשאיר את --service-account: בלעדיו, הכלי לתכנון פועל כסוכן השירות שמוגדר כברירת מחדל של Agent Runtime, ולא יכול לקרוא ל-Gatekeeper (ראו למה חשבון השירות הזה? בשלב 7).
איך המתכנן שנפרס מגיע אל שומר הסף:
-
agents-cli deployמעתיק את הערכים ב-.envלפריסה, כך שהמתכנן מקבל את ה-GATEKEEPER_A2A_URLשהוספתם למעלה. - ב-Agent Runtime,
GoogleAuthRefreshב-app/auth.pyמקבל את הזהות של המתכנן שנפרס במקום את הזהות שלכם.
הפריסה נמשכת כ-5 עד 8 דקות. בסיום, בודקים איזו זהות מפעילה את המתכנן:
export PLANNER_ID=$(jq -r .remote_agent_runtime_id deployment_metadata.json)
curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${PLANNER_ID}" \
| jq -r .spec.effectiveIdentity
כדי לנסות את המערכת שנפרסה:
- במסוף Cloud, חוזרים אל Agent Platform > Deployments.
- בוחרים באפשרות track-planner ופותחים את הכרטיסייה Playground.
- מוסיפים את הפרטים הבאים:
Design and homologate a Formula E circuit at Tokyo Bay. - מחכים שהסטטוס של התוכנית ב-Gatekeeper יהיה APPROVED.
- חוזרים אל Deployments, בוחרים באפשרות gatekeeper ופותחים את הכרטיסייה Sessions. הסשן החדש ביותר של
A2A_USER_הגיע מהכלי לתכנון רשתות שנפרס, ולא מ-Cloud Shell.
כשמנקים בשלב הבא, מוחקים גם את המתכנן:
curl -X DELETE -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${PLANNER_ID}?force=true"
9. 9. פתרון בעיות וניקוי
פתרון בעיות
תיאור הבעיה | תיקון |
| צריך לאשר את התנאים וההגבלות במסוף Cloud ואז לנסות שוב. |
הפרויקט הוא | מריצים מחדש את פקודות הפרויקט בשלב 2. |
| מריצים את |
| משלימים את שלב 4 או מעתיקים את |
| מפעילים את Gatekeeper המקומי (שלב 5) או מגדירים את |
| אי אפשר להשתמש ב-Agent Identity בחשבון שלך. פועלים לפי ההוראות לניקוי בשלב 7, ואז משתמשים בחשבון השירות לפריסה. |
הכלי לתכנון מסלולים שנפרס מדווח על | לזהות של המתכנן אין הרשאה להתקשר ל-Gatekeeper. פורסים אותו מחדש באמצעות |
| הגעת למכסת השימוש ב-Gemini. צריך לחכות דקה או להוסיף את |
| צריך לעצור את השרת השני או לבחור |
הסרת המשאבים
מוחקים את Gatekeeper שנפרס כדי שהוא לא ימשיך לפעול:
export RUNTIME_ID=$(jq -r .remote_agent_runtime_id ~/gatekeeper/deployment_metadata.json)
: "${RUNTIME_ID:?No deployed Gatekeeper found.}"
curl -X DELETE -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${RUNTIME_ID}?force=true"
אם יצרתם פרויקט רק בשביל ה-Codelab הזה, אתם יכולים למחוק את הפרויקט כולו. אם אתם משתתפים באירוע, אל תחליפו את הפרויקט שקיבלתם עד שהמארגנים יגידו לכם לעשות את זה.
מה למדתם
-
agents-cli scaffold createנותן לכם פרויקט ADK סטנדרטי שאפשר לפרוס. אתם רק צריכים לכתוב סוכנים, מיומנויות והערכות. - הסקילים של הסוכן מאפשרים להשאיר את הידע בתחום מחוץ להנחיות עד שהסוכן צריך אותו.
- ב-
thinking_levelאתם יכולים לבחור אם אתם מעדיפים שהסוכן יחשוב לעומק או יענה מהר. agents-cli eval runהופך את השאלה "האם זה עובד?" לציונים שאפשר לעקוב אחריהם.- התכונות Agent Identity ו-A2A מאפשרות לסוכנים שנפרסו בנפרד לעבוד יחד בצורה מאובטחת.