1. 1. Présentation
Dans cet atelier de programmation, vous allez créer un système multi-agent qui conçoit un circuit urbain de Formule E et le fait approuver par rapport à un ensemble simplifié de règles de la FIA.
Vous allez utiliser agents-cli pour générer deux projets Agent Development Kit (ADK) standards, puis écrire les parties importantes : une compétence d'agent, trois agents et une évaluation. Tout le reste (mise en page du projet, serveur, dépendances, configuration du déploiement) provient de la CLI.
Vous découvrez la Formule E ?
Vous n'avez pas besoin de vous y connaître en sport automobile. Ces cinq termes suffisent :
- Formule E : le championnat de course automobile 100 % électrique de la FIA. La plupart des courses se déroulent sur des circuits urbains temporaires dans les centres-villes.
- Homologation : approbation officielle de la FIA attestant qu'un circuit est sûr pour la course. Pas d'homologation, pas de course.
- Freinage régénératif : lorsque la voiture freine, ses moteurs rechargent la batterie. Un freinage plus brusque permet de récupérer plus d'énergie. Les règles de cet atelier de programmation exigent donc au moins une zone de freinage brusque.
- Calques CAO : calques nommés dans les dessins de conception du circuit, tels que la trajectoire idéale, la voie des stands et les barrières. La FIA vérifie que les éléments obligatoires sont présents.
- Mode Attaque : les pilotes bénéficient d'un boost de puissance temporaire en traversant une zone d'activation située en dehors de la trajectoire de course.
Vos agents jouent sur les deux tableaux : l'un conçoit le circuit, et deux autres le vérifient pour la FIA.
Objectifs de l'atelier
Les cases vertes représentent les agents et les cases en pointillés leurs outils, de la même manière que le playground ADK les dessine. Deux des outils encapsulent d'autres agents : fia_assessor est l'agent FIA Assessor doté de la compétence de conformité FIA, et remote_gatekeeper appelle l'agent Gatekeeper dans l'autre projet via A2A.
Agent | Projet | Job |
|
Architecte principal |
| Lit le lieu, demande à l'évaluateur, résout les problèmes, demande l'approbation du contrôleur d'accès |
|
Évaluateur FIA |
| Vérifie la mise en page à l'aide de la compétence FIA et d'un outil de notation |
|
Gatekeeper de jumeau numérique |
| Exécute la checklist d'homologation finale |
|
Objectifs de l'atelier
- Comment
agents-cli scaffold createorganise un projet ADK et quels fichiers vous modifiez. - Comment empaqueter des connaissances du domaine en tant que compétence d'agent (
SKILL.md,references/,scripts/) et la charger avecSkillToolsetd'ADK. - Comment faire correspondre
thinking_levelau travail de chaque agent. - Évaluer des agents avec
agents-cli eval run - Comment déployer un agent sur Agent Runtime, en quoi l'identité de l'agent diffère d'un compte de service et comment appeler l'agent déployé via le protocole A2A.
2. 2. Configurer votre environnement
Avant de commencer
Vous devez disposer d'un projet Google Cloud pour lequel la facturation est activée. Si vous suivez cet atelier de programmation lors d'un événement, utilisez le compte et le projet qui vous ont été fournis.
Ouvrir Cloud Shell et définir votre projet
Ouvrez Cloud Shell, puis exécutez la commande suivante :
# 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"
Créer des identifiants pour vos agents
gcloud est déjà connecté, mais le code Python exécuté par vos agents utilise les identifiants par défaut de l'application (ADC), qui nécessitent une connexion distincte :
gcloud auth application-default login
Ouvrez le lien qui s'affiche, connectez-vous avec le même compte, copiez le code et collez-le dans Cloud Shell. Ensuite, définissez le projet auquel le quota est facturé :
gcloud auth application-default set-quota-project "$GOOGLE_CLOUD_PROJECT"
Activer les 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
À quoi sert chaque API :
API | Utilisation |
| Modèles Gemini et Agent Runtime |
| Vérifications des projets et des autorisations exécutées par |
| Crée le compte de service Compute Engine par défaut utilisé par le déploiement à l'étape 7. |
| Stockage, journaux et traces, comme recommandé dans le guide de configuration d'Agent Runtime |
| Builds et images de conteneurs, inclus par précaution pour le déploiement à l'étape 7 |
De nombreux projets ont déjà activé certaines de ces fonctionnalités. L'activation d'une API déjà activée ne change rien.
Installer uv et 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
Cet atelier de programmation a été testé avec agents-cli 1.10.0. Installez donc cette version pour obtenir les mêmes fichiers générés.
3. 3. Créer les projets et ajouter les assets
Générer les deux projets
agents-cli scaffold create génère un projet ADK complet et déployable. Exécutez-la deux fois, une fois pour chaque système d'agent.
Tout d'abord, le planificateur de parcours :
cd ~
agents-cli scaffold create track-planner \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
Ensuite, le gardien :
cd ~
agents-cli scaffold create gatekeeper \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
Option | Signification |
| Commencer à partir du modèle ADK Python |
| Générer le serveur et la configuration pour Agent Runtime |
| Ignorer l'intégration/le déploiement continus ; conserver un projet minimal |
| Accepter les valeurs par défaut sans demander confirmation |
Explorer la mise en page
Le projet généré se présente comme suit. Vous ne modifiez que les fichiers marqués d'un ✍️ :
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`
Pour obtenir une description de chaque fichier généré, consultez Structure du projet dans le guide de la CLI Agents.
Essayer l'agent généré
Avant de modifier quoi que ce soit, exécutez l'agent du modèle pour voir ce que l'échafaudage vous donne. Installez les dépendances et démarrez l'environnement de test local sur le port 8080 :
cd ~/track-planner
agents-cli install
agents-cli playground --port 8080
Pour l'ouvrir, cliquez sur le bouton Aperçu sur le Web dans la barre d'outils Cloud Shell (l'icône en forme d'œil en haut à droite), puis sélectionnez Prévisualiser sur le port 8080.
Dans le playground, posez à l'agent modèle une question à laquelle ses outils peuvent répondre, par exemple :
What's the weather in San Francisco?
Le panneau latéral affiche chaque événement, y compris l'appel de l'outil get_weather et son résultat. Vous utiliserez la même vue plus tard pour suivre vos propres agents.
Lorsque vous avez terminé, revenez au terminal et appuyez sur Ctrl+C pour arrêter le playground.
Ajouter les assets Formula E
Les données sur le circuit, les règles de la FIA, le script physique, les outils et les ensembles de données d'évaluation ne font pas partie de la leçon. Vous les copiez donc depuis GitHub au lieu de les saisir :
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 est un tag de version fixe, de sorte que tout le monde reçoit les mêmes fichiers. $ASSETS a été défini à l'étape 2 et pointe vers le dossier que vous venez de cloner.
Cela ajoute les fichiers suivants :
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
Installer et tester
(cd ~/track-planner && agents-cli install && uv run pytest tests/unit)
(cd ~/gatekeeper && agents-cli install && uv run pytest tests/unit)
agents-cli install exécute uv sync pour créer un environnement virtuel pour chaque projet. Tous les tests unitaires doivent réussir.
4. 4. Rédiger la compétence de conformité FIA
Une compétence agentique regroupe des instructions, des documents de référence et des scripts dans un seul dossier. SkillToolset d'ADK le charge à trois niveaux, de sorte que l'agent ne lit que ce dont il a besoin :
Niveau | Fichier | Quand l'agent le voit |
1 |
| Toujours (quelques dizaines de jetons) |
2 |
| Lorsqu'il appelle |
3 |
| Lorsqu'il appelle |
La compétence se trouve dans app/skills/, car le Dockerfile généré ne copie que app/ dans l'image déployée.
Consulter les fichiers du niveau 3
Vous avez copié les fichiers de niveau 3 de la compétence à l'étape 3 :
references/track_regulations.mdcontient les règles que l'Assesseur vérifie : les limites de longueur et de largeur, la barrière dont chaque zone de freinage a besoin, les couches CAO obligatoires (ainsi que les couches médicales pour les itinéraires vers les hôpitaux), l'objectif de régénération et les règles du mode Attaque.scripts/calculate_regen_zones.pyest une calculatrice. À partir de la vitesse d'entrée, de la vitesse de sortie et de la distance de freinage d'une zone de freinage, il calcule l'énergie récupérée et la barrière nécessaire pour le virage. L'agent n'a donc jamais à deviner les lois de la physique.
Exécutez le script pour le virage 10 de Londres, où les voitures freinent de 215 à 55 km/h sur 82 mètres :
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
La voiture récupère environ 508 kW ici, ce qui est supérieur à l'objectif de 250 kW. Il ralentit à plus de 2G, de sorte que le virage nécessite des barrières 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"}
Écrire SKILL.md
Créez le fichier qui associe la compétence :
cloudshell edit app/skills/fia-compliance-skill/SKILL.md
Ajoutez le contenu suivant :
---
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.
Le description est ce que le modèle lit pour décider quand utiliser la compétence. Il indique donc à la fois ce que la compétence couvre et quand l'utiliser.
Découvrez comment la compétence est connectée
Ouvrez app/tools.py dans l'éditeur Cloud Shell :
cloudshell edit app/tools.py
Recherchez la fonction 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_dirlit le dossier de la compétence :SKILL.md,references/etscripts/.SkillToolsetles transforme en outils que l'agent peut appeler :list_skills,load_skill,load_skill_resourceetrun_skill_script.UnsafeLocalCodeExecutorpermet àrun_skill_scriptd'exécuter le script Python sur cette machine. Cela convient pour un atelier, mais utilisez un exécuteur en bac à sable en production.
Vous associerez cet ensemble d'outils à l'évaluateur à l'étape suivante.
5. 5. Écrire les agents
Les modèles Gemini 3 contrôlent le raisonnement avec thinking_level (LOW, MEDIUM ou HIGH) au lieu d'un budget de jetons. Dans ADK, vous le définissez avec types.ThinkingConfig(thinking_level=types.ThinkingLevel.HIGH). Adaptez-le à la tâche de chaque agent : plus la réflexion est poussée, plus la planification est efficace, mais plus la latence et les coûts sont élevés.
Le Gatekeeper (LOW)
Le Gatekeeper n'exécute qu'une checklist déterministe. Il n'a donc pas besoin de beaucoup de raisonnement. Remplacez l'agent de modèle :
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",
)
Exécuter Gatekeeper localement
Ouvrez un deuxième onglet Cloud Shell et démarrez le serveur généré par Gatekeeper sur le port 8001 :
cd ~/gatekeeper
APP_URL=http://localhost:8001 uv run uvicorn app.fast_api_app:app --port 8001
Revenez au premier onglet et examinez la fiche d'agent A2A de Gatekeeper. Voici comment les autres agents découvrent ce qu'est le Gatekeeper et ce qu'il peut faire :
curl -s http://localhost:8001/a2a/app/.well-known/agent-card.json | jq .
Vous devriez voir un fichier JSON semblable à celui-ci (raccourci) :
{
"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 ..."}
]
}
nameetdescriptionproviennent directement de votre définitionAgent(...).skillsliste ce que l'agent peut faire. ADK a ajoutéverify_infrastructure_checklistautomatiquement, en utilisant la docstring de l'outil.supportedInterfacesindique aux appelants où envoyer les requêtes A2A. C'est pourquoi vous avez démarré le serveur avecAPP_URL=http://localhost:8001: un appelant lit d'abord la carte, puis envoie ses requêtes à l'urlannoncé par la carte.
Rien n'a été écrit à la main : le serveur échafaudé crée la fiche à partir de votre agent. Le planificateur de parcours lira cette carte pour trouver et appeler le Gatekeeper.
L'évaluateur (MEDIUM) et l'architecte principal (HIGH)
Le planificateur de parcours comporte deux agents :
- L'évaluateur pondère plusieurs règles, il obtient donc
MEDIUM. Il est encapsulé dans unAgentTool. L'architecte principal l'appelle donc comme une fonction et obtient le verdict. - L'architecte en chef planifie, corrige et coordonne, de sorte qu'il obtient
HIGH. Elle atteint Gatekeeper via unRemoteA2aAgent, créé parcreate_remote_gatekeeper_agent()dansapp/auth.py, et l'encapsule également dans unAgentTool.
Pourquoi encapsuler les deux assistants en tant qu'outils ? Un AgentTool renvoie sa réponse à l'appelant. L'architecte principal reste donc aux commandes et rédige le plan final. Si le Gatekeeper était un sub_agent, le Lead Architect lui transmettrait la conversation, et l'état court du Gatekeeper deviendrait la réponse finale.
Ouvrez le fichier app/agent.py du planificateur de parcours :
cloudshell edit ~/track-planner/app/agent.py
Copiez le code suivant et remplacez l'intégralité du contenu de ~/track-planner/app/agent.py par celui-ci :
"""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",
)
Exécuter l'ensemble du système dans le playground
Assurez-vous que Gatekeeper est toujours en cours d'exécution dans votre deuxième onglet. Dans le premier onglet, démarrez le playground du planificateur de parcours :
cd ~/track-planner
agents-cli playground --port 8080
Cliquez sur Aperçu sur le Web > Prévisualiser sur le port 8080, comme vous l'avez fait à l'étape 3.
Demandez un circuit dans un lieu qui respecte les règles :
Design and homologate a Formula E circuit at Tokyo Bay.
Observez le panneau des événements pendant que les agents travaillent. Vous devriez voir, dans l'ordre :
get_track_topology: l'architecte principal charge les données de la baie de Tokyo.fia_assessor: l'architecte principal transmet la mise en page à l'évaluateur, qui appelleload_skill,load_skill_resourceetrun_skill_script(une fois par zone de freinage), puisevaluate_track_layout.remote_gatekeeper: l'architecte principal appelle le Gatekeeper via A2A. La requête est enregistrée dans le deuxième onglet.- Un plan final de l'architecte principal, listant chaque calque CAO et l'état APPROUVÉ du Gatekeeper.
Cliquez sur un événement pour afficher ses entrées et sorties exactes.
Démarrez maintenant une nouvelle session et essayez un lieu qui ne respecte pas les règles :
Can the Monaco Harbour layout be homologated? If not, fix it and try again.
Cette fois, l'évaluateur rejette la chicane de 6,8 m, l'architecte principal en propose une plus large, et la disposition fixe est renvoyée à l'évaluateur avant d'atteindre le responsable de la validation.
Lorsque vous avez terminé, appuyez sur Ctrl+C dans le premier onglet pour arrêter le playground. Laissez Gatekeeper s'exécuter dans le deuxième onglet : vous en aurez besoin à l'étape suivante.
6. 6. Évaluer les agents
agents-cli eval run exécute votre agent sur un ensemble de données, enregistre chaque tour et chaque appel d'outil, et note les résultats. Vous décidez ce que vous souhaitez mesurer dans tests/eval/eval_config.yaml.
Examiner l'ensemble de données
Ouvrez l'ensemble de données dans l'éditeur Cloud Shell :
cd ~/track-planner
cloudshell edit tests/eval/datasets/track_eval.json
Le fichier contient une liste de eval_cases. Chaque cas comporte un eval_case_id, un prompt (ce que l'utilisateur demande) et un reference (ce à quoi ressemble une bonne réponse). Le juge LLM compare la réponse de l'agent à la référence.
| Ce qu'il teste |
| Un établissement qui respecte toutes les règles et qui est approuvé |
| La chicane de 6,8 m ne respecte pas la règle de largeur |
| Le circuit de 4 350 m ne respecte pas la règle de longueur |
| Une mise en page sans les calques CAO obligatoires |
| Une zone de freinage en dessous de l'objectif de 250 kW |
| Accès à l'hôpital nécessitant des calques de CAO médicale |
| Une zone Attack Mode sur la trajectoire de course |
| Une conversation multitour : Monaco est rejeté, l'utilisateur demande une correction et la mise en page corrigée doit être approuvée. |
Le dernier cas utilise agent_data au lieu de prompt. Il rejoue les tours précédents d'une conversation, ce qui vous permet de tester la façon dont l'agent gère une demande de suivi, et pas seulement une seule question.
track_eval_quick.json dans le même dossier ne contient que deux cas : le cas 1 (une seule question) et le cas 8 (une conversation). Vous allez exécuter celui-ci, car il est plus rapide et utilise moins de quota.
Écrire les métriques
L'ensemble de données indique quoi demander à l'agent. eval_config.yaml indique comment noter les réponses. agents-cli eval run le lit une fois que l'agent a répondu à chaque cas, puis exécute chaque métrique sur chaque réponse.
Ouvrez le fichier généré par le scaffold :
cloudshell edit tests/eval/eval_config.yaml
Il contient déjà un juge LLM générique (custom_response_quality) et une métrique agent_turn_count qui ne compte que les tours. C'est un bon début pour n'importe quel agent, mais cela ne dit rien sur la Formule E. Vous allez conserver le juge et ajouter une métrique qui vérifie une règle spécifique à ce domaine.
Les bonnes évaluations combinent généralement deux types de métriques :
Type | Comment il est évalué | Utilisation | Compromis |
LLM-as-a-judge | Un modèle lit la réponse et le | Qualités floues : la réponse est-elle correcte, complète et claire ? | Coûte un appel de modèle par cas ; les scores peuvent varier légèrement d'une exécution à l'autre |
Métrique de code | Une petite fonction Python vérifie la réponse. | Faits exacts et vérifiables : la réponse inclut-elle un élément qui doit s'y trouver ? | Ne vérifie que ce que vous pouvez exprimer dans le code |
Remplacez le contenu du fichier par ce qui suit :
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"),
}
Fonction de chaque partie :
metrics_to_runliste les métriques à exécuter, par nom. Si vous supprimez un nom ici, la métrique correspondante sera désactivée, mais pas supprimée.custom_response_qualityest le juge LLM.custom_function_filepointe verstests/eval/response_quality.py, qui a été généré par l'échafaudage. Ouvrez-le si vous souhaitez voir la requête d'évaluation.fia_cad_layer_complianceest votre métrique de code, écrite de manière intégrée souscustom_function. Pour chaque cas, il reçoit uninstance(la requête, laresponsefinale de l'agent et lareference). Pour les cas où la réponse attendue est une approbation, il vérifie que la réponse nomme les quatre couches de CAO obligatoires et liste celles qui sont manquantes. Un plan qui ometF1_TEC3, par exemple, obtient un score de 0,75. Les autres cas obtiennent un score de 1,0, car un refus ou une réponse en mode Attaque n'a pas besoin de lister chaque couche.
Pourquoi vérifier les calques CAO ? Un plan approuvé qui omet une couche obligatoire est incorrect, même s'il est bien rédigé, et un juge LLM peut passer à côté de ce problème. Une vérification de code applique la même règle de la même manière à chaque exécution.
Exécuter l'évaluation
Laissez le Gatekeeper local s'exécuter dans votre deuxième onglet, puis exécutez la commande suivante :
agents-cli eval run \
--dataset tests/eval/datasets/track_eval_quick.json \
--config tests/eval/eval_config.yaml \
--concurrency 1
ls artifacts/grade_results/
L'évaluation prend quelques minutes. Chaque cas exécute l'intégralité du flux multi-agent, soit environ dix appels de modèle avec l'architecte principal sur la réflexion HIGH. Step 1/2: eval generate est donc la partie lente. Il n'est pas bloqué.
Une fois l'opération terminée, ouvrez le rapport HTML dans artifacts/grade_results/ avec l'éditeur Cloud Shell. Des scores fia_cad_layer_compliance faibles indiquent que la réponse finale de l'architecte principal omet des couches. Essayez de resserrer ses instructions et de relancer l'évaluation.
7. 7. Déployer le Gatekeeper sur Agent Runtime
Vous ne déployez que Gatekeeper. Le planificateur de pistes continue de s'exécuter dans Cloud Shell et l'appelle.
Ouvrir un nouvel onglet Cloud Shell
Le déploiement prend cinq à huit minutes. Effectuez-le donc dans un nouvel onglet pendant que l'évaluation de l'étape 6 se termine :
- Cliquez sur Ouvrir un nouvel onglet (+) dans la barre d'outils Cloud Shell.
- Un nouvel onglet ne conserve pas les variables de l'étape 2. Définissez-les à nouveau :
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"
Laissez le Gatekeeper local s'exécuter dans votre deuxième onglet : l'évaluation l'utilise toujours, et le déploiement n'a pas besoin qu'il soit arrêté.
Déployer
Dans le nouvel onglet, déployez Gatekeeper. Il s'exécute en tant que compte de service Compute Engine par défaut du projet :
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
Le déploiement prend environ cinq à huit minutes. Ne fermez pas l'onglet Cloud Shell pendant l'exécution. Si le flux de journaux se déconnecte, vérifiez la progression avec agents-cli deploy --status. En attendant, revenez à l'étape 6 et lisez votre rapport d'évaluation.
Inspecter l'identité de l'agent
agents-cli enregistre la ressource déployée dans 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 deuxième ligne de sortie correspond à l'identité sous laquelle Gatekeeper s'exécute :
Déploiement réalisé avec | Exemple de résultat : |
Le compte de service (par défaut) |
|
Identité de l'agent |
|
Le compte de service est partagé par tous les éléments du projet qui l'utilisent. Une identité d'agent appartient à cet agent. Vous pouvez donc lui attribuer exactement les rôles dont il a besoin et voir ses actions séparément dans les journaux d'audit.
8. 8. Se connecter au Gatekeeper déployé via A2A
Agent Runtime diffuse les routes A2A générées par Gatekeeper derrière un chemin d'accès /api authentifié.
Assurez-vous que l'évaluation de l'étape 6 est terminée, puis arrêtez le Gatekeeper local dans votre deuxième onglet (Ctrl+C). Désormais, le planificateur de parcours appelle le modèle déployé. Dans votre premier onglet, pointez le planificateur de parcours vers celui-ci :
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
Pourquoi le client actualise son jeton
Ouvrez app/auth.py. Les jetons d'accès Google Cloud expirent au bout d'une heure. Par conséquent, un client qui définit un en-tête Authorization fixe au démarrage commence à échouer avec l'erreur 401 Unauthorized au bout d'une heure. GoogleAuthRefresh est une sous-classe de httpx.Auth. Elle vérifie les identifiants à chaque requête et les actualise si nécessaire. create_remote_gatekeeper_agent() ne l'associe qu'aux URL https://.
Exécuter le pipeline de bout en bout
Redémarrez le playground pour qu'il prenne en compte le nouveau GATEKEEPER_A2A_URL :
agents-cli playground --port 8080
Cliquez sur Aperçu sur le Web > Prévisualiser sur le port 8080, démarrez une nouvelle session et posez la question suivante :
Assess the Monaco Harbour layout, widen the chicane to 11m, and get Gatekeeper approval.
Les événements sont identiques à ceux de l'étape 5, mais l'appel remote_gatekeeper est désormais envoyé au Gatekeeper sur Agent Runtime au lieu de votre deuxième onglet.
Voir l'appel arriver sur Agent Runtime
Prouvez que la requête a bien atteint le Gatekeeper déployé via A2A :
- Dans la console Cloud, recherchez Agent Platform, puis ouvrez Déploiements dans le menu de gauche.
- Sélectionnez gatekeeper.
- Ouvrez l'onglet Sessions.
Une nouvelle session s'affiche, dont l'ID utilisateur commence par A2A_USER_. Le serveur A2A de Gatekeeper l'a créé lorsque votre planificateur de parcours l'a appelé. Ouvrez l'onglet Traces sur la même page pour afficher l'appel de modèle de Gatekeeper et son appel d'outil verify_infrastructure_checklist pour cette requête.
Facultatif : déployez également le planificateur de parcours
Pour l'instant, le planificateur de parcours s'exécute dans Cloud Shell. Ses appels A2A au Gatekeeper utilisent donc vos identifiants. Déployez également le planificateur. Les deux agents s'exécutent sur Agent Runtime et s'appellent mutuellement avec leurs propres identités déployées.
Appuyez sur Ctrl+C pour arrêter le playground, puis déployez le planificateur de la même manière que le 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
Les deux agents s'exécutent en tant que même compte de service Compute Engine. Conservez --service-account : sans cela, le planificateur s'exécute en tant qu'agent de service par défaut d'Agent Runtime et ne peut pas appeler le Gatekeeper (voir Pourquoi ce compte de service ? à l'étape 7).
Comment le planificateur déployé atteint le Gatekeeper :
agents-cli deploycopie les valeurs de.envdans le déploiement, de sorte que le planificateur obtienne leGATEKEEPER_A2A_URLque vous avez ajouté ci-dessus.- Dans Agent Runtime,
GoogleAuthRefreshdansapp/auth.pyrécupère l'identité déployée du planificateur au lieu de la vôtre.
Le déploiement prend environ cinq à huit minutes. Une fois l'opération terminée, vérifiez l'identité sous laquelle le planificateur s'exécute :
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
Pour tester le système déployé :
- Dans la console Cloud, revenez à Agent Platform > Déploiements.
- Sélectionnez track-planner et ouvrez l'onglet Playground.
- Saisissez cette commande :
Design and homologate a Formula E circuit at Tokyo Bay. - Attendez que le plan passe à l'état APPROUVÉ par le validateur.
- Revenez à Déploiements, sélectionnez gatekeeper, puis ouvrez l'onglet Sessions. La session
A2A_USER_la plus récente provient du planificateur déployé, et non de Cloud Shell.
Lorsque vous effectuerez le nettoyage à l'étape suivante, supprimez également le planificateur :
curl -X DELETE -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${PLANNER_ID}?force=true"
9. 9. Dépannage et nettoyage
Dépannage
Problème constaté | Solution |
| Acceptez les conditions d'utilisation dans la console Cloud, puis réessayez. |
Le projet est | Réexécutez les commandes du projet de l'étape 2. |
| Exécutez |
| Effectuez l'étape 4 ou copiez |
De | Démarrez le Gatekeeper local (étape 5) ou définissez |
| Votre compte ne peut pas utiliser l'identité de l'agent. Suivez les instructions de l'encadré "Nettoyage" à l'étape 7, puis utilisez le compte de service "deploy". |
Le planificateur de suivi déployé signale | L'identité du planificateur n'est pas autorisée à appeler le Gatekeeper. Redéployez-le avec |
| Vous avez atteint le quota Gemini. Attendez une minute ou ajoutez |
| Arrêtez l'autre serveur ou choisissez un autre |
Effectuer un nettoyage
Supprimez le Gatekeeper déployé pour qu'il ne continue pas à s'exécuter :
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"
Si vous avez créé un projet spécifiquement pour cet atelier de programmation, vous pouvez le supprimer entièrement. Si vous participez à un événement, conservez le projet qui vous a été attribué jusqu'à ce que les organisateurs vous indiquent le contraire.
Ce que vous avez appris
agents-cli scaffold createvous fournit un projet ADK standard et déployable. Vous n'avez qu'à écrire des agents, des compétences et des évaluations.- Les compétences d'agent permettent de ne pas inclure les connaissances du domaine dans les prompts tant que l'agent n'en a pas besoin.
thinking_levelvous permet de privilégier la vitesse plutôt que la profondeur de raisonnement pour chaque agent.agents-cli eval runtransforme la question "Est-ce que ça fonctionne ?" en scores que vous pouvez suivre.- L'identité d'agent et l'A2A permettent aux agents déployés indépendamment de travailler ensemble de manière sécurisée.