0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gemini API Maps Grounding入門 — 250M地点データをAIアプリに組み込む

0
Last updated at Posted at 2026-03-31

はじめに

Gemini API に Grounding with Google Maps というツールが追加され、2026年3月18日に Gemini 3 モデルファミリーへ拡張されました。このツールを有効にすると、Gemini は世界中の 2億5,000万以上の地点データ(営業時間・口コミ・写真・ルート)をリアルタイムに参照しながら回答を生成します。

この記事では、Maps Grounding の仕組みと API の使い方を、Python のコード例を交えながら解説します。

この記事で学べること

  • Gemini API の Maps Grounding が何を解決するか
  • 対応モデルと料金体系
  • Python での基本実装(場所検索・近傍検索)
  • マルチツール連携(Google Search + Maps)
  • インタラクティブ地図ウィジェットの埋め込み

対象読者

  • Gemini API を使って位置情報 AI アプリを開発したいエンジニア
  • 場所の推薦・ルート案内などのユースケースを検討している方
  • 地理情報をエージェントに渡す方法を探している方

前提環境

  • Python 3.10+
  • google-genai SDK(pip install google-genai
  • Google AI Studio の API キー(GOOGLE_API_KEY

TL;DR

  • tools=[{"googleMaps": {}}] を追加するだけで Gemini が Maps データを参照
  • 世界2億5,000万地点・営業時間・口コミ・写真をリアルタイム取得
  • 料金は $25/1,000 grounded prompts、1日500リクエストまで無料
  • Gemini 3.1 Pro / Flash・Gemini 2.5 シリーズで利用可能
  • Google Search と組み合わせて「ウェブ情報+地図情報」のマルチ検索も可

Grounding with Google Maps とは

従来の課題

LLM は学習データのカットオフ以降の情報を持たないため、「今日の営業時間」「近くのレストランのメニュー」などリアルタイムな地点情報の質問には正確に答えられませんでした。

Maps Grounding が解決すること

googleMaps ツールを有効にすると、Gemini はクエリを受け取った時点で Google Maps の最新データをフェッチし、その情報を根拠にして回答を生成します。

取得できる情報
場所の名称・住所 「六本木ヒルズ 住所」
営業時間 「今日開いているカフェ」
口コミ・評価 「星4以上のイタリアン」
写真 店舗の外観・内観
ルート・所要時間 「渋谷から新宿まで徒歩で何分?」
近傍の場所 「東京タワーから500m以内の駐車場」

リリース履歴

日付 内容
2025-10-17 一般提供開始(Gemini 2.x モデル対応)
2026-03-18 Gemini 3 モデルファミリーへ拡張。マルチツール連携(Context Circulation)対応

対応モデルと料金

対応モデル

モデル 概要
gemini-3.1-pro-preview 最高精度。複雑な地理クエリに最適
gemini-3.1-flash-lite-preview 高速・低コスト版
gemini-3-flash-preview バランス型
gemini-2.5-pro 高精度・長文推論対応
gemini-2.5-flash コスト効率重視
gemini-2.0-flash 軽量・高速

料金

項目 料金
Grounded prompts(Maps データを参照した場合) $25 / 1,000 リクエスト
無料枠 1日 500 リクエスト
Maps データを参照しなかった場合 課金なし(通常の Gemini API 料金のみ)

Maps grounding の課金は、レスポンスに Maps ソース(groundingChunks)が1つ以上含まれた場合のみ発生します。クエリが地理情報と無関係と判断された場合は課金されません。

基本実装

セットアップ

pip install google-genai
export GOOGLE_API_KEY="your_api_key"

シンプルな場所検索

import os
from google import genai
from google.genai import types

client = genai.Client(api_key=os.environ["GOOGLE_API_KEY"])

response = client.models.generate_content(
    model="gemini-3.1-pro-preview",
    contents="東京タワー周辺で夜遅くまで営業しているおすすめのカフェを3件教えてください。",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_maps=types.GoogleMaps())]
    )
)

print(response.text)

# 引用された Maps ソースを確認
if response.candidates[0].grounding_metadata:
    metadata = response.candidates[0].grounding_metadata
    for chunk in metadata.grounding_chunks:
        if chunk.retrieved_context:
            print(f"ソース: {chunk.retrieved_context.title}")
            print(f"URI: {chunk.retrieved_context.uri}")

ユーザー位置情報を渡す(近傍検索)

latLng を指定することで、ユーザーの現在地に基づいた近傍検索ができます。

response = client.models.generate_content(
    model="gemini-3.1-pro-preview",
    contents="今いる場所の近くでランチに使えるラーメン店を教えてください。",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_maps=types.GoogleMaps())],
        tool_config=types.ToolConfig(
            retrieval_config=types.RetrievalConfig(
                lat_lng=types.LatLng(
                    latitude=35.6812,    # 東京駅
                    longitude=139.7671
                )
            )
        )
    )
)

print(response.text)

レスポンスの grounding metadata を解析する

def parse_maps_grounding(response) -> dict:
    """Maps Grounding のメタデータを解析する"""
    result = {
        "text": response.text,
        "sources": [],
        "widget_token": None
    }

    if not response.candidates:
        return result

    metadata = response.candidates[0].grounding_metadata
    if not metadata:
        return result

    # 引用ソースを取得
    for chunk in metadata.grounding_chunks:
        if chunk.retrieved_context:
            result["sources"].append({
                "title": chunk.retrieved_context.title,
                "uri": chunk.retrieved_context.uri,
            })

    # インタラクティブマップウィジェット用トークン
    if hasattr(metadata, "google_maps_widget_context_token"):
        result["widget_token"] = metadata.google_maps_widget_context_token

    return result

# 使用例
parsed = parse_maps_grounding(response)
print(f"回答: {parsed['text'][:100]}...")
print(f"引用ソース数: {len(parsed['sources'])}")
for source in parsed["sources"]:
    print(f"  - {source['title']}: {source['uri']}")

インタラクティブ地図ウィジェット

enableWidget=True を設定すると、レスポンスに googleMapsWidgetContextToken が含まれます。このトークンを使って、フロントエンドに Google Maps の埋め込みウィジェットを表示できます。

response = client.models.generate_content(
    model="gemini-3.1-pro-preview",
    contents="渋谷駅周辺のおすすめ観光スポットを地図で見せてください。",
    config=types.GenerateContentConfig(
        tools=[types.Tool(
            google_maps=types.GoogleMaps(enable_widget=True)
        )]
    )
)

# トークンを取得してフロントエンドに渡す
metadata = response.candidates[0].grounding_metadata
widget_token = metadata.google_maps_widget_context_token
# → このトークンを使って Maps Embed API でウィジェットを表示

マルチツール連携(Google Search + Maps)

2026年3月18日のアップデートで、Google SearchGoogle Maps を同一リクエストで組み合わせられるようになりました(Context Circulation)。

response = client.models.generate_content(
    model="gemini-3.1-pro-preview",
    contents=(
        "最近オープンしたばかりの東京のクラフトビールバーで、"
        "口コミ評価が高い店を3件教えてください。"
    ),
    config=types.GenerateContentConfig(
        tools=[
            types.Tool(google_search=types.GoogleSearch()),  # ウェブ検索
            types.Tool(google_maps=types.GoogleMaps()),       # Maps データ
        ]
    )
)

print(response.text)

このように設定すると、Gemini は必要に応じてウェブ検索と Maps データの両方を使い分けます。

マルチツールを指定した場合、Gemini はクエリの内容を判断して適切なツールを選択します。両方のツールが同時に使われる場合もあります。

実践ユースケース

旅行プランナー

def create_travel_plan(destination: str, days: int) -> str:
    """目的地と日数を受け取り、詳細な旅行プランを生成する"""
    prompt = f"""
    {destination}への{days}日間の旅行プランを作成してください。
    各日のモデルルート・おすすめレストラン・観光スポットを含めてください。
    営業時間や混雑具合も考慮してください。
    """
    response = client.models.generate_content(
        model="gemini-3.1-pro-preview",
        contents=prompt,
        config=types.GenerateContentConfig(
            tools=[types.Tool(google_maps=types.GoogleMaps())]
        )
    )
    return response.text

plan = create_travel_plan("京都", 3)
print(plan)

近傍施設検索 API

from fastapi import FastAPI

app = FastAPI()

@app.get("/nearby")
async def nearby_places(
    lat: float,
    lng: float,
    query: str
):
    """位置情報と検索クエリを受け取り、近傍の場所を返す"""
    response = client.models.generate_content(
        model="gemini-3-flash-preview",
        contents=f"現在地から最も近い{query}を3件教えてください。評価が高い順で。",
        config=types.GenerateContentConfig(
            tools=[types.Tool(google_maps=types.GoogleMaps())],
            tool_config=types.ToolConfig(
                retrieval_config=types.RetrievalConfig(
                    lat_lng=types.LatLng(latitude=lat, longitude=lng)
                )
            )
        )
    )
    return {"result": response.text}

注意点

対応していない機能(Restricted Preview)

ルーティング(「A地点からB地点まで○分」)は現時点で Restricted Preview です。一般提供を利用するには Google への申請が必要です1

ロケール設定

デフォルトでは英語の地名・レビューが返ることがあります。日本語の回答が必要な場合は、プロンプトに明示的に「日本語で回答してください」を含めるか、system_instruction で指定します。

コスト管理

無料枠(500 req/日)を超えると $25/1,000 req の課金が発生します。開発環境では gemini-3-flash-preview などコストの低いモデルを使い、本番環境では利用量の上限を設定することを推奨します。

# 開発時は Flash モデルで動作確認
model = "gemini-3-flash-preview"      # 開発
# model = "gemini-3.1-pro-preview"   # 本番(高精度)

まとめ

  • Gemini API の Grounding with Google Maps を使うことで、2億5,000万地点のリアルタイムデータを AI アプリに組み込める
  • API ツールに {"googleMaps": {}} を追加するだけで有効化できる
  • $25/1,000 リクエスト、1日 500 リクエスト無料 でコスト計算しやすい
  • Gemini 3.1 Pro / Flash と Gemini 2.5 系で利用可能
  • Google Search との マルチツール連携(Context Circulation)で「ウェブ情報+地図情報」を組み合わせた回答が生成できる
  • 旅行プランナー・近傍検索・ルート提案など幅広いユースケースで活用できる

参考リンク

  1. ルーティング機能(Directions API との連携)は Restricted Preview のため、利用には Google への申請が必要です(2026年3月時点)。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?