1. 1. Descripción general
En este codelab, crearás un sistema multiagente que diseña un circuito urbano de Fórmula E y obtiene su aprobación en función de un conjunto simplificado de reglas de la FIA.
Usarás agents-cli para generar dos proyectos estándar del Kit de desarrollo de agentes (ADK) y, luego, escribirás las partes importantes: una habilidad de agente, tres agentes y una evaluación. Todo lo demás (diseño del proyecto, servidor, dependencias y configuración de la implementación) proviene de la CLI.
¿Es la primera vez que ves la Fórmula E?
No necesitas saber de automovilismo. Estos cinco términos son suficientes:
- Fórmula E: el campeonato de carreras totalmente eléctricas de la FIA. La mayoría de las carreras se realizan en circuitos urbanos temporales en los centros de las ciudades.
- Homologación: Es la aprobación oficial de la FIA de que un circuito es seguro para competir. Sin homologación, no hay carrera.
- Frenado regenerativo: Cuando el auto frena, los motores recargan la batería. Un frenado más brusco recupera más energía, por lo que las reglas de este codelab requieren al menos una zona de frenado brusco.
- Capas de CAD: Son capas con nombre en los dibujos de diseño del circuito, como la línea de carrera, la calle de boxes y las barreras. La FIA verifica que estén presentes los obligatorios.
- Modo de ataque: Los conductores obtienen un aumento temporal de potencia cuando conducen por una zona de activación ubicada fuera de la línea de carrera.
Tus agentes juegan en ambos lados: uno diseña el circuito y dos lo revisan para la FIA.
Qué compilarás
Los cuadros verdes son agentes y los cuadros con líneas punteadas son sus herramientas, de la misma manera que los dibuja la zona de pruebas del ADK. Dos de las herramientas unen a otros agentes: fia_assessor es el agente de FIA Assessor con la habilidad de cumplimiento de la FIA, y remote_gatekeeper llama al agente de Gatekeeper en el otro proyecto a través de A2A.
Agente | Proyecto | Trabajo |
|
Arquitecto principal |
| Analiza el entorno, le pregunta al evaluador, soluciona problemas y le pide aprobación al guardián |
|
Asesor de FIA |
| Verifica el diseño con la habilidad de FIA y una herramienta de puntuación |
|
Gatekeeper de gemelos digitales |
| Ejecuta la lista de tareas de homologación final. |
|
Qué aprenderás
- Cómo
agents-cli scaffold creatediseña un proyecto de ADK y qué archivos editas - Cómo empaquetar el conocimiento del dominio como una habilidad del agente (
SKILL.md,references/,scripts/) y cargarlo conSkillToolsetdel ADK - Cómo hacer coincidir
thinking_levelcon el trabajo de cada agente. - Cómo evaluar agentes con
agents-cli eval run - Cómo implementar un agente en Agent Runtime, en qué se diferencia la identidad del agente de una cuenta de servicio y cómo llamar al agente implementado a través del protocolo A2A.
2. 2. Configura tu entorno
Antes de comenzar
Necesitas un proyecto de Google Cloud con la facturación habilitada. Si estás siguiendo este codelab en un evento, usa la cuenta y el proyecto que se te proporcionaron.
Abre Cloud Shell y configura tu proyecto
Abre Cloud Shell y, luego, ejecuta lo siguiente:
# 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 credenciales para tus agentes
gcloud ya accedió, pero el código de Python que ejecutan tus agentes usa las credenciales predeterminadas de la aplicación (ADC), que necesitan un acceso independiente:
gcloud auth application-default login
Abre el vínculo que se imprime, accede con la misma cuenta, copia el código y pégalo de nuevo en Cloud Shell. Luego, configura el proyecto al que se factura la cuota:
gcloud auth application-default set-quota-project "$GOOGLE_CLOUD_PROJECT"
Habilita las APIs
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
Para qué sirve cada API:
API | Se usa para |
| Modelos de Gemini y Agent Runtime |
| Las verificaciones de proyectos y permisos que ejecutan |
| Crea la cuenta de servicio predeterminada de Compute Engine que usa la implementación en el paso 7. |
| Almacenamiento, registros y seguimientos, como se recomienda en la guía de configuración de Agent Runtime |
| Compilaciones e imágenes de contenedores, incluidas como precaución para la implementación en el paso 7 |
Muchos proyectos ya tienen algunas de estas opciones activadas. Habilitar una API que ya está activada no cambia nada.
Instala uv y 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
Este codelab se probó con agents-cli 1.10.0, por lo que debes instalar esa versión para obtener los mismos archivos generados.
3. 3. Crea la estructura de los proyectos y agrega los recursos
Genera ambos proyectos
agents-cli scaffold create genera un proyecto del ADK completo y que se puede implementar. Ejecútalo dos veces, una para cada sistema de agentes.
Primero, el planificador de pistas:
cd ~
agents-cli scaffold create track-planner \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
Luego, la persona responsable de filtrar las conversaciones:
cd ~
agents-cli scaffold create gatekeeper \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
Marcar | Significado |
| Comienza con la plantilla de ADK de Python |
| Genera el servidor y la configuración para Agent Runtime |
| Omitir CI/CD; mantener el proyecto al mínimo |
| Acepta los valores predeterminados sin preguntar |
Explora el diseño
El proyecto generado se ve de la siguiente manera. Solo debes editar los archivos marcados 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`
Para obtener una descripción de cada archivo generado, consulta Estructura del proyecto en la guía de la CLI de Agents.
Prueba el agente generado
Antes de cambiar algo, ejecuta el agente de plantilla para ver qué te ofrece el scaffolding. Instala las dependencias y, luego, inicia la zona de pruebas local en el puerto 8080:
cd ~/track-planner
agents-cli install
agents-cli playground --port 8080
Para abrirla, haz clic en el botón Vista previa en la Web en la barra de herramientas de Cloud Shell (el ícono de ojo en la parte superior derecha) y, luego, selecciona Vista previa en el puerto 8080.
En la zona de pruebas, hazle al agente de plantilla una pregunta que sus herramientas puedan responder, por ejemplo:
What's the weather in San Francisco?
En el panel lateral, se muestra cada evento, incluida la llamada a la herramienta get_weather y su resultado. Más adelante, usarás la misma vista para seguir a tus propios agentes.
Cuando termines, vuelve a la terminal y presiona Ctrl+C para detener la zona de pruebas.
Agrega los recursos de la Fórmula E
Los datos del lugar, las reglas de la FIA, la secuencia de comandos de física, las herramientas y los conjuntos de datos de evaluación no son la lección, por lo que los copias de GitHub en lugar de escribirlos:
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 es una etiqueta de versión fija, por lo que todos obtienen los mismos archivos. $ASSETS se configuró en el paso 2 y apunta a la carpeta que acabas de clonar.
Esto agrega los siguientes archivos:
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
Instala y prueba
(cd ~/track-planner && agents-cli install && uv run pytest tests/unit)
(cd ~/gatekeeper && agents-cli install && uv run pytest tests/unit)
agents-cli install ejecuta uv sync para crear un entorno virtual para cada proyecto. Todas las pruebas de unidades deberían aprobarse.
4. 4. Escribe la habilidad de cumplimiento de la FIA
Una habilidad para agentes empaqueta instrucciones, documentos de referencia y secuencias de comandos en una sola carpeta. El SkillToolset del ADK lo carga en tres niveles, por lo que el agente solo lee lo que necesita:
Nivel | Archivo | Cuando el agente lo ve |
1 |
| Siempre (unas pocas decenas de tokens) |
2 |
| Cuando llama a |
3 |
| Cuando llama a |
La habilidad reside en app/skills/ porque el Dockerfile generado solo copia app/ en la imagen implementada.
Observa los archivos de nivel 3
En el paso 3, copiaste los archivos del nivel 3 de la habilidad:
references/track_regulations.mdcontiene las reglas que verifica el evaluador: los límites de longitud y ancho, qué barrera necesita cada zona de frenado, las capas de CAD obligatorias (además de las capas médicas para las rutas de los hospitales), el objetivo de regeneración y las reglas del modo de ataque.scripts/calculate_regen_zones.pyes una calculadora. Dadas la velocidad de entrada, la velocidad de salida y la distancia de frenado de una zona de frenado, calcula la energía recuperada y la barrera que necesita la curva, por lo que el agente nunca tiene que adivinar la física.
Ejecuta la secuencia de comandos para la curva 10 de Londres, en la que los autos frenan de 215 a 55 km/h en 82 metros:
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
El auto recupera alrededor de 508 kW aquí, por encima del objetivo de 250 kW. Se desacelera a más de 2G, por lo que la curva necesita barreras 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"}
Escribe SKILL.md
Crea el archivo que une la habilidad:
cloudshell edit app/skills/fia-compliance-skill/SKILL.md
Agrega este contenido:
---
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.
El description es lo que lee el modelo para decidir cuándo usar la habilidad, por lo que indica qué abarca la habilidad y cuándo usarla.
Observa cómo se conecta la habilidad
Abre app/tools.py en el Editor de Cloud Shell:
cloudshell edit app/tools.py
Busca la función 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_dirlee la carpeta de habilidades:SKILL.md,references/yscripts/.SkillToolsetlas convierte en herramientas a las que el agente puede llamar:list_skills,load_skill,load_skill_resourceyrun_skill_script.UnsafeLocalCodeExecutorpermite querun_skill_scriptejecute la secuencia de comandos de Python en esta máquina. Está bien para un lab, pero usa un ejecutor de zona de pruebas en producción.
En el siguiente paso, adjuntarás este conjunto de herramientas al evaluador.
5. 5. Escribe los agentes
Los modelos de Gemini 3 controlan el razonamiento con thinking_level (LOW, MEDIUM o HIGH) en lugar de un presupuesto de tokens. En el ADK, lo configuras con types.ThinkingConfig(thinking_level=types.ThinkingLevel.HIGH). Haz que coincida con el trabajo de cada agente: más razonamiento significa una mejor planificación, pero más latencia y costo.
El guardián (LOW)
El Gatekeeper solo ejecuta una lista de tareas determinística, por lo que necesita poco razonamiento. Reemplaza el agente de plantilla:
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",
)
Ejecuta Gatekeeper de forma local
Abre una segunda pestaña de Cloud Shell y, luego, inicia el servidor generado por Gatekeeper en el puerto 8001:
cd ~/gatekeeper
APP_URL=http://localhost:8001 uv run uvicorn app.fast_api_app:app --port 8001
Regresa a la primera pestaña y observa la tarjeta de agente de A2A de Gatekeeper. Así es como otros agentes descubren qué es el Gatekeeper y qué puede hacer:
curl -s http://localhost:8001/a2a/app/.well-known/agent-card.json | jq .
Deberías ver un JSON como este (abreviado):
{
"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 ..."}
]
}
nameydescriptionprovienen directamente de tu definición deAgent(...).skillsenumera lo que puede hacer el agente. El ADK agregóverify_infrastructure_checklistautomáticamente con la cadena de documentación de la herramienta.supportedInterfacesindica a los emisores dónde enviar las solicitudes de A2A. Por eso, iniciaste el servidor conAPP_URL=http://localhost:8001: un emisor lee primero la tarjeta y, luego, envía sus solicitudes a cualquierurlque anuncie la tarjeta.
No se escribió nada a mano: el servidor con scaffolding compila la tarjeta a partir de tu agente. El planificador de pistas leerá esta tarjeta para encontrar y llamar al Gatekeeper.
El evaluador (MEDIUM) y el arquitecto principal (HIGH)
El planificador de pistas tiene dos agentes:
- El evaluador sopesa varias reglas, por lo que obtiene
MEDIUM. Está unida en unAgentTool, por lo que el arquitecto principal la llama como una función y obtiene el veredicto. - El arquitecto principal planifica, corrige y coordina, por lo que obtiene
HIGH. Llega al Gatekeeper a través de unRemoteA2aAgent, creado porcreate_remote_gatekeeper_agent()enapp/auth.py, y también lo une en unAgentTool.
¿Por qué se deben unir ambos ayudantes como herramientas? Un AgentTool devuelve su respuesta al emisor, por lo que el arquitecto principal sigue a cargo y escribe el plano final. Si el Gatekeeper fuera un sub_agent, el Lead Architect le entregaría la conversación y el estado breve del Gatekeeper se convertiría en la respuesta final.
Abre el archivo app/agent.py del planificador de pistas:
cloudshell edit ~/track-planner/app/agent.py
Copia el siguiente código y reemplaza todo el contenido de ~/track-planner/app/agent.py con él:
"""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",
)
Ejecuta todo el sistema en Playground
Asegúrate de que Gatekeeper siga ejecutándose en la segunda pestaña. En la primera pestaña, inicia el playground del planificador de pistas:
cd ~/track-planner
agents-cli playground --port 8080
Haz clic en Vista previa en la Web > Vista previa en el puerto 8080, como hiciste en el paso 3.
Solicita un circuito en un lugar que cumpla con las siguientes reglas:
Design and homologate a Formula E circuit at Tokyo Bay.
Observa el panel de eventos mientras los agentes trabajan. Deberías ver lo siguiente, en orden:
get_track_topology: El arquitecto principal carga los datos de la bahía de Tokio.fia_assessor: El arquitecto principal entrega el diseño al evaluador, que llama aload_skill,load_skill_resourceyrun_skill_script(una vez por zona de frenado) y, luego, aevaluate_track_layout.remote_gatekeeper: El arquitecto principal llama al guardián a través de A2A. Verás la solicitud registrada en la segunda pestaña.- Un plano final del arquitecto principal, en el que se enumeran todas las capas de CAD y el estado APROBADO del responsable de aprobación.
Haz clic en cualquier evento para ver sus entradas y salidas exactas.
Ahora, inicia una nueva sesión y prueba con un lugar que no cumpla con las reglas:
Can the Monaco Harbour layout be homologated? If not, fix it and try again.
Esta vez, el evaluador rechaza la chicana de 6.8 m, el arquitecto principal propone una más ancha y el diseño corregido vuelve al evaluador antes de llegar al guardián.
Cuando termines, presiona Ctrl+C en la primera pestaña para detener la zona de pruebas. Deja que Gatekeeper se ejecute en la segunda pestaña, ya que lo necesitarás en el siguiente paso.
6. 6. Evalúa los agentes
agents-cli eval run ejecuta tu agente en un conjunto de datos, registra cada turno y llamada a la herramienta, y califica los resultados. Tú decides qué medir en tests/eval/eval_config.yaml.
Observa el conjunto de datos
Abre el conjunto de datos en el editor de Cloud Shell:
cd ~/track-planner
cloudshell edit tests/eval/datasets/track_eval.json
El archivo contiene una lista de eval_cases. Cada caso tiene un eval_case_id, un prompt (lo que pregunta el usuario) y un reference (cómo se ve una buena respuesta). El juez de LLM compara la respuesta del agente con la de referencia.
| Qué se prueba |
| Un lugar que cumple con todas las reglas y se aprueba |
| La chicana de 6.8 m no cumple con la regla de ancho |
| El circuito de 4,350 m no cumple con la regla de longitud |
| Un diseño al que le faltan capas de CAD obligatorias |
| Una zona de frenado por debajo del objetivo de 250 kW |
| Acceso al hospital que requiere capas de CAD médicas |
| Una zona de Attack Mode en la línea de carrera |
| Una conversación de varios turnos: Se rechaza Mónaco, el usuario pide una corrección y se debe aprobar el diseño corregido |
En el último caso, se usa agent_data en lugar de prompt. Reproduce los turnos anteriores de una conversación, por lo que puedes probar cómo el agente maneja una solicitud de seguimiento, no solo una pregunta.
track_eval_quick.json en la misma carpeta contiene solo dos casos: el caso 1 (una sola pregunta) y el caso 8 (una conversación). Ejecutarás esa porque es más rápida y usa menos cuota.
Escribe las métricas
El conjunto de datos indica qué preguntarle al agente. eval_config.yaml indica cómo calificar las respuestas. agents-cli eval run lo lee después de que el agente haya respondido cada caso y ejecuta cada métrica en cada respuesta.
Abre el archivo que generó el scaffold:
cloudshell edit tests/eval/eval_config.yaml
Ya contiene un juez de LLM genérico (custom_response_quality) y una métrica agent_turn_count que solo cuenta los turnos. Ese es un buen comienzo para cualquier agente, pero no dice nada sobre la Fórmula E. Mantendrás el juez y agregarás una métrica que verifique una regla específica para este dominio.
Las buenas evaluaciones suelen mezclar dos tipos de métricas:
Tipo | Cómo se calcula la puntuación | Ideal para | Desventajas |
LLM-as-a-judge | Un modelo lee la respuesta y el | Cualidades difusas: ¿La respuesta es correcta, completa y clara? | Cuesta una llamada al modelo por caso; las puntuaciones pueden variar ligeramente entre ejecuciones |
Métrica de código | Una pequeña función de Python verifica la respuesta. | Datos exactos y verificables: ¿La respuesta incluyó algo que debe estar allí? | Solo verifica lo que puedes expresar en el código. |
Reemplaza el contenido del archivo por lo siguiente:
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"),
}
Qué hace cada parte:
metrics_to_runenumera las métricas que se ejecutarán, por nombre. Si quitas un nombre aquí, se desactivará esa métrica sin borrarla.custom_response_qualityes el juez de LLM.custom_function_fileapunta atests/eval/response_quality.py, que generó el scaffold. Ábrelo si quieres ver la instrucción de evaluación.fia_cad_layer_compliancees la métrica de tu código, escrita de forma intercalada encustom_function. Para cada caso, recibe uninstance(el mensaje, laresponsefinal del agente y lareference). En los casos en los que la respuesta esperada es una aprobación, verifica que la respuesta nombre las cuatro capas de CAD obligatorias y enumere las que falten. Por ejemplo, un plano que omiteF1_TEC3obtiene una puntuación de 0.75. En otros casos, se obtiene una puntuación de 1.0, ya que un rechazo o una respuesta en el modo de ataque no necesitan enumerar todas las capas.
¿Por qué verificar las capas de CAD? Un plano aprobado que omite una capa obligatoria es incorrecto, incluso si se lee bien, y un juez de LLM puede pasarlo por alto. Una verificación de código aplica la misma regla de la misma manera en cada ejecución.
Ejecutar la evaluación
Mantén el Gatekeeper local en ejecución en la segunda pestaña y, luego, ejecuta lo siguiente:
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 evaluación tarda unos minutos. Cada caso ejecuta todo el flujo de varios agentes, alrededor de diez llamadas al modelo con el arquitecto principal en HIGH, por lo que Step 1/2: eval generate es la parte lenta. No está atascado.
Cuando finalice, abre el informe HTML en artifacts/grade_results/ con el editor de Cloud Shell. Las puntuaciones bajas de fia_cad_layer_compliance indican que la respuesta final del arquitecto principal omite capas. Intenta ajustar su instrucción y vuelve a ejecutar la evaluación.
7. 7. Implementa el Gatekeeper en Agent Runtime
Solo implementas el Gatekeeper. El planificador de pistas se sigue ejecutando en Cloud Shell y lo llama.
Abre una pestaña nueva de Cloud Shell
La implementación tarda entre 5 y 8 minutos, por lo que debes hacerlo en una pestaña nueva mientras finaliza la evaluación del paso 6:
- Haz clic en Abrir una pestaña nueva (+) en la barra de herramientas de Cloud Shell.
- En una pestaña nueva, no se conservan las variables del paso 2, por lo que debes volver a configurarlas:
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"
Deja el Gatekeeper local en ejecución en la segunda pestaña: la evaluación aún lo usa y la implementación no necesita que se detenga.
Implementar
En la pestaña nueva, implementa Gatekeeper. Se ejecuta como la cuenta de servicio predeterminada de Compute Engine del proyecto:
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
La implementación tarda entre 5 y 8 minutos. No cierres la pestaña de Cloud Shell mientras se ejecuta. Si se desconecta la transmisión de registros, verifica el progreso con agents-cli deploy --status. Mientras esperas, vuelve al paso 6 y lee tu informe de evaluación.
Inspecciona la identidad del agente
agents-cli registra el recurso implementado en 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 segunda línea del resultado es la identidad con la que se ejecuta Gatekeeper:
Implementado con | Ejemplo de resultado: |
La cuenta de servicio (predeterminada) |
|
Identidad del agente |
|
La cuenta de servicio se comparte con todo lo que la use en el proyecto. Una identidad de agente pertenece a este agente, por lo que puedes otorgarle exactamente los roles que necesita y ver sus acciones por separado en los registros de auditoría.
8. 8. Conéctate al Gatekeeper implementado a través de A2A
Agent Runtime entrega las rutas de A2A generadas por Gatekeeper detrás de una ruta de acceso /api autenticada.
Asegúrate de que la evaluación del paso 6 haya finalizado y, luego, detén el Gatekeeper local en la segunda pestaña (Ctrl + C). A partir de ahora, el planificador de pistas llama al que se implementó. En la primera pestaña, apunta el planificador de pistas hacia ella:
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
Por qué el cliente actualiza su token
Abre app/auth.py. Los tokens de acceso de Google Cloud vencen después de una hora, por lo que un cliente que establece un encabezado Authorization fijo en el inicio comienza a fallar con 401 Unauthorized después de una hora. GoogleAuthRefresh hereda de httpx.Auth y verifica las credenciales en cada solicitud, actualizándolas cuando sea necesario. create_remote_gatekeeper_agent() solo lo adjunta para las URLs de https://.
Ejecútalo de extremo a extremo
Vuelve a iniciar la zona de pruebas para que se aplique el nuevo GATEKEEPER_A2A_URL:
agents-cli playground --port 8080
Haz clic en Vista previa en la Web > Vista previa en el puerto 8080, inicia una sesión nueva y pregunta lo siguiente:
Assess the Monaco Harbour layout, widen the chicane to 11m, and get Gatekeeper approval.
Los eventos se ven igual que en el paso 5, pero la llamada remote_gatekeeper ahora se dirige al Gatekeeper en Agent Runtime en lugar de a la segunda pestaña.
Observa cómo llega la llamada a Agent Runtime
Demuestra que la solicitud realmente llegó al Gatekeeper implementado a través de A2A:
- En la consola de Cloud, busca Agent Platform y, luego, abre Implementaciones en el menú de la izquierda.
- Selecciona gatekeeper.
- Abre la pestaña Sesiones.
Verás una sesión nueva cuyo ID de usuario comienza con A2A_USER_. El servidor de A2A de Gatekeeper lo creó cuando lo llamó tu planificador de pistas. Abre la pestaña Seguimientos en la misma página para ver la llamada al modelo de Gatekeeper y su llamada a la herramienta verify_infrastructure_checklist para esa solicitud.
Opcional: Implementa también el planificador de recorridos
Hasta ahora, el planificador de pistas se ejecuta en Cloud Shell, por lo que sus llamadas de A2A al Gatekeeper usan tus credenciales. Implementa también el planificador y ambos agentes se ejecutarán en Agent Runtime, llamándose entre sí con sus propias identidades implementadas.
Presiona Ctrl + C para detener la zona de pruebas y, luego, implementa el planificador de la misma manera que el 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
Ambos agentes se ejecutan como la misma cuenta de servicio de Compute Engine. Mantén --service-account: sin él, el planificador se ejecuta como el agente de servicio predeterminado de Agent Runtime y no puede llamar al Gatekeeper (consulta ¿Por qué esta cuenta de servicio? en el paso 7).
Cómo el planificador implementado se comunica con el responsable de filtrar las comunicaciones:
agents-cli deploycopia los valores de.enven la implementación, por lo que el planificador obtiene elGATEKEEPER_A2A_URLque agregaste anteriormente.- Dentro de Agent Runtime,
GoogleAuthRefreshenapp/auth.pytoma la identidad implementada del planificador en lugar de la tuya.
La implementación tarda entre 5 y 8 minutos. Cuando finalice, verifica con qué identidad se ejecuta el planificador:
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
Para probar el sistema implementado, haz lo siguiente:
- En la consola de Cloud, vuelve a Agent Platform > Implementaciones.
- Selecciona track-planner y abre la pestaña Playground.
- Escribe lo siguiente:
Design and homologate a Formula E circuit at Tokyo Bay. - Espera a que el plano tenga el estado APROBADO de Gatekeeper.
- Regresa a Implementaciones, selecciona gatekeeper y abre la pestaña Sesiones. La sesión de
A2A_USER_más reciente provino del planificador implementado, no de Cloud Shell.
Cuando realices la limpieza en el siguiente paso, borra también el planificador:
curl -X DELETE -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${PLANNER_ID}?force=true"
9. 9. Solución de problemas y limpieza
Solución de problemas
Síntoma | Corregir |
| Acepta las Condiciones del Servicio en la consola de Cloud y, luego, vuelve a intentarlo. |
El proyecto es | Vuelve a ejecutar los comandos del proyecto del paso 2. |
| Ejecuta |
| Completa el paso 4 o copia |
De | Inicia el Gatekeeper local (paso 5) o establece |
| Tu cuenta no puede usar la identidad del agente. Sigue las instrucciones del cuadro de limpieza del paso 7 y, luego, usa la cuenta de servicio deploy. |
El planificador de pistas implementado informa | La identidad del planificador no tiene permiso para llamar al Gatekeeper. Vuelve a implementarla con |
| Alcanzaste la cuota de Gemini. Espera un minuto o agrega |
| Detén el otro servidor o elige otro |
Limpia
Borra el Gatekeeper implementado para que no siga ejecutándose:
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 creaste un proyecto solo para este codelab, puedes borrar todo el proyecto. Si estás en un evento, conserva el proyecto que te asignaron hasta que los organizadores indiquen lo contrario.
Qué aprendiste
agents-cli scaffold createte brinda un proyecto de ADK estándar y que se puede implementar. Solo debes escribir agentes, habilidades y evaluaciones.- Las habilidades de los agentes mantienen el conocimiento del dominio fuera de las instrucciones hasta que el agente lo necesita.
thinking_levelte permite cambiar la profundidad del razonamiento por la velocidad por agente.agents-cli eval runconvierte la pregunta "¿funciona?" en puntuaciones de las que puedes hacer un seguimiento.- La identidad del agente y A2A permiten que los agentes implementados de forma independiente trabajen juntos de forma segura.