Как генерировать структурированный JSON через Gemini API: полное руководство

От JSON в промпте и responseMimeType до responseSchema / JSON Schema — структурированный вывод Gemini, примеры Python и REST, Function Calling и проверка перед релизом.

Предыдущая статьяПочему Агенты искусственного интеллекта не могут жить без JSONотслеживаются Tool Calling и MCP шаг за шагом. Этот смотрит наокончательный ответмодель дает пользователю или последующей программе: как заставить Gemini генерировать JSON, который можно анализировать, проверять и хранить, а не прозу, которая просто выглядит как JSON.

Это структурированные выходные данные (контролируемая генерация) в документации Gemini. Он разделяет идеи схемы с Function Calling, но имеет другую цель: первый ограничиваетокончательная полезная нагрузка; последнее ограничиваетинструмент аргументы. Держите их отдельно, чтобы Агент не воспринимал «извлечение счета» и «вызов платежа API» как один и тот же тип вызова.

Три подхода, каждый более строгий

Команды обычно пробуют три способа «заставить Gemini выводить JSON». Надежность отличается на порядок:

ПодходЧто вы контролируетеКогда этого достаточно
Только запрос: «пожалуйста, выведите JSON».Мягкое ограничение; ограничения уценки и завершающие комментарии все еще появляютсяИсследование, одноразовые скрипты
responseMimeType: application/jsonВывод должен быть действительным текстом JSON.Форма варьируется; вам нужен только parse(), чтобы добиться успеха
MIME + responseSchema / responseJsonSchemaПоля, типы, перечисления и обязательные ключи ограничены.Извлечение продукции, формы, полезная нагрузка от агента к агенту

Everyone has seen the first failure mode: a ```json fence, an extra paragraph, single quotes, a trailing comma. The second layer parses, but price may be a string and items may be missing. The third layer is this tutorial: hand JSON Schema to the API so the decoder avoids illegal paths at each token.

Ограниченное декодирование: почему Schema превосходит приглашение

A prompt only raises the odds that the model wants to comply. Structured Output compiles the Schema into generation: if the next token would break JSON syntax or leave the Schema (for example starting an undeclared field), its probability is suppressed. So response.text is usually a parseable object — no regex to strip fences.

Since 2025 the Gemini API complements the OpenAPI 3.0-style responseSchema with standard JSON Schema (often responseJsonSchema on the wire). Pydantic model_json_schema() and Zod exports can be sent almost as-is. Gemini 2.5 and later also tend to preserve property order from the Schema, which helps CSV columns and tables downstream.

Classification has a side path: responseMimeType: text/x.enum emits only the enum string (for example Keyboard), with no braces. Use application/json when you need an object; use the enum MIME when you need a single label.

Python: полный пример google-genai

Prefer the current SDK google-genai (from google import genai). Do not mix it with the legacy google-generativeai package. With GEMINI_API_KEY set:

from google import genai
from pydantic import BaseModel, Field


class LineItem(BaseModel):
    name: str = Field(description="Product name")
    qty: int = Field(description="Quantity, positive integer")
    unit_price_cents: int = Field(description="Unit price in cents")


class Invoice(BaseModel):
    vendor: str
    currency: str = Field(description="ISO 4217, e.g. CNY")
    items: list[LineItem]
    total_cents: int


client = genai.Client()
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Extract an invoice from: Acme sold 2 keyboards at 199 CNY each.",
    config={
        "response_mime_type": "application/json",
        "response_schema": Invoice,
    },
)

print(response.text)      # JSON string
invoice = response.parsed  # Invoice instance (Pydantic path)
print(invoice.total_cents)

response.parsed is meaningful when response_schema is a Pydantic or SDK type. If you pass a raw JSON Schema dict (next section), json.loads(response.text) and validate yourself.

For many records use list[Invoice] or wrap invoices: list[Invoice] in an object. An array at the root is less stable on some models than always returning an object; production code usually does the latter.

response_schema против JSON Schema

Не думайте, какой ключ конфигурации использовать:

  • response_schema: модель Pydantic, объект Python Enum или SDK Schema. SDK сопоставляет его с подмножеством OpenAPI.
  • response_json_schema: a JSON Schema object (dict). Use it for Invoice.model_json_schema(), Zod toJSONSchema(), and richer keywords such as additionalProperties, minimum / maximum, and prefixItems.
schema = {
  "type": "object",
  "properties": {
    "vendor": { "type": "string" },
    "currency": { "type": "string", "enum": ["CNY", "USD", "EUR"] },
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "qty": { "type": "integer", "minimum": 1 },
          "unit_price_cents": { "type": "integer", "minimum": 0 }
        },
        "required": ["name", "qty", "unit_price_cents"],
        "additionalProperties": False
      }
    },
    "total_cents": { "type": "integer" }
  },
  "required": ["vendor", "currency", "items", "total_cents"],
  "additionalProperties": False
}

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Extract the invoice: …",
    config={
        "response_mime_type": "application/json",
        "response_json_schema": schema,
    },
)

Older REST docs use uppercase types in responseSchema (OBJECT, STRING, ARRAY, INTEGER). The JSON Schema path uses lowercase object / string. Do not mix the two keyword sets. Put field meaning in description: it enters the model context and decides whether qty is pieces or cases. Types alone cannot.

Как выглядит запрос REST

On the Gemini Developer API, generateContent puts structured output under generationConfig. The key goes in x-goog-api-key or a query param — never in a frontend repo.

POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent

{
  "contents": [
    {
      "role": "user",
      "parts": [{ "text": "Extract an invoice from the text: …" }]
    }
  ],
  "generationConfig": {
    "responseMimeType": "application/json",
    "responseJsonSchema": {
      "type": "object",
      "properties": {
        "vendor": { "type": "string" },
        "total_cents": { "type": "integer" }
      },
      "required": ["vendor", "total_cents"]
    }
  }
}

On success the candidate text is candidates[0].content.parts[0].text — a JSON string. Vertex AI uses the same field names; only the endpoint and GCP auth change. Images and PDFs can be inputs: the Schema constrains output, not multimodal input.

Как разделить работу с помощью Вызова функции

Оба используют Schema для управления JSON, но они находятся на разных переходах:

Структурированный выводВызов функции / Вызов инструмента
Что ограниченоОкончательный ответ JSONИнструмент-аргумент JSON
У кого возникают побочные эффектыНикто; это просто данныеХост / MCP Сервер
Типичная конфигурацияresponseMimeType + Схемаинструменты[].parameters / inputSchema
При неудачеПовторите попытку или вернитесь к человеку.Запишите ошибку в виде сообщения инструмента и повторите запрос.

Извлечение счетов, метки модерации, превращение заметок в список задач: структурированный вывод. Поиск инвентаря, создание заявки, чтение файла репо: инструменты — см.статья о потоке данныхиJSON Схема и MCP эволюция. Не используйте структурированный вывод, чтобы представить, что платеж API уже выполнен — модель его не вызывала.

Проверка времени выполнения и распространенные ошибки

Ограниченное декодирование не является бизнес-корректностью. Держите двое ворот:

  1. Syntax and Schema: after json.loads, validate again with the same JSON Schema (required, enum, minimum).
  2. Business invariants: for example sum(item.qty * item.unit_price_cents) == total_cents. Schema cannot express that; you write it.

Распространенные ошибки:

  • Неподдерживаемые ключевые слова: сброс полного проекта схемы 2020-12 может молча игнорировать некоторые ключевые слова. Начните с типа/свойств/обязательных/перечислений/элементов, затем добавьте additionalProperties и мин/макс.
  • Array at the root: { "items": [ ... ] } as an object root is often more reliable.
  • Смешение комментариев Markdown с JSON: если включен JSON MIME, не спрашивайте «сначала объясните, затем JSON».
  • Усечение: поднять maxOutputTokens или разделить «сначала список, затем заполнить каждую строку».
  • Ключи во фронтенде: демо со структурированным выводом в браузере пропускают ключи API. Схема может быть общедоступной; ключ остается на сервере.

Во время разработки храните схему и два-три положительных/отрицательных образца в git. Проверяйте структуру и сравнивайте локально в JSON Toolbox — та же привычка тестирования контрактов, что и в REST, с Gemini в качестве потребителя.

Часто задаваемые вопросы

В чем разница между типом JSON MIME и отправкой схемы?

Используя только responseMimeType application/json, модель пытается выдать действительный JSON, но имена полей, типы и необходимые ключи не ограничены. Добавление responseSchema или responseJsonSchema ограничивает токены во время декодирования, поэтому форма достаточно стабильна, чтобы сохраняться или передаваться следующему агенту.

Как мне выбрать response_schema или response_json_schema?

Используйте response_schema с моделью Pydantic или схемой SDK; SDK может предоставить ответ.parsed. Используйте response_json_schema для полного объекта JSON Schema (additionalProperties, min/max, prefixItems) или при отправке Pydantic/Zod model_json_schema() как есть. Оба требуют response_mime_type=application/json.

Может ли структурированный вывод заменить Вызов функции?

Нет. Структурированный вывод ограничивает конечный JSON, который видит пользователь или последующий код. Вызов функции/Вызов инструмента ограничивает аргумент инструмента JSON и по-прежнему требует, чтобы хост выполнил инструмент. Используйте структурированный вывод для извлечения, классификации и заполнения форм; используйте инструменты для погоды, файлов и MCP. Агентные конвейеры часто используют оба.

Гарантирует ли модель 100% соответствие схеме?

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

Поддерживаются ли вложенные объекты, массивы и перечисления?

Да. Объекты, массивы и перечисления строк представляют собой обычную комбинацию. Для классификации вы можете установить MIME на text/x.enum, чтобы модель выдавала только значение перечисления, а не объект JSON. Очень глубокая вложенность или циклические ссылки могут быть отклонены — сгладьте схему.

Как проверить схему и образец вывода локально?

Сохраните responseJsonSchema и несколько образцов выходных данных модели в виде файлов JSON. Проверьте синтаксис и структуру локально в JSON Toolbox в браузере — ничего не загружается. Используйте ту же схему еще раз во время выполнения после отправки.

Краткое содержание

To get structured JSON from Gemini, the order is: Schema first, JSON MIME second, prompt last. The prompt owns meaning (what to extract); the Schema owns shape (what fields look like). Pydantic / Zod are author-friendly fronts; on the wire you send response_schema or response_json_schema.

Run one real invoice or a support transcript: write the Schema → call generateContent once → paste response.text into a validator. Only then wire a database or the next agent. Tool arguments still go through Function Calling / MCP — do not collapse them into one API.