Cloud Run で実行されているバックエンド ADK エージェントを呼び出す gradio フロントエンド アプリをデプロイする方法

1. はじめに

概要

この Codelab では、ADK エージェントをバックエンド サービスとして Cloud Run にデプロイし、ADK エージェントの gradio フロントエンドを 2 番目の Cloud Run サービスとしてデプロイします。この Codelab では、ADK エージェント サービスへの認証を必須にし、gradio フロントエンド サービスから認証された呼び出しを行う方法について説明します。

学習内容

  • ADK エージェントを Cloud Run にデプロイする方法
  • gradio アプリを Cloud Run にデプロイする方法
  • Cloud Run で認証済みのサービス間呼び出しを行う方法

2. API を有効にする

まず、Google Cloud プロジェクトを設定します。

gcloud config set project <YOUR_PROJECT_ID>

Google Cloud プロジェクトを確認するには、次のコマンドを実行します。

gcloud config get-value project

この Codelab では、次の API を有効にする必要があります。

gcloud services enable run.googleapis.com \
    compute.googleapis.com \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    aiplatform.googleapis.com

3. 設定と要件

このセクションでは、2 つのサービス アカウントを作成し、適切な IAM ロールを付与します。各 Cloud Run サービスには独自のサービス アカウントがあります。

まず、この Codelab 全体で使用する環境変数を設定します。

export PROJECT_ID=<YOUR_PROJECT_ID>
export REGION=<YOUR_REGION>

export SERVICE_ACCOUNT_ADK="adk-agent-cr"
export SERVICE_ACCOUNT_ADDRESS_ADK=$SERVICE_ACCOUNT_ADK@$PROJECT_ID.iam.gserviceaccount.com

export SERVICE_ACCOUNT_GRADIO="adk-agent-gradio"
export SERVICE_ACCOUNT_ADDRESS_GRADIO=$SERVICE_ACCOUNT_GRADIO@$PROJECT_ID.iam.gserviceaccount.com

export AGENT_APP_NAME="multi_tool_agent"

次に、ADK エージェントのサービス アカウントを作成します。

gcloud iam service-accounts create $SERVICE_ACCOUNT_ADK \
--display-name="Service account for adk agent on cloud run"

ADK サービス アカウントに「Vertex AI ユーザー」ロールを付与します。

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_ADDRESS_ADK" \
  --role="roles/aiplatform.user"

次に、Gradio フロントエンドのサービス アカウントを作成します。

gcloud iam service-accounts create $SERVICE_ACCOUNT_GRADIO \
  --display-name="Service account for gradio frontend cloud run"

また、Gradio フロントエンドに Cloud Run 起動元のロールを付与します。これにより、Cloud Run でホストされている ADK エージェントを呼び出すことができます。

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_ADDRESS_GRADIO" \
  --role="roles/run.invoker"

4. ADK アプリを作成する

次のステップでは、ADK クイックスタート アプリケーションのコードを作成します。

注: ラボの終了時、ファイル構造は次のようになります。

- codelab-gradio-adk  <-- you'll deploy the ADK agent from here
  - gradio-frontend
    - app.py
    - requirements.txt
  - multi_tool_agent  <-- you'll deploy the gradio app from here
    - __init__.py
    - agent.py
    - requirements.txt

まず、全体的な Codelab のディレクトリを作成します。

mkdir codelab-gradio-adk
cd codelab-gradio-adk

次に、ADK エージェント サービスのディレクトリを作成します。

mkdir multi_tool_agent && cd multi_tool_agent

__init__.py ファイルを作成し、次の内容を追加します。

from . import agent

requirements.txt ファイルを作成します。

google-adk

agent.py というファイルを作成します。

import datetime
from zoneinfo import ZoneInfo
from google.adk.agents import Agent

def get_weather(city: str) -> dict:
    """Retrieves the current weather report for a specified city.

    Args:
        city (str): The name of the city for which to retrieve the weather report.

    Returns:
        dict: status and result or error msg.
    """
    if city.lower() == "new york":
        return {
            "status": "success",
            "report": (
                "The weather in New York is sunny with a temperature of 25 degrees"
                " Celsius (77 degrees Fahrenheit)."
            ),
        }
    else:
        return {
            "status": "error",
            "error_message": f"Weather information for '{city}' is not available.",
        }


def get_current_time(city: str) -> dict:
    """Returns the current time in a specified city.

    Args:
        city (str): The name of the city for which to retrieve the current time.

    Returns:
        dict: status and result or error msg.
    """

    if city.lower() == "new york":
        tz_identifier = "America/New_York"
    else:
        return {
            "status": "error",
            "error_message": (
                f"Sorry, I don't have timezone information for {city}."
            ),
        }

    tz = ZoneInfo(tz_identifier)
    now = datetime.datetime.now(tz)
    report = (
        f'The current time in {city} is {now.strftime("%Y-%m-%d %H:%M:%S %Z%z")}'
    )
    return {"status": "success", "report": report}


root_agent = Agent(
    name="weather_time_agent",
    model="gemini-2.5-flash",
    description=(
        "Agent to answer questions about the time and weather in a city."
    ),
    instruction=(
        "You are a helpful agent who can answer user questions about the time and weather in a city."
    ),
    tools=[get_weather, get_current_time],
)

5. ADK エージェントをデプロイする

このセクションでは、ADK エージェントを Cloud Run にデプロイします。次に、ADK で提供される開発ウェブ UI を使用して、デプロイが機能したことを確認します。最後に、このサービスへの認証済み呼び出しが必要になります。

親フォルダに移動します。

注: ADK エージェント コードには、ルートフォルダとして multi_tool_agent フォルダを含める必要があります。

cd ..

まず、Cloud Run サービスを作成します。

注: --with_ui は、次の手順に示すように、Dev UI でテストする場合は省略可能です。

注: -- コマンドを使用すると、コマンドライン フラグを基盤となる gcloud run deploy コマンドに渡すことができます。

注: uvx --from は google-adk パッケージのコマンドを実行します。uvx は一時的な仮想環境を作成し、google-adk をインストールして、指定されたコマンドを実行してから、環境を破棄します。

uvx --from google-adk \
adk deploy cloud_run \
    --project=$PROJECT_ID \
    --region=$REGION \
    --service_name=adk-agent-cr \
    --with_ui \
    ./multi_tool_agent \
    -- \
    --service-account=$SERVICE_ACCOUNT_ADDRESS_ADK \
    --allow-unauthenticated

次に、この Codelab の後半で使用する環境変数として URL を保存します。

AGENT_SERVICE_URL=$(gcloud run services describe adk-agent-cr --region $REGION --format 'value(status.url)')

エージェントを試す

ウェブブラウザでサービス URL を開き、「tell me about the weather in new york」と入力します。「ニューヨークの天気は晴れで、気温は 25 度(77 度)です」のようなレスポンスが表示されます。

最後に、エージェントを保護します。

次に、エージェントへのアクセスを保護します。次のセクションでは、このバックエンド サービスに対して認証された呼び出しを行う Cloud Run サービスをデプロイします。

gcloud run services remove-iam-policy-binding adk-agent-cr \
  --member="allUsers" \
  --role="roles/run.invoker" \
  --region=$REGION

6. Gradio フロントエンドをデプロイする

このステップでは、ADK エージェントの gradio フロントエンドを作成します。

注: gradio アプリは ADK エージェントと同じサービスに配置できます。この Codelab では、Cloud Run で認証済みのサービス間呼び出しを行う方法を示すために、2 つの個別のサービスを提供します。

まず、multi_tool_agent フォルダとともにアプリを作成します。

mkdir gradio-frontend && cd gradio-frontend

次に、次の内容を含む requirements.txt ファイルを作成します。

gradio
requests
google-auth

app.py ファイルを作成します

import gradio as gr
import requests
import json
import uuid
import os
import google.auth.transport.requests
import google.oauth2.id_token

# https://weather-time-service2-392295011265.us-west4.run.app
BASE_URL = os.environ.get("AGENT_SERVICE_URL")

# multi_tool_agent
APP_NAME = os.environ.get("AGENT_APP_NAME")

# Generate a unique user ID for each session of the Gradio app
USER_ID = f"gradio-user-{uuid.uuid4()}"

# API Endpoints
CREATE_SESSION_URL = f"{BASE_URL}/apps/{APP_NAME}/users/{USER_ID}/sessions"
RUN_SSE_URL = f"{BASE_URL}/run_sse"

def get_id_token():
    """Get an ID token to authenticate with the other Cloud Run service."""
    audience = BASE_URL
    request = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(request, audience)
    return id_token

def create_session() -> str | None:
    """Creates a new session and returns the session ID."""
    try:
        id_token = get_id_token()
        headers = {"Authorization": f"Bearer {id_token}"}
        response = requests.post(CREATE_SESSION_URL, headers=headers)
        response.raise_for_status()
        return response.json().get("id")
    except Exception as e:
        print(f"Error creating session: {e}")
        return None

def query_agent(prompt: str):
    """Sends a prompt to the agent and returns the streamed response."""
    session_id = create_session()
    if not session_id:
        return "Error: Could not create a session."

    id_token = get_id_token()
    headers = {
        "Content-Type": "application/json",
        "Accept": "text/event-stream",
        "Authorization": f"Bearer {id_token}",
    }
    payload = {
        "app_name": APP_NAME,
        "user_id": USER_ID,
        "session_id": session_id,
        "new_message": {"role": "user", "parts": [{"text": prompt}]},
        "streaming": True
    }

    full_response = ""
    try:
        with requests.post(RUN_SSE_URL, headers=headers, json=payload, stream=True) as response:
            response.raise_for_status()
            for chunk in response.iter_lines():
                if chunk and chunk.decode('utf-8').startswith('data:'):
                    json_data = chunk.decode('utf-8')[len('data:'):].strip()
                    try:
                        data = json.loads(json_data)
                        text = data.get("content", {}).get("parts", [{}])[0].get("text", "")
                        if text:
                            full_response = text
                    except json.JSONDecodeError:
                        pass # Ignore chunks that are not valid JSON
        return full_response
    except requests.exceptions.RequestException as e:
        return f"An error occurred: {e}"

iface = gr.Interface(
    fn=query_agent,
    inputs=gr.Textbox(lines=2, placeholder="e.g., What's the weather in new york?"),
    outputs="text",
    title="Weather and Time Agent",
    description="Ask a question about the weather or time in a specific location.",
)

if __name__ == "__main__":
    iface.launch()

7. Gradio アプリをデプロイしてテストする

このステップでは、フロントエンドの gradio アプリを Cloud Run にデプロイします。

gradio アプリのディレクトリにいることを確認します。

pwd

codelab-gradio-adk/gradio-frontend が表示されます。

次に、gradio アプリをデプロイします。

注: この gradio フロントエンド サービスは一般公開されているウェブサイトですが、バックエンド サービスには認証が必要です。この例では、フロントエンド サービスにユーザー認証(Firebase Auth など)を追加し、ログインしたユーザーのみがバックエンド サービスを呼び出せるようにします。

gcloud run deploy my-adk-gradio-frontend \
--source . \
--region $REGION \
--allow-unauthenticated \
--set-env-vars AGENT_SERVICE_URL=$AGENT_SERVICE_URL,AGENT_APP_NAME=$AGENT_APP_NAME \
--service-account=$SERVICE_ACCOUNT_ADDRESS_GRADIO

デプロイしたら、what's the weather in new york? をリクエストします。The weather in New York is sunny with a temperature of 25 degrees Celsius (77 degrees Fahrenheit). のようなレスポンスが返されます。

8. 完了

以上で、この Codelab は完了です。

AI アプリとエージェントのホスティングに関するドキュメントを確認することをおすすめします。

学習した内容

  • ADK エージェントを Cloud Run にデプロイする方法
  • gradio アプリを Cloud Run にデプロイする方法
  • Cloud Run で認証済みのサービス間呼び出しを行う方法

9. クリーンアップ

たとえば、Cloud Run サービスが無料枠の月間 Cloud Run 呼び出し割り当てよりも多く呼び出された場合など、意図しない課金を避けるには、ステップ 6 で作成した Cloud Run サービスを削除します。

Cloud Run サービスを削除するには、https://console.cloud.google.com/run で Cloud Run Cloud Console に移動し、my-adk-gradio-frontend サービスと adk-agent-cr サービスを削除します。

プロジェクト全体を削除するには、[リソースの管理] に移動し、ステップ 2 で作成したプロジェクトを選択して、[削除] を選択します。プロジェクトを削除した場合は、Cloud SDK でプロジェクトを変更する必要があります。gcloud projects list を実行すると、使用可能なすべてのプロジェクトのリストを表示できます。