Сравнение структурированного вывода у популярных провайдеров LLM: OpenAI, Gemini, Anthropic, Mistral и AWS Bedrock

Для работы с несколько отличающимися API требуется особый подход.

Содержимое страницы

Вот сравнительная таблица поддержки структурированного вывода (получение надежного JSON) у популярных провайдеров LLM, а также минимальные примеры на Python

colorised bars standing

Мы уже рассмотрели, как запрашивать структурированный вывод от LLM, размещенного в Ollama. После того как JSON появился в ответе, статья о валидации структурированного вывода LLM на Python описывает разбор, проверки через Pydantic, повторные попытки и тесты в вашем сервисе. Здесь мы рассмотрим, как запрашивать то же самое от других провайдеров.

Таблица TL;DR

Провайдер Нативный «JSON-режим» Принуждение к Схеме JSON Типичный параметр Примечания
OpenAI Да Да (первоклассная поддержка) response_format={"type":"json_schema", ...} Работает через Responses API или Chat Completions; также возможно использование вызова функций.
Google Gemini Да Да (первоклассная поддержка) response_schema= + response_mime_type="application/json" Возвращает строго валидированный JSON, когда указана схема.
Anthropic (Claude) Косвенно Да (через Tool Use со схемой JSON) tools=[{input_schema=...}] + tool_choice Заставляет модель «вызвать» инструмент, определенный схемой; возвращает аргументы в соответствии со схемой.
Mistral Да Частичная (только JSON; без серверной схемы) response_format={"type":"json_object"} Гарантирует JSON, но валидацию по вашей схеме нужно выполнять на стороне клиента.
AWS Bedrock (платформа) Зависит от модели Да (через Tool/Converse schema) toolConfig.tools[].toolSpec.inputSchema API Converse в Bedrock валидирует входные данные инструмента по схеме JSON.

Структурированный вывод LLM — Общая информация

Структурированный вывод LLM относится к способности больших языковых моделей (LLM) генерировать ответы, которые строго соответствуют заранее заданному формату или структуре, а не просто произвольный текст. Этот структурированный вывод может быть в форматах, таких как JSON, XML, таблицы или шаблоны, что делает данные машиночитаемыми, последовательными и легко парсируемыми программным обеспечением для использования в различных приложениях.

Структурированные выводы отличаются от традиционных выводов LLM, которые обычно генерируют открытый естественный язык. Вместо этого структурированные выводы принудительно применяют схему или формат, такую как JSON-объекты с определенными ключами и типами значений, или определенные классы в выводе (например, ответы с множественным выбором, классы тональности или форматы строк базы данных). Этот подход повышает надежность, снижает ошибки и галлюцинации, а также упрощает интеграцию в системы, такие как базы данных, API или рабочие процессы.

Генерация структурированных выводов в LLM часто включает такие методы, как:

  • Указание подробных инструкций в промпте, чтобы направить модель к созданию вывода в желаемом формате.
  • Использование инструментов валидации и разбора, таких как Pydantic в Python, чтобы убедиться, что вывод соответствует схеме.
  • Иногда принудительное соблюдение ограничений декодирования на основе грамматики или конечных автоматов для обеспечения соответствия токенов формату.

Преимущества структурированных выводов LLM включают:

  • Машиночитаемость и легкость интеграции.
  • Снижение вариативности и ошибок.
  • Повышенную предсказуемость и проверяемость для задач, требующих согласованных форматов данных.

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

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

Примеры структурированного вывода на Python

Все фрагменты кода извлекают информацию об событии в формате JSON: {title, date, location}. Заменяйте ключи/модели по своему усмотрению.

1) OpenAI — JSON Schema (строгий)

from openai import OpenAI
import json

client = OpenAI()

schema = {
    "name": "Event",
    "schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "date":  {"type": "string", "description": "YYYY-MM-DD"},
            "location": {"type": "string"}
        },
        "required": ["title", "date", "location"],
        "additionalProperties": False
    },
    "strict": True
}

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}
    ],
    response_format={"type": "json_schema", "json_schema": schema},
)

data = json.loads(resp.choices[0].message.content)
print(data)

Функция Structured Outputs от OpenAI обеспечивает соблюдение этой схемы на стороне сервера.


2) Google Gemini — схема ответа + JSON MIME

import google.generativeai as genai
from google.genai import types

# Configure with your API key
# genai.configure(api_key="your-api-key")

schema = types.Schema(
    type=types.Type.OBJECT,
    properties={
        "title": types.Schema(type=types.Type.STRING),
        "date": types.Schema(type=types.Type.STRING),
        "location": types.Schema(type=types.Type.STRING),
    },
    required=["title", "date", "location"],
    additional_properties=False,
)

resp = genai.generate_content(
    model="gemini-2.0-flash",
    contents="Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'",
    generation_config=genai.GenerationConfig(
        response_mime_type="application/json",
        response_schema=schema,
    ),
)

print(resp.text)  # already valid JSON per schema

Gemini вернет строгий JSON, соответствующий response_schema.


3) Anthropic (Claude) — Использование инструментов (Tool Use) со схемой JSON

from anthropic import Anthropic
import json

client = Anthropic()

tool = {
    "name": "extract_event",
    "description": "Return event details.",
    "input_schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "date": {"type": "string"},
            "location": {"type": "string"}
        },
        "required": ["title", "date", "location"],
        "additionalProperties": False
    }
}

msg = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=256,
    tools=[tool],
    tool_choice={"type": "tool", "name": "extract_event"},  # force schema
    messages=[{"role": "user", "content":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)

# Claude will "call" the tool; grab the args (which match your schema)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))

У Claude нет общего переключателя «JSON-режима»; вместо этого Tool Use с input_schema дает вам валидированные аргументы, соответствующие схеме (и вы можете принудительно использовать этот метод).


4) Mistral — JSON-режим (валидация на стороне клиента)

from mistralai import Mistral
import json

client = Mistral()

resp = client.chat.complete(
    model="mistral-large-latest",
    messages=[{"role":"user","content":
        "Return JSON with keys title, date (YYYY-MM-DD), location for: "
        "'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
    response_format={"type": "json_object"}  # guarantees valid JSON
)

data = json.loads(resp.choices[0].message.content)
print(data)
# Tip: validate `data` against your Pydantic/JSON Schema locally.

Параметр json_object в Mistral обеспечивает формат JSON (но не вашу точную схему) — валидируйте на стороне клиента.


5) AWS Bedrock — Схема инструмента Converse API (независимо от модели)

import boto3, json

bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0"

tools = [{
    "toolSpec": {
        "name": "extract_event",
        "inputSchema": {
            "json": {
                "type": "object",
                "properties": {
                    "title": {"type": "string"},
                    "date": {"type": "string"},
                    "location": {"type": "string"}
                },
                "required": ["title","date","location"],
                "additionalProperties": False
            }
        }
    }
}]

resp = bedrock.converse(
    modelId=model_id,
    toolConfig={"tools": tools},
    toolChoice={"tool": {"name": "extract_event"}},  # force schema
    messages=[{"role":"user","content":[{"text":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)

# Pull toolUse content
tool_use = next(
    c["toolUse"] for c in resp["output"]["message"]["content"] if "toolUse" in c
)
print(json.dumps(tool_use["input"], indent=2))

Bedrock валидирует входные данные инструмента по вашей схеме JSON, и многие размещенные модели (например, Claude) поддерживают это через Converse.


Практические рекомендации и валидация

  • Если вам нужны самые сильные гарантии на стороне сервера: используйте структурированные выводы OpenAI или схему ответа Gemini.
  • Если вы уже используете Claude/Bedrock: определите Tool со схемой JSON и принудительно используйте его; считывайте аргументы инструмента как ваш типизированный объект.
  • Если вы используете Mistral: включите json_object и валидируйте локально (например, с помощью Pydantic).

Шаблон валидации (работает для всех)

from pydantic import BaseModel, ValidationError

class Event(BaseModel):
    title: str
    date: str
    location: str

try:
    event = Event.model_validate(data)  # `data` from any provider
except ValidationError as e:
    # handle / retry / ask model to fix with e.errors()
    print(e)

Полезные ссылки

Подписаться

Получайте новые материалы про системы, инфраструктуру и AI engineering.