1. はじめに
このハンズオン セッションでは、基本的なステートレス チャットボットから一歩進んで、Gemini を活用した AI エージェントである Smart Cafe Concierge を作成します。これは、フレンドリーなバリスタとして機能します。セッション状態に記録されたコーヒーの注文を取得し、ユーザー スコープ状態の長期的な食事の好みを記憶し、すべてを Cloud SQL PostgreSQL データベースに永続化します。最終的に、エージェントはアプリケーションを再起動して新しい会話を開始した後でも、あなたが乳糖不耐症であることを記憶しています。
構築するシステム アーキテクチャ

前提条件
- トライアルの請求先アカウントを含む Google Cloud アカウント
- Python に関する基本的な知識
- ADK、AI エージェント、Cloud SQL の使用経験は不要です
学習内容
- カスタムツールを使用して Google の Agent Development Kit(ADK)で AI エージェントを作成する
ToolContextを介してセッション状態を読み書きするツールを定義する- セッション スコープの state とユーザー スコープの state(
user:接頭辞)を区別する - Cloud SQL PostgreSQL インスタンスをプロビジョニングし、Cloud Shell から接続する
- ローカル ストレージ(
adk webコマンドを使用する場合のデフォルト)から、専用データベースを使用した永続ストレージのDatabaseSessionServiceに移行する - エージェントのメモリがアプリケーションの再起動や個別の会話セッションをまたいで保持されることを確認する
必要なもの
- 動作するパソコンと安定したインターネット接続。
- Google Cloud コンソールにアクセスするためのブラウザ(Chrome など)
- 好奇心と学習意欲がある。
2. 環境をセットアップする
このステップでは、Cloud Shell 環境を準備し、Google Cloud プロジェクトを構成します。
Cloud Shell を開く
ブラウザで Cloud Shell を開きます。Cloud Shell には、この Codelab で必要なすべてのツールがプリインストールされた環境が用意されています。プロンプトが表示されたら、[Authorize] をクリックします。
インターフェースは次のようになります。

これがメイン インターフェースになります。上部に IDE、下部にターミナルが表示されます。
作業ディレクトリを設定する
作業ディレクトリを作成します。この Codelab で作成するすべてのコードは、参照リポジトリとは別に、ここに保存されます。
# Create your working directory
mkdir -p ~/build-agent-adk-cloudsql
# Change cloudshell workspace and working directory into previously created dir
cloudshell workspace ~/build-agent-adk-cloudsql && cd ~/build-agent-adk-cloudsql
ターミナルを生成するには、[View] -> [Terminal] を探します。

Google Cloud プロジェクトと初期環境変数を設定する
プロジェクト設定スクリプトを作業ディレクトリにダウンロードします。
curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh
スクリプトを実行します。トライアルの請求先アカウントを確認し、新しいプロジェクトを作成(または既存のプロジェクトを検証)し、プロジェクト ID を現在のディレクトリの .env ファイルに保存し、ターミナルでアクティブ プロジェクトを設定します。
bash setup_verify_trial_project.sh && source .env
このコマンドを実行すると、プロジェクト ID 名の候補が表示されます。Enter を押して続行します。

しばらく待ってから、コンソールに次の出力が表示されたら、次のステップ
に進む準備が整いました。
実行されたスクリプトは次の手順を行います。
- 有効なトライアルの請求先アカウントがあることを確認する
.envに既存のプロジェクトがあるかどうかを確認します(ある場合)。- 新しいプロジェクトを作成するか、既存のプロジェクトを再利用する
- トライアルの請求先アカウントをプロジェクトにリンクする
- プロジェクト ID を .env に保存する
- プロジェクトをアクティブな gcloud プロジェクトとして設定する
Cloud Shell ターミナルのプロンプトで、作業ディレクトリの横にある黄色のテキストを確認して、プロジェクトが正しく設定されていることを確認します。プロジェクト ID が表示されます。

必要な API を有効にする
この Codelab に必要な Google Cloud APIs を有効にします。
gcloud services enable \
aiplatform.googleapis.com \
sqladmin.googleapis.com \
compute.googleapis.com
- Vertex AI API(
aiplatform.googleapis.com)- エージェントは Vertex AI を介して Gemini モデルを使用します。 - Cloud SQL Admin API(
sqladmin.googleapis.com) - 永続ストレージ用の PostgreSQL インスタンスをプロビジョニングして管理します。 - Compute Engine API(
compute.googleapis.com)- Cloud SQL インスタンスの作成に必要です。
Gemini と Cloud プロダクトのリージョンを構成する
続行する前に、操作するプロダクトに必要なロケーション/リージョン構成も設定しましょう。.env ファイルに次の構成を追加します。
# This is for our Gemini endpoint
echo "GOOGLE_CLOUD_LOCATION=global" >> .env
# This is for our other Cloud products
echo "REGION=us-central1" >> .env
source .env
次のステップに進みましょう
3. Cloud SQL を設定する
このステップでは、Cloud SQL PostgreSQL インスタンスをプロビジョニングし、エージェントをインメモリからデータベース バックアップ ストレージに切り替えます。インスタンスの作成には数分かかるため、まずインスタンスの作成を開始します。作成が完了するまで、次のトピックについて話し合うことができます。
インスタンスの作成を開始する
データベースのパスワードを .env ファイルに追加して再読み込みします。パスワードには cafe-agent-pwd-2025 を使用します。
echo "DB_PASSWORD=cafe-agent-pwd-2025" >> .env
source .env
このコマンドを実行して、Cloud SQL PostgreSQL インスタンスを作成します。完了するまでに数分かかります。実行したまま次のセクションに進んでください。
gcloud sql instances create cafe-concierge-db \
--database-version=POSTGRES_17 \
--edition=ENTERPRISE \
--region=${REGION} \
--availability-type=ZONAL \
--project=${GOOGLE_CLOUD_PROJECT} \
--tier=db-f1-micro \
--root-password=${DB_PASSWORD} \
--quiet &
上記のコマンドに関する注意事項は次のとおりです。
db-f1-microは最小(かつ最も安価)の Cloud SQL 階層であり、この Codelab には十分です。--root-passwordは、デフォルトの postgres ユーザーのパスワードを設定します。- コマンドの接尾辞
&は、コマンドをバックグラウンドで実行して、作業を継続できるようにします。
プロセスはバックグラウンドで実行されますが、コンソール出力は現在のターミナルに表示されることがあります。Cloud Shell で新しいターミナルタブを開き(+ アイコンをクリック)、集中できるようにしましょう。

作業ディレクトリに再度移動し、以前のセットアップ スクリプトを使用してプロジェクトを有効にします。
cd ~/build-agent-adk-cloudsql
bash setup_verify_trial_project.sh && source .env
それでは、次のセクションに進みましょう。
4. カフェ コンシェルジュ エージェントを構築する
この手順では、ADK エージェントのプロジェクト構造を作成し、メニュー ツールを含む基本的な Cafe Concierge を定義します。
Python プロジェクトを初期化する
このコードラボでは、1 つのツールで仮想環境と依存関係を処理する高速 Python パッケージ マネージャーである uv を使用します。Cloud Shell にプリインストールされています。
Python プロジェクトを初期化し、ADK を依存関係として追加します。
uv init
uv add google-adk==1.25.0 asyncpg
uv init は pyproject.toml と仮想環境を作成します。uv add は依存関係をインストールし、pyproject.toml に記録します。
エージェント プロジェクト構造を初期化する
ADK では、特定フォルダ レイアウトが想定されています。エージェント ディレクトリ内に __init__.py、agent.py、.env を含む、エージェントの名前が付けられたディレクトリ
ADK には、この設定をすばやく行うためのコマンドが組み込まれています。次のコマンドを実行します。
uv run adk create cafe_concierge \
--model gemini-2.5-flash \
--project ${GOOGLE_CLOUD_PROJECT} \
--region ${GOOGLE_CLOUD_LOCATION}
このコマンドは、gemini-2.5-flash をブレインとするエージェント構造を作成します。ディレクトリは次のようになります。
build-agent-adk-cloudsql/ ├── cafe_concierge/ │ ├── __init__.py │ ├── agent.py │ └── .env ├── pyproject.toml ├── .env ├── .venv/ └── ...
エージェントを作成する
Cloud Shell エディタで cafe_concierge/agent.py を開く
cloudshell edit cafe_concierge/agent.py
次のコードでファイルを上書きします。
# cafe_concierge/agent.py
from google.adk.agents import LlmAgent
from google.adk.tools import ToolContext
CAFE_MENU = {
"espresso": {
"price": 3.50,
"description": "Rich and bold single shot",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"latte": {
"price": 5.00,
"description": "Espresso with steamed milk",
"tags": ["gluten-free"],
},
"oat milk latte": {
"price": 5.50,
"description": "Espresso with steamed oat milk",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"cappuccino": {
"price": 4.50,
"description": "Espresso with equal parts steamed milk and foam",
"tags": ["gluten-free"],
},
"cold brew": {
"price": 4.00,
"description": "Slow-steeped for 12 hours, served over ice",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"matcha latte": {
"price": 5.50,
"description": "Ceremonial grade matcha with steamed milk",
"tags": ["gluten-free"],
},
"croissant": {
"price": 3.00,
"description": "Buttery, flaky French pastry",
"tags": [],
},
"banana bread": {
"price": 3.50,
"description": "Homemade with walnuts",
"tags": ["vegan"],
},
}
def get_menu() -> dict:
"""Returns the full cafe menu with prices, descriptions, and dietary tags.
Use this tool when the customer asks what's available, wants to see
the menu, or asks about specific items.
"""
return CAFE_MENU
root_agent = LlmAgent(
name="cafe_concierge",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable barista at "The Cloud Cafe".
Your job:
- Help customers browse the menu and answer questions about items.
- Take coffee and food orders.
- Remember and respect dietary preferences.
Be conversational, warm, and concise. If a customer mentions a dietary
restriction, acknowledge it and suggest suitable options from the menu.
""",
tools=[get_menu],
)
これは、1 つのツール(get_menu())を持つ基本的なエージェントを定義します。エージェントはメニューに関する質問には回答できますが、注文の追跡や好みの記憶はまだできません。
エージェントが実行されていることを確認する
作業ディレクトリから ADK 開発 UI を起動します。
cd ~/build-agent-adk-cloudsql
uv run adk web
Cloud Shell のウェブ プレビュー機能を使用して、ターミナルに表示された URL(通常は http://localhost:8000)を開きます。左上隅のエージェント プルダウンから cafe_concierge を選択します。
チャットバーに次のテキストを入力し、エージェントがメニュー項目と価格で応答することを確認します。
What's on the menu?

続行する前に、Ctrl+C キーを押して開発 UI を停止します。
5. ステートフル注文管理を追加する
エージェントはメニューを表示できますが、注文を受け付けたり、設定を記憶したりすることはできません。このステップでは、ADK の状態システムを使用して会話内の注文を追跡し、会話間で食事の好みを保存する 4 つのツールを追加します。
セッション イベントと状態について
ADK のすべての会話は Session オブジェクト内に存在します。セッションでは、イベントと状態という 2 つの異なるものがトラッキングされます。この違いを理解することは、正しいことを正しい方法で記憶するエージェントを構築するうえで重要です。
イベントは、会話で発生したすべての出来事を時系列で記録したものです。すべてのユーザー メッセージ、すべてのエージェント レスポンス、すべてのツール呼び出しとその戻り値は、それぞれ Event として記録され、セッションのイベント リストに追加されます。イベントは不変です。記録されたイベントは変更されません。イベントは会話の完全な文字起こしと考えることができます。
状態は、エージェントが会話中に読み取りと書き込みを行う Key-Value スクラッチパッドです。イベントとは異なり、状態は可変です。会話の進行に合わせて値が変化します。状態とは、エージェントがアクションに必要な構造化データを保存する場所です。現在の注文、顧客の好み、合計金額などです。状態は、エージェントがトランスクリプトの横に貼っておく付箋のようなものと考えることができます。
両者の関係は次のとおりです。

ツールは、ToolContext を介して状態を読み書きします。ToolContext は、パラメータとして宣言するツール関数に ADK が自動的に挿入するオブジェクトです。自分で作成することはありません。tool_context.state を使用すると、ツールはセッションの状態スクラッチパッドの読み取りと書き込みを行うことができます。ADK は関数シグネチャを検査します。型 ToolContext のパラメータは挿入され、他のすべてのパラメータは会話に基づいて LLM によって入力されます。
ツールが tool_context.state に書き込むと、ADK はその変更をイベント内の state_delta として記録します。次に、SessionService はセッションの現在の状態に差分を適用します。つまり、状態の変化は常に、その原因となったイベントまで追跡できます。これは、callback_context などの他の形式のコンテキストにも当てはまります。
状態接頭辞について
状態キーは接頭辞を使用してスコープを制御します。
接頭辞 | スコープ | 再起動後も保持されるか?(DB あり) |
(なし) | 現在のセッションのみ | はい |
| このユーザーのすべてのセッション | はい |
| すべてのセッション、すべてのユーザー | はい |
| 現在の呼び出しのみ | いいえ |
この Codelab では、セッション スコープのデータ(現在の注文 - この会話にのみ関連)の接頭辞なしのキーと、ユーザー スコープのデータ(食事の好み - このユーザーのすべての会話に関連)の user: キーの 2 つの接頭辞を使用します。
ステートフル ツールを追加する
Cloud Shell エディタで cafe_concierge/agent.py を開きます。
cloudshell edit cafe_concierge/agent.py
次に、root_agent 定義の上に次の 4 つの関数を追加します。
# cafe_concierge/agent.py (add below get_menu, above root_agent)
def place_order(tool_context: ToolContext, items: list[str]) -> dict:
"""Places an order for the specified menu items.
Use this tool when the customer confirms they want to order something.
Args:
tool_context: Provided automatically by ADK.
items: A list of menu item names the customer wants to order.
"""
valid_items = []
invalid_items = []
total = 0.0
for item in items:
item_lower = item.lower()
if item_lower in CAFE_MENU:
valid_items.append(item_lower)
total += CAFE_MENU[item_lower]["price"]
else:
invalid_items.append(item)
if not valid_items:
return {"error": f"None of these items are on our menu: {invalid_items}"}
order = {"items": valid_items, "total": round(total, 2)}
tool_context.state["current_order"] = order
result = {"order": order}
if invalid_items:
result["warning"] = f"These items are not on our menu: {invalid_items}"
return result
def get_order_summary(tool_context: ToolContext) -> dict:
"""Returns the current order summary for this session.
Use this tool when the customer asks about their current order,
wants to review what they ordered, or asks for the total.
Args:
tool_context: Provided automatically by ADK.
"""
order = tool_context.state.get("current_order")
if order:
return {"order": order}
return {"message": "No order has been placed yet in this session."}
def set_dietary_preference(tool_context: ToolContext, preference: str) -> dict:
"""Saves a dietary preference that persists across all conversations.
Use this tool when the customer mentions a dietary restriction or
preference (e.g., "I'm vegan", "I'm lactose intolerant",
"I have a nut allergy").
Args:
tool_context: Provided automatically by ADK.
preference: The dietary preference to save (e.g., "vegan",
"lactose intolerant", "nut allergy").
"""
existing = tool_context.state.get("user:dietary_preferences", [])
if not isinstance(existing, list):
existing = []
preference_lower = preference.lower().strip()
if preference_lower not in existing:
existing.append(preference_lower)
tool_context.state["user:dietary_preferences"] = existing
return {
"saved": preference_lower,
"all_preferences": existing,
}
def get_dietary_preferences(tool_context: ToolContext) -> dict:
"""Retrieves the customer's saved dietary preferences.
Use this tool when you need to check the customer's dietary
restrictions before making recommendations.
Args:
tool_context: Provided automatically by ADK.
"""
preferences = tool_context.state.get("user:dietary_preferences", [])
if preferences:
return {"preferences": preferences}
return {"message": "No dietary preferences saved yet."}
次の 2 点に注意してください。
place_orderとget_order_summaryは、接頭辞のないキー(current_order)を使用します。この状態は現在のセッションに関連付けられています。新しい会話は空の注文で始まります。set_dietary_preferenceとget_dietary_preferencesはuser:プレフィックス(user:dietary_preferences)を使用します。この状態は、同じユーザーのすべてのセッションで共有されます。
新しいツールと手順でエージェントを更新する
ファイルの下部にある既存の root_agent 定義を次のように置き換えます。
# cafe_concierge/agent.py (replace the existing root_agent)
root_agent = LlmAgent(
name="cafe_concierge",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable barista at "The Cloud Cafe".
Your job:
- Help customers browse the menu and answer questions about items.
- Take coffee and food orders.
- Remember and respect dietary preferences.
The customer's saved dietary preferences are: {user:dietary_preferences?}
IMPORTANT RULES:
- When a customer mentions a dietary restriction, ALWAYS save it using the
set_dietary_preference tool before doing anything else.
- Before recommending items, check the customer's dietary preferences. If they
have preferences saved, only recommend items compatible with those
restrictions. Check the menu item tags to determine compatibility.
- When placing an order, confirm the items and total with the customer.
Be conversational, warm, and concise.
""",
tools=[
get_menu,
place_order,
get_order_summary,
set_dietary_preference,
get_dietary_preferences,
],
)
この手順では、状態挿入テンプレート {user:dietary_preferences?} を使用して、この顧客の保存済み設定をプロンプトに直接挿入します。
完全なファイルを確認する
cafe_concierge/agent.py には次のものが含まれます。
CAFE_MENU辞書- 5 つのツール関数:
get_menu、place_order、get_order_summary、set_dietary_preference、get_dietary_preferences - 5 つのツールすべてを含む
root_agent定義
6. ADK 開発 UI でエージェントをテストする
このステップでは、エージェントを実行し、順序付け、設定の追跡、クロスセッション メモリ(同じプロセス内)など、すべてのステートフル機能をテストします。また、[Events] パネルと [State] パネルを調べて、ADK が会話を内部的に追跡する方法を確認します。
開発 UI を起動する
cd ~/build-agent-adk-cloudsql
uv run adk web
ポート 8000 でウェブ プレビューを開き、プルダウンから cafe_concierge を選択します。
会話 1: 注文して設定を行う
次のプロンプトを順番に試してください。
What's on the menu?
I'm lactose intolerant
What would you recommend?
I'll have an oat milk latte and a banana bread
What's my order?
セッション イベントを検査する
すべてのイベントがキャプチャされ、ウェブ UI に表示されます。チャットボックスには、プロンプトとレスポンスだけでなく、tool_call と tool_response も表示されます。

イベントのリストが順番に表示されます。各イベントには、作成者(イベントを生成したユーザー)とタイプ(イベントが表すインタラクションの種類)があります。
著者 | 型 | 意味 |
|
| チャットで入力したメッセージ |
|
| エージェントのテキスト レスポンス |
|
| エージェントがツールを呼び出すことを決定した(関数名と引数が表示される) |
|
| ツール呼び出しからの戻り値 |
tool_call イベント(set_dietary_preference 呼び出しなど)のいずれかをクリックします。以下のように表示されます。
- 関数名:
set_dietary_preference - Arguments:
{"preference": "lactose intolerant"}
次に、その直下の対応する tool_response イベントをクリックします。戻り値が表示されます。
- 回答:
{"saved": "lactose intolerant", "all_preferences": ["lactose intolerant"]}

tool_response イベント内で state_delta フィールドを探します。これにより、このツール呼び出しの結果としてどの状態が変化したかが正確に示されます。
state_delta: {"user:dietary_preferences": ["lactose intolerant"]}
すべての状態変化は特定のイベントに追跡できます。このようにして、ADK は状態スクラッチパッドが会話履歴と同期されるようにします。
セッションの状態を検査する
[State] タブをクリックします。イベントログ(履歴全体を表示)とは異なり、[状態] タブには、エージェントが現在認識している内容のスナップショット(すべての状態キーの現在の値)が表示されます。

次の 2 つのエントリが表示されます。
current_order—{"items": ["oat milk latte", "banana bread"], "total": 9.0}user:dietary_preferences—["lactose intolerant"]
キー名の違いに注目してください。
current_orderには接頭辞がありません。セッション スコープです。この会話でのみ存在し、セッションが終了すると消えます。user:dietary_preferencesにはuser:接頭辞が付いています。これはユーザー スコープです。このユーザーのすべてのセッションで共有されます。
この区別はコードでは見えませんが(どちらも tool_context.state を使用)、データの到達範囲を制御します。これは次のテストで確認できます。
会話 2: セッション間のユーザーの状態を確認する
開発 UI の [New Session] ボタンをクリックして、新しい会話を開始します。これにより、同じユーザーの新しいセッションが作成されます。

次のプロンプトを試してみましょう。
What do you recommend for me?
新しいセッションの [状態] タブを確認します。user:dietary_preferences キーは引き継がれますが、current_order はなくなります。この状態は前のセッションに関連付けられていました。

7. ローカル ストレージの制限を監視する
エージェントはセッション間で設定を記憶しますが、ローカル ストレージが存在する場合に限ります。この手順は、ローカル ストレージの基本的な制限を示しています。
エージェントを再度起動する
前の手順の最後に開発 UI を停止しました。ローカル ストレージを削除して再起動し、ステートレスなサーバーレス環境をシミュレートします。
cd ~/build-agent-adk-cloudsql
rm -f cafe_concierge/.adk/session.db
uv run adk web
ポート 8000 でウェブ プレビューを開き、cafe_concierge を選択します。
設定の再呼び出しをテストする
タイプ:
Do you remember my dietary preferences?
エージェントは覚えていません。食事の好みや注文履歴など、すべて消えてしまいました。

ローカル ストレージを削除すると、すべてが完全に消去されました。これは通常、サーバーレス環境を使用するときに発生します。session.db は、すべての状態をプロセス メモリに保存します。削除すると、すべてが消去されます。
解決策: DatabaseSessionService を指定します。このチュートリアルでは、すべてのセッション データが Cloud SQL の PostgreSQL データベースに保存されます。エージェント コードとツールはまったく同じで、ストレージ バックエンドのみが変更されます。
続行する前に、Ctrl+C キーを押して開発 UI を停止します。
8. データベースの設定を再確認する
この時点で、データベース インスタンスの作成はすでに完了しているはずです。確認するには、次のコマンドを実行します。
gcloud sql instances describe cafe-concierge-db --format="value(state)"
次の出力が表示されます。完了としてマークします。
RUNNABLE
データベースを作成する
エージェントのセッション データ専用のデータベースを作成します。
gcloud sql databases create agent_db --instance=cafe-concierge-db
Cloud SQL Auth Proxy を起動する
Cloud SQL Auth Proxy は、IP アドレスをホワイトリストに登録しなくても、Cloud Shell から Cloud SQL インスタンスへの安全な認証済み接続を提供します。Cloud Shell にはすでにプリインストールされています。
cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &
コマンドの & 接尾辞により、プロキシがバックグラウンドで実行されます。次のように、プロキシの準備が完了したことを確認する出力が表示されます。
[your-project-id:your-region:cafe-concierge-db] Listening on 127.0.0.1:5432 The proxy has started successfully and is ready for new connections!
接続を確認する
プロキシ経由でデータベースに接続できることをテストします。
psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "SELECT 'Connection ok' AS status;"
以下のように表示されます。
status --------------------- Connection ok (1 row)
9. セッション間で永続メモリを確認する
このステップでは、cafe_concierge/.adk/session_db(ローカル データベース)が削除され、会話セッションにまたがっていることを確認することで、エージェントのメモリがリセット後も保持されることを証明します。
エージェントを起動する
Cloud SQL Auth Proxy がまだ実行されていることを確認します(ジョブで確認します)。そうでない場合は、再起動します。
if ss -tlnp | grep -q ':5432 '; then
echo "Cloud SQL Auth Proxy is already running."
else
cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &
fi
次に、データベースをセッション サービスとして指定して ADK 開発 UI を起動します。
uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db
ポート 8000 でウェブ プレビューを開き、cafe_concierge を選択します。
テスト 1: 注文して設定を指定する
最初のセッションで、次のプロンプトを実行します。
Show me the menu
I'm vegan
What can I eat?
I'll have a cold brew and banana bread
テスト 2: 再起動を乗り切る
Ctrl+C でデベロッパー UI を停止し、ローカル session.db が削除されていることを確認します。
rm -f cafe_concierge/.adk/session.db
その後、開発 UI サーバーを再実行します。
uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db
ポート 8000 でウェブ プレビューを開き、cafe_concierge を選択して新しいセッションを開始します。次に、
What are my dietary preferences?
エージェントは、保存された設定(ビーガン)で応答します。データはローカル ストレージではなく PostgreSQL に保存されるようになったため、再起動後もデータは残ります。user: 状態はこのユーザーの新しいセッションごとに引き継がれるため、新しいセッションを作成した場合も同様です。

データベースを直接検査する
Cloud Shell で新しいターミナル タブを開き、データベースにクエリを実行して保存されたデータを表示します。
psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "\dt"
ADK がセッション、イベント、状態を保存するために自動的に作成したテーブルが、次の例のように表示されます。
List of relations Schema | Name | Type | Owner --------+-----------------------+-------+---------- public | adk_internal_metadata | table | postgres public | app_states | table | postgres public | events | table | postgres public | sessions | table | postgres public | user_states | table | postgres (5 rows)
状態の動作の概要
状態キー | 接頭辞 | スコープ | セッション間で共有されますか? |
| (なし) | セッション | いいえ |
|
| ユーザー | はい |
10. おめでとうございます / クリーンアップ
おめでとうございます!ADK と Cloud SQL を使用して、永続的でステートフルな AI エージェントを構築できました。
学習した内容
- セッションの状態を読み書きするカスタムツールを使用して ADK エージェントを作成する方法
- セッション スコープの状態(プレフィックスなし)とユーザー スコープの状態(
user:プレフィックス)の違い - デフォルトの adk local
session.dbが開発にのみ適している理由 - 削除時にすべてのデータが失われる(削除が簡単でバックアップがない)、ステートレスなサーバーレス デプロイには適していない - Cloud SQL PostgreSQL インスタンスをプロビジョニングして Cloud SQL Auth Proxy で接続する方法
- 最小限のコード変更で CloudSQL の PostgreSQL を使用して DatabaseSessionService に接続する方法 - 同じツール、同じエージェント、異なるバックエンド
- ユーザー スコープの状態が個別の会話セッション間でどのように保持されるか
クリーンアップ
Google Cloud アカウントに課金されないようにするには、この Codelab で作成したリソースをクリーンアップします。
オプション 1: プロジェクトを削除する(推奨)
最も簡単にクリーンアップするには、プロジェクトを削除します。これにより、プロジェクトに関連付けられているすべてのリソースが削除されます。
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
オプション 2: 個々のリソースを削除する
プロジェクトを保持し、この Codelab で作成したリソースのみを削除する場合は:
gcloud sql instances delete cafe-concierge-db --quiet