Интеграция OpenAI Structured Outputs для парсинга ответов
Structured Outputs гарантирует, что ответ модели точно соответствует заданной JSON-схеме. В отличие от response_format: json_object (который просто просит вернуть JSON), Structured Outputs обеспечивает соответствие конкретной схеме через constrained decoding — модель физически не может вернуть невалидный JSON.
Базовая интеграция с Pydantic
from openai import OpenAI
from pydantic import BaseModel
from typing import Literal, Optional
client = OpenAI()
# Схема для извлечения данных
class Invoice(BaseModel):
vendor_name: str
invoice_number: str
date: str
total_amount: float
currency: str
line_items: list["InvoiceItem"]
vat_amount: Optional[float] = None
class InvoiceItem(BaseModel):
description: str
quantity: float
unit_price: float
total: float
Invoice.model_rebuild() # Необходимо для forward references
# Парсинг — гарантированное соответствие схеме
def extract_invoice(text: str) -> Invoice:
response = client.beta.chat.completions.parse(
model="gpt-4o",
messages=[
{"role": "system", "content": "Извлеки данные счёта из текста"},
{"role": "user", "content": text}
],
response_format=Invoice,
)
return response.choices[0].message.parsed # Сразу Pydantic объект
Классификация с Enum
from enum import Enum
class TicketCategory(str, Enum):
technical = "technical"
billing = "billing"
feature_request = "feature_request"
complaint = "complaint"
general = "general"
class TicketClassification(BaseModel):
category: TicketCategory
priority: Literal["low", "medium", "high", "critical"]
sentiment: Literal["positive", "neutral", "negative", "angry"]
requires_human: bool
summary: str
tags: list[str]
def classify_ticket(text: str) -> TicketClassification:
response = client.beta.chat.completions.parse(
model="gpt-4o-mini", # Structured Outputs доступны и в mini
messages=[{"role": "user", "content": f"Классифицируй тикет: {text}"}],
response_format=TicketClassification,
temperature=0,
)
return response.choices[0].message.parsed
Structured Outputs через JSON Schema (без Pydantic)
# Для языков без Pydantic или сложных схем
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Данные продукта"}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "product_data",
"strict": True,
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"},
"in_stock": {"type": "boolean"},
"categories": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["name", "price", "in_stock", "categories"],
"additionalProperties": False,
}
}
}
)
import json
data = json.loads(response.choices[0].message.content)
Ограничения Structured Outputs
-
strict: TrueтребуетadditionalProperties: Falseна всех уровнях - Не поддерживаются: nullable fields через
"type": ["string", "null"](используйтеanyOf) - Максимальная вложенность: 5 уровней
- Для рекурсивных схем — использовать
$ref
Когда использовать
| Сценарий | Метод |
|---|---|
| Извлечение данных из документов | Structured Outputs |
| Классификация | Structured Outputs |
| Ответы с предсказуемой структурой | Structured Outputs |
| Свободный JSON (неизвестная структура) | json_object mode |
| Простые ответы | Обычный текст |
Сроки
- Базовое извлечение с Pydantic: 0.5–1 день
- Комплексные вложенные схемы: 1–2 дня







