Crea un pianificatore di tracciati di Formula E multiagente con ADK e A2A

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

Architettura: nel progetto track-planner, in esecuzione in Cloud Shell, l'agente track_planner utilizza get_track_topology, fia_assessor e remote_gatekeeper. remote_gatekeeper chiama l'agente gatekeeper tramite A2A. Nel progetto gatekeeper, in esecuzione su Agent Runtime, l'agente gatekeeper utilizza verify_infrastructure_checklist.

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

thinking_level

Lead Architect

track-planner

Legge la sede, chiede all'Assessor, risolve i problemi, chiede l'approvazione al Gatekeeper

HIGH

FIA Assessor

track-planner

Controlla il layout utilizzando la skill FIA e uno strumento di punteggio

MEDIUM

Digital Twin Gatekeeper

gatekeeper

Esegue l'elenco di controllo di omologazione finale

LOW

Cosa imparerai a fare

  • In che modo agents-cli scaffold create struttura un progetto ADK e quali file devi modificare.
  • Come pacchettizzare la conoscenza del dominio come skill dell'agente (SKILL.md, references/, scripts/) e caricarla con SkillToolset dell'ADK.
  • Come abbinare thinking_level al 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

aiplatform

Modelli Gemini e Agent Runtime

cloudresourcemanager, serviceusage e iam

I controlli dei progetti e delle autorizzazioni eseguiti da gcloud e agents-cli deploy

compute

Crea il service account Compute Engine predefinito utilizzato dal deployment nel passaggio 7

storage, logging e cloudtrace

Spazio di archiviazione, log e tracce, come consigliato nella guida alla configurazione di Agent Runtime

cloudbuild, artifactregistry

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

--agent adk

Inizia dal template ADK Python

--deployment-target agent_runtime

Genera il server e la configurazione per Agent Runtime

--prototype

Salta la CI/CD; mantieni il progetto al minimo

--yes

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

SKILL.md front matter (name, description)

Sempre (poche decine di token)

2

SKILL.md corpo

Quando chiama load_skill

3

references/, scripts/

Quando chiama load_skill_resource o run_skill_script

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.md contiene 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_dir legge la cartella delle skill: SKILL.md, references/ e scripts/.
  • SkillToolset lo trasforma in strumenti che l'agente può chiamare: list_skills, load_skill, load_skill_resource e run_skill_script.
  • UnsafeLocalCodeExecutor consente a run_skill_script di 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 ..."}
  ]
}
  • name e description provengono direttamente dalla definizione di Agent(...).
  • skills elenca ciò che l'agente può fare. ADK ha aggiunto verify_infrastructure_checklist automaticamente, utilizzando la docstring dello strumento.
  • supportedInterfaces indica ai chiamanti dove inviare le richieste A2A. Ecco perché hai avviato il server con APP_URL=http://localhost:8001: un chiamante legge prima la scheda, poi invia le sue richieste a qualsiasi url pubblicizzato 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 un AgentTool, 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 un RemoteA2aAgent, creato da create_remote_gatekeeper_agent() in app/auth.py, e lo racchiude anche in un AgentTool.

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:

  1. get_track_topology: l'architetto principale carica i dati della baia di Tokyo.
  2. fia_assessor: l'architetto capo consegna il layout al valutatore, che chiama load_skill, load_skill_resource e run_skill_script (una volta per zona di frenata), quindi evaluate_track_layout.
  3. remote_gatekeeper: il Lead Architect chiama il Gatekeeper tramite A2A. Vedrai la richiesta registrata nella seconda scheda.
  4. 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.

eval_case_id

Cosa testa

fe_001_tokyo_compliant

Un luogo che supera tutte le regole e viene approvato

fe_002_monaco_narrow

La chicane di 6,8 m non rispetta la regola della larghezza

fe_003_berlin_too_long

Il circuito da 4350 m non rispetta la regola della lunghezza

fe_004_missing_layers

Un layout in cui mancano i layer CAD obbligatori

fe_005_low_regen

Una zona di frenata al di sotto del target di 250 kW

fe_006_sao_paulo_medical

Accesso ospedaliero che richiede layer CAD medici

fe_007_attack_mode

Una zona Attack Mode sulla traiettoria di gara

fe_008_multiturn_remediation

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 reference della richiesta, quindi assegna un punteggio da 1 a 5 con una spiegazione

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_run elenca 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_file punta a tests/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 in custom_function. Per ogni caso, riceve un instance (il prompt, la response finale dell'agente e la reference). 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 omette F1_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:

  1. Fai clic su Apri una nuova scheda (+) nella barra degli strumenti di Cloud Shell.
  2. 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)

123456789012-compute@developer.gserviceaccount.com

Agent Identity

agents.global.org-.system.id.goog/resources/aiplatform/projects//locations/us-central1/reasoningEngines/

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:

  1. Nella console Cloud, cerca Agent Platform, quindi apri Deployment nel menu a sinistra.
  2. Seleziona Gatekeeper.
  3. 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 deploy copia i valori in .env nel deployment, in modo che il planner riceva il GATEKEEPER_A2A_URL che hai aggiunto sopra.
  • All'interno di Agent Runtime, GoogleAuthRefresh in app/auth.py utilizza 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:

  1. Nella console Cloud, torna ad Agent Platform > Deployment.
  2. Seleziona track-planner e apri la scheda Playground.
  3. Digita:
    Design and homologate a Formula E circuit at Tokyo Bay.
    
  4. Attendi il progetto con lo stato APPROVED di Gatekeeper.
  5. 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

UREQ_TOS_NOT_ACCEPTED

Accetta i Termini di servizio nella console Cloud, quindi riprova.

Il progetto è (unset)

Esegui di nuovo i comandi del progetto nel Passaggio 2.

service account info is missing 'email' field

Esegui gcloud auth application-default login (passaggio 2), quindi riavvia tutti i server in esecuzione.

FileNotFoundError per SKILL.md

Completa il passaggio 4 o copia $ASSETS/solution/track-planner/. in ~/track-planner/.

Da Connection refused a localhost:8001

Avvia il Gatekeeper locale (passaggio 5) o imposta GATEKEEPER_A2A_URL su quello di cui è stato eseguito il deployment (passaggio 8).

Permission 'resourcemanager.projects.setIamPolicy' denied al deployment

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 403 Forbidden da Gatekeeper

L'identità del planner non è autorizzata a chiamare il Gatekeeper. Rifai il deployment con --service-account come nel passaggio 7 o con --agent-identity se sei il proprietario del progetto.

429 RESOURCE_EXHAUSTED

Hai raggiunto la quota di Gemini. Attendi un minuto o aggiungi --concurrency 1 --qps 2 a agents-cli eval run.

Address already in use

Arresta l'altro server o scegli un altro --port.

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 create ti 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_level ti consente di scambiare la profondità di ragionamento con la velocità per agente.
  • agents-cli eval run trasforma 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.

Scopri di più