Сравнение структурированного вывода среди популярных поставщиков LLM — OpenAI, Gemini, Anthropic, Mistral и AWS Bedrock
Немного отличающиеся API требуют особого подхода.
Вот сравнение поддержки структурированного вывода (получение надежного JSON) среди популярных поставщиков LLM, а также минимальные примеры на Python
Мы уже рассматривали, как запрашивать структурированный вывод от LLM, размещенного на Ollama. Здесь мы рассматриваем, как запросить то же самое от других поставщиков.
Краткая сводка
Поставщик | Нативный режим “JSON” | Принудительное соблюдение схемы JSON | Типичный параметр | Примечания |
---|---|---|---|---|
OpenAI | Да | Да (первоклассный) | response_format={"type":"json_schema", ...} |
Работает через 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) | toolConfig.tools[].toolSpec.inputSchema |
API Converse Bedrock валидирует вход инструмента по схеме JSON. |
Структурированный вывод LLM - общая информация
Структурированный вывод LLM относится к способности больших языковых моделей (LLMs) генерировать ответы, которые строго соответствуют заранее определенному, конкретному формату или структуре, а не просто производить свободный текст. Такой структурированный вывод может быть в форматах 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": "Извлеките мероприятие из: 'PyData Sydney проходит 2025-11-03 в Дарлинг-Харборе.'"}
],
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
# Настройка с вашим API-ключом
# 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="Извлеките мероприятие из: 'PyData Sydney проходит 2025-11-03 в Дарлинг-Харборе.'",
generation_config=genai.GenerationConfig(
response_mime_type="application/json",
response_schema=schema,
),
)
print(resp.text) # уже валидный JSON по схеме
Gemini вернет строгий JSON, соответствующий response_schema
.
3) Anthropic (Claude) — Использование инструмента с JSON схемой
from anthropic import Anthropic
import json
client = Anthropic()
tool = {
"name": "extract_event",
"description": "Возвращает детали мероприятия.",
"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"}, # принудительно применяем схему
messages=[{"role": "user", "content":
"Извлеките мероприятие из: 'PyData Sydney проходит 2025-11-03 в Дарлинг-Харборе.'"}],
)
# Claude "вызовет" инструмент; получите аргументы (которые соответствуют вашей схеме)
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":
"Верните JSON с ключами title, date (YYYY-MM-DD), location для: "
"'PyData Sydney проходит 2025-11-03 в Дарлинг-Харборе.'"}],
response_format={"type": "json_object"} # гарантирует валидный JSON
)
data = json.loads(resp.choices[0].message.content)
print(data)
# Совет: валидируйте `data` по вашей схеме Pydantic/JSON Schema локально.
Режим json_object
Mistral навязывает форму JSON (не вашу точную схему) — валидируйте на стороне клиента.
5) AWS Bedrock — Схема инструмента API Converse (независимо от модели)
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"}}, # принудительно применяем схему
messages=[{"role":"user","content":[{"text":
"Извлеките мероприятие из: 'PyData Sydney проходит 2025-11-03 в Дарлинг-Харборе.'"}]}],
)
# Получаем содержимое toolUse
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: определите Инструмент со схемой 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` от любого поставщика
except ValidationError as e:
# обработать / повторить / попросить модель исправить с e.errors()
print(e)
Полезные ссылки
- https://platform.openai.com/docs/guides/structured-outputs
- https://ai.google.dev/gemini-api/docs/structured-output
- https://docs.mistral.ai/capabilities/structured-output/json_mode/
- https://aws.amazon.com/blogs/machine-learning/structured-data-response-with-amazon-bedrock-prompt-engineering-and-tool-use
- https://github.com/aws-samples/anthropic-on-aws/blob/main/complex-schema-tool-use/README.md
- https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html
- Как запросить структурированный вывод от LLM, размещенного на Ollama
- Шпаргалка по Python
- AWS SAM + AWS SQS + Python PowerTools
- Сравнение производительности AWS Lambda: JavaScript vs Python vs Golang