はじめに

こんにちは!アイレットに入社して早半年となります、森です!

LLM(大規模言語モデル)をアプリケーションに組み込む際、最大の課題の一つは「AI の出力をいかにプログラムで扱いやすくするか」です。

自由なテキスト回答は魅力的ですが、システム連携においては特定の JSON 形式で返ってこないとエラーの原因になります。そこで役立つのが、Gemini API の「構造化出力(Structured Output)」機能です。

今回の記事では、Gemini API の基本機能から、Google のエージェント開発 SDK(ADK)での応用までを詳しく紹介します。

 Gemini API の構造化出力とは?

構造化出力とは、Gemini からのレスポンスを、開発者が定義した JSON スキーマに従った形式で強制的に出力させる機能です。

単純に「次に示す JSON 形式で出力してください」とプロンプトで指示することでも可能ですが、より確実に API レベルで出力形式を定義できます。

なぜ構造化出力が必要なのか?

プロンプトで直接指示するのと比較して、以下のメリットがあります。

  • パースエラーの防止: ```json などの余計な装飾が入ったり、キー名が勝手に変わったりすることがなくなり、確実に指定した型のデータが得られます。
  • 型安全な開発: プログラム側で定義したインターフェースやクラスにそのままマッピングできます。
  • 後処理の自動化: 抽出したデータをそのままデータベースに保存したり、次の関数に渡したりすることが容易になります。
  • 解釈のヒント: 出力の型を指定することで Gemini が返答する時のヒントとなります。

実装のポイント

Gemini API では、config の中で response_mime_typeapplication/json に設定し、response_schema で具体的な構造を定義します。

例:レシピ生成のスキーマ定義(Python 例)


from pydantic import BaseModel, Field
from typing import Literal
from google import genai
from google.colab import userdata

# スキーマ定義
class Activity(BaseModel):
    start_time: str = Field(
        json_schema_extra={"format": "date-time"}, # date-time型へフォーマット
        description="アクティビティの開始時間"
    )
    location: str = Field(description="アクティビティの開催場所")
    description: str
    category: Literal["観光", "食事", "移動", "宿泊"]
    estimated_cost_jpy: int

class DayPlan(BaseModel):
    day_number: int
    activities: list[Activity] = Field(
        json_schema_extra={"min_items": 1, "max_items": 3} # 最小1最大3つまで出力されます
    )

class TravelItinerary(BaseModel):
    destination: str
    total_budget: int
    plans: list[DayPlan] = Field(
        json_schema_extra={"min_items": 1, "max_items": 3} # 最小1最大3つまで出力されます
    )

# クライアントの初期化
api_key = userdata.get("GEMINI_API_KEY")
client = genai.Client(api_key=api_key)

# 実行
response = client.models.generate_content(
    model="gemini-3.1-pro-preview",
    contents="京都2泊3日の一人旅のプランを提案して。予算は5万円以内。",
    config={
        "response_mime_type": "application/json",
        "response_schema": TravelItinerary.model_json_schema(),
    },
)

# 結果の表示
print(TravelItinerary.model_validate_json(response.text))

このように定義することで、必ず指定のデータを持つ JSON が返ってきます。

サポートされている JSON スキーマに関してはこちらを参照ください

ツールを使用した構造化出力(Gemini 3 〜)

さらに Gemini 3 以上のモデルでは、構造化された出力を、Google 検索によるグラウンディングURL コンテキストコード実行ファイル検索関数呼び出しなどの組み込みツールと組み合わせることができるようになりました。Google 検索をして最新の情報を取得したり、数値の計算をしたり、特定の情報ソースに基づいた回答が可能で、大幅にパワーアップしたと言えるでしょう。


response = client.models.generate_content(
    model="gemini-3.1-pro-preview",
    contents="京都2泊3日の一人旅のプランを提案して。予算は5万円以内。",
    config={
        "tools": [
            {"google_search": {}},
            {"url_context": {}}
        ],
        "response_mime_type": "application/json",
        "response_json_schema": TravelItinerary.model_json_schema(),
    },
)


ADK(Agent SDK)における output_schema の活用

Gemini API を単体で使うだけでなく、複数のツールや推論ステップを組み合わせるエージェント開発においても、この構造化出力は強力な武器になります。

Google が提供する ADK(Agent Development Kit)では、エージェントや各タスクの出力を絞り込むために、output_schema を利用できます。

エージェント開発での重要性

エージェントは「ユーザーの入力を解釈し、自律的にツールを選んで実行する」存在です。エージェントが最終的な回答を出す際、その回答が特定のデータ形式(例えば「予約確定データ」や「分析レポートのオブジェクト」)である必要がある場合、output_schema で出力を制約します。特にマルチエージェント構成の開発を行う場合、次のエージェントに決められた型のデータを渡すことを確約できます。

ADK での記述イメージ


import datetime
import zoneinfo
from pydantic import BaseModel, Field
from typing import Literal
from google.adk.agents.llm_agent import Agent
from google.adk.tools import ToolContext

# スキーマ定義(省略)
# ....

# 現在時刻を知るツール定義
async def get_start_time_tool(tool_context: ToolContext):
    """
    現在時刻(東京基準)を返却します
    """
    return datetime.datetime.now(tz=zoneinfo.ZoneInfo("Asia/Tokyo")).isoformat()

# エージェントの構成
travel_agent = Agent(
    model='gemini-3.1-pro-preview',
    name='travel_planner_agent',
    description='構造化された旅程を出力する専門エージェント',
    instruction="""
あなたはプロのトラベルプランナーです。
`get_start_time_tool` を使用して現在の日付を確認し、そこから2泊3日の現実的なプランを作成してください。

[制約事項]
- 出力は必ず指定された JSON スキーマに従うこと。
- 予算内に収まるように見積もること。
""",
    tools=[get_start_time_tool],
    # ここがポイント:定義した Pydantic モデルを渡す
    output_schema=TravelItinerary.model_json_schema()
)

# 実行と結果の受け取りイメージ
# result = await travel_agent.run("京都のグルメ満喫旅を提案して")
# print(result.data.destination)

このように output_schema を設定することで、エージェントが生成した最終的な結果を、フロントエンドの UI コンポーネントにそのまま流し込むといった高度な連携が可能になります。

構造化出力が活きるユースケース

1. データ抽出:
大量の非構造化ドキュメント(契約書や領収書)から、日付、金額、会社名などを JSON として抽出する。

2. 感情分析・分類:
カスタマーレビューを読み込み、{ "sentiment": "positive", "score": 0.9 } のような形式で分類結果を得る。

3. 外部ツールとの連携:
AI が判断したアクション(例:カレンダー登録、メール送信)を、特定の関数呼び出しに最適な JSON 形式で出力する。

まとめ:信頼性の高い AI アプリケーションを目指して

Gemini API の構造化出力と ADK の output_schema は、LLM を「賢いチャットボット」から「信頼できるシステム構成要素」へと進化させる重要な機能です。

  • Gemini API では `response_schema` を活用し、
  • ADK では `output_schema` でエージェントの振る舞いを制御する。

これらを組み合わせることで、開発者はパースエラーに悩まされることなく、本来のロジック開発に集中できるようになります。ぜひ皆さんのプロジェクトでも、構造化出力を積極的に取り入れてみてください!

参考リンク