Сравнение структурированного вывода популярных провайдеров 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; также поддерживает function calling.
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 Converse API в Bedrock валидирует вход инструмента против схемы JSON.

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

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

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

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

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

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

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

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

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

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

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

1) OpenAI — Схема JSON (строгая)

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) — Использование инструментов со схемой 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.