構造化出力

デフォルトでは、Gemini は非構造化テキストを生成しますが、代わりに 構造化出力(JSON または列挙型の値)で応答するようにモデルを制約できます。この構造化出力機能は、非構造化データから情報を抽出し、アプリケーションで使用できるように処理する必要がある場合に特に便利です。たとえば、この機能を使用して履歴書から標準化された情報を抽出し、その情報からデータベースを構築できます。また、レシピから材料を抽出し、材料ごとに食料品店のウェブサイトへのリンクを表示することもできます。

このガイドでは、Gemini API を使用して構造化出力を生成する方法について説明します。

JSON の生成

Gemini API を使用して JSON を生成する方法は 2 つあります。

  • モデルにスキーマを構成する
  • テキスト プロンプトでスキーマを指定する

JSON を生成する方法として、モデルにスキーマを構成することをおすすめします。これにより、モデルが JSON を出力するように制約されます。

スキーマの構成

JSON を生成するモデルを制約するには、responseSchema を構成します。モデルは、JSON 形式の出力でプロンプトに応答します。

Python

from google import genai
from pydantic import BaseModel

class Recipe(BaseModel):
    recipe_name: str
    ingredients: list[str]

client = genai.Client(api_key="GOOGLE_API_KEY")
response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents="List a few popular cookie recipes, and include the amounts of ingredients.",
    config={
        "response_mime_type": "application/json",
        "response_schema": list[Recipe],
    },
)
# Use the response as a JSON string.
print(response.text)

# Use instantiated objects.
my_recipes: list[Recipe] = response.parsed

JavaScript

import { GoogleGenAI, Type } from "@google/genai";

const ai = new GoogleGenAI({ "GOOGLE_API_KEY" });

async function main() {
  const response = await ai.models.generateContent({
    model: "gemini-2.0-flash",
    contents:
      "List a few popular cookie recipes, and include the amounts of ingredients.",
    config: {
      responseMimeType: "application/json",
      responseSchema: {
        type: Type.ARRAY,
        items: {
          type: Type.OBJECT,
          properties: {
            recipeName: {
              type: Type.STRING,
            },
            ingredients: {
              type: Type.ARRAY,
              items: {
                type: Type.STRING,
              },
            },
          },
          propertyOrdering: ["recipeName", "ingredients"],
        },
      },
    },
  });

  console.log(response.text);
}

main();

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, &genai.ClientConfig{
        APIKey:  "GOOGLE_API_KEY",
        Backend: genai.BackendGeminiAPI,
    })
    if err != nil {
        log.Fatal(err)
    }

    config := &genai.GenerateContentConfig{
        ResponseMIMEType: "application/json",
        ResponseSchema: &genai.Schema{
            Type: genai.TypeArray,
            Items: &genai.Schema{
                Type: genai.TypeObject,
                Properties: map[string]*genai.Schema{
                    "recipeName": {Type: genai.TypeString},
                    "ingredients": {
                        Type:  genai.TypeArray,
                        Items: &genai.Schema{Type: genai.TypeString},
                    },
                },
                PropertyOrdering: []string{"recipeName", "ingredients"},
            },
        },
    }

    result, err := client.Models.GenerateContent(
        ctx,
        "gemini-2.0-flash",
        genai.Text("List a few popular cookie recipes, and include the amounts of ingredients."),
        config,
    )
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(result.Text())
}

REST

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
      "contents": [{
        "parts":[
          { "text": "List a few popular cookie recipes, and include the amounts of ingredients." }
        ]
      }],
      "generationConfig": {
        "responseMimeType": "application/json",
        "responseSchema": {
          "type": "ARRAY",
          "items": {
            "type": "OBJECT",
            "properties": {
              "recipeName": { "type": "STRING" },
              "ingredients": {
                "type": "ARRAY",
                "items": { "type": "STRING" }
              }
            },
            "propertyOrdering": ["recipeName", "ingredients"]
          }
        }
      }
}' 2> /dev/null | head

出力は次のようになります。

[
  {
    "recipeName": "Chocolate Chip Cookies",
    "ingredients": [
      "1 cup (2 sticks) unsalted butter, softened",
      "3/4 cup granulated sugar",
      "3/4 cup packed brown sugar",
      "1 teaspoon vanilla extract",
      "2 large eggs",
      "2 1/4 cups all-purpose flour",
      "1 teaspoon baking soda",
      "1 teaspoon salt",
      "2 cups chocolate chips"
    ]
  },
  ...
]

テキスト プロンプトでスキーマを指定する

スキーマを構成する代わりに、テキスト プロンプトで自然言語または疑似コードとしてスキーマを指定できます。この方法は、出力の品質が低下する可能性があるため、またモデルがスキーマに従う制約を受けないため、推奨されません

テキスト プロンプトで指定されたスキーマの一般的な例を次に示します。

List a few popular cookie recipes, and include the amounts of ingredients.

Produce JSON matching this specification:

Recipe = { "recipeName": string, "ingredients": array<string> }
Return: array<Recipe>

モデルはプロンプトのテキストからスキーマを取得するため、スキーマの表現方法に柔軟性を持たせることができます。ただし、このようにスキーマをインラインで指定しても、モデルは JSON を返すように制約されません。より確定的で質の高いレスポンスを得るには、モデルにスキーマを構成し、テキスト プロンプトでスキーマを複製しないでください。

JSON スキーマ

JSON レスポンスを返すようにモデルを構成する場合は、Schema オブジェクトを使用して JSON データのシェイプを定義します。Schema は、OpenAPI 3.0 スキーマ オブジェクトの一部のサブセットを表し、propertyOrdering フィールドも追加します。

すべての Schema フィールドの疑似 JSON 表現を次に示します。

{
  "type": enum (Type),
  "format": string,
  "description": string,
  "nullable": boolean,
  "enum": [
    string
  ],
  "maxItems": integer,
  "minItems": integer,
  "properties": {
    string: {
      object (Schema)
    },
    ...
  },
  "required": [
    string
  ],
  "propertyOrdering": [
    string
  ],
  "items": {
    object (Schema)
  }
}

スキーマの Type は、OpenAPI のデータ型のいずれか、またはそれらの型の共用体(anyOf を使用)である必要があります。各 Type で有効なのはフィールドのサブセットのみです。次のリストは、各 Type を、そのタイプで有効なフィールドのサブセットにマッピングしています。

  • string -> enumformatnullable
  • integer -> formatminimummaximumenumnullable
  • number -> formatminimummaximumenumnullable
  • boolean -> nullable
  • array -> minItemsmaxItemsitemsnullable
  • object -> propertiesrequiredpropertyOrderingnullable

有効な型とフィールドの組み合わせを示すスキーマの例を次に示します。

{ "type": "string", "enum": ["a", "b", "c"] }

{ "type": "string", "format": "date-time" }

{ "type": "integer", "format": "int64" }

{ "type": "number", "format": "double" }

{ "type": "boolean" }

{ "type": "array", "minItems": 3, "maxItems": 3, "items": { "type": ... } }

{ "type": "object",
  "properties": {
    "a": { "type": ... },
    "b": { "type": ... },
    "c": { "type": ... }
  },
  "nullable": true,
  "required": ["c"],
  "propertyOrdering": ["c", "b", "a"]
}

Gemini API で使用されるスキーマ フィールドの詳細については、スキーマ リファレンスをご覧ください。

宿泊施設の並べ替え

Gemini API で JSON スキーマを操作する場合、プロパティの順序が重要になります。デフォルトでは、API はプロパティをアルファベット順に並べ替え、プロパティが定義された順序は保持しません(ただし、Google Gen AI SDK ではこの順序が保持される場合があります)。スキーマが構成されたモデルにサンプルを提供するときに、サンプルのプロパティの順序がスキーマのプロパティの順序と一致しない場合、出力が冗長または予期しないものになる可能性があります。

プロパティの順序を一定にして予測できるようにするには、省略可能な propertyOrdering[] フィールドを使用します。

"propertyOrdering": ["recipeName", "ingredients"]

propertyOrdering[] - OpenAPI 仕様の標準フィールドではありません。レスポンス内のプロパティの順序を決定するために使用される文字列の配列です。プロパティの順序を指定し、その順序でプロパティを含む例を指定すると、結果の品質が向上する可能性があります。propertyOrdering は、types.Schema を手動で作成する場合にのみサポートされます。

Python のスキーマ

このセクションでは、Python ライブラリを使用して JSON スキーマを操作する際の追加ガイダンスについて説明します。

Python ライブラリを使用している場合、response_schema の値は次のいずれかである必要があります。

スキーマを定義する最も簡単な方法は、Pydantic 型を使用することです(上の例を参照)。

Python

config={'response_mime_type': 'application/json',
        'response_schema': list[Recipe]}

Pydantic 型を使用すると、Python ライブラリが JSON スキーマを構築して API に送信します。その他の例については、Python ライブラリのドキュメントをご覧ください。

Python ライブラリは、次の型で定義されたスキーマをサポートしています(ここで、AllowedType は許可される任意の型です)。

  • int
  • float
  • bool
  • str
  • list[AllowedType]
  • AllowedType|AllowedType|...
  • 構造化型の場合:
    • dict[str, AllowedType]。このアノテーションは、すべての辞書値が同じ型であることを宣言しますが、どのキーを含めるかを指定しません。
    • ユーザー定義の Pydantic モデル。このアプローチでは、キー名を指定し、各キーに関連付けられた値にさまざまな型(ネストされた構造など)を定義できます。

列挙値の生成

場合によっては、モデルにオプションのリストから 1 つのオプションを選択させる必要があります。この動作を実装するには、スキーマで列挙型を渡します。列挙型は文字列の配列であるため、responseSchemastring を使用できる場所であればどこでも、列挙型オプションを使用できます。JSON スキーマと同様に、列挙型を使用すると、アプリケーションの要件を満たすようにモデル出力を制約できます。

たとえば、楽器を "Percussion""String""Woodwind""Brass""Keyboard" の 5 つのカテゴリのいずれかに分類するアプリを開発しているとします。このタスクを支援するために列挙型を作成できます。

次の例では、列挙型を responseSchema として渡し、最も適切なオプションを選択するようにモデルを制約します。

Python

from google import genai
import enum

class Instrument(enum.Enum):
  PERCUSSION = "Percussion"
  STRING = "String"
  WOODWIND = "Woodwind"
  BRASS = "Brass"
  KEYBOARD = "Keyboard"

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='What type of instrument is an oboe?',
    config={
        'response_mime_type': 'text/x.enum',
        'response_schema': Instrument,
    },
)

print(response.text)
# Woodwind

Python ライブラリは、API の型宣言を変換します。ただし、この API は OpenAPI 3.0 スキーマのサブセット(スキーマ)を受け入れます。

列挙型を指定する方法は他に 2 つあります。Literal を使用できます。

Python

Literal["Percussion", "String", "Woodwind", "Brass", "Keyboard"]

スキーマを JSON として渡すこともできます。

Python

from google import genai

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='What type of instrument is an oboe?',
    config={
        'response_mime_type': 'text/x.enum',
        'response_schema': {
            "type": "STRING",
            "enum": ["Percussion", "String", "Woodwind", "Brass", "Keyboard"],
        },
    },
)

print(response.text)
# Woodwind

基本的な多肢選択式の問題以外にも、JSON スキーマの任意の場所で列挙型を使用できます。たとえば、レシピのタイトルのリストをモデルにリクエストし、Grade 列挙型を使用して各タイトルに人気度を割り当てることができます。

Python

from google import genai

import enum
from pydantic import BaseModel

class Grade(enum.Enum):
    A_PLUS = "a+"
    A = "a"
    B = "b"
    C = "c"
    D = "d"
    F = "f"

class Recipe(BaseModel):
  recipe_name: str
  rating: Grade

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='List 10 home-baked cookie recipes and give them grades based on tastiness.',
    config={
        'response_mime_type': 'application/json',
        'response_schema': list[Recipe],
    },
)

print(response.text)

レスポンスは次のようになります。

[
  {
    "recipe_name": "Chocolate Chip Cookies",
    "rating": "a+"
  },
  {
    "recipe_name": "Peanut Butter Cookies",
    "rating": "a"
  },
  {
    "recipe_name": "Oatmeal Raisin Cookies",
    "rating": "b"
  },
  ...
]

考慮事項

レスポンス スキーマを使用する場合は、次の考慮事項とベスト プラクティスに注意してください。

  • レスポンス スキーマのサイズは、入力トークン制限にカウントされます。
  • デフォルトでは、フィールドは省略可能です。つまり、モデルはフィールドにデータを入力することも、フィールドをスキップすることもできます。フィールドを必須として設定すると、モデルに値を提供させることができます。関連する入力プロンプトに十分なコンテキストがない場合、モデルは主にトレーニングに使用されたデータに基づいてレスポンスを生成します。
  • 複雑なスキーマを使用すると、InvalidArgument: 400 エラーが発生する可能性があります。複雑になる要因としては、プロパティ名が長い、配列長の上限が大きい、列挙型の値が多い、オブジェクトのオプション プロパティが多い、またはこれらの要因の組み合わせが考えられます。

    有効なスキーマでこのエラーが発生する場合は、次の変更を 1 つ以上行ってエラーを解決します。

    • プロパティ名または列挙型名を短くする。
    • ネストされた配列をフラット化する。
    • 最小値と最大値が設定された数値など、制約のあるプロパティの数を減らす。
    • 複雑な制約を持つプロパティの数を減らす。たとえば、date-time のような複雑な形式のプロパティは減らす。
    • オプションのプロパティの数を減らす。
    • 列挙型の有効な値の数を減らす。
  • 期待どおりの結果が表示されない場合は、入力プロンプトにコンテキストを追加するか、レスポンス スキーマを修正します。たとえば、構造化出力なしでモデルのレスポンスを確認して、モデルがどのように応答するかを確認します。その後、モデルの出力により適したレスポンス スキーマを更新できます。

次のステップ

構造化出力を生成する方法を学習したので、Gemini API ツールの使用を試すことができます。