
Структурований вивід LLM — це механізм, який гарантує, що відповідь мовної моделі відповідає попередньо визначеній схемі, причому це не просто валідний JSON, а відповідний схемі JSON із точно вказаними полями, типами та обмеженнями. Кожен великий провайдер тепер підтримує його нативно, і це змінило підхід до створення production-додатків на основі LLM.
Короткий огляд: Структуровані виводи за кілька секунд
Якщо у вас мало часу, ось поточний стан справ у 2026 році:
| Аспект | Деталі |
|---|---|
| Що це таке | Відповіді від LLM із примусовим дотриманням схеми, гарантована структура, а не «найкраща спроба» |
| Хто підтримує | OpenAI, Anthropic, Gemini, Cohere, xAI (Grok), а також локально через Ollama/vLLM |
| Ключовий механізм | Обмежене декодування, недійсні токени маскуються перед семплуванням |
| JSON Mode проти Strict Mode | JSON Mode = лише валідний синтаксис. Strict Mode = повна відповідність схемі |
| Бібліотека Python | Pydantic (BaseModel + Field) для визначення схеми |
| Бібліотека TypeScript | Zod (z.object + .describe) для визначення схеми |
| Найкращий старт | OpenAI з Pydantic або Zod через нативний SDK |
| Найкраща бібліотека для продакшену | Instructor (Python) або нативний SDK (TypeScript) |
| Найпоширеніша помилка | Розміщення поля міркувань ПІСЛЯ поля відповіді, модель приймає рішення до того, як подумає |
| Затримка | 50-200 мс при першому виклику (компіляція схеми), далі кешується |
Тепер розберемо кожен елемент детальніше.
Що таке структурований вивід LLM?
Структурований вивід — це різниця між надією на те, що LLM поверне валідний JSON, і гарантією цього. Коли ви вмикаєте структурований вивід, модель фізично не може генерувати токени, які порушують вашу схему. Ви визначаєте JSON Schema (або модель Pydantic, або схему Zod), передаєте її в API і отримуєте відповідь, яка відповідає їй щоразу.
Чому це важливо? До появи структурованого виводу розробники писали крихкі парсери на основі регулярних виразів, загортали кожен виклик LLM у блоки try/catch JSON.parse і все одно стикалися з відповідями, які були «майже правильними»: валідний JSON, але з відсутнім полем або неправильним типом. Цілий клас багів зник.
Існує три рівні примусового структурування, які представляють чітку еволюцію:
- Інжиніринг промптів: «Будь ласка, поверніть JSON із цими полями». Ненадійно. Модель може виконати це в 80-90% випадків.
- JSON Mode: Гарантує синтаксично валідний JSON, але не забезпечує дотримання вашої схеми. Ви можете отримати
{"foo": "bar"}, коли очікували{"name": string, "age": number}. - Strict Mode / Обмежене декодування: Гарантує 100% відповідність схемі. Модель буквально не може вивести недійсні токени. Саме це означає «структурований вивід» у 2026 році.
Станом на початок 2026 року OpenAI, Anthropic та Google Gemini підтримують нативний структурований вивід. Екосистема конвергувала.
Вердикт: Якщо ви парсите відповіді LLM за допомогою регулярних виразів або JSON.parse у продакшені, ви робите це складним шляхом. Нативний структурований вивід усуває цей режим відмови повністю.
JSON Mode проти Strict Mode: що реально змінилося?
Ця відмінність часто бентежить розробників, оскільки назви звучать схоже. Але вони не є однаковими.
| Функція | JSON Mode | Strict Mode (Структуровані виводи) |
|---|---|---|
| Параметр API | type: "json_object" | type: "json_schema" з strict: true |
| Гарантує валідний JSON | Так | Так |
| Гарантує відповідність схемі | Ні | Так |
| Механізм | Постфактум зміщення токенів | Обмежене декодування (FSM) |
| Може повертати неочікувані поля | Так | Ні |
| Може пропускати обов'язкові поля | Так | Ні |
| Примусове дотримання типів | Відсутнє | Повне (string, number, array тощо) |
| Коли використовувати | У вас немає заздалегідь визначеної схеми | Все у продакшені |
Хронологія: OpenAI представила JSON Mode наприкінці 2023 року. Це був крок уперед, але розробники швидко зрозуміли, що «валідного JSON» недостатньо, їм потрібен JSON, відповідний схемі. У серпні 2024 року OpenAI запустила Structured Outputs із Strict Mode, який використовує обмежене декодування для гарантії відповідності схемі. До 2025-2026 років кожен великий провайдер прийняв той самий підхід.
JSON Mode все ще має вузьке застосування: коли ви дійсно не знаєте заздалегідь форми відповіді і просто хочете якийсь валідний JSON для неструктурованого дослідження. Але у продакшені це рідкість.
Вердикт: Використовуйте Strict Mode для всього у продакшені. JSON Mode фактично застарів для випадків, прив'язаних до схеми. Якщо у вас є схема (а вона має бути), використовуйте type: "json_schema" з strict: true.
Як насправді працює обмежене декодування?
Ось механізм, який робить можливим 100% відповідність схемі, не 99,9%, а буквально 100%.
Коли ви надсилаєте JSON Schema провайдеру з увімкненим Strict Mode, схема компілюється в скінченний автомат (FSM). Цей FSM представляє кожен валідний шлях через вашу схему. На кожному кроці генерації токенів інференс-рушій перевіряє, які токени залишать вивід на валідному шляху, а які — ні. Недійсні токени отримують свої логіти, встановлені в негативну нескінченність перед семплуванням, що означає нульову ймовірність їхнього вибору.
<!-- IMAGE: constrained-decoding diagram showing FSM token masking during structured output generation -->Уявіть це як автодоповнення на стероїдах. Якщо модель щойно вивела {"rating":, а ваша схема каже, що rating є цілим числом, єдиними дозволеними наступними токенами будуть цифри. Лапки, літери, дужки — все замасковано. Модель не може вивести "five", навіть якщо «хоче» цього.
Це той самий основний механізм, який використовується в XGrammar (рушій позаду vLLM, SGLang і більшості локальних серверів інференсу) та Outlines (бібліотека Python з відкритим кодом для обмеженої генерації). Провайдери API просто вбудували його в свою інференс-інфраструктуру.
Є один компроміс, про який варто знати: перший запит із новою схемою зазнає затримки компіляції (зазвичай 50-200 мс), поки будується FSM. Наступні запити з тією ж схемою використовують кешований FSM і додають майже нульове навантаження. Також існує тонкий аспект якості: обмеження словника токенів іноді може знижувати якість виводу для креативних або довільних полів, тому тримайте свої схеми сфокусованими на дійсно структурованих даних.
Вердикт: Обмежене декодування — це те, що відрізняє «зазвичай працює» від «працює завжди». Це інженерія, яка робить структурований вивід готовим до продакшену.
Реалізація для кількох провайдерів: OpenAI, Anthropic та Gemini
Ось те, чого не показують інші посібники: одне й те саме завдання вилучення даних, реалізоване для всіх трьох основних провайдерів. Ми вилучимо структурований огляд продукту з неструктурованого тексту.
Схема Pydantic (спільна для всіх провайдерів):
from pydantic import BaseModel, Field
from typing import Literal
class ProductReview(BaseModel):
reasoning: str = Field(description="Think through the review before scoring")
rating: int = Field(description="Rating from 1-5", ge=1, le=5)
sentiment: Literal["positive", "negative", "neutral"]
pros: list[str] = Field(description="Key positive points")
cons: list[str] = Field(description="Key negative points")
summary: str = Field(description="One-sentence summary")Реалізація для OpenAI
from openai import OpenAI
client = OpenAI()
response = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": "Extract a structured review from the text."},
{"role": "user", "content": review_text}
],
response_format=ProductReview, # Pydantic model directly
)
review = response.choices[0].message.parsed # Typed ProductReview objectРеалізація OpenAI є найбільш зрілою. Метод parse() приймає модель Pydantic безпосередньо і повертає типізований об'єкт. Одне обмеження: Strict Mode від OpenAI підтримує підмножину JSON Schema, без $ref, обмежений anyOf, і всі поля мають бути обов'язковими з additionalProperties: false.
Реалізація для Anthropic
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=1024,
messages=[
{"role": "user", "content": f"Extract a structured review:\n\n{review_text}"}
],
output_config={
"format": {
"type": "json_schema",
"json_schema": ProductReview.model_json_schema()
}
}
)
import json
review_data = json.loads(response.content[0].text)
review = ProductReview(**review_data)Нативний структурований вивід Anthropic використовує output_config.format із JSON Schema. Він досяг статусу GA на початку 2026 року. Anthropic також підтримує старіший шаблон визначення «фейкового» інструменту та вилучення через tool_use, це все ще працює, але нативний структурований вивід чистіший для чистого вилучення даних.
Реалізація для Gemini
from google import genai
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.0-flash",
contents=f"Extract a structured review:\n\n{review_text}",
config={
"response_mime_type": "application/json",
"response_schema": ProductReview, # Pydantic model directly
}
)
import json
review = ProductReview(**json.loads(response.text))Gemini підтримує моделі Pydantic безпосередньо у Python SDK через response_schema. Унікальна особливість: Gemini поважає propertyOrdering у схемі, тому ви можете контролювати порядок виводу полів (корисно для шаблону «спочатку міркування»).
Порівняння провайдерів
| Функція | OpenAI | Anthropic | Gemini |
|---|---|---|---|
| Параметр API | response_format | output_config.format | response_schema |
| Вхід схеми | Pydantic або JSON Schema | JSON Schema | Pydantic або JSON Schema |
| Строгий режим | strict: true | Неявний із json_schema | Неявний |
| Потокова передача | Так (частковий JSON) | Так | Так |
| Обробка відмов | Поле message.refusal | Помилка у відповіді | Помилка у відповіді |
| Альтернатива tool-use | Так | Так (оригінальний метод) | Так |
| Кеш компіляції схеми | Так (на стороні сервера) | Так | Так |
| Порядок властивостей | Без нативної підтримки | Ні | Так (propertyOrdering) |
Вердикт: OpenAI має найполірованіший DX зі своїм методом parse(). Anthropic пропонує найпотужніші базові моделі. Властивість упорядкування властивостей Gemini є унікально корисною. Усі троє виконують роботу, обирайте залежно від ваших наявних відносин із провайдером.
Шаблони Pydantic для розробників Python
Pydantic є де-факто стандартом для визначення схем структурованого виводу в Python. Ось шаблони, які мають значення.
Базова схема з описами
from pydantic import BaseModel, Field
from typing import Literal, Optional
class ExtractedEntity(BaseModel):
reasoning: str = Field(description="Think step by step about the entity")
name: str = Field(description="Full name of the entity")
entity_type: Literal["person", "company", "location"]
confidence: float = Field(description="Confidence score 0.0-1.0", ge=0.0, le=1.0)
context: Optional[str] = Field(description="Surrounding context, if relevant")Ці рядки description не просто для документації, вони стають частиною JSON Schema, що надсилається моделі, і безпосередньо впливають на те, що генерує модель. Вважайте їх інжинірингом промптів всередині схеми.
Вкладені моделі
class Address(BaseModel):
street: str
city: str
country: str
postal_code: Optional[str] = None
class Company(BaseModel):
reasoning: str = Field(description="Analysis of the company details")
name: str
industry: Literal["tech", "finance", "healthcare", "retail", "other"]
headquarters: Address # Nested model
key_products: list[str] = Field(description="Top 3 products or services")Обмежте вкладеність 2-3 рівнями максимум. Глибоко вкладені схеми збільшують частоту помилок і уповільнюють компіляцію схеми.
Шаблон «Спочатку міркування»
Це найвпливовіший шаблон проектування схеми. Розмістіть поле reasoning перед полями відповіді:
# Reliable JSON from Any LLM: Pydantic + Zod Patterns for 2026
class ClassificationBad(BaseModel):
category: Literal["spam", "ham"]
confidence: float
# Good -- model reasons through the problem first
class ClassificationGood(BaseModel):
reasoning: str = Field(description="Analyze the text before classifying")
category: Literal["spam", "ham"]
confidence: float = Field(ge=0.0, le=1.0)LLM генерують токени зліва направо. Якщо category йде першим, модель обирає категорію, а потім раціоналізує її. Якщо reasoning йде першим, модель опрацьовує проблему і потім commits до категорії. Це ланцюжок думок, вбудований у схему.
Експорт JSON Schema
# Generate the JSON Schema for any Pydantic model
schema = ProductReview.model_json_schema()
# Pass this to any provider that accepts raw JSON SchemaВердикт: Pydantic + описові поля + порядок «спочатку міркування» — це тріада структурованого виводу Python. Опануйте ці три шаблони, і ви впораєтеся з 90% випадків використання.
Шаблони Zod для розробників TypeScript
Zod є TypeScript-еквівалентом Pydantic, і він так само важливий для робочих процесів структурованого виводу.
Базова схема з описами
import { z } from "zod";
const ProductReview = z.object({
reasoning: z.string().describe("Think through the review before scoring"),
rating: z.number().int().min(1).max(5),
sentiment: z.enum(["positive", "negative", "neutral"]),
pros: z.array(z.string()).describe("Key positive points"),
cons: z.array(z.string()).describe("Key negative points"),
summary: z.string().describe("One-sentence summary"),
});
// Infer the TypeScript type automatically
type ProductReview = z.infer<typeof ProductReview>;Як і Field(description=...) у Pydantic, .describe() у Zod стає частиною JSON Schema і спрямовує вивід моделі.
Інтеграція з OpenAI Node SDK
import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
const client = new OpenAI();
const response = await client.beta.chat.completions.parse({
model: "gpt-4o-2024-08-06",
messages: [
{ role: "system", content: "Extract a structured review." },
{ role: "user", content: reviewText },
],
response_format: zodResponseFormat(ProductReview, "product_review"),
});
const review = response.choices[0].message.parsed; // Typed!Інтеграція з Vercel AI SDK
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";
const { object: review } = await generateObject({
model: openai("gpt-4o"),
schema: ProductReview,
prompt: `Extract a structured review:\n\n${reviewText}`,
});
// review is fully typed as ProductReviewVercel AI SDK нативно використовує Zod із generateObject(), роблячи його найчистішою інтеграцією для TypeScript. Він працює з OpenAI, Anthropic, Gemini та іншими провайдерами через єдиний API.
Конвертація JSON Schema
import { zodToJsonSchema } from "zod-to-json-schema";
const jsonSchema = zodToJsonSchema(ProductReview);
// Use with any provider that accepts raw JSON SchemaВердикт: Zod + .describe() + Vercel AI SDK — це стек структурованого виводу TypeScript. Якщо ви в екосистемі Node/Next.js, це шлях найменшого опору.
Структурований вивід проти виклику функцій: коли що використовувати?
Це одне з найпоширеніших джерел плутанини. Обидва підходи включають схеми, обидва повертають структуровані дані, але вирішують різні проблеми.
Структурований вивід каже: «Дай мені дані в цій конкретній формі». Це для вилучення, класифікації та форматування. Ви витягуєте структуровану інформацію з неструктурованого тексту.
Виклик функцій (використання інструментів) каже: «Ось дії, які ви можете виконати, вирішіть, яку запустити, і надайте аргументи». Це для агентських робочих процесів, де модель обирає з кількох інструментів і запускає дії.
Плутанина має сенс історично. Оригінальний «структурований вивід» Anthropic був буквально викликом функцій: ви визначали фейковий інструмент під назвою extract_review і захоплювали аргументи. Це все ще працює, але нативний структурований вивід простіший для чистого вилучення.
| Сценарій | Найкращий підхід | Чому |
|---|---|---|
| Вилучення даних з тексту | Структурований вивід | Прямо, нижча затримка, одна схема |
| Класифікація за категоріями | Структурований вивід | Одна відповідь, одна схема |
| Агент вирішує, який інструмент викликати | Виклик функцій | Модель обирає з кількох інструментів |
| Багатоетапна оркестрація | Виклик функцій | Послідовні виклики інструментів |
| Вилучення даних І вирішення наступної дії | Обидва | Структурований вивід для вилучення, виклик функцій для оркестрації |
Структурований вивід живить пайплайни виклику інструментів у системах AI-агентів. Дивіться наш посібник із AI-агентів для бізнесу, щоб дізнатися, як вони вписуються у виробничі робочі процеси.
Вердикт: Використовуйте структурований вивід, коли ви знаєте, якою має бути форма даних. Використовуйте виклик функцій, коли модель повинна обрати дію. На практиці більшість додатків використовують обидва: структурований вивід для вилучення даних і виклик функцій для оркестрації агентів.
Production-шаблони: помилки, повторні спроби та потокова передача
Запустити структурований вивід у демо легко. Зберегти його надійним у продакшені вимагає обробки трьох речей: відмов, помилок валідації та потокової передачі.
Обробка відмов
Іноді модель відмовляється генерувати запитаний вами вивід, зазвичай тому, що фільтри безпеки позначили вхідні дані. Коли це трапляється, API структурованого виводу не повертають вашу схему. Вони повертають відмову.
response = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=messages,
response_format=ProductReview,
)
# ALWAYS check for refusal before accessing parsed content
if response.choices[0].message.refusal:
print(f"Model refused: {response.choices[0].message.refusal}")
else:
review = response.choices[0].message.parsedЯкщо ви пропустите перевірку відмови і спробуєте звернутися до .parsed при відмові, ви отримаєте None і незрозумілу помилку далі по ланцюжку. Завжди перевіряйте спочатку.
Шаблони повторних спроб із зворотним зв'язком валідації
Відповідність схемі гарантується обмеженим декодуванням, але семантична правильність — ні. Модель може повернути {"rating": 1, "sentiment": "positive"}, валідна схема, суперечливий контент. Саме тут на допомогу приходять валідація + повторні спроби.
import instructor
client = instructor.from_openai(OpenAI())
# Instructor handles retries automatically
review = client.chat.completions.create(
model="gpt-4o",
response_model=ProductReview,
max_retries=3, # Retries with validation error feedback
messages=[
{"role": "user", "content": review_text}
],
)Instructor передає помилку валідації назад моделі під час повторної спроби, щоб вона могла виправитися сама. Для ручних шаблонів повторних спроб без Instructor:
from pydantic import ValidationError
for attempt in range(3):
try:
response = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=messages,
response_format=ProductReview,
)
review = response.choices[0].message.parsed
# Run additional semantic validation here
break
except ValidationError as e:
messages.append({"role": "assistant", "content": str(response)})
messages.append({"role": "user", "content": f"Validation error: {e}. Fix it."})Потокова передача структурованого виводу
Для великих структурованих відповідей, довгих масивів, багатьох полів, складних вкладених об'єктів потокова передача дозволяє прогресивно відображати часткові результати.
import instructor
client = instructor.from_openai(OpenAI())
# Stream partial results as fields populate
review_stream = client.chat.completions.create_partial(
model="gpt-4o",
response_model=ProductReview,
messages=[{"role": "user", "content": review_text}],
)
for partial_review in review_stream:
# Fields populate one by one as tokens stream in
if partial_review.summary:
print(f"Summary so far: {partial_review.summary}")Один нюанс: окремі чанки потокової передачі самі по собі не є відповідними схемі. Поле reasoning може бути заповнене, тоді як rating все ще None. Плануйте свій UI відповідно, показуйте стан завантаження для незаповнених полів.
Вердикт: Перевірки відмов є обов'язковими. Повторні спроби зі зворотним зв'язком валідації ловлять семантичні помилки. Потокова передача варта того для будь-якої відповіді, яка займає більше кількох секунд.
Порівняння бібліотек структурованого виводу
Ви можете використовувати структурований вивід через нативні API, але бібліотеки додають валідацію, повторні спроби, потокову передачу та підтримку кількох провайдерів. Ось ландшафт.
Instructor є найпопулярнішим варіантом із 11K+ зірок на GitHub і 3M+ щомісячних завантажень. Він обгортає OpenAI, Anthropic, Gemini, Cohere, Ollama та інші з єдиним інтерфейсом на основі Pydantic. Ключові функції: автоматичні повторні спроби зі зворотним зв'язком валідації, потокова передача через create_partial() і надпросте налаштування (instructor.from_openai(client)). Якщо ви команда Python, починайте звідси.
BAML використовує інший підхід: спочатку схема через власний DSL. Ви визначаєте схеми у файлах .baml і автоматично генеруєте клієнти для Python, TypeScript, Ruby тощо. Його алгоритм SAP (parsing, узгоджений зі схемою) елегантно обробляє брудний вивід моделей. Найкраще для команд, що працюють з кількома мовами, або коли вам потрібні контракти між вашим шаром LLM і шаром додатка. Компроміс: додатковий крок збірки та новий синтаксис для вивчення.
LangChain пропонує .with_structured_output(schema) для структурованого виводу, незалежного від провайдера. Зручно, якщо ви вже в екосистемі LangChain. Компроміс: це важка залежність, і абстракція може приховувати специфічні для провайдера функції, які можуть вам знадобитися.
Нативні API, прямі виклики з response_format / output_config, вимагають нульових залежностей, окрім SDK провайдера. Ви отримуєте повний контроль і повну видимість. Найкраще для простих випадків використання або команд, які віддають перевагу мінімальній абстракції.
| Бібліотека | Мови | Провайдери | Автоповторні спроби | Потокова передача | Зірки GitHub | Крива навчання |
|---|---|---|---|---|---|---|
| Instructor | Python, TS | 15+ | Так | Так | 11K+ | Низька |
| BAML | Python, TS, Ruby, Go | Усі (незалежно від DSL) | Так | Так | 7K+ | Середня |
| LangChain | Python, TS | 20+ | Частково | Так | 100K+ | Середня-Висока |
| Нативні API | Будь-яка | 1 на SDK | Ні | Так | N/A | Низька |
Вибір правильної бібліотеки структурованого виводу є частиною ширшого рішення щодо стека AI. Ми розбираємо повний стек у нашому посібнику «Найкращий AI-стек для SaaS».
Дивіться нашу статтю «Найкращі бібліотеки для структурованого виводу LLM» [скоро] для детального порівняння Instructor, BAML, Mirascope та інших.
Вердикт: Почніть з Instructor для Python, нативних API для TypeScript. Переходьте на BAML, якщо вам потрібні контракти схем для кількох мов. Уникайте LangChain лише для структурованого виводу, це overkill.
Найкращі практики проектування схем (і поширені помилки)
Дизайн вашої схеми безпосередньо впливає на якість виводу. Ось шаблони, які мають значення, і помилки, які коштують вам точності.
Ставте міркування перед відповідями
Ми розглянули це в розділі Pydantic, але варто повторити, оскільки це рішення з найвищим впливом:
# Before: model guesses the answer, then rationalizes
class Bad(BaseModel):
answer: str
reasoning: str
# After: model thinks first, then commits
class Good(BaseModel):
reasoning: str = Field(description="Think step by step")
answer: strLLM генерують зліва направо. Порядок полів — це порядок промпту. Міркування першими означають, що модель повинна опрацювати проблему, перш ніж commit до відповіді.
Таблица антипатернів
| Помилка | Проблема | Виправлення |
|---|---|---|
| Поле міркувань після відповіді | Модель приймає рішення до того, як подумає | Перемістити міркування перед відповіддю |
| Глибока вкладеність (4+ рівні) | Вища частота помилок, повільніша компіляція | Сплощити до 2-3 рівнів |
| Відсутність описів полів | Модель вгадує, що ви хочете | Додати .describe() / Field(description=...) |
| Відсутня обробка null | Модель галюцинує значення, щоб заповнити поле | Використовувати Optional / .nullable() |
| Надто великі схеми (50+ полів) | Таймаут компіляції, деградація якості | Розбити на кілька викликів |
| Нечіткі варіанти enum | Модель обирає неправильну категорію | Використовувати конкретні, неперетинні варіанти |
Явно обробляйте Nulls
Якщо поле може не мати даних у вихідному тексті, зробіть його необов'язковим. Примусове використання обов'язкового поля, коли дані відсутні, призводить до галюцинацій:
class PersonInfo(BaseModel):
name: str # Always present
email: Optional[str] = Field(None, description="Email if mentioned, null otherwise")
phone: Optional[str] = Field(None, description="Phone if mentioned, null otherwise")Тримайте схеми сфокусованими
Одна схема на завдання. Не намагайтеся вилучити все в одній масивній схемі. Якщо вам потрібно 50+ полів, розбийте на кілька викликів вилучення. Strict Mode від OpenAI має практичні обмеження на складність схеми, і навіть коли це працює, дуже великі схеми погіршують якість виводу.
Вердикт: Спочатку міркування, описові поля, явні nulls і сфокусовані схеми. Зробіть ці чотири речі правильно, і точність вашого структурованого виводу помітно зросте.
Структурований вивід з локальними LLM
Вам не потрібен провайдер API для структурованого виводу. Локальні рушії інференсу підтримують його через обмежене декодування на основі граматики, той самий фундаментальний механізм, що працює на вашому власному обладнанні.
Ollama
Найпростіший шлях для локального структурованого виводу. Ollama приймає JSON Schema через параметр format:
import ollama
from pydantic import BaseModel
class Country(BaseModel):
name: str
capital: str
languages: list[str]
response = ollama.chat(
model="llama3.2",
messages=[{"role": "user", "content": "Tell me about Japan."}],
format=Country.model_json_schema(),
)
import json
country = Country(**json.loads(response.message.content))Ollama використовує XGrammar під капотом для обмеженого декодування. Та сама гарантія, що й у провайдерів API: 100% відповідність схемі.
vLLM і SGLang
Для локального інференсу рівня продакшену vLLM і SGLang обидва підтримують структурований вивід через параметри guided_json і guided_regex. XGrammar є бекендом за замовчуванням, забезпечуючи майже нульове навантаження на генерацію JSON, до 3,5 разів швидше за альтернативні граматики.
Outlines
Outlines — це бібліотека Python з відкритим кодом, яка піонером у обмеженій генерації на основі граматики. Вона працює з будь-якою моделлю Hugging Face і підтримує JSON Schema, регулярні вирази та повні обмеження контекстно-вільної граматики (CFG/EBNF). Вона також інтегрована в vLLM і SGLang як опція бекенду граматики.
Ключова відмінність від провайдерів API: локальний структурований вивід не має обмежень підмножини схеми. Ви повністю контролюєте граматику. Але якість моделі варіюється більше, локальна модель на 7B параметрів не зрівняється з GPT-4o або Claude у складних завданнях вилучення. Схема завжди буде валідною; якість контенту залежить від моделі.
Вердикт: Ollama для розробки, vLLM/SGLang з XGrammar для продакшену. Локальний структурований вивід достатньо зрілий для більшості випадків використання, із застереженням, що менші моделі створюють контент нижчої якості в межах схеми.
FAQ
Що таке структурований вивід у LLM?
Структурований вивід — це механізм, який гарантує, що відповідь LLM відповідає попередньо визначеній JSON Schema. На відміну від простого тексту або навіть JSON Mode, структурований вивід використовує обмежене декодування, щоб забезпечити дотримання кожного поля, типу та обмеження у вашій схемі — 100% часу, а не «зазвичай».
У чому різниця між JSON Mode і Structured Outputs?
JSON Mode гарантує синтаксично валідний JSON, але не забезпечує дотримання вашої схеми, ви можете отримати будь-який валідний JSON-об'єкт. Structured Outputs (Strict Mode) гарантує повну відповідність схемі через обмежене декодування. Використовуйте Strict Mode для продакшену; JSON Mode актуальний лише тоді, коли у вас немає заздалегідь визначеної схеми.
Які провайдери LLM підтримують структурований вивід нативно?
OpenAI (з серпня 2024), Google Gemini (2024, розширено 2026), Anthropic (бета листопад 2025, GA початок 2026), Cohere та xAI (Grok) усі підтримують нативний структурований вивід. На локальному боці Ollama, vLLM і SGLang підтримують його через обмежене декодування на основі граматики.
Як обмежене декодування гарантує відповідність схемі?
JSON Schema компілюється в скінченний автомат (FSM). На кожному кроці генерації токенів дозволені лише ті токени, які залишають вивід на валідному шляху через FSM, недійсні токени отримують свої логіти, встановлені в негативну нескінченність. Це означає, що недійсні токени мають нульову ймовірність генерації, даючи вам математичну гарантію, а не статистичну.
Чи слід мені використовувати структурований вивід чи виклик функцій?
Використовуйте структурований вивід для вилучення та класифікації, коли ви хочете дані в конкретній формі. Використовуйте виклик функцій для агентських робочих процесів, коли модель повинна вирішити, яку дію виконати. Багато production-додатків використовують обидва: структурований вивід для вилучення даних і виклик функцій для оркестрації.
Чи можу я передавати структурований вивід у потоковому режимі?
Так. OpenAI підтримує потокову передачу з методом parse(), а Instructor надає create_partial() для потокової передачі моделей Pydantic, які заповнюються поле за полем. Майте на увазі, що окремі чанки потокової передачі не є індивідуально відповідними схемі, поля заповнюються поступово.
Що таке бібліотека Instructor?
Instructor — це найпопулярніша бібліотека структурованого виводу (11K+ зірок на GitHub, 3M+ щомісячних завантажень). Вона обгортає SDK провайдерів із валідацією на основі Pydantic, автоматичними повторними спробами зі зворотним зв'язком валідації та підтримкою потокової передачі. Вона працює з OpenAI, Anthropic, Gemini, Cohere, Ollama та 10+ іншими провайдерами.
Чи працює структурований вивід з локальними LLM?
Так. Ollama підтримує структурований вивід через параметр format із JSON Schema. vLLM і SGLang підтримують його через параметри guided_json. Усі троє використовують XGrammar або Outlines для обмеженого декодування. Гарантія відповідності схемі така ж, як у провайдерів API; якість контенту залежить від моделі.
Які поширені помилки проектування схем?
Найпоширеніші помилки: розміщення поля міркувань після поля відповіді (модель приймає рішення до того, як подумає), глибоко вкладені схеми (4+ рівні збільшують помилки), відсутність описів полів (модель вгадує намір), відсутня обробка null для необов'язкових даних (змушує до галюцинацій) і надто великі схеми (50+ полів погіршують якість).
Чи додає структурований вивід затримку?
Існує накладні витрати на компіляцію схеми при першому запиті, зазвичай 50-200 мс, поки будується FSM. Наступні запити з тією ж схемою використовують кешований FSM і додають майже нульову затримку. Для більшості додатків це незначно порівняно із загальним часом інференсу моделі.
Чи можу я використовувати структурований вивід із зображеннями або мультимодальними входами?
Так. Структурований вивід застосовується до формату відповіді, а не входу. Ви можете надіслати зображення до GPT-4o або Gemini зі схемою структурованого виводу і отримати назад аналіз зображення, відповідний схемі. Це потужно для робочих процесів візуального вилучення, вилучення структурованих даних із квитанцій, форм або зображень продуктів.