1. 1. 概要
この Codelab では、フォーミュラ E のストリート サーキットを設計し、簡素化された FIA ルールに照らして承認を得るマルチエージェント システムを構築します。
agents-cli を使用して 2 つの標準的な Agent Development Kit(ADK)プロジェクトを生成し、重要な部分(エージェント スキル、3 つのエージェント、評価)を記述します。それ以外(プロジェクト レイアウト、サーバー、依存関係、デプロイ構成)はすべて CLI から取得されます。
フォーミュラ E を初めてご覧になる方へ
モータースポーツに詳しくなくても大丈夫。次の 5 つの用語で十分です。
- フォーミュラ E: FIA の完全電気自動車レース選手権。ほとんどのレースは、都市中心部の仮設ストリート サーキットで開催されます。
- ホモロゲーション: サーキットが安全にレースを行えることを示す FIA の公式承認。ホモロゲーションがなければ、レースはできません。
- 回生ブレーキ: 車がブレーキをかけると、モーターがバッテリーを充電します。ブレーキを強くかけるほど、より多くのエネルギーを回収できるため、この Codelab のルールでは、少なくとも 1 つの急ブレーキ ゾーンを設ける必要があります。
- CAD レイヤ: レーシング ライン、ピットレーン、バリアなど、サーキットの設計図に名前が付けられたレイヤ。FIA は、必須のものが存在することを確認します。
- アタック モード: ドライバーは、レーシング ラインの外に配置されたアクティビティ エリアを通過することで、一時的にパワーをブーストできます。
エージェントは両方の役割を担います。1 つはサーキットを設計し、2 つは FIA のためにサーキットをチェックします。
作業内容
緑色のボックスはエージェント、点線のボックスはツールです。これは ADK プレイグラウンドでの描画と同じです。2 つのツールは他のエージェントをラップします。fia_assessor は FIA コンプライアンス スキルを持つ FIA 評価者エージェントで、remote_gatekeeper は A2A 経由で他のプロジェクトの Gatekeeper エージェントを呼び出します。
エージェント | プロジェクト | ジョブ |
|
リード アーキテクト |
| 会場を読み取り、評価者に質問し、問題を修正し、ゲートキーパーに承認を求める |
|
FIA 評価者 |
| FIA スキルとスコアリング ツールを使用してレイアウトを確認する |
|
デジタルツイン ゲートキーパー |
| 最終的なホモロゲーション チェックリストを実行する |
|
学習内容
agents-cli scaffold createが ADK プロジェクトをレイアウトする方法と、編集するファイル。- ドメイン知識をエージェント スキル(
SKILL.md、references/、scripts/)としてパッケージ化し、ADK のSkillToolsetで読み込む方法。 thinking_levelを各エージェントのジョブに一致させる方法。agents-cli eval runを使用してエージェントを評価する方法。- Agent Runtime にエージェントをデプロイする方法、エージェント ID とサービス アカウントの違い、A2A プロトコルを介してデプロイされたエージェントを呼び出す方法。
2. 2. 環境を設定する
始める前に
課金が有効になっている Google Cloud プロジェクトが必要です。イベントでこの Codelab を実施する場合は、提供されたアカウントとプロジェクトを使用してください。
Cloud Shell を開いてプロジェクトを設定する
Cloud Shell を開き、次のコマンドを実行します。
# Cloud Shell sometimes opens without a project set. If so, this sets it to
# the first project on your account.
if [ -z "$(gcloud config get-value project 2>/dev/null)" ]; then
gcloud config set project "$(gcloud projects list --format='value(projectId)' --limit=1)"
fi
export GOOGLE_CLOUD_PROJECT="$(gcloud config get-value project)"
export REGION="us-central1"
export ASSETS="$HOME/devrel-demos/codelabs/formula-e-track-planner"
echo "Project: $GOOGLE_CLOUD_PROJECT Region: $REGION"
エージェントの認証情報を作成する
gcloud はすでにログインしていますが、エージェントが実行する Python コードはアプリケーションのデフォルト認証情報(ADC)を使用するため、別途ログインする必要があります。
gcloud auth application-default login
出力されたリンクを開き、同じアカウントでログインしてコードをコピーし、Cloud Shell に貼り付けます。次に、割り当ての請求先となるプロジェクトを設定します。
gcloud auth application-default set-quota-project "$GOOGLE_CLOUD_PROJECT"
API を有効にする
gcloud services enable \
aiplatform.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
storage.googleapis.com \
cloudresourcemanager.googleapis.com \
serviceusage.googleapis.com \
compute.googleapis.com \
iam.googleapis.com \
logging.googleapis.com \
cloudtrace.googleapis.com
各 API の用途:
API | 用途 |
| Gemini モデルと Agent Runtime |
|
|
| ステップ 7 のデプロイで使用する Compute Engine のデフォルトのサービス アカウントを作成します。 |
| ストレージ、ログ、トレース(Agent Runtime 設定ガイドで推奨されているとおり) |
| コンテナのビルドとイメージ(ステップ 7 のデプロイの予防措置として含まれています) |
多くのプロジェクトでは、これらの機能の一部がすでに有効になっています。すでに有効になっている API を有効にしても、何も変更されません。
uv と agents-cli をインストールする
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv tool install google-agents-cli==1.10.0
agents-cli --version
この Codelab は agents-cli 1.10.0 でテスト済みです。同じ生成ファイルを取得するには、このバージョンをインストールしてください。
3. 3. プロジェクトをスキャフォールディングしてアセットを追加する
両方のプロジェクトを生成する
agents-cli scaffold create は、デプロイ可能な完全な ADK プロジェクトを生成します。エージェント システムごとに 1 回ずつ、2 回実行します。
まず、トラック プランナーです。
cd ~
agents-cli scaffold create track-planner \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
受付担当者の対応:
cd ~
agents-cli scaffold create gatekeeper \
--agent adk \
--deployment-target agent_runtime \
--region "$REGION" \
--prototype \
--yes
フラグ | 意味 |
| Python ADK テンプレートから始める |
| Agent Runtime のサーバーと構成を生成する |
| CI/CD をスキップする。プロジェクトを最小限に抑える |
| プロンプトを表示せずにデフォルトを受け入れる |
レイアウトを確認する
生成されたプロジェクトは次のようになります。編集するのは ✍️ マークが付いたファイルのみです。
track-planner/
├── agents-cli-manifest.yaml # Records the template, deployment target and root agent name
├── pyproject.toml # Dependencies (google-adk, a2a-sdk, ...)
├── .env # Your project and model location, filled in for you
├── Dockerfile # Used by `agents-cli deploy`; copies app/ into the image
├── app/
│ ├── agent.py # ✍️ Your agents
│ ├── fast_api_app.py # Generated server: ADK API, A2A routes, Agent Runtime routes
│ └── app_utils/ # Generated helpers (A2A, sessions)
└── tests/
├── unit/ # Fast tests with no model calls
├── integration/ # Generated server tests
└── eval/ # ✍️ eval_config.yaml and datasets for `agents-cli eval`
生成された各ファイルの説明については、Agents CLI ガイドのプロジェクト構造をご覧ください。
生成されたエージェントを試す
変更を加える前に、テンプレート エージェントを実行して、スキャフォールドで何が得られるかを確認します。依存関係をインストールし、ポート 8080 でローカル プレイグラウンドを起動します。
cd ~/track-planner
agents-cli install
agents-cli playground --port 8080
これを開くには、Cloud Shell ツールバーの [ウェブでプレビュー] ボタン(右上の目のアイコン)をクリックし、[ポート 8080 でプレビュー] を選択します。
プレイグラウンドで、テンプレート エージェントに、ツールが回答できる質問をします。例:
What's the weather in San Francisco?
サイドパネルには、get_weather ツール呼び出しとその結果を含む各イベントが表示されます。このビューは、後で自分のエージェントをフォローする際にも使用します。
完了したら、ターミナルに戻り、Ctrl+C キーを押して Playground を停止します。
Formula E のアセットを追加する
会場データ、FIA 規則、物理スクリプト、ツール、評価データセットはレッスンではないため、入力するのではなく GitHub からコピーします。
cd ~
git clone --depth 1 --filter=blob:none --sparse \
--branch formula-e-lab-v1 \
https://github.com/tdsymonds/devrel-demos.git
git -C devrel-demos sparse-checkout set codelabs/formula-e-track-planner
cp -r "$ASSETS/track-planner/." ~/track-planner/
cp -r "$ASSETS/gatekeeper/." ~/gatekeeper/
formula-e-lab-v1 は固定のリリースラベルであるため、すべてのユーザーが同じファイルを取得します。$ASSETS はステップ 2 で設定したもので、クローンを作成したフォルダを指しています。
これにより、次のファイルが追加されます。
track-planner/
├── app/
│ ├── tools.py # get_track_topology, evaluate_track_layout
│ ├── auth.py # A2A client with per-request token refresh
│ ├── data/circuits.json # Five candidate venues
│ └── skills/fia-compliance-skill/
│ ├── references/track_regulations.md # The FIA rules
│ └── scripts/calculate_regen_zones.py # Braking-energy calculator
└── tests/
├── unit/test_tools.py
└── eval/datasets/track_eval.json, track_eval_quick.json
gatekeeper/
├── app/tools.py # verify_infrastructure_checklist
└── tests/unit/test_tools.py
インストールしてテストする
(cd ~/track-planner && agents-cli install && uv run pytest tests/unit)
(cd ~/gatekeeper && agents-cli install && uv run pytest tests/unit)
agents-cli install は uv sync を実行して、プロジェクトごとに仮想環境を作成します。すべての単体テストに合格する必要があります。
4. 4. FIA コンプライアンス スキルを記述する
エージェント スキルは、指示、参照ドキュメント、スクリプトを 1 つのフォルダにまとめたものです。ADK の SkillToolset は、3 つのレベルで読み込みを行うため、エージェントは必要な情報のみを読み取ります。
レベル | ファイル | エージェントがそれを見ると |
1 |
| 常に(数十トークン) |
2 |
|
|
3 |
|
|
生成された Dockerfile は app/ のみをデプロイされたイメージにコピーするため、スキルは app/skills/ に存在します。
レベル 3 のファイルを確認する
ステップ 3 で、スキルのレベル 3 のファイルをコピーしました。
references/track_regulations.mdには、査定者がチェックするルール(長さと幅の制限、各ブレーキゾーンに必要なバリア、必須の CAD レイヤー(病院ルートの医療レイヤーを含む)、回生目標、アタック モードのルール)が保持されます。scripts/calculate_regen_zones.pyは計算ツールです。ブレーキゾーンの進入速度、退出速度、ブレーキ距離を指定すると、回収されるエネルギーとコーナーに必要なバリアが計算されるため、エージェントが物理法則を推測する必要はありません。
ロンドンのターン 10 のスクリプトを実行します。ここでは、車は 82 メートルにわたって 215 km/h から 55 km/h に減速します。
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
この車両は、目標の 250 kW を上回る約 508 kW を回収しています。2G を超えると減速するため、コーナーには Tecpro バリア(F1_TEC3)が必要です。
{"entry_kph": 215.0, "exit_kph": 55.0, "brake_dist_m": 82.0, "deceleration_g": 2.07, "estimated_regen_kw": 507.7, "meets_250kw_target": true, "required_barrier_layer": "F1_TEC3"}
SKILL.md を書き込む
スキルをまとめるファイルを作成します。
cloudshell edit app/skills/fia-compliance-skill/SKILL.md
次の内容を追加します。
---
name: fia-compliance-skill
description: >
FIA Formula E street circuit rules: length and width limits, mandatory CAD
layers, barrier selection, and Gen3 regenerative braking estimates. Use when
designing, checking or fixing a Formula E circuit layout.
---
# FIA Formula E Compliance
Follow these steps for every circuit you check.
1. **Read the rules.** Call `load_skill_resource` with
`file_path="references/track_regulations.md"`.
2. **Estimate regeneration for every heavy braking zone.** Call
`run_skill_script` with `file_path="scripts/calculate_regen_zones.py"` and
`args={"entry-kph": <entry>, "exit-kph": <exit>, "brake-dist-m": <distance>}`.
Never guess kW values. Use the highest `estimated_regen_kw` as the
circuit's peak regeneration.
3. **Check barriers.** Any zone whose `required_barrier_layer` is `F1_TEC3`
needs the `F1_TEC3` CAD layer.
4. **Report.** List every rule the layout fails and a concrete fix for each
one.
description は、モデルがスキルを使用するタイミングを判断するために読み取るものです。そのため、スキルがカバーする内容と、スキルを使用するタイミングの両方が記述されています。
スキルの接続方法を確認する
Cloud Shell エディタで app/tools.py を開きます。
cloudshell edit app/tools.py
build_fia_skill_toolset 関数を見つけます。
def build_fia_skill_toolset() -> SkillToolset:
return SkillToolset(
skills=[load_skill_from_dir(SKILL_DIR)],
code_executor=UnsafeLocalCodeExecutor(),
)
load_skill_from_dirは、スキルフォルダSKILL.md、references/、scripts/を読み取ります。SkillToolsetは、エージェントが呼び出すことができるツール(list_skills、load_skill、load_skill_resource、run_skill_script)に変換します。UnsafeLocalCodeExecutorを使用すると、run_skill_scriptはこのマシンで Python スクリプトを実行できます。ラボでは問題ありませんが、本番環境ではサンドボックス化されたエグゼキュータを使用してください。
このツールセットは、次のステップで Assessor にアタッチします。
5. 5. エージェントを記述する
Gemini 3 モデルは、トークン予算ではなく thinking_level(LOW、MEDIUM、HIGH)を使用して推論を制御します。ADK では、types.ThinkingConfig(thinking_level=types.ThinkingLevel.HIGH) を使用して設定します。各エージェントのジョブに合わせます。思考を増やすと、計画は改善されますが、レイテンシとコストが増加します。
ゲートキーパー(LOW)
Gatekeeper は決定論的なチェックリストのみを実行するため、推論はほとんど必要ありません。テンプレート エージェントを置き換えます。
cloudshell edit ~/gatekeeper/app/agent.py
"""FIA Digital Twin Gatekeeper agent.
This agent runs in its own project and is deployed to Agent Runtime. The track
planner calls it over the A2A protocol.
"""
from google.adk.agents import Agent
from google.adk.apps import App
from google.adk.models import Gemini
from google.genai import types
from app.tools import verify_infrastructure_checklist
# Tested with Gemini 3.8 Flash. To try Gemini 4 Argon, change this to
# "gemini-4-argon", delete the `temperature` settings below (Argon ignores
# them) and run `uv add "google-genai>=2.30.1"` in this project first.
MODEL = "gemini-3.8-flash"
root_agent = Agent(
# Must match `root_agent_name` in agents-cli-manifest.yaml.
name="gatekeeper",
model=Gemini(
model=MODEL,
retry_options=types.HttpRetryOptions(attempts=3),
),
description=(
"FIA Digital Twin Gatekeeper. Runs the final homologation checklist "
"for a Formula E circuit blueprint."
),
instruction=(
"You are the FIA Digital Twin Gatekeeper. For every circuit blueprint "
"you receive, call `verify_infrastructure_checklist` with its circuit "
"ID, CAD layers, minimum width and peak regeneration. Reply with the "
"status and any missing CAD layers. Never approve a blueprint the "
"checklist rejects."
),
# A deterministic checklist needs little reasoning: keep it fast and cheap.
generate_content_config=types.GenerateContentConfig(
temperature=0.0,
thinking_config=types.ThinkingConfig(
thinking_level=types.ThinkingLevel.LOW,
),
),
tools=[verify_infrastructure_checklist],
)
app = App(
root_agent=root_agent,
name="app",
)
Gatekeeper をローカルで実行する
2 つ目の Cloud Shell タブを開き、ポート 8001 で Gatekeeper の生成されたサーバーを起動します。
cd ~/gatekeeper
APP_URL=http://localhost:8001 uv run uvicorn app.fast_api_app:app --port 8001
最初のタブに戻り、ゲートキーパーの A2A エージェント カードを確認します。他のエージェントは、次のようにして Gatekeeper の概要と機能を検出します。
curl -s http://localhost:8001/a2a/app/.well-known/agent-card.json | jq .
次のような JSON が表示されます(短縮版)。
{
"name": "gatekeeper",
"description": "FIA Digital Twin Gatekeeper. Runs the final homologation checklist for a Formula E circuit blueprint.",
"supportedInterfaces": [
{"url": "http://localhost:8001/a2a/app", "protocolBinding": "JSONRPC", "protocolVersion": "1.0"}
],
"skills": [
{"id": "gatekeeper", "name": "model", "description": "FIA Digital Twin Gatekeeper. ..."},
{"id": "gatekeeper-verify_infrastructure_checklist", "name": "verify_infrastructure_checklist", "description": "Runs the final homologation checklist ..."}
]
}
nameとdescriptionは、Agent(...)定義から直接取得されます。skillsには、エージェントが実行できることが一覧表示されます。ADK は、ツールの docstring を使用してverify_infrastructure_checklistを自動的に追加しました。supportedInterfacesは、A2A リクエストの送信先を呼び出し元に指示します。そのため、APP_URL=http://localhost:8001を使用してサーバーを起動しました。呼び出し元はまずカードを読み取り、カードがアドバタイズするurlにリクエストを送信します。
ここで手動で記述されたものは何もありません。スキャフォールディングされたサーバーがエージェントからカードをビルドします。トラック プランナーは、このカードを読み取ってゲートキーパーを見つけ、呼び出します。
評価者(MEDIUM)とリード アーキテクト(HIGH)
トラック プランナーには、次の 2 つのエージェントがあります。
- Assessor は複数のルールを評価するため、
MEDIUMを取得します。これはAgentToolでラップされているため、リード アーキテクトは関数のように呼び出して判定結果を取得します。 - リード アーキテクトは、計画、修正、調整を行い、
HIGHを獲得します。app/auth.pyのcreate_remote_gatekeeper_agent()によって作成されたRemoteA2aAgentを介して Gatekeeper に到達し、AgentToolでラップします。
両方のヘルパーをツールとしてラップする理由AgentTool は呼び出し元に回答を返すため、リード アーキテクトが引き続き担当し、最終的な設計図を作成します。Gatekeeper が sub_agent の場合、Lead Architect は会話を Gatekeeper に引き渡し、Gatekeeper の短いステータスが最終的な回答になります。
トラック プランナーの app/agent.py ファイルを開きます。
cloudshell edit ~/track-planner/app/agent.py
次のコードをコピーして、~/track-planner/app/agent.py の内容全体を置き換えます。
"""Formula E track planner: Lead Architect, FIA Assessor and remote Gatekeeper.
- The Lead Architect (root agent) designs the circuit and stays in charge.
- The FIA Assessor checks the layout and is called as a tool (`AgentTool`).
- The Gatekeeper runs in a separate project. It is also called as a tool, over
A2A, so its verdict comes back to the Lead Architect.
"""
from google.adk.agents import Agent
from google.adk.apps import App
from google.adk.models import Gemini
from google.adk.tools.agent_tool import AgentTool
from google.genai import types
from app.auth import create_remote_gatekeeper_agent
from app.tools import build_fia_skill_toolset
from app.tools import evaluate_track_layout
from app.tools import get_track_topology
# Tested with Gemini 3.8 Flash. To try Gemini 4 Argon, change this to
# "gemini-4-argon", delete the `temperature` settings below (Argon ignores
# them) and run `uv add "google-genai>=2.30.1"` in this project first.
MODEL = "gemini-3.8-flash"
fia_skill_toolset = build_fia_skill_toolset()
# 1. FIA Assessor: MEDIUM thinking to weigh several rules without much latency.
assessor_agent = Agent(
name="fia_assessor",
model=Gemini(
model=MODEL,
retry_options=types.HttpRetryOptions(attempts=3),
),
description=(
"FIA safety and energy assessor. Audits a proposed circuit against "
"the geometry, regeneration and CAD layer rules."
),
instruction=(
"You are the FIA Assessor. Load the `fia-compliance-skill` and follow "
"it. Estimate regeneration for each braking zone with "
"`calculate_regen_zones.py`, then call `evaluate_track_layout` with "
"the highest value. Reply with the verdict, the score and every "
"remediation note."
),
generate_content_config=types.GenerateContentConfig(
temperature=0.1,
thinking_config=types.ThinkingConfig(
thinking_level=types.ThinkingLevel.MEDIUM,
),
),
tools=[fia_skill_toolset, evaluate_track_layout],
)
# 2. Remote Gatekeeper, reached over A2A (see app/auth.py).
remote_gatekeeper = create_remote_gatekeeper_agent()
# 3. Lead Architect: HIGH thinking for multi-step planning and trade-offs.
root_agent = Agent(
# Must match `root_agent_name` in agents-cli-manifest.yaml.
name="track_planner",
model=Gemini(
model=MODEL,
retry_options=types.HttpRetryOptions(attempts=3),
),
description=(
"Lead Formula E circuit architect. Designs FIA-compliant street "
"circuits and gets them homologated."
),
instruction=(
"You are the Lead Formula E Circuit Architect. For every request:\n"
"1. Call `get_track_topology` for the venue.\n"
"2. Call the `fia_assessor` tool with the full topology.\n"
"3. If the Assessor rejects the layout, propose concrete fixes (for "
"example widen a sector to 10.0m or add missing CAD layers) and "
"re-assess the fixed layout.\n"
"4. Once the Assessor passes it, call the `remote_gatekeeper` tool "
"with the circuit ID, CAD layers, minimum width and peak "
"regeneration for final approval.\n"
"5. Finish with a short blueprint: circuit ID, length, minimum width, "
"peak regeneration, every CAD layer by name, and the Gatekeeper's "
"status."
),
generate_content_config=types.GenerateContentConfig(
temperature=0.2,
thinking_config=types.ThinkingConfig(
thinking_level=types.ThinkingLevel.HIGH,
),
),
# Both helpers are tools, so their answers come back to the Lead Architect
# and it writes the final blueprint.
tools=[
get_track_topology,
AgentTool(agent=assessor_agent),
AgentTool(agent=remote_gatekeeper),
],
)
app = App(
root_agent=root_agent,
name="app",
)
プレイグラウンドでシステム全体を実行する
2 つ目のタブで Gatekeeper が実行されていることを確認します。最初のタブで、トラック プランナーのプレイグラウンドを起動します。
cd ~/track-planner
agents-cli playground --port 8080
手順 3 と同様に、[ウェブでプレビュー] > [ポート 8080 でプレビュー] をクリックします。
ルールを満たす会場のサーキットをリクエストします。
Design and homologate a Formula E circuit at Tokyo Bay.
エージェントが作業している間、イベントパネルを監視します。次の順序で表示されます。
get_track_topology: リード アーキテクトが東京湾のデータを読み込みます。fia_assessor: リード アーキテクトがレイアウトを評価者に渡します。評価者はload_skill、load_skill_resource、run_skill_script(ブレーキゾーンごとに 1 回)、evaluate_track_layoutを呼び出します。remote_gatekeeper: リード アーキテクトが A2A 経由でゲートキーパーを呼び出します。2 つ目のタブにリクエストが記録されていることがわかります。- リード アーキテクトが作成した最終的な設計図。すべての CAD レイヤと、ゲートキーパーの APPROVED ステータスが記載されています。
イベントをクリックすると、その正確な入力と出力が表示されます。
次に、新しいセッションを開始して、ルールに違反する会場を試します。
Can the Monaco Harbour layout be homologated? If not, fix it and try again.
今回は、評価者が 6.8 メートルのシケインを却下し、リード アーキテクトがより広いシケインを提案します。修正されたレイアウトは、ゲートキーパーに届く前に評価者に戻されます。
完了したら、最初のタブで Ctrl+C キーを押して、プレイグラウンドを停止します。2 つ目のタブで Gatekeeper を実行したままにします。これは次のステップで必要になります。
6. 6. エージェントを評価する
agents-cli eval run は、データセットに対してエージェントを実行し、すべてのターンとツール呼び出しを記録して、結果を評価します。tests/eval/eval_config.yaml で測定する対象を決定します。
データセットを確認する
Cloud Shell エディタでデータセットを開きます。
cd ~/track-planner
cloudshell edit tests/eval/datasets/track_eval.json
このファイルには eval_cases のリストが格納されます。各ケースには、eval_case_id、prompt(ユーザーの質問)、reference(適切な回答の例)があります。LLM 判定モデルは、エージェントの回答を基準と比較します。
| テスト内容 |
| すべてのルールに合格して承認された会場 |
| 6.8 m のシケインは幅のルールに違反 |
| 4,350 m の回路は長さのルールに違反している |
| 必須の CAD レイヤが欠落しているレイアウト |
| 目標の 250 kW を下回るブレーキゾーン |
| 医療用 CAD レイヤを必要とする病院アクセス |
| レーシング ライン上のアタックモード ゾーン |
| マルチターンの会話: モナコが不承認となり、ユーザーが修正を求め、修正されたレイアウトが承認される |
最後のケースでは、prompt ではなく agent_data を使用しています。会話の前のターンを再生するため、単一の質問だけでなく、エージェントがフォローアップ リクエストをどのように処理するかをテストできます。
同じフォルダ内の track_eval_quick.json には、ケース 1(1 つの質問)とケース 8(会話)の 2 つのケースのみが含まれています。このクエリは、より高速で、使用する割り当てが少ないため、こちらを実行します。
指標を書き込む
データセットには、エージェントに何を尋ねるかが記載されています。eval_config.yaml には、回答を採点する方法が記載されています。agents-cli eval run は、エージェントがすべてのケースに回答した後にこれを読み取り、各回答に対して各指標を実行します。
スキャフォールドによって生成されたファイルを開きます。
cloudshell edit tests/eval/eval_config.yaml
これには、一般的な LLM 判定(custom_response_quality)と、ターンのみをカウントする agent_turn_count 指標がすでに含まれています。これはエージェントの開始としては問題ありませんが、フォーミュラ E については何も言及していません。ジャッジはそのままにして、このドメインに固有のルールをチェックする指標を追加します。
通常、適切な評価には次の 2 種類の指標が混在しています。
種類 | スコアの算出方法 | 用途 | トレードオフ |
LLM-as-a-judge | モデルが回答とケースの | ファジー品質: 回答は正確、完全、明確か? | ケースごとにモデル呼び出しの費用が発生。実行ごとにスコアが若干異なる場合がある |
コード指標 | 小さな Python 関数が回答をチェックする | 正確で検証可能な事実: 回答に、必ず含まれているべき情報が含まれていましたか。 | コードで表現できることのみをチェックする |
ファイルの内容を次のように置き換えます。
metrics_to_run:
- custom_response_quality
- fia_cad_layer_compliance
custom_metrics:
# LLM-as-a-judge. response_quality.py is generated by `agents-cli scaffold
# create`; it grades the final answer against the case's `reference`.
- name: custom_response_quality
custom_function_file: response_quality.py
# Deterministic code metric: an approved blueprint must name every
# mandatory FIA CAD layer.
- name: fia_cad_layer_compliance
custom_function: |
def evaluate(instance):
response = str(instance.get("response") or "")
reference = str(instance.get("reference") or "")
# Only approvals must list every layer. Rejections and other
# questions (such as Attack Mode) don't, so skip them.
if "APPROVED" not in reference:
return {"score": 1.0, "explanation": "Not an approval case."}
required = [
"F1_TRACK_CENTRELINE",
"F1_PIT_ENTRY_SPEED_LIMIT_LANE",
"F1_WALL_TEMP",
"F1_TEC3",
]
missing = [layer for layer in required if layer not in response]
return {
"score": round(1 - len(missing) / len(required), 2),
"explanation": "Missing: " + (", ".join(missing) or "none"),
}
各部分の役割は次のとおりです。
metrics_to_runには、実行する指標を名前で指定します。ここで名前を削除すると、その指標は削除されずにオフになります。custom_response_qualityは LLM 判定モデルです。custom_function_fileは、スキャフォールドによって生成されたtests/eval/response_quality.pyを指しています。判定プロンプトを表示する場合は、これを開きます。fia_cad_layer_complianceはコード指標で、custom_functionの下にインラインで記述されます。各ケースで、instance(プロンプト、エージェントの最終的なresponse、reference)を受け取ります。期待される回答が承認であるケースでは、回答に 4 つの必須 CAD レイヤがすべて含まれていることを確認し、不足しているレイヤをリストします。たとえば、F1_TEC3を除外したブループリントのスコアは 0.75 です。その他のケースは 1.0 点です。拒否や攻撃モードの回答では、すべてのレイヤを列挙する必要がないためです。
CAD レイヤを確認する理由承認済みのブループリントに必須のレイヤが欠けている場合、読みやすくても不適切であり、LLM 判定者はそれを見落とす可能性があります。コードチェックでは、実行するたびに同じルールが同じ方法で適用されます。
評価を実行する
2 つ目のタブでローカルの Gatekeeper を実行したまま、次のコマンドを実行します。
agents-cli eval run \
--dataset tests/eval/datasets/track_eval_quick.json \
--config tests/eval/eval_config.yaml \
--concurrency 1
ls artifacts/grade_results/
評価には数分かかります。各ケースでは、マルチエージェント フロー全体が実行されます。HIGH の思考に関するリード アーキテクトとのモデル呼び出しが約 10 回行われるため、Step 1/2: eval generate が遅い部分です。スタックしていない。
完了したら、Cloud Shell エディタを使用して artifacts/grade_results/ で HTML レポートを開きます。fia_cad_layer_compliance スコアが低い場合は、リード アーキテクトの最終回答にレイヤが欠落していることを示しています。指示を厳密にして、評価を再度実行してみてください。
7. 7. Gatekeeper を Agent Runtime にデプロイする
Gatekeeper のみをデプロイします。トラック プランナーは Cloud Shell で実行され、それを呼び出します。
新しい Cloud Shell タブを開く
デプロイには 5 ~ 8 分かかるため、ステップ 6 の評価が完了する間に新しいタブでデプロイします。
- Cloud Shell ツールバーの [新しいタブを開く](+)をクリックします。
- 新しいタブではステップ 2 の変数が保持されないため、再度設定します。
export GOOGLE_CLOUD_PROJECT="$(gcloud config get-value project)" export REGION="us-central1" export ASSETS="$HOME/devrel-demos/codelabs/formula-e-track-planner" export PATH="$HOME/.local/bin:$PATH" echo "Project: $GOOGLE_CLOUD_PROJECT Region: $REGION"
2 つ目のタブでローカルの Gatekeeper を実行したままにします。評価では引き続き Gatekeeper が使用されます。デプロイでは Gatekeeper を停止する必要はありません。
デプロイ
新しいタブで、Gatekeeper をデプロイします。プロジェクトの Compute Engine のデフォルト サービス アカウントとして実行されます。
cd ~/gatekeeper
PROJECT_NUMBER=$(gcloud projects describe "$GOOGLE_CLOUD_PROJECT" --format="value(projectNumber)")
agents-cli deploy \
--no-agent-identity \
--service-account "${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--project "$GOOGLE_CLOUD_PROJECT" \
--region "$REGION" \
--no-confirm-project
デプロイには 5 ~ 8 分ほどかかります。実行中は Cloud Shell タブを閉じないでください。ログストリームが切断された場合は、agents-cli deploy --status で進行状況を確認します。待っている間に、ステップ 6 に戻って評価レポートを読んでください。
エージェントの ID を確認する
agents-cli は、デプロイされたリソースを deployment_metadata.json に記録します。
export RUNTIME_ID=$(jq -r .remote_agent_runtime_id ~/gatekeeper/deployment_metadata.json)
echo "$RUNTIME_ID"
curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${RUNTIME_ID}" \
| jq -r .spec.effectiveIdentity
出力の 2 行目は、Gatekeeper が実行される ID です。
デプロイに使用: | 出力例 |
サービス アカウント(デフォルト) |
|
Agent Identity |
|
サービス アカウントは、それを使用するプロジェクト内のすべてのリソースで共有されます。エージェント ID はこの 1 つのエージェントに属しているため、必要なロールを正確に付与し、監査ログでそのアクションを個別に確認できます。
8. 8. A2A 経由でデプロイされた Gatekeeper に接続する
Agent Runtime は、認証済みの /api パスの背後で Gatekeeper が生成した A2A ルートを提供します。
ステップ 6 の評価が完了していることを確認し、2 つ目のタブでローカル Gatekeeper を停止します(Ctrl+C)。今後は、トラック プランナーがデプロイされたものを呼び出します。最初のタブで、トラック プランナーをその場所に向ける。
export RUNTIME_ID=$(jq -r .remote_agent_runtime_id ~/gatekeeper/deployment_metadata.json)
: "${RUNTIME_ID:?No deployed Gatekeeper found. Complete Step 7 first.}"
cd ~/track-planner
echo "GATEKEEPER_A2A_URL=https://${REGION}-aiplatform.googleapis.com/reasoningEngines/v1/${RUNTIME_ID}/api/a2a/app" >> .env
クライアントがトークンを更新する理由
app/auth.py を開きます。Google Cloud アクセス トークンは 1 時間後に期限切れになるため、起動時に固定の Authorization ヘッダーを設定するクライアントは、1 時間後に 401 Unauthorized で失敗し始めます。GoogleAuthRefresh は httpx.Auth のサブクラスであり、リクエストごとに認証情報を確認し、必要に応じて更新します。create_remote_gatekeeper_agent() は、https:// URL にのみ添付します。
エンドツーエンドで実行する
プレイグラウンドを再起動して、新しい GATEKEEPER_A2A_URL を取得します。
agents-cli playground --port 8080
[ウェブでプレビュー] > [ポート 8080 でプレビュー] をクリックし、新しいセッションを開始して、次のように質問します。
Assess the Monaco Harbour layout, widen the chicane to 11m, and get Gatekeeper approval.
イベントはステップ 5 と同じように見えますが、remote_gatekeeper 呼び出しは 2 番目のタブではなく、Agent Runtime の Gatekeeper に送信されます。
Agent Runtime で通話の着信を確認する
リクエストが A2A 経由でデプロイされた Gatekeeper に実際に到達したことを証明します。
- Cloud コンソールで「Agent Platform」を検索し、左側のメニューで [デプロイ] を開きます。
- [gatekeeper] を選択します。
- [セッション] タブを開きます。
ユーザー ID が A2A_USER_ で始まる新しいセッションが表示されます。これは、トラック プランナーが Gatekeeper の A2A サーバーを呼び出したときに作成されたものです。同じページの [トレース] タブを開いて、Gatekeeper のモデル呼び出しと、そのリクエストに対する verify_infrastructure_checklist ツール呼び出しを確認します。
省略可: トラック プランナーもデプロイする
これまでのところ、トラック プランナーは Cloud Shell で実行されているため、Gatekeeper への A2A 呼び出しではユーザーの認証情報が使用されます。プランナーもデプロイし、両方のエージェントが Agent Runtime で実行され、デプロイされた独自の ID で相互に呼び出します。
Ctrl+C キーを押して Playground を停止し、Gatekeeper と同じ方法でプランナーをデプロイします。
cd ~/track-planner
PROJECT_NUMBER=$(gcloud projects describe "$GOOGLE_CLOUD_PROJECT" --format="value(projectNumber)")
agents-cli deploy \
--no-agent-identity \
--service-account "${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--project "$GOOGLE_CLOUD_PROJECT" \
--region "$REGION" \
--no-confirm-project
両方のエージェントは、同じ Compute Engine サービス アカウントとして実行されます。--service-account はそのままにします。これがないと、プランナーは Agent Runtime のデフォルトのサービス エージェントとして実行され、Gatekeeper を呼び出すことができません(ステップ 7 のこのサービス アカウントを使用する理由をご覧ください)。
デプロイされたプランナーが Gatekeeper にアクセスする方法:
agents-cli deployは.envの値をデプロイにコピーするため、プランナーは上記で追加したGATEKEEPER_A2A_URLを取得します。- Agent Runtime 内では、
app/auth.pyのGoogleAuthRefreshが、ユーザーの ID ではなく、プランナーのデプロイされた ID を取得します。
デプロイには 5 ~ 8 分ほどかかります。完了したら、プランナーがどの ID で実行されているかを確認します。
export PLANNER_ID=$(jq -r .remote_agent_runtime_id deployment_metadata.json)
curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${PLANNER_ID}" \
| jq -r .spec.effectiveIdentity
デプロイされたシステムを試すには:
- Cloud コンソールで、[Agent Platform] > [デプロイ] に戻ります。
- [track-planner] を選択し、[Playground] タブを開きます。
- 次のように入力します。
Design and homologate a Formula E circuit at Tokyo Bay. - Gatekeeper の APPROVED ステータスを持つブループリントを待ちます。
- [Deployments] に戻り、[gatekeeper] を選択して [Sessions] タブを開きます。最新の
A2A_USER_セッションは、Cloud Shell ではなく、デプロイされたプランナーから取得されています。
次のステップでクリーンアップを行う際に、プランナーも削除します。
curl -X DELETE -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${PLANNER_ID}?force=true"
9. 9. トラブルシューティングとクリーンアップ
トラブルシューティング
症状 | 修正 |
| Cloud コンソールで利用規約に同意してから、もう一度お試しください。 |
プロジェクトは | ステップ 2 のプロジェクト コマンドを再実行します。 |
|
|
| ステップ 4 を完了するか、 |
| ローカル Gatekeeper を起動するか(ステップ 5)、 |
デプロイ時の | お使いのアカウントではエージェント ID を使用できません。ステップ 7 のクリーンアップ ボックスに沿って操作し、サービス アカウントのデプロイを使用します。 |
デプロイされたトラック プランナーが Gatekeeper から | プランナーの ID には、Gatekeeper を呼び出す権限がありません。ステップ 7 のように |
| Gemini の割り当てに達しました。しばらく待つか、 |
| 他のサーバーを停止するか、別の |
クリーンアップ
デプロイされた Gatekeeper を削除して、実行を継続しないようにします。
export RUNTIME_ID=$(jq -r .remote_agent_runtime_id ~/gatekeeper/deployment_metadata.json)
: "${RUNTIME_ID:?No deployed Gatekeeper found.}"
curl -X DELETE -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://${REGION}-aiplatform.googleapis.com/v1beta1/${RUNTIME_ID}?force=true"
この Codelab 用にプロジェクトを作成した場合は、プロジェクト全体を削除することもできます。イベントに参加している場合は、主催者から指示がない限り、割り当てられたプロジェクトをそのまま使用してください。
学習した内容
agents-cli scaffold createは、デプロイ可能な標準の ADK プロジェクトを提供します。エージェント、スキル、評価を記述するだけで済みます。- エージェント スキルは、エージェントが必要とするまで、ドメイン知識をプロンプトから除外します。
thinking_levelを使用すると、エージェントごとに推論の深さと速度をトレードオフできます。agents-cli eval runは、「機能しているか」を追跡可能なスコアに変換します。- エージェント ID と A2A により、独立してデプロイされたエージェントが安全に連携できます。