GitHub Actions 経由で Vertex AI Agent Engine に ADK エージェントをデプロイする際ハマったこと

こんにちは!機械学習エンジニアをしている深澤です。

Google Agent Development Kit(ADK) を用いてエージェント開発をしており、Vertex AI Agent Engine を活用しています。 その際に悩み抜いたことがあり、ようやく解決できたので学びを共有します。

まとめ

  • 普段 Workload Identity SA で GitHub Actions(GHA) 上での認証を通している
  • BigQuery Tool を使うエージェントをデプロイしようとしている
  • 2025/08/05現在の公式ドキュメントの記述に沿ってデプロイスクリプトを作ってしまうと、Workload Identity SA から発行されたトークンで ADC 認証が行われる→すぐに失効してデプロイしたエージェントが BigQuery Tool を触れない
  • google.auth.default() で認証情報取得することはせず、何も書かないで BigQuery Client を使うときに走る認証に任せればいい

※ Google ADK は v1.9.0, google-cloud-aiplatform[adk,agent_engines] は 1.106.0 を使っています。

前提:コミューンの Google Cloud Run へのデプロイ時の認証

普段からGHA 経由で Cloud Run へのデプロイを行っています。

その際、Google Cloud への認証は Workload Identity を通じて行っています。

- id: auth
  uses: google-github-actions/auth@v2
  with:
    workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER}}

- name: Set up Cloud SDK
  uses: google-github-actions/setup-gcloud@v2
  with:
    project_id: ${{ secrets.GCP_PROJECT_ID }}

github.com

ここではサービスアカウントを指定せず、Direct Workload Identity Federation によって認証しています。(サービスアカウントやその認証情報 JSON ファイルを使用せずに、外部の ID プロバイダ (IDP) を通じて GCP のサービスにアクセスするための認証方法)

認証情報をほとんど何も書かなくて良いので、弊社では殆どの場面でこの方式を採用しています。

Agent Engine に ADK エージェントをデプロイしたい

本題なのですが、note で書いた以下の記事でも紹介した Community Sage というアプリケーションで、Google Agent Development Kit を利用しています。 note.com

community sage

このアプリケーションでは BigQuery Tool を用いて、ユーザからクエリが来たら必要に応じてエージェントが tool を呼び出してデータを取得し、解釈して発話しています。

これを Vertex AI Agent Engine にデプロイして社内利用で試しています。

短期記憶は Session Service が勝手についてくるし、長期記憶も Memory Bank に必要に応じて接続して、最高だ〜〜〜!と思っていました。が、問題がありました。ローカルからデプロイするとうまく動くのですが、GHA 経由でのデプロイだとうまく動かないのです。

うまく動かせずに四苦八苦

動かないにも色々あると思いますが、今回出ていたエラーはこちらでした。

{'id': 'adk-xxx', 
'name': 'execute_sql', 
'response': {'status': 'ERROR', 
'error_details': '(\'Unable to retrieve Identity Pool subject token\', 
\'{"source":"actions-run-service","statusCode":400,
"errorMessage":"job is already completed"}\')'}}

Unable to retrieve Identity Pool subject token ということで、Workload Identity から token を取得できないよ、というメッセージです。ではここで、実際に用いているデプロイスクリプトを共有します。

from typing import cast

import vertexai
from community_sage_agent.agent import root_agent
from config.config import settings
from core.logger import get_logger
from vertexai import agent_engines

PROJECT_ID = settings.PROJECT_ID
AGENT_ENGINE_REGION = settings.AGENT_ENGINE_REGION
BUCKET_NAME = settings.BUCKET_NAME
SERVICE_ACCOUNT = settings.SERVICE_ACCOUNT
DISPLAY_NAME = "community_sage_adk_agent"

LOGGER = get_logger(module_name="community_sage_agent_logs")

def main() -> None:
    vertexai.init(project=PROJECT_ID, location=AGENT_ENGINE_REGION, staging_bucket=f"gs://{BUCKET_NAME}")

    requirements = [
        "google-cloud-aiplatform[adk,agent_engines]==1.106.0",
        "google-adk==1.9.0",
        "pydantic==2.11.7",
        "cloudpickle==3.1.1",
        "pandas==2.3.1",
    ]
    extra_packages = [
        "community_sage_agent/prompts",
        "community_sage_agent/callbacks",
        "community_sage_agent/sub_agents",
        "community_sage_agent/sub_agents/community_name_resolver",
    ]

    LOGGER.info("Deploying a new agent.")
    # Create a new agent
    _ = agent_engines.create(
        root_agent,  # type: ignore
        display_name=DISPLAY_NAME,
        requirements=requirements,
        extra_packages=extra_packages,
        service_account=SERVICE_ACCOUNT,
    )

if __name__ == "__main__":
    main()

このスクリプトは次のエージェントを呼び出します。

import google.auth
from google.adk.agents import Agent
from google.adk.tools.bigquery import BigQueryCredentialsConfig, BigQueryToolset
from google.adk.tools.bigquery.config import BigQueryToolConfig, WriteMode

from .callbacks.bq_after_tool import safe_dates_after_tool
from .config.config import settings
from .prompts.prompts import get_bq_instruction

MODEL_NAME = settings.MODEL_NAME
AGENT_NAME = settings.AGENT_NAME

creds, _ = google.auth.default()
credentials_cfg = BigQueryCredentialsConfig(credentials=creds)

# read only allowed
tool_cfg = BigQueryToolConfig(write_mode=WriteMode.BLOCKED)

bq_toolset = BigQueryToolset(
    credentials_config=credentials_cfg,
    bigquery_tool_config=tool_cfg,
)

# generate instruction from schema directory
instruction = get_bq_instruction()

# Agent definition
root_agent = Agent(
    model=MODEL_NAME,
    name=AGENT_NAME,
    instruction=instruction,
    tools=[bq_toolset],
    after_tool_callback=safe_dates_after_tool,
)

これは公式ドキュメントに乗っていたサンプルをほとんどそのまま持ってきているだけですね。https://google.github.io/adk-docs/tools/built-in-tools/#bigquery

これでデプロイするときに、GHA 経由で実行すると上述したエラーが出ていました。

Workload Identity 経由のトークンが埋め込まれてしまっていた

原因はエラーメッセージを見ればはっきりしていて、デプロイスクリプト実行時に Workload Identity 経由のトークンが google.auth で取得され、それが渡ったということでした。pickle された google.auth の Credentials が、Agent Engine 上で Workload Identity Federation の subject token を再取得できずに Refresh に失敗していたようです。

じゃあなんでそんな事が起きたのかというと、それは Agent Engine のデプロイが特殊なことにあります。

Cloud Run とは異なり、Agent Engine は Python オブジェクトをそのまま pickle で丸め込んで GCS に送ります。それを Agent Engine 上に展開しています。ということはどういうことかというと、上述したデプロイスクリプト上で、一度 Python オブジェクトがすべて実体化しています。Vertex AI Agent Engine は GCS にアップロードされたバンドル(*.pkl, requirements.txt, dependencies.tar.gz)を受け取ると、バックエンドでコンテナを自動ビルドしてエージェントを起動します。

最初からコンテナにまとめて、クラウド環境でコンテナが展開される方式ならこうはならないのですが、 ADK は GHA 上で Python を実行して pickle にまとめる方式なのでこの問題でスタックしてしまいました。冷静になってみればそれはそうなんですが… GHA 経由でデプロイして動かすサンプルが見当たらなかったので大分混乱しました。

解決: ライブラリ側に任せる

紆余曲折ありましたが、最終的には google.auth でトークンを取得して渡す部分を丸々削除することで動くようになりました。

# import google.auth
from google.adk.agents import Agent
# from google.adk.tools.bigquery import BigQueryCredentialsConfig
from google.adk.tools.bigquery import BigQueryToolset
from google.adk.tools.bigquery.config import BigQueryToolConfig, WriteMode

from .callbacks.bq_after_tool import safe_dates_after_tool
from .config.config import settings
from .prompts.prompts import get_bq_instruction

MODEL_NAME = settings.MODEL_NAME
AGENT_NAME = settings.AGENT_NAME

# creds, _ = google.auth.default()
# credentials_cfg = BigQueryCredentialsConfig(credentials=creds)

# read only allowed
tool_cfg = BigQueryToolConfig(write_mode=WriteMode.BLOCKED)

bq_toolset = BigQueryToolset(
#  credentials_config=credentials_cfg,
    bigquery_tool_config=tool_cfg,
)

# generate instruction from schema directory
instruction = get_bq_instruction()

# Agent definition
root_agent = Agent(
    model=MODEL_NAME,
    name=AGENT_NAME,
    instruction=instruction,
    tools=[bq_toolset],
    after_tool_callback=safe_dates_after_tool,
)

なんでこれがうまくいくのかというと、コードを追っていくと最終的には from google.cloud import bigquery を用いていることが分かるためです。

BigQueryToolset

BigQueryToolset に渡す credential は None でも良いことがソースを見るとわかります。

@experimental
class BigQueryToolset(BaseToolset):
"""BigQuery Toolset contains tools for interacting with BigQuery data and metadata."""
    
def __init__(
    self,
    *,
    tool_filter: Optional[Union[ToolPredicate, List[str]]] = None,
 →→ credentials_config: Optional[BigQueryCredentialsConfig] = None,
    bigquery_tool_config: Optional[BigQueryToolConfig] = None,
):
    self.tool_filter = tool_filter
    self._credentials_config = credentials_config
    self._tool_config = bigquery_tool_config

BigQueryTool

BigQueryToolset の次に credential が渡っていく BigQueryTool ですが、こちらは credentials_config is None なら BigQueryCredentialsManager を生成しません。 run_async() では credentials=None のまま各ツール関数へ進みます。ソース

ちなみに追ってみるとわかりますが、2025/08/05時点(7c9b0a2)では type hint が間違っていて、ここは None も入り得ます

BigQueryTool

QueryTool

BigQueryTool は最終的に各ツールを呼び出します。ここでは QueryTool を見てみますと、BigQuery Client を呼び出す事がわかります。ソース

def get_bigquery_client(
    *, project: Optional[str], credentials: Credentials
) -> bigquery.Client:
  """Get a BigQuery client."""

  client_info = google.api_core.client_info.ClientInfo(user_agent=USER_AGENT)

  bigquery_client = bigquery.Client(
      project=project, credentials=credentials, client_info=client_info
  )

  return bigquery_client

BigQuery Client は credentials がない場合は裏で google auth による認証を試みます。このとき実行されている場所に ADC が設定されていればそれによる認証が行われます。Agent Engine 実行時に指定されているサービスアカウントが正しければあとはそれで動く、というわけですね。

その他試したこと

  • ImpersonatedCredential で使ってほしいサービスアカウントを指定してなりすませようとした
  • credential 取得の部分を関数にまとめて遅延実行しようとした
    • これはうまくいけばいけたんじゃないかな、と思うのですが自分ではだめでした

まとめ

解決の糸口を探るうえで adk-sample の方もかなり見ていたんですが、BigQuery のサンプルがちょっと想定と違っていて困りました…

ということで、Workload Identity 認証の GHA から Agent Engine へ BigQuery Tool を持たせた ADK エージェントをデプロイしようとしている方は、google.auth なしでそのままツールを定義して利用するのが良さそうです。ただ、ADK はかなりアップデートが激しいので、リリース情報は注意しておくのがよさそうです。

また、ここで共有した問題に加えて、実はまだ重要な問題があり、リソースを更新すると AuthConfig が json にシリアライズできない 、というエラーが出ます。これは多分 Google Cloud の問題かな…と思ってサポートに聞いてみています。解決してほしい… github.com

皆様もよき ADK・Agent Engine ライフをお送りください…!

さて、コミューンでは、私たちと一緒に働く仲間を募集しています!生成AIを活用したプロダクト開発に興味をお持ちの方、ぜひカジュアル面談でお話ししましょう。

open.talentio.com