Структурированный вывод

Вы можете настроить Gemini для структурированного вывода вместо неструктурированного текста, что позволит точно извлекать и стандартизировать информацию для дальнейшей обработки. Например, вы можете использовать структурированный вывод для извлечения информации из резюме, стандартизировать их для создания структурированной базы данных.

Gemini может генерировать значения JSON или перечисления в виде структурированного вывода.

Генерация JSON

Существует два способа создания JSON с помощью Gemini API:

  • Настройка схемы в модели
  • Предоставьте схему в текстовой подсказке

Настройка схемы в модели — рекомендуемый способ создания JSON, поскольку он ограничивает вывод модели JSON.

Настройка схемы (рекомендуется)

Чтобы ограничить модель генерацией JSON, настройте responseSchema . Затем модель ответит на любой запрос выводом в формате JSON.

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
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();
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())
}
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. Для более детерминированного и более качественного ответа настройте схему на модели и не дублируйте схему в текстовом приглашении.

Генерация значений перечисления

В некоторых случаях вам может потребоваться, чтобы модель выбирала один вариант из списка вариантов. Чтобы реализовать такое поведение, вы можете передать перечисление в свою схему. Вы можете использовать параметр перечисления везде, где можно использовать string в responseSchema , поскольку перечисление представляет собой массив строк. Подобно схеме JSON, перечисление позволяет ограничить выходные данные модели в соответствии с требованиями вашего приложения.

Например, предположим, что вы разрабатываете приложение для классификации музыкальных инструментов по одной из пяти категорий: "Percussion" , "String" , "Woodwind" , "Brass" или « "Keyboard" ». Вы можете создать перечисление, которое поможет справиться с этой задачей.

В следующем примере вы передаете перечисление в качестве responseSchema , ограничивая модель выбором наиболее подходящего варианта.

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 ( Schema ).

Есть два других способа указать перечисление. Вы можете использовать Literal :

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

И вы также можете передать схему в формате JSON:

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 , чтобы присвоить каждому названию оценку популярности:

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"
  },
  ...
]

О схемах JSON

Настройка модели для вывода JSON с использованием параметра responseSchema зависит от объекта Schema , определяющего его структуру. Этот объект представляет собой выбранное подмножество объекта схемы OpenAPI 3.0 , а также добавляет поле propertyOrdering .

Вот псевдо-JSON-представление всех полей Schema :

{
  "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 -> enum , format , nullable
  • integer -> format , minimum , maximum , enum , nullable
  • number -> format , minimum , maximum , enum , nullable
  • boolean -> nullable
  • array -> minItems , maxItems , items , nullable
  • object -> properties , required , propertyOrdering , nullable

Вот несколько примеров схем, показывающих допустимые комбинации типа и поля:

{ "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, см. в справочнике по схеме .

Заказ недвижимости

Когда вы работаете со схемами JSON в Gemini API, порядок свойств важен. По умолчанию API упорядочивает свойства в алфавитном порядке и не сохраняет порядок, в котором они определены (хотя SDK Google Gen AI могут сохранять этот порядок). Если вы предоставляете примеры для модели с настроенной схемой, а порядок свойств примеров не соответствует порядку свойств схемы, выходные данные могут быть бессвязными или неожиданными.

Чтобы обеспечить согласованный и предсказуемый порядок свойств, вы можете использовать необязательное поле propertyOrdering[] .

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

propertyOrdering[] — не стандартное поле в спецификации OpenAPI — представляет собой массив строк, используемый для определения порядка свойств в ответе. Указав порядок свойств, а затем предоставив примеры свойств в том же порядке, вы потенциально можете улучшить качество результатов. propertyOrdering поддерживается только при создании types.Schema вручную.

Схемы в Python

Когда вы используете библиотеку Python, значение response_schema должно быть одним из следующих:

  • Тип, который вы бы использовали в аннотации типа (см. модуль typing Python).
  • Экземпляр genai.types.Schema
  • dict эквивалент genai.types.Schema

Самый простой способ определить схему — использовать тип Pydantic (как показано в предыдущем примере):

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] . Эта аннотация объявляет, что все значения dict имеют один и тот же тип, но не указывает, какие ключи следует включить.
    • Пользовательские модели Pydantic . Этот подход позволяет указать имена ключей и определить различные типы значений, связанных с каждым из ключей, включая вложенные структуры.

Лучшие практики

При использовании схемы ответа учитывайте следующие соображения и рекомендации:

  • Размер вашей схемы ответа учитывается при расчете лимита входного токена.
  • По умолчанию поля являются необязательными, то есть модель может заполнять поля или пропускать их. Вы можете установить поля по мере необходимости, чтобы модель предоставила значение. Если в связанном приглашении ввода недостаточно контекста, модель генерирует ответы в основном на основе данных, на которых она обучалась.
  • Сложная схема может привести к ошибке InvalidArgument: 400 . Сложность может возникнуть из-за длинных имен свойств, длинных ограничений длины массива, перечислений со многими значениями, объектов с множеством необязательных свойств или комбинации этих факторов.

    Если вы получаете эту ошибку с допустимой схемой, внесите одно или несколько из следующих изменений, чтобы устранить ошибку:

    • Сократите имена свойств или имена перечислений.
    • Сглаживание вложенных массивов.
    • Уменьшите количество свойств с ограничениями, например числами с минимальными и максимальными пределами.
    • Сократите количество свойств со сложными ограничениями, например свойств со сложными форматами, например date-time .
    • Уменьшите количество дополнительных свойств.
    • Уменьшите количество допустимых значений для перечислений.
  • Если вы не видите ожидаемых результатов, добавьте больше контекста к подсказкам для ввода или пересмотрите схему ответа. Например, просмотрите реакцию модели без структурированного вывода, чтобы увидеть, как реагирует модель. Затем вы можете обновить схему ответа, чтобы она лучше соответствовала выходным данным модели.

Что дальше

Теперь, когда вы узнали, как генерировать структурированный вывод, вы можете попробовать использовать инструменты Gemini API: