1. はじめに
このラボでは、クライアント エージェント サービスの実装とデプロイに焦点を当てます。Agent Development Kit(ADK)を使用して、ラボ 1 で作成した MCP サーバーなどのリモートツールを使用する AI エージェントを構築します。ここで重要なのが、アーキテクチャの基本原則である「責任の分担」です。これは、安全な API を介して推論レイヤ(エージェント)が、明確に分離されたツールレイヤ(MCP サーバー)と通信する仕組みによって実現します。
ラボ 1 では、Gemini CLI などを使用する際に、架空の動物園に登場する動物データを LLM に提供する MCP サーバーを作成しました。このラボでは、架空の動物園のツアーガイド エージェントを構築します。エージェントは、ラボ 1 の同じ MCP サーバーを使用して動物園の動物に関する詳細情報にアクセスし、Wikipedia の情報も使用して、優れたツアーガイド体験を実現します。

最後に、ツアーガイド エージェントを Google Cloud Run にデプロイします。これにより、ローカルで実行するだけでなく、動物園のすべての来園者がアクセスできるようになります。
前提条件
- Cloud Run で実行中の MCP サーバー、またはその関連サービスの URL。
- 課金が有効になっている Google Cloud プロジェクト。
学習内容
- ADK デプロイ用に Python プロジェクトを構造化する方法。
- google-adk を使って、ツールを使用するエージェントを実装する方法。
- エージェントをリモートの MCP サーバーに接続してツールセットを利用する方法。
- Python アプリケーションをサーバーレス コンテナとして Cloud Run にデプロイする方法。
- IAM ロールを使用して、サービス間の安全な認証を構成する方法。
- Cloud リソースを削除して、今後の費用発生を回避する方法。
必要なもの
- Google Cloud アカウントと Google Cloud プロジェクト
- ウェブブラウザ(Chrome など)
2. Cloud Run にデプロイする理由
Cloud Run はサーバーレス プラットフォームであり、ADK エージェントのホスティングに最適です。基盤となるインフラストラクチャを管理する必要がないため、開発者はコードに集中できます。運用作業は Google が行います。
ポップアップ ショップのように、顧客(リクエスト)が来たときにのみオープンしてリソースを使用します。顧客がいないときは完全に閉店します。そのため、使用していないリソースに対して料金は発生しません。
主な機能
コンテナをどこでも実行可能:
- アプリを格納したコンテナ(Docker イメージ)を用意します。
- Cloud Run は Google のインフラストラクチャ上でコンテナを実行します。
- OS のパッチ適用、VM の設定、スケーリングなどの管理作業から解放されます。
自動スケーリング:
- アプリのユーザーが 0 人の場合 → 実行中のインスタンスは 0 となり、インスタンスがゼロにスケールダウンされるため、費用対効果が高くなります。
- リクエスト数が 1,000 件になった場合 → 必要に応じてコピーがスピンアップされます。
デフォルトでステートレス:
- 各リクエストは異なるインスタンスに送信される場合があります。
- ステートを保存する必要がある場合は、Cloud SQL、Firestore、Memorystore などの外部サービスを使用します。
あらゆる言語やフレームワークをサポート:
- Cloud Run では、Linux コンテナで実行能であれば、Python、Go、Node.js、Java、.Net など、あらゆる言語やフレームワークを利用できます。
従量課金制:
- リクエストベースの課金: リクエスト数とコンピューティング時間(100 ミリ秒単位)に基づいて課金されます。
- インスタンス ベースの課金: インスタンスのライフサイクル全体に対して課金されます(リクエストごとの料金は発生しません)。
3. 設定と要件
セルフペース型の環境設定
- Google Cloud Console にログインして、プロジェクトを新規作成するか、既存のプロジェクトを再利用します。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。



- プロジェクト名は、このプロジェクトの参加者に表示される名称です。Google API では使用されない文字列です。いつでも更新できます。
- プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Cloud コンソールでは一意の文字列が自動生成されます。通常は、この内容を意識する必要はありません。ほとんどの Codelab では、プロジェクト ID(通常は
PROJECT_IDと識別されます)を参照する必要があります。生成された ID が好みではない場合は、ランダムに別の ID を生成できます。または、ご自身で試して、利用可能かどうかを確認することもできます。このステップ以降は変更できず、プロジェクトを通して同じ ID になります。 - なお、3 つ目の値として、一部の API が使用するプロジェクト番号があります。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
- 次に、Cloud のリソースや API を使用するために、Cloud コンソールで課金を有効にする必要があります。この Codelab の操作をすべて行って、費用が生じたとしても、少額です。このチュートリアルの終了後に請求が発生しないようにリソースをシャットダウンするには、作成したリソースを削除するか、プロジェクトを削除します。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。
Cloud Shell の起動
Cloud Shell エディタに移動します。
ターミナルが画面の下部に表示されない場合は、開きます。
- [Terminal] をクリックします。
- [New Terminal] をクリックします。

ターミナルで、次のコマンドを使用してプロジェクトを設定します。ラボ 1 を完了している場合は、同じプロジェクト ID を使用していることを確認します。
gcloud config set project [YOUR-PROJECT-ID]
プロジェクト ID がわからない場合は、次のコマンドでプロジェクト ID をすべて一覧表示できます。
gcloud projects list | awk '/PROJECT_ID/{print $2}'
4. 承認を求められたら、[承認] をクリックして続行します。

5. 次のようなメッセージが表示されます。
Updated property [core/project].
If you see a `WARNING` and are asked `Do you want to continue (Y/n)?`,
then you have likely entered the project ID incorrectly. Press `n`,
press `Enter`, and try to run the `gcloud config set project` command again.
4. 始める前に
API を有効にして環境変数を設定する
必要なサービスをすべて有効にします。
gcloud services enable \
run.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com \
aiplatform.googleapis.com \
compute.googleapis.com
想定される出力
Operation "operations/acat.p2-[GUID]" finished successfully.
5. プロジェクト フォルダを作成する
プロジェクト ディレクトリを作成します。
このコマンドにより、エージェントのソースコード用メインフォルダがラボに作成されます。
cd && mkdir zoo_guide_agent && cd zoo_guide_agent
requirements.txt ファイルを作成します。このファイルには、エージェントに必要な Python ライブラリがリストされています。次のコマンドは、ファイルを作成してデータを入力します。
cloudshell edit requirements.txt
google-adk==1.14.0
langchain-community==0.3.27
wikipedia==1.4.0
現在のプロジェクト ID とプロジェクト番号の変数を設定し、プロジェクト専用のサービス アカウントを作成します。これは、これらのコマンドを実行するより堅牢な方法です。
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export SA_NAME=lab2-cr-service
export SERVICE_ACCOUNT="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud iam service-accounts create ${SA_NAME} \
--display-name="Service Account for lab 2 "
zoo_guide_agent ディレクトリ内のエージェントを認証するための .env ファイルを作成して開きます。
cloudshell edit .env
cloudshell edit コマンドを実行すると、ターミナルの上のエディタで .env ファイルが開きます。.env ファイルに以下を入力して、ターミナルに戻ります。
MODEL="gemini-2.5-flash"
MCP サーバーの URL を追加します。ラボ 1 を完了している場合は、次の手順でラボ 1 で作成した MCP サーバーを使用します。
- Cloud Run サービス ID にリモート MCP サーバーを呼び出す権限を付与する
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/run.invoker"
- ラボ 1 の MCP サーバー URL を環境変数に保存します。
echo -e "\nMCP_SERVER_URL=https://zoo-mcp-server-${PROJECT_NUMBER}.europe-west1.run.app/mcp" >> .env
パブリック MCP サーバーリンクを使用している場合、次のコマンドを実行し、PROJECT_NUMBER を提供されたものに置き換えます。
echo -e "\nMCP_SERVER_URL=https://zoo-mcp-server-${PROJECT_NUMBER}.europe-west1.run.app/mcp" >> .env
6. エージェントのワークフローを作成する
init.py ファイルを作成する
init.py ファイルを作成します。このファイルは、zoo_guide_agent ディレクトリが Python パッケージであることを Python に伝えます。
cloudshell edit __init__.py
上記のコマンドを実行すると、コードエディタが開きます。__init__.py に次のコードを追加します。
from . import agent
メインの agent.py ファイルを作成する
メインの agent.py ファイルを作成します。このコマンドは、Python ファイルを作成し、マルチエージェント システムの完全なコードを貼り付けます。
cloudshell edit agent.py
ステップ 1: インポートと初期設定
最初のブロックでは、ADK と Google Cloud から必要なライブラリをすべて取り込みます。また、ロギングを設定し、.env ファイルから環境変数を読み込みます。これは、モデルやサーバーの URL にアクセスするために必要です。
次のコードを agent.py ファイルに追加します。
import os
import logging
import google.cloud.logging
from dotenv import load_dotenv
from google.adk import Agent
from google.adk.agents import SequentialAgent
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StreamableHTTPConnectionParams
from google.adk.tools.tool_context import ToolContext
from google.adk.tools.langchain_tool import LangchainTool
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
import google.auth
import google.auth.transport.requests
import google.oauth2.id_token
# --- Setup Logging and Environment ---
cloud_logging_client = google.cloud.logging.Client()
cloud_logging_client.setup_logging()
load_dotenv()
model_name = os.getenv("MODEL")
ステップ 2: ツール(エージェントの機能)を定義する

エージェントの機能は、使用できるツールによって決まります。このセクションでは、データを保存するカスタム関数、セキュアな MCP サーバーに接続する MCP ツール、Wikipedia ツールなど、エージェントが利用できるすべての機能を定義します。
次のコードを agent.py の末尾に追加します。
# Greet user and save their prompt
def add_prompt_to_state(
tool_context: ToolContext, prompt: str
) -> dict[str, str]:
"""Saves the user's initial prompt to the state."""
tool_context.state["PROMPT"] = prompt
logging.info(f"[State updated] Added to PROMPT: {prompt}")
return {"status": "success"}
# Configuring the MCP Tool to connect to the Zoo MCP server
mcp_server_url = os.getenv("MCP_SERVER_URL")
if not mcp_server_url:
raise ValueError("The environment variable MCP_SERVER_URL is not set.")
def get_id_token():
"""Get an ID token to authenticate with the MCP server."""
target_url = os.getenv("MCP_SERVER_URL")
audience = target_url.split('/mcp/')[0]
request = google.auth.transport.requests.Request()
id_token = google.oauth2.id_token.fetch_id_token(request, audience)
return id_token
"""
# Use this code if you are using the public MCP Server and comment out the code below defining mcp_tools
mcp_tools = MCPToolset(
connection_params=StreamableHTTPConnectionParams(
url=mcp_server_url
)
)
"""
mcp_tools = MCPToolset(
connection_params=StreamableHTTPConnectionParams(
url=mcp_server_url,
headers={
"Authorization": f"Bearer {get_id_token()}",
},
),
)
# Configuring the Wikipedia Tool
wikipedia_tool = LangchainTool(
tool=WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
)
3 つのツールについて
add_prompt_to_state📝
このツールは、動物園の来園者が尋ねた内容を記憶します。たとえば、来園者が「ライオンはどこにいますか?」と尋ねると、その具体的な質問がエージェントのメモリに保存され、ワークフロー内の他のエージェントが次に調査すべきことを判断できるようになります。
方法: このツールは Python 関数として実装されており、訪問者のプロンプトを共有の tool_context.state ディクショナリに書き込みます。このツールのコンテキストは、1 回の会話におけるエージェントの短期記憶を表します。1 つのエージェントが State に保存したデータは、ワークフロー内の次のエージェントで読み取ることができます。
MCPToolset🦁
これは、ツアーガイド エージェントをラボ 1 で作成した動物園 MCP サーバーに接続するために使用されます。このサーバーには、動物に関する具体的な情報(名前、年齢、飼育施設など)を検索できる専用のツールが用意されています。
方法: このツールセットは、動物園のプライベート サーバーの URL に安全に接続します。さらに、get_id_token を使用してセキュアな「キーカード」(サービス アカウントの ID トークン)を自動的に取得し、そのトークンを使って ID を証明してアクセス権を取得します。
LangchainTool🌍
これにより、ツアーガイド エージェントは一般的な世界に関する知識を得ることができます。たとえば、来園者が「野生のライオンは何を食べるの?」など、動物園のデータベースに含まれない質問をした場合、エージェントはこのツールを使用して Wikipedia で回答を検索できます。
方法: このツールはアダプタとして機能し、エージェントが LangChain ライブラリの事前構築済み WikipediaQueryRun ツールを使用できるようにします。
リソース:
ステップ 3: 専門エージェントを定義する
次に、リサーチャー エージェントと回答フォーマッタ エージェントを定義します。リサーチャー エージェントは、オペレーション全体の「頭脳」として機能します。このエージェントは、共有された State からユーザーのプロンプトを取得し、強力なツール(動物園の MCP サーバーツールと Wikipedia ツール)から、どちらを使って回答を検索するかを判断します。
回答フォーマッタ エージェントはプレゼンテーションを担当します。このエージェントは、新しい情報を検索するツールは使用せず、リサーチャー エージェントが収集した元データを State から取得します。そのデータを LLM の言語能力で整形し、フレンドリーな会話形式の回答へと変換します。
agent.py の末尾に次のコードを追加します。
# 1. Researcher Agent
comprehensive_researcher = Agent(
name="comprehensive_researcher",
model=model_name,
description="The primary researcher that can access both internal zoo data and external knowledge from Wikipedia.",
instruction="""
You are a helpful research assistant. Your goal is to fully answer the user's PROMPT.
You have access to two tools:
1. A tool for getting specific data about animals AT OUR ZOO (names, ages, locations).
2. A tool for searching Wikipedia for general knowledge (facts, lifespan, diet, habitat).
First, analyze the user's PROMPT.
- If the prompt can be answered by only one tool, use that tool.
- If the prompt is complex and requires information from both the zoo's database AND Wikipedia,
you MUST use both tools to gather all necessary information.
- Synthesize the results from the tool(s) you use into preliminary data outputs.
PROMPT:
{{ PROMPT }}
""",
tools=[
mcp_tools,
wikipedia_tool
],
output_key="research_data" # A key to store the combined findings
)
# 2. Response Formatter Agent
response_formatter = Agent(
name="response_formatter",
model=model_name,
description="Synthesizes all information into a friendly, readable response.",
instruction="""
You are the friendly voice of the Zoo Tour Guide. Your task is to take the
RESEARCH_DATA and present it to the user in a complete and helpful answer.
- First, present the specific information from the zoo (like names, ages, and where to find them).
- Then, add the interesting general facts from the research.
- If some information is missing, just present the information you have.
- Be conversational and engaging.
RESEARCH_DATA:
{{ research_data }}
"""
)
ステップ 4: ワークフロー エージェント
ワークフロー エージェントは、動物園ツアー全体の「バックオフィス」を管理するマネージャーとして機能します。リサーチ リクエストを受け取り、上記で定義した 2 つのエージェントが、必ず正しい順序(最初にリサーチ、次にフォーマット)でジョブを実行できるように調整します。これにより、来園者の質問に一貫して回答できる、予測可能で信頼性の高いプロセスが作成されます。
方法: このエージェントは SequentialAgent として動作し、自身で推論を行わない特別なタイプのエージェントです。唯一の役割は、sub_agents(リサーチャー エージェントと回答フォーマッタ エージェント)のリストを、あらかじめ定められた順序で実行することです。実行時には、共有メモリを自動的に受け渡しながら処理を進めます。
次のコードブロックを agent.py の末尾に追加します。
tour_guide_workflow = SequentialAgent(
name="tour_guide_workflow",
description="The main workflow for handling a user's request about an animal.",
sub_agents=[
comprehensive_researcher, # Step 1: Gather all data
response_formatter, # Step 2: Format the final response
]
)
最終ステップ: メイン ワークフローを組み立てる 
このエージェントは root_agent として指定されます。ADK フレームワークでは、このエージェントがすべての新規会話の開始点になります。このエージェントは、プロセス全体をオーケストレートする役割を担い、初期コントローラとして会話の最初のやり取りを管理します。
次のコードブロックを agent.py の末尾に追加します。
root_agent = Agent(
name="greeter",
model=model_name,
description="The main entry point for the Zoo Tour Guide.",
instruction="""
- Let the user know you will help them learn about the animals we have in the zoo.
- When the user responds, use the 'add_prompt_to_state' tool to save their response.
After using the tool, transfer control to the 'tour_guide_workflow' agent.
""",
tools=[add_prompt_to_state],
sub_agents=[tour_guide_workflow]
)
これで agent.py ファイルが完成しました。このように構築することで、各コンポーネント(ツール、ワーカー エージェント、マネージャー エージェント)が、最終的なインテリジェント システムの中で、それぞれ明確な役割を担っていることがわかります。それでは、デプロイに進みましょう。
7. デプロイに向けてアプリケーションを準備する
ローカル環境の準備が整ったら、次はデプロイ用に Google Cloud プロジェクトを準備します。このステップでは、エージェントのファイル構造の最終チェックを行い、デプロイ コマンドに対応していることを確認します。さらに、デプロイされた Cloud Run サービスがユーザーに代わって Vertex AI モデルを呼び出すために必須の IAM 権限を構成します。これらの手順を完了すると、クラウド環境でエージェントを正常に実行できるようになります。
source コマンドを実行して、変数をシェル セッションに読み込みます。
source .env
サービス アカウントに Vertex AI ユーザーロールを付与します。これにより、予測を行う権限と Google のモデルを呼び出す権限が、サービス アカウントに付与されます。
# Grant the "Vertex AI User" role to your service account
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/aiplatform.user"
8. ADK CLI を使用してエージェントをデプロイする
ローカルコードの準備が整い、Google Cloud プロジェクトも用意できたので、次はエージェントをデプロイします。ここでは、デプロイ ワークフロー全体を自動化する便利なツールである adk deploy cloud_run コマンドを使用します。1 つのコマンドで、コードのパッケージ化、コンテナ イメージのビルド、Artifact Registry への push、Cloud Run でのサービスの起動までを行い、ウェブからアクセスできる状態にします。
導入
次のコマンドを実行して、エージェントをデプロイします。uvx コマンドを使用すると、Python パッケージとして公開されたコマンドライン ツールを、グローバルにインストールしなくても実行できます。
# Run the deployment command
uvx --from google-adk==1.14.0 \
adk deploy cloud_run \
--project=$PROJECT_ID \
--region=europe-west1 \
--service_name=zoo-tour-guide \
--with_ui \
. \
-- \
--labels=dev-tutorial=codelab-adk \
--service-account=$SERVICE_ACCOUNT
プロンプトを受け入れる
次のようなメッセージが表示されることがあります。
Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [europe-west1] will be created. Do you want to continue (Y/n)?
「Y」と入力して Enter キーを押します。
次のようなメッセージが表示されることがあります。
Allow unauthenticated invocations to [your-service-name] (y/N)?.
このラボでは、テストを簡単にするために未認証の呼び出しを許可します。「y」と入力して Enter キーを押します。
デプロイリンクを取得する
実行が成功すると、デプロイされた Cloud Run サービスの URL がコマンドから返されます。(https://zoo-tour-guide-123456789.europe-west1.run.app のような URL になります)。次のタスクのためにこの URL をコピーします。
9. デプロイしたエージェントをテストする
エージェントが Cloud Run で稼働するようになったので、デプロイが成功したことと、エージェントが想定どおりに動作していることを確認するテストを行います。公開サービス URL(https://zoo-tour-guide-123456789.europe-west1.run.app/ など)を使用して ADK のウェブ インターフェースにアクセスし、エージェントとやり取りします。
ウェブブラウザで公開 Cloud Run サービス URL を開きます。--with_ui flag を使用したため、ADK のデベロッパー UI が表示されます。
右上にある Token Streaming をオンにします。
これで、動物園エージェントとやり取りできるようになりました。
「hello」と入力して Enter キーを押すと、新しい会話が始まります。
結果を確認します。エージェントは、挨拶をすぐに返します。
"Hello! I'm your Zoo Tour Guide. I can help you learn about the amazing animals we have here. What would you like to know or explore today?"
エージェントに次のような質問をします。
Where can I find the polar bears in the zoo and what is their diet?

エージェントのフローの説明
システムはインテリジェントなマルチエージェントのチームとして機能します。このプロセスは明確な順序で管理されているため、ユーザーの質問から最終的な詳細回答に至るまでのフローは、スムーズかつ効率的です。
1. 動物園の案内係(ウェルカム デスク)
プロセス全体は、案内係エージェントから始まります。
役割: 会話を始めることです。ユーザーに挨拶し、どの動物について知りたいかを尋ねるように指示されています。
ツール: ユーザーが応答すると、案内係は add_prompt_to_state ツールを使用して、ユーザーの発言(例: 「ライオンについて教えて」)をそのままキャプチャし、システムメモリに保存します。
引き継ぎ: プロンプトを保存すると、すぐにサブエージェントである tour_guide_workflow に制御が移ります。
2. 包括的リサーチャー(スーパー リサーチャー)
メイン ワークフローの最初のステップであり、オペレーション全体の「頭脳」として機能します。大規模なチームではなく、利用可能なすべての情報にアクセスできる、高いスキルを持つエージェントが 1 人いるイメージです。
役割: ユーザーの質問を分析し、インテリジェントな計画を立てます。言語モデルの高度なツール使用能力を活用して、次のどの情報源を使うべきかを判断します。
- 動物園の記録からの内部データ(MCP サーバー経由)。
- ウェブからの一般的な知識(Wikipedia API 経由)。
- 複雑な質問の場合はその両方。
動作: 必要なツールを実行して、回答に必要な元データをすべて収集します。たとえば、ユーザーが「ライオンは何歳で、野生では何を食べているの?」と尋ねた場合、年齢の情報は MCP サーバーから取得し、食事に関する情報は Wikipedia ツールから取得します。
3. 回答フォーマッタ(プレゼンター)
包括的リサーチャーがすべての情報を収集した後、最後に実行されるエージェントです。
役割: 動物園ツアーガイドのフレンドリーな声として機能します。1 つまたは両方の情報源から収集した元データを取り込み、推敲します。
動作: すべての情報を統合し、一貫性があり、わかりやすく魅力的な回答へと仕上げます。指示に従い、まず動物園の具体的な情報を提示し、次に興味深い一般的な事実を追加します。
最終結果: このエージェントが生成したテキストは、ユーザーがチャット ウィンドウで確認できる、完全で詳細な回答です。
エージェントの構築について詳しくは、以下のリソースをご覧ください。
10. 環境をクリーンアップする
gcloud run services delete zoo-tour-guide --region=europe-west1 --quiet
gcloud artifacts repositories delete cloud-run-source-deploy --location=europe-west1 --quiet
11. 完了
以上で、この Codelab は完了です。
学習した内容
- ADK コマンドライン インターフェースでデプロイするために Python プロジェクトを構造化する方法。
- SequentialAgent と ParallelAgent を使用してマルチエージェント ワークフローを実装する方法。
- MCPToolset を使用してリモート MCP サーバーに接続し、そのツールを使用する方法。
- Wikipedia API などの外部ツールを統合して内部データを拡張する方法。
- adk deploy コマンドを使用して、エージェントをサーバーレス コンテナとして Cloud Run にデプロイする方法。
12. アンケート
出力:
