1. 1. Panoramica
In questo codelab creerai un sistema multi-agente che progetta un circuito cittadino di Formula E e lo fa approvare in base a un insieme semplificato di regole della FIA.
Utilizzerai agents-cli per generare due progetti Agent Development Kit (ADK) standard, quindi scriverai le parti importanti: una skill dell'agente, tre agenti e una valutazione. Tutto il resto (layout del progetto, server, dipendenze, configurazione del deployment) proviene dall'interfaccia a riga di comando.
Non conosci ancora la Formula E?
Non è necessario conoscere il motorsport. Questi cinque termini sono sufficienti:
- Formula E: il campionato di corse completamente elettriche della FIA. La maggior parte delle gare si svolge su circuiti stradali temporanei nei centri urbani.
- Omologazione: l'approvazione ufficiale della FIA che un circuito è sicuro per le gare. Nessuna omologazione, nessuna gara.
- Frenata rigenerativa: quando l'auto frena, i suoi motori ricaricano la batteria. Una frenata più brusca recupera più energia, quindi le regole di questo codelab richiedono almeno una zona di frenata brusca.
- Layer CAD: layer denominati nei disegni di progettazione del circuito, come la traiettoria ideale, la corsia dei box e le barriere. La FIA verifica che siano presenti quelli obbligatori.
- Attack Mode: i piloti ottengono un aumento temporaneo della potenza guidando attraverso una zona di attivazione posizionata fuori dalla traiettoria di gara.
I tuoi agenti giocano su entrambi i fronti: uno progetta il circuito e due lo controllano per la FIA.
Cosa creerai
Le caselle verdi sono gli agenti e quelle tratteggiate sono i loro strumenti, proprio come vengono disegnati nel playground dell'ADK. Due degli strumenti eseguono il wrapping di altri agenti: fia_assessor è l'agente FIA Assessor con la skill di conformità FIA e remote_gatekeeper chiama l'agente Gatekeeper nell'altro progetto tramite A2A.
Agente | Progetto | Job |
|
Lead Architect |
| Legge la sede, chiede all'Assessor, risolve i problemi, chiede l'approvazione al Gatekeeper |
|
FIA Assessor |
| Controlla il layout utilizzando la skill FIA e uno strumento di punteggio |
|
Digital Twin Gatekeeper |
| Esegue l'elenco di controllo di omologazione finale |
|
Cosa imparerai a fare
- In che modo
agents-cli scaffold createstruttura un progetto ADK e quali file devi modificare. - Come pacchettizzare la conoscenza del dominio come skill dell'agente (
SKILL.md,references/,scripts/) e caricarla conSkillToolsetdell'ADK. - Come abbinare
thinking_levelal lavoro di ogni agente. - Come valutare gli agenti con
agents-cli eval run. - Come eseguire il deployment di un agente in Agent Runtime, in che modo l'identità dell'agente differisce da un service account e come chiamare l'agente di cui è stato eseguito il deployment tramite il protocollo A2A.
2. 2. Configura l'ambiente
Prima di iniziare
È necessario un progetto Google Cloud con la fatturazione abilitata. Se stai seguendo questo codelab durante un evento, utilizza l'account e il progetto che ti sono stati assegnati.
Apri Cloud Shell e imposta il progetto
Apri Cloud Shell, quindi esegui:
# 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"
Crea le credenziali per gli agenti
gcloud ha già eseguito l'accesso, ma il codice Python eseguito dagli agenti utilizza le Credenziali predefinite dell'applicazione (ADC), che richiedono un accesso separato:
gcloud auth application-default login
Apri il link stampato, accedi con lo stesso account, copia il codice e incollalo di nuovo in Cloud Shell. Poi imposta il progetto a cui viene addebitata la quota:
gcloud auth application-default set-quota-project "$GOOGLE_CLOUD_PROJECT"
Abilita le 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
A cosa serve ogni API:
API | Utilizzata per |
| Modelli Gemini e Agent Runtime |
| I controlli dei progetti e delle autorizzazioni eseguiti da |
| Crea il service account Compute Engine predefinito utilizzato dal deployment nel passaggio 7 |
| Spazio di archiviazione, log e tracce, come consigliato nella guida alla configurazione di Agent Runtime |
| Build e immagini container, incluse come precauzione per il deployment nel passaggio 7 |
Molti progetti hanno già alcune di queste funzionalità attive. L'abilitazione di un'API già attiva non comporta alcuna modifica.
Installa uv e 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
Questo codelab è stato testato con agents-cli 1.10.0, quindi installa questa versione per ottenere gli stessi file generati.
3. 3. Crea l'impalcatura dei progetti e aggiungi gli asset
Genera entrambi i progetti
agents-cli scaffold create genera un progetto ADK completo e di cui è possibile eseguire il deployment. Eseguilo due volte, una per ogni sistema agente.
Innanzitutto, il pianificatore di percorsi:
cd ~
agents-cli scaffold create track-planner \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
Poi il gatekeeper:
cd ~
agents-cli scaffold create gatekeeper \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
Flag | Significato |
| Inizia dal template ADK Python |
| Genera il server e la configurazione per Agent Runtime |
| Salta la CI/CD; mantieni il progetto al minimo |
| Accetta i valori predefiniti senza chiedere conferma |
Esplora il layout
Il progetto generato ha il seguente aspetto. Modifica solo i file contrassegnati con ✍️:
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`
Per una descrizione di ogni file generato, consulta Struttura del progetto nella guida di Agents CLI.
Prova l'agente generato
Prima di apportare modifiche, esegui l'agente modello per vedere cosa ti offre lo scaffold. Installa le dipendenze e avvia il playground locale sulla porta 8080:
cd ~/track-planner
agents-cli install
agents-cli playground --port 8080
Per aprirla, fai clic sul pulsante Anteprima web nella barra degli strumenti di Cloud Shell (l'icona a forma di occhio in alto a destra), quindi seleziona Anteprima sulla porta 8080.
Nel playground, fai all'agente del template una domanda a cui i suoi strumenti possono rispondere, ad esempio:
What's the weather in San Francisco?
Il riquadro laterale mostra ogni evento, inclusa la chiamata dello strumento get_weather e il relativo risultato. Utilizzerai la stessa visualizzazione in un secondo momento per seguire i tuoi agenti.
Al termine, torna al terminale e premi Ctrl+C per arrestare il playground.
Aggiungi gli asset di Formula E
I dati della sede, le regole della FIA, lo script di fisica, gli strumenti e i set di dati di valutazione non fanno parte della lezione, quindi copiali da GitHub anziché digitarli:
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 è un tag di release fisso, quindi tutti ricevono gli stessi file. $ASSETS è stato impostato nel passaggio 2 e punta alla cartella che hai appena clonato.
Vengono aggiunti i seguenti file:
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
Installa e testa
(cd ~/track-planner && agents-cli install && uv run pytest tests/unit)
(cd ~/gatekeeper && agents-cli install && uv run pytest tests/unit)
agents-cli install esegue uv sync per creare un ambiente virtuale per ogni progetto. Tutti i test delle unità devono essere superati.
4. 4. Scrivi la skill di conformità FIA
Una skill dell'agente raggruppa istruzioni, documenti di riferimento e script in un'unica cartella. SkillToolset di ADK lo carica in tre livelli, in modo che l'agente legga solo ciò di cui ha bisogno:
Livello | File | Quando l'agente lo vede |
1 |
| Sempre (poche decine di token) |
2 |
| Quando chiama |
3 |
| Quando chiama |
La skill si trova in app/skills/ perché il Dockerfile generato copia solo app/ nell'immagine di cui è stato eseguito il deployment.
Guarda i file di livello 3
Hai copiato i file di livello 3 della skill nel passaggio 3:
references/track_regulations.mdcontiene le regole che l'Assessor controlla: limiti di lunghezza e larghezza, quale barriera è necessaria per ogni zona di frenata, i livelli CAD obbligatori (più i livelli medici per i percorsi ospedalieri), il target di rigenerazione e le regole della modalità di attacco.scripts/calculate_regen_zones.pyè un calcolatore. In base alla velocità di ingresso, alla velocità di uscita e alla distanza di frenata di una zona di frenata, calcola l'energia recuperata e la barriera necessaria per la curva, in modo che l'agente non debba mai indovinare la fisica.
Esegui lo script per la curva 10 di Londra, dove le auto frenano da 215 a 55 km/h in 82 metri:
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
L'auto recupera circa 508 kW, superando l'obiettivo di 250 kW. Rallenta a più di 2 G, quindi la curva richiede barriere 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"}
Scrivi SKILL.md
Crea il file che unisce la skill:
cloudshell edit app/skills/fia-compliance-skill/SKILL.md
Aggiungi questi contenuti:
---
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.
La description è ciò che il modello legge per decidere quando utilizzare la skill, quindi indica sia cosa copre la skill sia quando utilizzarla.
Scopri come è strutturata la skill
Apri app/tools.py nell'editor di Cloud Shell:
cloudshell edit app/tools.py
Trova la funzione 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_dirlegge la cartella delle skill:SKILL.md,references/escripts/.SkillToolsetlo trasforma in strumenti che l'agente può chiamare:list_skills,load_skill,load_skill_resourceerun_skill_script.UnsafeLocalCodeExecutorconsente arun_skill_scriptdi eseguire lo script Python su questa macchina. Va bene per un lab; utilizza un esecutore in modalità sandbox in produzione.
Nel passaggio successivo, collegherai questo set di strumenti all'Assessor.
5. 5. Scrivi gli agenti
I modelli Gemini 3 controllano il ragionamento con thinking_level (LOW, MEDIUM o HIGH) anziché con un budget di token. In ADK, lo imposti con types.ThinkingConfig(thinking_level=types.ThinkingLevel.HIGH). Abbinalo al job di ogni agente: un maggiore ragionamento significa una migliore pianificazione, ma anche una latenza e un costo maggiori.
Il Gatekeeper (LOW)
Il Gatekeeper esegue solo un elenco di controllo deterministico, quindi richiede un ragionamento minimo. Sostituisci l'agente del modello:
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",
)
Esegui Gatekeeper in locale
Apri una seconda scheda di Cloud Shell e avvia il server generato da Gatekeeper sulla porta 8001:
cd ~/gatekeeper
APP_URL=http://localhost:8001 uv run uvicorn app.fast_api_app:app --port 8001
Torna alla prima scheda e guarda la scheda agente A2A di Gatekeeper. Ecco come gli altri agenti scoprono cos'è il Gatekeeper e cosa può fare:
curl -s http://localhost:8001/a2a/app/.well-known/agent-card.json | jq .
Dovresti vedere un JSON simile a questo (abbreviato):
{
"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 ..."}
]
}
nameedescriptionprovengono direttamente dalla definizione diAgent(...).skillselenca ciò che l'agente può fare. ADK ha aggiuntoverify_infrastructure_checklistautomaticamente, utilizzando la docstring dello strumento.supportedInterfacesindica ai chiamanti dove inviare le richieste A2A. Ecco perché hai avviato il server conAPP_URL=http://localhost:8001: un chiamante legge prima la scheda, poi invia le sue richieste a qualsiasiurlpubblicizzato dalla scheda.
Niente di tutto questo è stato scritto a mano: il server con scaffolding crea la scheda dal tuo agente. Il pianificatore del percorso leggerà questa carta per trovare e chiamare il Guardiano.
Il valutatore (MEDIUM) e l'architetto principale (HIGH)
Il pianificatore di tracce ha due agenti:
- L'Assessor valuta diverse regole, quindi ottiene
MEDIUM. È racchiuso in unAgentTool, quindi il Lead Architect lo chiama come una funzione e riceve il verdetto. - Il Lead Architect pianifica, corregge e coordina, quindi ottiene
HIGH. Raggiunge il Gatekeeper tramite unRemoteA2aAgent, creato dacreate_remote_gatekeeper_agent()inapp/auth.py, e lo racchiude anche in unAgentTool.
Perché inserire entrambi gli helper come strumenti? Un AgentTool restituisce la risposta al chiamante, in modo che il Lead Architect mantenga il controllo e scriva il progetto finale. Se il Gatekeeper fosse un sub_agent, il Lead Architect gli passerebbe la conversazione e lo stato breve del Gatekeeper diventerebbe la risposta finale.
Apri il file app/agent.py del pianificatore di tracce:
cloudshell edit ~/track-planner/app/agent.py
Copia il seguente codice e sostituisci l'intero contenuto di ~/track-planner/app/agent.py con questo:
"""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",
)
Esegui l'intero sistema nel playground
Assicurati che Gatekeeper sia ancora in esecuzione nella seconda scheda. Nella prima scheda, avvia il playground del track planner:
cd ~/track-planner
agents-cli playground --port 8080
Fai clic su Anteprima web > Anteprima sulla porta 8080, come hai fatto nel passaggio 3.
Chiedi un circuito in un luogo che soddisfi le regole:
Design and homologate a Formula E circuit at Tokyo Bay.
Osserva il riquadro degli eventi mentre gli agenti lavorano. Dovresti vedere, nell'ordine:
get_track_topology: l'architetto principale carica i dati della baia di Tokyo.fia_assessor: l'architetto capo consegna il layout al valutatore, che chiamaload_skill,load_skill_resourceerun_skill_script(una volta per zona di frenata), quindievaluate_track_layout.remote_gatekeeper: il Lead Architect chiama il Gatekeeper tramite A2A. Vedrai la richiesta registrata nella seconda scheda.- Un progetto finale dell'architetto capo, che elenca ogni livello CAD e lo stato APPROVATO del Gatekeeper.
Fai clic su un evento per visualizzarne gli input e gli output esatti.
Ora avvia una nuova sessione e prova un luogo che infrange le regole:
Can the Monaco Harbour layout be homologated? If not, fix it and try again.
Questa volta l'Assessor rifiuta la chicane da 6, 8 m, il Lead Architect ne propone una più ampia e il layout corretto torna all'Assessor prima di raggiungere il Gatekeeper.
Al termine, premi Ctrl+C nella prima scheda per arrestare il playground. Lascia Gatekeeper in esecuzione nella seconda scheda: ti servirà nel passaggio successivo.
6. 6. Valuta gli agenti
agents-cli eval run esegue l'agente su un set di dati, registra ogni turno e chiamata dello strumento e valuta i risultati. Sei tu a decidere cosa misurare in tests/eval/eval_config.yaml.
Esamina il set di dati
Apri il set di dati nell'editor di Cloud Shell:
cd ~/track-planner
cloudshell edit tests/eval/datasets/track_eval.json
Il file contiene un elenco di eval_cases. Ogni caso ha un eval_case_id, un prompt (ciò che l'utente chiede) e un reference (come appare una buona risposta). Il giudice LLM confronta la risposta dell'agente con il riferimento.
| Cosa testa |
| Un luogo che supera tutte le regole e viene approvato |
| La chicane di 6,8 m non rispetta la regola della larghezza |
| Il circuito da 4350 m non rispetta la regola della lunghezza |
| Un layout in cui mancano i layer CAD obbligatori |
| Una zona di frenata al di sotto del target di 250 kW |
| Accesso ospedaliero che richiede layer CAD medici |
| Una zona Attack Mode sulla traiettoria di gara |
| Una conversazione multi-turn: Monaco viene rifiutato, l'utente chiede una correzione e il layout corretto deve essere approvato |
L'ultimo caso utilizza agent_data anziché prompt. Riproduce i turni precedenti di una conversazione, in modo da poter testare il modo in cui l'agente gestisce una richiesta di follow-up, non solo una singola domanda.
track_eval_quick.json nella stessa cartella contiene solo due casi: il caso 1 (una singola domanda) e il caso 8 (una conversazione). Eseguirai quest'ultima perché è più veloce e utilizza meno quota.
Scrivi le metriche
Il set di dati indica cosa chiedere all'agente. eval_config.yaml spiega come valutare le risposte. agents-cli eval run lo legge dopo che l'agente ha risposto a ogni richiesta ed esegue ogni metrica su ogni risposta.
Apri il file generato dallo scaffold:
cloudshell edit tests/eval/eval_config.yaml
Contiene già un giudice LLM generico (custom_response_quality) e una metrica agent_turn_count che conta solo i turni. È un buon inizio per qualsiasi agente, ma non dice nulla sulla Formula E. Manterrai il giudice e aggiungerai una metrica che controlla una regola specifica per questo dominio.
Le valutazioni di buona qualità di solito combinano due tipi di metriche:
Tipo | Come viene calcolato il punteggio | Ideale per | Compromesso |
LLM-as-a-judge | Un modello legge la risposta e il | Qualità sfumate: la risposta è corretta, completa e chiara? | Costo di una chiamata al modello per caso; i punteggi possono variare leggermente tra le esecuzioni |
Metrica del codice | Una piccola funzione Python controlla la risposta | Fatti esatti e verificabili: la risposta includeva qualcosa che deve essere presente? | Controlla solo ciò che puoi esprimere nel codice |
Sostituisci i contenuti del file con:
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"),
}
A cosa serve ogni parte:
metrics_to_runelenca le metriche da eseguire in base al nome. Se rimuovi un nome qui, la metrica viene disattivata senza essere eliminata.custom_response_qualityè il giudice LLM.custom_function_filepunta atests/eval/response_quality.py, generato dallo scaffold. Aprilo se vuoi vedere il prompt di valutazione.fia_cad_layer_complianceè la metrica del codice, scritta in linea incustom_function. Per ogni caso, riceve uninstance(il prompt, laresponsefinale dell'agente e lareference). Per i casi in cui la risposta prevista è un'approvazione, verifica che la risposta indichi tutti e quattro i livelli CAD obbligatori ed elenchi quelli mancanti. Un progetto che ometteF1_TEC3, ad esempio, ottiene un punteggio di 0,75. Gli altri casi ricevono un punteggio di 1,0, perché un rifiuto o una risposta in modalità di attacco non deve elencare ogni livello.
Perché controllare i layer CAD? Un progetto approvato che omette un livello obbligatorio è errato anche se è ben scritto e un giudice LLM può trascurare questo aspetto. Un controllo del codice applica la stessa regola nello stesso modo a ogni esecuzione.
Esegui la valutazione
Mantieni in esecuzione il Gatekeeper locale nella seconda scheda, quindi esegui:
agents-cli eval run \
--dataset tests/eval/datasets/track_eval_quick.json \
--config tests/eval/eval_config.yaml \
--concurrency 1
ls artifacts/grade_results/
La valutazione richiede alcuni minuti. Ogni caso esegue l'intero flusso multi-agente, circa dieci chiamate al modello con il Lead Architect su HIGH, quindi Step 1/2: eval generate è la parte lenta. Non è bloccato.
Al termine, apri il report HTML in artifacts/grade_results/ con l'editor di Cloud Shell. I punteggi fia_cad_layer_compliance bassi indicano che la risposta finale del Lead Architect tralascia dei livelli. Prova a rendere più precise le istruzioni ed esegui nuovamente la valutazione.
7. 7. Esegui il deployment di Gatekeeper in Agent Runtime
Esegui il deployment solo di Gatekeeper. Il pianificatore di tracce continua a essere eseguito in Cloud Shell e lo chiama.
Apri una nuova scheda di Cloud Shell
Il deployment richiede da 5 a 8 minuti, quindi eseguilo in una nuova scheda mentre la valutazione del passaggio 6 viene completata:
- Fai clic su Apri una nuova scheda (+) nella barra degli strumenti di Cloud Shell.
- Una nuova scheda non conserva le variabili del passaggio 2, quindi impostale di nuovo:
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"
Lascia in esecuzione Gatekeeper locale nella seconda scheda: la valutazione lo utilizza ancora e il deployment non richiede l'arresto.
Esegui il deployment
Nella nuova scheda, esegui il deployment di Gatekeeper. Viene eseguito come service account predefinito di Compute Engine del progetto:
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
Il deployment richiede circa 5-8 minuti. Non chiudere la scheda di Cloud Shell durante l'esecuzione. Se il flusso di log si disconnette, controlla l'avanzamento con agents-cli deploy --status. Nell'attesa, torna al passaggio 6 e leggi il report di valutazione.
Ispeziona l'identità dell'agente
agents-cli registra la risorsa di cui è stato eseguito il deployment in 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
La seconda riga dell'output è l'identità con cui viene eseguito Gatekeeper:
Deployment eseguito con | Output di esempio |
Il service account (predefinito) |
|
Agent Identity |
|
Il service account è condiviso da tutti gli elementi del progetto che lo utilizzano. Un'identità agente appartiene a questo singolo agente, quindi puoi concedergli esattamente i ruoli di cui ha bisogno e visualizzare le sue azioni separatamente nei log di controllo.
8. 8. Connettiti al Gatekeeper di cui è stato eseguito il deployment tramite A2A
Agent Runtime gestisce le route A2A generate dal Gatekeeper dietro un percorso /api autenticato.
Assicurati che la valutazione del passaggio 6 sia terminata, quindi interrompi il Gatekeeper locale nella seconda scheda (Ctrl+C). Da questo momento in poi, il pianificatore di tracce chiama quello di cui è stato eseguito il deployment. Nella prima scheda, indirizza il pianificatore di tracce verso:
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
Perché il client aggiorna il token
Apri app/auth.py. I token di accesso di Google Cloud scadono dopo un'ora, quindi un client che imposta un'intestazione Authorization fissa all'avvio inizia a non funzionare con 401 Unauthorized dopo un'ora. GoogleAuthRefresh è una sottoclasse di httpx.Auth e controlla le credenziali su ogni richiesta, aggiornandole quando necessario. create_remote_gatekeeper_agent() lo allega solo per gli URL https://.
Eseguilo end-to-end
Riavvia il playground in modo che rilevi il nuovo GATEKEEPER_A2A_URL:
agents-cli playground --port 8080
Fai clic su Anteprima web > Anteprima sulla porta 8080, avvia una nuova sessione e chiedi:
Assess the Monaco Harbour layout, widen the chicane to 11m, and get Gatekeeper approval.
Gli eventi sono gli stessi del passaggio 5, ma la chiamata remote_gatekeeper ora va al Gatekeeper su Agent Runtime anziché alla seconda scheda.
Visualizza la chiamata in arrivo su Agent Runtime
Dimostra che la richiesta ha effettivamente raggiunto il Gatekeeper di cui è stato eseguito il deployment tramite A2A:
- Nella console Cloud, cerca Agent Platform, quindi apri Deployment nel menu a sinistra.
- Seleziona Gatekeeper.
- Apri la scheda Sessioni.
Verrà visualizzata una nuova sessione il cui ID utente inizia con A2A_USER_. Il server A2A di Gatekeeper lo ha creato quando è stato chiamato dal tuo pianificatore di percorsi. Apri la scheda Tracce nella stessa pagina per visualizzare la chiamata al modello di Gatekeeper e la relativa chiamata allo strumento verify_infrastructure_checklist per la richiesta.
(Facoltativo) Esegui il deployment anche del pianificatore di tracce
Finora il pianificatore di tracce viene eseguito in Cloud Shell, quindi le sue chiamate A2A al Gatekeeper utilizzano le tue credenziali. Esegui il deployment anche del planner ed entrambi gli agenti verranno eseguiti su Agent Runtime, chiamandosi a vicenda con le proprie identità di cui è stato eseguito il deployment.
Premi Ctrl+C per arrestare il playground, quindi esegui il deployment del planner nello stesso modo di 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
Entrambi gli agenti vengono eseguiti con lo stesso service account Compute Engine. Mantieni --service-account: senza questo, il planner viene eseguito come agente di servizio predefinito di Agent Runtime e non può chiamare Gatekeeper (vedi Perché questo service account? nel passaggio 7).
In che modo il planner di cui è stato eseguito il deployment raggiunge il Gatekeeper:
agents-cli deploycopia i valori in.envnel deployment, in modo che il planner riceva ilGATEKEEPER_A2A_URLche hai aggiunto sopra.- All'interno di Agent Runtime,
GoogleAuthRefreshinapp/auth.pyutilizza l'identità di cui è stato eseguito il deployment del planner anziché la tua.
Il deployment richiede circa 5-8 minuti. Al termine, controlla l'identità con cui viene eseguito il planner:
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
Per provare il sistema di cui è stato eseguito il deployment:
- Nella console Cloud, torna ad Agent Platform > Deployment.
- Seleziona track-planner e apri la scheda Playground.
- Digita:
Design and homologate a Formula E circuit at Tokyo Bay. - Attendi il progetto con lo stato APPROVED di Gatekeeper.
- Torna a Deployment, seleziona gatekeeper e apri la scheda Sessioni. La sessione
A2A_USER_più recente proviene dal planner di cui è stato eseguito il deployment, non da Cloud Shell.
Quando esegui la pulizia nel passaggio successivo, elimina anche il planner:
curl -X DELETE -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${PLANNER_ID}?force=true"
9. 9. Risoluzione dei problemi e pulizia
Risoluzione dei problemi
Sintomo | Correggi |
| Accetta i Termini di servizio nella console Cloud, quindi riprova. |
Il progetto è | Esegui di nuovo i comandi del progetto nel Passaggio 2. |
| Esegui |
| Completa il passaggio 4 o copia |
Da | Avvia il Gatekeeper locale (passaggio 5) o imposta |
| Il tuo account non può utilizzare l'identità dell'agente. Segui le istruzioni nel riquadro di pulizia nel passaggio 7, quindi utilizza il deployment del service account. |
Il pianificatore di tracce di cui è stato eseguito il deployment segnala | L'identità del planner non è autorizzata a chiamare il Gatekeeper. Rifai il deployment con |
| Hai raggiunto la quota di Gemini. Attendi un minuto o aggiungi |
| Arresta l'altro server o scegli un altro |
Esegui la pulizia
Elimina il Gatekeeper di cui hai eseguito il deployment in modo che non continui a essere eseguito:
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"
Se hai creato un progetto solo per questo codelab, puoi eliminare l'intero progetto. Se partecipi a un evento, conserva il progetto che ti è stato assegnato finché gli organizzatori non ti dicono diversamente.
Che cosa hai imparato
agents-cli scaffold createti offre un progetto ADK standard di cui è possibile eseguire il deployment; devi solo scrivere agenti, skill e valutazioni.- Le competenze dell'agente mantengono la conoscenza del dominio fuori dai prompt finché l'agente non ne ha bisogno.
thinking_levelti consente di scambiare la profondità di ragionamento con la velocità per agente.agents-cli eval runtrasforma la domanda "Funziona?" in punteggi che puoi monitorare.- L'identità dell'agente e l'A2A consentono agli agenti di cui è stato eseguito il deployment in modo indipendente di collaborare in sicurezza.