📈

ADK と MCP Toolbox for Databases を使った BigQuery エージェントの開発

に公開

モチベーション

先日、GitHub で公開されている BigQuery 連携ツール mcp-bigquery-server を試用しました。
触ってみた第一印象としては、非常にポテンシャルを感じるツールでした。

一方で、特に分析用 SQL の自動生成のようなユースケースにおいては、事前の準備、すなわち「前提を揃える」ことの重要性を再認識しました。
テーブル構造、カラムの意味、データの状態などをツール側が正確に理解できるような情報を提供しなければ、意図した通りの SQL を生成させることは難しいという印象です。
このあたりは、プロンプトエンジニアリングやメタデータの整備が鍵になりそうです。

そんな中、Google から Agent Development Kit (ADK) と MCP Toolbox for Databases (genai-toolbox) という、生成AIアプリケーション開発を支援するツール群がリリースされました。
これらの Google 製ツールを活用することで、BigQuery MCP のような試みで直面した課題の一部が解決され、BigQuery を含むデータソースと生成AIの連携がさらに加速するのではないかと思っています。

https://google.github.io/adk-docs/

https://googleapis.github.io/genai-toolbox/

今回はそんな 2 つのツールを使って BigQuery MCP とは違った分析ツールを作ってみたいと思います。

MCP Toolbox for Databases(genai-toolbox) とは

MCP Toolbox for Databases は、データベースアクセス用ツールの開発を簡単にするオープンソースのMCPサーバーです。
接続管理などを自動化し、安全かつ迅速なツール開発・共有を実現します。

接続情報やデータベースとのやり取りを yaml 形式であらかじめ記述しておくことで MCP におけるツールをあっという間に開発することができるのが魅力です。
対応しているデータベースも色々ありますが、今回は BigQuery を想定して話を進めます。

準備

MCP Toolbox のサイトにあった例を元に BigQuery 側にサンプルデータを用意します。
以下はホテルの情報を管理するテーブルを作成しています。

https://googleapis.github.io/genai-toolbox/getting-started/local_quickstart/

CREATE TABLE IF NOT EXISTS `${your_dataset}.hotels` (
  id            INT64 NOT NULL,
  name          STRING NOT NULL,
  location      STRING NOT NULL,
  price_tier    STRING NOT NULL,
  checkin_date  DATE NOT NULL,
  checkout_date DATE NOT NULL,
  booked        BOOLEAN NOT NULL
);

INSERT INTO `${your_dataset}.hotels` (id, name, location, price_tier, checkin_date, checkout_date, booked)
VALUES
  (1, 'Hilton Basel', 'Basel', 'Luxury', '2024-04-20', '2024-04-22', FALSE),
  (2, 'Marriott Zurich', 'Zurich', 'Upscale', '2024-04-14', '2024-04-21', FALSE),
  (3, 'Hyatt Regency Basel', 'Basel', 'Upper Upscale', '2024-04-02', '2024-04-20', FALSE),
  (4, 'Radisson Blu Lucerne', 'Lucerne', 'Midscale', '2024-04-05', '2024-04-24', FALSE),
  (5, 'Best Western Bern', 'Bern', 'Upper Midscale', '2024-04-01', '2024-04-23', FALSE),
  (6, 'InterContinental Geneva', 'Geneva', 'Luxury', '2024-04-23', '2024-04-28', FALSE),
  (7, 'Sheraton Zurich', 'Zurich', 'Upper Upscale', '2024-04-02', '2024-04-27', FALSE),
  (8, 'Holiday Inn Basel', 'Basel', 'Upper Midscale', '2024-04-09', '2024-04-24', FALSE),
  (9, 'Courtyard Zurich', 'Zurich', 'Upscale', '2024-04-03', '2024-04-13', FALSE),
  (10, 'Comfort Inn Bern', 'Bern', 'Midscale', '2024-04-04', '2024-04-16', FALSE);

実装

続いて MCP Toolbox の yaml も用意します。
これも公式サイトにあった yaml をそのまま使用します。

以下はホテルを検索するためのツールを 2 つ提供しています。
名前と場所をそれぞれ引数に受け取り、あいまい検索する用のツールが提供されています。

tools.yml
sources:
  my-bigquery-source:
    kind: bigquery
    project: ${your_project}
    location: asia-northeast1
toolsets:
  my-toolset:
    - search-hotels-by-name
    - search-hotels-by-location
tools:
  search-hotels-by-name:
    kind: bigquery-sql
    source: my-bigquery-source
    description: Search for hotels based on name.
    parameters:
      - name: name
        type: string
        description: The name of the hotel.
    statement: SELECT * FROM `${your_dataset}.hotels` WHERE LOWER(name) LIKE LOWER(CONCAT('%', @name, '%'));
  search-hotels-by-location:
    kind: bigquery-sql
    source: my-bigquery-source
    description: Search for hotels based on location.
    parameters:
      - name: location
        type: string
        description: The location of the hotel.
    statement: SELECT * FROM `${your_dataset}.hotels` WHERE LOWER(location) LIKE LOWER(CONCAT('%', @location, '%'));

続いて ADK 側の実装です。
ADK のサイトに Toolbox で公開した MCP サーバをエージェントに組み込む方法が記されているのでこちらを参考に実装します。

https://google.github.io/adk-docs/tools/google-cloud-tools/#toolbox-tools-for-databases

agent.py
import os
from google.adk.agents import Agent
from google.adk.tools.toolbox_tool import ToolboxTool

TOOLBOX_URL = os.getenv('TOOLBOX_URL', 'http://localhost:5001')
toolbox = ToolboxTool(TOOLBOX_URL)

tools = toolbox.get_toolset(toolset_name='my-toolset')

prompt = """
  You're a helpful hotel assistant. You handle hotel searching. When the user searches for a hotel, mention it's name, id,
  location and price tier. Always mention hotel ids while performing any
  searches. This is very important for any operations.
"""

root_agent = Agent(
    model='gemini-2.0-flash',
    name='hotel_agent',
    description='A helpful AI assistant that can search hotels.',
    instruction=prompt,
    tools=tools
)

今回はこれらを Docker Compose で立ち上げてテストしてみます。
このときローカルで ADC は取得しておくことが前提条件です。

ディレクトリ構成はこんな感じ。
載ってないけど ADK を使うための .env の設定もお忘れなく。

.
├── compose.yml
├── hotel_agent
│   ├── Dockerfile
│   ├── agent
│   │   ├── __init__.py
│   │   └── agent.py
│   └── requirements.txt
└── toolbox
    └── tools.yml
compose.yml
services:
  toolbox:
    image:  us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest
    hostname: toolbox
    platform: linux/amd64
    ports:
      - "5001:5001"
    environment:
      - CLOUDSDK_CONFIG=/.gcp/config
      - GOOGLE_APPLICATION_CREDENTIALS=/.gcp/config/application_default_credentials.json
    volumes:
      - ./toolbox:/config
      - $HOME/.config/gcloud:/.gcp/config
    command: [ "toolbox", "--tools_file", "/config/tools.yml", "--address", "0.0.0.0", "--port", "5001" ]
    networks:
      - tool-network
  hotet_agent:
    build:
      context: ./hotel_agent
      dockerfile: Dockerfile
    env_file: .env
    environment:
      - TOOLBOX_URL=http://toolbox:5001
    ports:
      - "8000:8000"
    entrypoint: ["adk", "web"]
    networks:
      - tool-network
    image: asia-northeast1-docker.pkg.dev/${your_project}/hogefuga/hotel-agent:latest
networks:
  tool-network:

localhost:8000 で ADK のチャット画面が見えるので質問してみます。

複数の条件を考慮する方法

上記の方法だと where 句が名前や場所で限られてしまい検索時の自由度が低くなってしまいます。
その場合は where の条件を引数にして LLM 側で自動生成するようにします。

where_condition は文字列で SQL に埋め込まれるため、EXECUTE IMMEDIATE FORMAT() を使うことで動的に SQL を組み立て実行できるようにしてあげることで実現できます。

search-hotels-by-everything:
    kind: bigquery-sql
    source: my-bigquery-source
    description: Search for hotels based on name or location or price_tier.
    parameters:
      - name: where_condition
        type: string
        description: |
          The search condition for the hotel. It can be a name, location, or price_tier.
          You can use the following operators: =, !=, <, <=, >, >=, LIKE.
          You can combine multiple conditions using AND or OR.
          You can use parentheses to group conditions.
          You can use the following keywords: name, location, price_tier.

          For example:
          - "name = 'Hotel California'"
          - "location = 'Los Angeles'"
          - "price_tier = 'Luxury'"
          - "name = 'Hotel California' and price_tier = 'Luxury'"

          Parameters:
          name: string
          location: string
          price_tier: string, enum: [Luxury, Upscale, Upper Upscale, Midscale, Upper Midscale]
    statement: |
      EXECUTE IMMEDIATE FORMAT("""
        SELECT * FROM `${your_dataset}.hotels` WHERE %s
      """, @where_condition);

今回は場所、名前、価格帯について質問してみます。

実際に発行されたパラメータを見ると想定通り動いてそうです。

感想

特筆すべきは、実装の容易さです。
BigQuery MCP と比較して、MCP Toolbox for Databases では YAML による設定管理が中心となり、データベースを新たな「ツール」として追加する際の負担が大幅に軽減されました。

さらに、このツールボックスでは、利用するテーブルや集計ロジックといった「前提知識」をあらかじめ定義しやすい点が大きなメリットだと感じました。
BigQuery MCP では難しかった LLM の挙動制御が容易になり、より意図した通りに動作させられることを確認できました。
これは LLM に対してデータベースの意味構造を教える、一種のセマンティックレイヤーを構築するようなものだと捉えられます。

また、ADK との連携により、チャットインターフェースを迅速に構築できる点も魅力です。
開発した AI エージェントをノンエンジニアの方々にも容易に試してもらう環境を整えることができます。
Google 製ツール間の連携のスムーズさは、さすがの一言です。

一方で、MCP Toolbox のデータベース連携機能は、定義済みの定型的な操作には非常に強力ですが、アドホックなクエリを実行するような自由度は、BigQuery MCP のようなアプローチに比べて低いと感じました。
EXECUTE IMMEDIATE FORMAT() を活用すればある程度の自由度を確保できますが、その代償としてパラメータ定義が複雑化し、プロンプトが長大になるという使いづらさも生じます。

これは BigQuery MCP を試した際にも感じた「前提知識をどのように埋め込むか」という根本的な課題に繋がります。
厳密な前提知識を与えることで LLM の動作は安定しますが、SQL (あるいはデータ操作) の自由度は制限されます。
逆に自由度を高めようとすると、LLM が意図しない動作をするリスクが高まり、それを防ぐためのプロンプトエンジニアリングが複雑化します。

データベース連携 AI ツールにおいては、この「SQL (操作) の自由度」と「前提知識による制御性」のトレードオフをどうバランスさせるかが、極めて重要な設計要素であると再認識しました。

おまけ、Cloud Run へのデプロイ

Toolbox と ADK の組み合わせは、LLM を活用した Text-to-SQL の検証に適しています。
この環境をさらに手軽に利用可能にするため、Cloud Run へのデプロイを試みました。

既に BigQuery などにデータが存在し、「まずは LLM でどんなことができるか試してみたい」という要望は多いはずです。
Toolbox でデータベース連携を設定し、ADK で簡易的なインターフェースを用意したアプリケーションを Cloud Run にデプロイすることで、こうしたニーズに対して、インフラを意識することなく迅速に Text-to-SQL の機能を試せる環境を提供できると考えられます。
これは、今後の活用アイデアの一つとして記録しておきます。
※ サクッと試して消したので IaC してないです🙏

1. Docker イメージの作成

まず ADK をつかって作ったエージェントの Docker イメージを作成して Artifact Registry に push します。
(上記で示した compose.yml の image を正しく指定してください。)

docker compose push hotel_agent

2. サービスアカウントを作成

次にサービスアカウントを作成して以下の IAM ロールを付与します。

  • BigQuery ジョブユーザー
  • BigQuery データ閲覧者
  • Secret Manager のシークレット アクセサー
  • Vertex AI ユーザー

3. Tools.yml を Secret Manager に登録

Tools.yml には BigQuery への接続情報などが記述されるため、一応 Secret Manager に登録します。

4. Cloud Run のデプロイ

今回 compose.yml にも記載した通りコンテナが 2 つ連携するツールとなります。
そのため Cloud Run をマルチコンテナで立ち上げることにします。
こうしておくことで Toolbox はエージェント越しにしか触ることができなくなるので安全です。

エージェント側の設定

1 で push した docker イメージを使います。
コマンドは adk web です。
環境変数に以下を設定します。
後の手順で toolbox コンテナも設定しますが、コンテナ間は localhost で通信できるみたいなので TOOLBOX_URLlocalhost:5001 を設定します。
今回 gemini-2.0-flash を Vertex AI 経由で使うため GOOGLE_GENAI_USE_VERTEXAI など設定する必要があります。
GOOGLE_CLOUD_LOCATION は Gemini を使う際のロケーションなので注意!(早く asia-northeast1 で使えるようになってほしい…)

TOOLBOX_URL=http://localhost:5001
GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_PROJECT=your_project
GOOGLE_CLOUD_LOCATION=us-central1

ToolBox 側の設定

イメージは Docker Compose でも使用した以下のイメージを使います。
立ち上げコマンドも一緒です

us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest

先ほど Secret Manager に登録した tools.yml/config 配下にマウントしておきます。

今回 toolbox のコンテナが起動してからエージェントのコンテナを起動させたいので、エージェント側のコンテナの依存関係に toolbox を追加する必要があります。
依存関係を使う際に toolbox 側に Startup Probe を設定する必要があったので注意が必要です。
http://localhost:5001/ に 10 秒間隔で問い合わせる設定にするとうまくいきました。

確認

上記の設定を元に Cloud Run を立ち上げることができました。
最後にチャット UI で確認したいのでプロキシしてブラウザから localhost:8080 にアクセスします。
(社内公開とかする場合は IAP などで保護すると良いでしょう。)

gcloud run services proxy hotel-agent --project your_project --region asia-northeast1

まとめ

Google が提供する Agent Development Kit (ADK) と MCP Toolbox for Databases (genai-toolbox) を活用し、BigQuery のデータを操作する AI エージェントを開発するプロセスを、具体的な実装例と共に紹介しました。

Toolbox のデータベース連携機能を用いることで、従来のアプローチと比較して YAML ベースで容易にデータベース操作ツールを定義できることを確認しました。
一方で、アドホックなクエリ実行における自由度の点で課題も残ります。
ある程度自由度を高める工夫も可能ですが、パラメータ設計やプロンプトの複雑化という新たな課題も生じます。
この「操作の自由度」と「前提知識による制御性」のトレードオフは、データベース連携 AI を設計する上で避けて通れない重要な検討事項です。

また ADK や MCP Toolbox の特徴で大きく感じたのは実装やデプロイの容易さです。
今回 Cloud Run へデプロイすることで、Text-to-SQL のような機能を迅速に検証・共有するための環境を構築できました。

Discussion