
Output-ul structurat LLM este mecanismul care garantează că răspunsul unui model de limbaj se conformează unei scheme predefinite, nu doar un JSON valid, ci un JSON valid conform schemei, cu câmpurile, tipurile și constrângerile exacte pe care le-ați specificat. Fiecare provider major suportă acum acest lucru nativ, iar modul în care sunt construite aplicațiile LLM de producție s-a schimbat.
Rezumat rapid: Output-uri structurate în detaliu
Dacă aveți puțin timp, iată panorama în 2026:
| Aspect | Detalii |
|---|---|
| Ce este | Răspunsuri impuse de schemă de la LLM-uri, structură garantată, nu „cel mai bun efort” |
| Cine suportă | OpenAI, Anthropic, Gemini, Cohere, xAI (Grok), plus local prin Ollama/vLLM |
| Mecanism cheie | Decodare constrânsă, token-urile invalide sunt mascate înainte de sampling |
| JSON Mode vs Strict Mode | JSON Mode = doar sintaxă validă. Strict Mode = conformitate totală cu schema |
| Librărie Python | Pydantic (BaseModel + Field) pentru definirea schemei |
| Librărie TypeScript | Zod (z.object + .describe) pentru definirea schemei |
| Cea mai bună abordare de start | OpenAI cu Pydantic sau Zod prin SDK-ul nativ |
| Cea mai bună librărie de producție | Instructor (Python) sau SDK nativ (TypeScript) |
| Cea mai mare capcană | Plasarea câmpului de raționament DUPĂ câmpul de răspuns; modelul decide înainte de a gândi |
| Overhead de latență | 50-200ms la primul apel (compilarea schemei), apoi cache-uit |
Să analizăm fiecare componentă în detaliu.
Ce sunt output-urile structurate LLM?
Output-ul structurat face diferența dintre a spera că un LLM returnează un JSON valid și a garanta acest lucru. Când activați output-ul structurat, modelul fizic nu poate produce token-uri care încalcă schema dumneavoastră. Definiți o JSON Schema (sau un model Pydantic, sau o schemă Zod), o transmiteți API-ului și primiți înapoi un răspuns care se potrivește cu aceasta de fiecare dată.
De ce contează acest lucru? Înainte de output-ul structurat, dezvoltatorii scriau parsere regex fragile, înfășurau fiecare apel LLM în blocuri try/catch JSON.parse și tot se confruntau cu răspunsuri „aproape corecte”, JSON valid cărora le lipsea un câmp sau aveau un tip greșit. Întreaga clasă de bug-uri a dispărut.
Există trei niveluri de impunere a structurii, care reprezintă o evoluție clară:
- Ingineria prompt-urilor: „Vă rugăm să returnați JSON cu aceste câmpuri.” Nesigur. Modelul se poate conforma 80-90% din timp.
- JSON Mode: Garantează JSON sintactic valid, dar nu impune schema dumneavoastră. Ați putea primi
{"foo": "bar"}când vă așteptați la{"name": string, "age": number}. - Strict Mode / Decodare constrânsă: Garantează conformitatea 100% cu schema. Modelul literalmente nu poate genera token-uri invalide. Aceasta este semnificația „output-ului structurat” în 2026.
Începând cu începutul anului 2026, OpenAI, Anthropic și Google Gemini suportă toate output-ul structurat nativ. Ecosistemul a convergat.
Verdict: Dacă parsezi răspunsurile LLM cu regex sau JSON.parse în producție, o faci greu. Output-ul structurat nativ elimină întregul mod de eșec.
JSON Mode vs Strict Mode: Ce s-a schimbat cu adevărat?
Această distincție îi derutează pe mulți dezvoltatori deoarece numele sună similar. Nu sunt la fel.
| Caracteristică | JSON Mode | Strict Mode (Output-uri Structurate) |
|---|---|---|
| Parametru API | type: "json_object" | type: "json_schema" cu strict: true |
| Garantează JSON valid | Da | Da |
| Garantează conformitatea cu schema | Nu | Da |
| Mecanism | Bias post-hoc al token-urilor | Decodare constrânsă (FSM) |
| Poate returna câmpuri neașteptate | Da | Nu |
| Poate omite câmpuri obligatorii | Da | Nu |
| Impunerea tipului | Niciuna | Totală (string, number, array etc.) |
| Când se folosește | Nu aveți o schemă prestabilită | Totul în producție |
Cronologia: OpenAI a introdus JSON Mode la sfârșitul anului 2023. A fost un pas înainte, dar dezvoltatorii au realizat rapid că „JSON valid” nu era suficient; aveau nevoie de JSON valid conform schemei. În august 2024, OpenAI a lansat Output-uri Structurate cu Strict Mode, care utilizează decodarea constrânsă pentru a garanta conformitatea cu schema. Până în 2025-2026, fiecare provider major adoptase aceeași abordare.
JSON Mode încă are un caz de utilizare îngust: când chiar nu cunoașteți forma răspunsului dinainte și doriți doar un JSON valid pentru explorare nestructurată. Dar acest lucru este rar în producție.
Verdict: Folosiți Strict Mode pentru tot ce ține de producție. JSON Mode este efectiv depreciat pentru cazurile de utilizare legate de scheme. Dacă aveți o schemă (și ar trebui să aveți), folosiți type: "json_schema" cu strict: true.
Cum funcționează de fapt decodarea constrânsă?
Iată mecanismul care face posibilă conformitatea 100% cu schema, nu 99,9%, ci literalmente 100%.
Când trimiteți o JSON Schema unui provider cu Strict Mode activat, schema este compilată într-o mașină cu stări finite (FSM). Această FSM reprezintă fiecare cale validă prin schema dumneavoastră. La fiecare pas de generare a token-urilor, motorul de inferență verifică ce token-uri ar menține output-ul pe o cale validă și care nu. Token-urile invalide își au logiții setați la minus infinit înainte de sampling, ceea ce înseamnă că au zero probabilitate de a fi selectați.
<!-- IMAGE: constrained-decoding diagram showing FSM token masking during structured output generation -->Gândiți-vă la asta ca la o completare automată (autocomplete) intensificată. Dacă modelul tocmai a generat {"rating": iar schema dumneavoastră spune că rating este un număr întreg, singurele token-uri permise în continuare sunt cele numerice. Ghilimelele, literele, parantezele, toate sunt mascate. Modelul nu poate genera "five" chiar dacă „ar vrea” să o facă.
Acesta este același mecanism de bază utilizat de XGrammar (motorul din spatele vLLM, SGLang și al majorității serverelor de inferență locale) și Outlines (librăria Python open-source pentru generare constrânsă). Providerii API au integrat acest lucru în infrastructura lor de inferență.
Există un compromis de știut: prima cerere cu o nouă schemă implică o penalizare de latență la compilare (de obicei 50-200ms) în timp ce se construiește FSM. Cererile ulterioare cu aceeași schemă folosesc un FSM cache-uit și adaugă un overhead aproape zero. Există, de asemenea, o considerație subtilă privind calitatea; constrângerea vocabularului de token-uri poate reduce ocazional calitatea output-ului pentru câmpuri creative sau libere, așa că mențineți schemele concentrate pe date cu adevărat structurate.
Verdict: Decodarea constrânsă este ceea ce separă „de obicei funcționează” de „funcționează mereu”. Este ingineria care face output-ul structurat gata de producție.
Implementare Multi-Provider: OpenAI, Anthropic și Gemini
Iată ceva ce niciun alt ghid nu vă arată: aceeași sarcină de extracție implementată pe toți cei trei provideri majori. Vom extrage un review de produs structurat din text nestructurat.
Schema Pydantic (partajată între toți providerii):
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")Implementare 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 objectImplementarea OpenAI este cea mai matură. Metoda parse() acceptă direct un model Pydantic și returnează un obiect tipizat. O constrângere: Strict Mode de la OpenAI suportă un subset de JSON Schema, fără $ref, anyOf limitat și toate câmpurile trebuie să fie obligatorii cu additionalProperties: false.
Implementare 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)Output-ul structurat nativ al Anthropic folosește output_config.format cu o JSON Schema. A ajuns GA la începutul lui 2026. Anthropic suportă, de asemenea, modelul mai vechi de definire a unui instrument „fals” și extragere prin tool_use; acesta încă funcționează, dar output-ul structurat nativ este mai curat pentru extracția pură.
Implementare 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 suportă modele Pydantic direct în SDK-ul Python prin response_schema. O caracteristică unică: Gemini respectă propertyOrdering din schemă, astfel încât puteți controla ordinea de output a câmpurilor (util pentru modelul raționament-prin-răspuns).
Compararea Providerilor
| Caracteristică | OpenAI | Anthropic | Gemini |
|---|---|---|---|
| Parametru API | response_format | output_config.format | response_schema |
| Input schemă | Pydantic sau JSON Schema | JSON Schema | Pydantic sau JSON Schema |
| Mod strict | strict: true | Implicit cu json_schema | Implicit |
| Streaming | Da (JSON parțial) | Da | Da |
| Gestionarea refuzului | Câmpul message.refusal | Răspuns de eroare | Răspuns de eroare |
| Alternativă tool-use | Da | Da (metoda originală) | Da |
| Cache compilare schemă | Da (lato-server) | Da | Da |
| Ordonarea proprietăților | Fără suport nativ | Nu | Da (propertyOrdering) |
Verdict: OpenAI are cea mai rafinată experiență de dezvoltator (DX) cu metoda sa parse(). Anthropic oferă cele mai capabile modele de bază. Ordonarea proprietăților de la Gemini este unic utilă. Toți trei își fac treaba; alegeți în funcție de relația existentă cu providerul.
Modele Pydantic pentru Dezvoltatorii Python
Pydantic este standardul de facto pentru definirea schemelor de output structurat în Python. Iată modelele care contează.
Schemă de bază cu descrieri
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")Șirurile description nu sunt doar pentru documentație; ele devin parte din JSON Schema trimisă modelului și influențează direct ceea ce generează modelul. Gândiți-vă la ele ca la ingineria prompt-urilor în interiorul schemei.
Modele Imbricate
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")Mențineți imbricarea la maximum 2-3 niveluri. Schemele profund imbricate cresc ratele de eroare și încetinesc compilarea schemei.
Modelul Raționament-Prin-Răspuns (Reasoning-First)
Acesta este cel mai impactant model de design al schemei. Puneți un câmp reasoning înainte de câmpurile de răspuns:
# 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-urile generează token-uri de la stânga la dreapta. Dacă category vine primul, modelul alege o categorie și apoi o raționalizează. Dacă reasoning vine primul, modelul parcurge problema și apoi se angajează într-o categorie. Este chain-of-thought încorporat în schemă.
Export JSON Schema
# Generate the JSON Schema for any Pydantic model
schema = ProductReview.model_json_schema()
# Pass this to any provider that accepts raw JSON SchemaVerdict: Pydantic + câmpuri descriptive + ordonare reasoning-first este trinitatea output-ului structurat în Python. Stăpâniți aceste trei modele și veți gestiona 90% din cazurile de utilizare.
Modele Zod pentru Dezvoltatorii TypeScript
Zod este echivalentul TypeScript al Pydantic și este la fel de central în fluxurile de lucru ale output-ului structurat.
Schemă de bază cu descrieri
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>;La fel ca Field(description=...) din Pydantic, .describe() din Zod devine parte din JSON Schema și ghidează output-ul modelului.
Integrare cu 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!Integrare cu 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 folosește Zod nativ cu generateObject(), făcându-l cea mai curată integrare TypeScript. Funcționează cu OpenAI, Anthropic, Gemini și alți provideri printr-un API unificat.
Conversie JSON Schema
import { zodToJsonSchema } from "zod-to-json-schema";
const jsonSchema = zodToJsonSchema(ProductReview);
// Use with any provider that accepts raw JSON SchemaVerdict: Zod + .describe() + Vercel AI SDK este stiva de output structurat pentru TypeScript. Dacă sunteți în ecosistemul Node/Next.js, aceasta este calea cu cea mai mică rezistență.
Output Structurat vs Function Calling: Când folosiți fiecare?
Aceasta este una dintre cele mai comune surse de confuzie. Ambele implică scheme, ambele returnează date structurate, dar rezolvă probleme diferite.
Output-ul structurat spune: „Dă-mi date în această formă exactă.” Este pentru extracție, clasificare și formatare. Extrageți informații structurate din text nestructurat.
Function calling (utilizarea instrumentelor) spune: „Iată acțiuni pe care le poți întreprinde, decidă care să ruleze și furnizează argumentele.” Este pentru fluxuri de lucru agentice unde modelul alege dintre multiple instrumente și declanșează acțiuni.
Confuzia are sens istoric. „Output-ul structurat” original al Anthropic era literalmente function calling; defineai un instrument fals numit extract_review și preluai argumentele. Acest lucru încă funcționează, dar output-ul structurat nativ este mai simplu pentru extracția pură.
| Scenariu | Cea mai bună abordare | De ce |
|---|---|---|
| Extragerea datelor din text | Output structurat | Direct, latență mai mică, o singură schemă |
| Clasificarea în categorii | Output structurat | Un răspuns, o schemă |
| Agentul decide ce instrument să apeleze | Function calling | Modelul alege dintre multiple instrumente |
| Orchestrare multi-pas | Function calling | Invocări secvențiale de instrumente |
| Extragerea datelor ȘI deciderea următoarei acțiuni | Ambele | Output structurat pentru extracție, function calling pentru orchestrare |
Output-ul structurat alimentează pipeline-urile de apelare a instrumentelor în sistemele de agenți AI. Consultați ghidul nostru despre agenții AI pentru afaceri pentru a vedea cum se potrivesc acestea în fluxurile de lucru de producție.
Verdict: Folosiți output-ul structurat când știți ce formă ar trebui să aibă datele. Folosiți function calling când modelul trebuie să aleagă o acțiune. În practică, majoritatea aplicațiilor folosesc ambele: output structurat pentru extracția datelor și function calling pentru orchestrarea agenților.
Modele de Producție: Erori, Retry-uri și Streaming
Este ușor să faceți output-ul structurat să funcționeze într-un demo. Menținerea fiabilității în producție necesită gestionarea a trei lucruri: refuzuri, eșecuri de validare și streaming.
Gestionarea Refuzurilor
Uneori un model refuză să genereze output-ul solicitat, de obicei deoarece filtrele de siguranță au semnalat input-ul. Când se întâmplă acest lucru, API-urile de output structurat nu returnează schema dumneavoastră. Ele returnează un refuz.
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.parsedDacă săriți verificarea refuzului și încercați să accesați .parsed pe un refuz, veți obține None și o eroare downstream confuză. Verificați întotdeauna mai întâi.
Modele de Retry cu Feedback de Validare
Conformitatea cu schema este garantată de decodarea constrânsă, dar corectitudinea semantică nu este. Modelul ar putea returna {"rating": 1, "sentiment": "positive"}, schemă validă, conținut contradictoriu. Aici intervin validarea + retry-urile.
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 transmite eroarea de validare înapoi modelului la retry, astfel încât acesta să se poată autocorecta. Pentru modele manuale de retry fără 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."})Streaming Output Structurat
Pentru răspunsuri structurate mari, tablouri lungi, multe câmpuri, obiecte imbricate complexe, streaming-ul vă permite să redați rezultatele parțiale progresiv.
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}")O capcană: chunk-urile individuale de streaming nu sunt valide conform schemei pe cont propriu. Câmpul reasoning ar putea fi populat în timp ce rating este încă None. Planificați UI-ul corespunzător, afișați o stare de încărcare pentru câmpurile nepopulate.
Verdict: Verificările de refuz sunt non-negociabile. Retry-urile cu feedback de validare prind erorile semantice. Streaming-ul merită pentru orice răspuns care durează mai mult de câteva secunde.
Compararea Librăriilor de Output Structurat
Puteți utiliza output-ul structurat prin API-uri native, dar librăriile adaugă validare, retry-uri, streaming și suport multi-provider. Iată panorama.
Instructor este cea mai populară opțiune, cu peste 11K stele pe GitHub și peste 3 milioane de descărcări lunare. Înfășoară OpenAI, Anthropic, Gemini, Cohere, Ollama și altele cu o interfață unificată bazată pe Pydantic. Caracteristici cheie: retry-uri automate cu feedback de validare, streaming prin create_partial() și configurare extrem de simplă (instructor.from_openai(client)). Dacă sunteți o echipă Python, începeți de aici.
BAML adoptă o abordare diferită: schemă-first printr-un DSL personalizat. Definiți schemele în fișiere .baml și generați automat clienți pentru Python, TypeScript, Ruby și altele. Algoritmul său SAP (schema-aligned parsing) gestionează grațios output-urile dezordonate ale modelelor. Cel mai bun pentru echipe cross-language sau când doriți contracte între stratul LLM și stratul aplicației. Compromis: pas suplimentar de build și o nouă sintaxă de învățat.
LangChain oferă .with_structured_output(schema) pentru output structurat agnostic de provider. Convenabil dacă sunteți deja în ecosistemul LangChain. Compromis: este o dependență grea, iar abstractizarea poate ascunde caracteristici specifice providerului de care ați putea avea nevoie.
API-uri Native, apeluri directe cu response_format / output_config, nu necesită zero dependențe în afara SDK-ului providerului. Obțineți control total și vizibilitate totală. Cel mai bun pentru cazuri simple sau echipe care preferă abstractizare minimă.
| Librărie | Limbaje | Provideri | Auto Retries | Streaming | Stele GitHub | Curba de învățare |
|---|---|---|---|---|---|---|
| Instructor | Python, TS | 15+ | Da | Da | 11K+ | Mică |
| BAML | Python, TS, Ruby, Go | Toate (agnostic DSL) | Da | Da | 7K+ | Medie |
| LangChain | Python, TS | 20+ | Parțial | Da | 100K+ | Medie-Mare |
| API-uri Native | Oricare | 1 per SDK | Nu | Da | N/A | Mică |
Alegerea librăriei potrivite de output structurat face parte dintr-o decizie mai largă privind stiva AI. Detaliem stiva completă în Ghidul Celei Mai Bune Stive AI pentru SaaS.
Consultați Cele Mai Bune Librării pentru Output-uri Structurate LLM [în curând] pentru o comparație aprofundată a Instructor, BAML, Mirascope și altele.
Verdict: Începeți cu Instructor pentru Python, API-uri native pentru TypeScript. Treceti la BAML dacă aveți nevoie de contracte de schemă cross-language. Evitați LangChain doar pentru output structurat, este excesiv.
Cele Mai Bune Practici de Design al Schemei (și Greșeli Comune)
Designul schemei dumneavoastră impactează direct calitatea output-ului. Iată modelele care contează și greșelile care vă costă acuratețea.
Puneți Raționamentul Înaintea Răspunsurilor
Am abordat acest aspect în secțiunea Pydantic, dar merită repetat deoarece este decizia de design cu cel mai mare impact:
# 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-urile generează de la stânga la dreapta. Ordinea câmpurilor este ordinea prompt-ului. Raționamentul primul înseamnă că modelul trebuie să parcurgă problema înainte de a se angaja într-un răspuns.
Tabelul Anti-Pattern
| Greșeală | Problemă | Soluție |
|---|---|---|
| Câmp de raționament după răspuns | Modelul decide înainte de a gândi | Mutați raționamentul înainte de răspuns |
| Imbricare profundă (4+ niveluri) | Rată de eroare mai mare, compilare mai lentă | Reduceți la 2-3 niveluri |
| Fără descrieri de câmp | Modelul ghicește ce doriți | Adăugați .describe() / Field(description=...) |
| Lipsa gestionării null-urilor | Modelul halucinează o valoare pentru a umple câmpul | Folosiți Optional / .nullable() |
| Scheme prea mari (50+ câmpuri) | Timeout compilare, degradarea calității | Împărțiți în mai multe apeluri |
| Opțiuni enum vagi | Modelul alege categoria greșită | Folosiți opțiuni specifice, care nu se suprapun |
Gestionați Null-urile Explicit
Dacă un câmp ar putea să nu aibă date în textul sursă, faceți-l opțional. Forțarea unui câmp obligatoriu atunci când datele nu există duce la halucinații:
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")Mențineți Schemele Concentrate
O schemă per sarcină. Nu încercați să extrageți totul într-o singură schemă masivă. Dacă aveți nevoie de 50+ câmpuri, împărțiți în mai multe apeluri de extracție. Strict Mode de la OpenAI are limite practice privind complexitatea schemei și, chiar dacă funcționează, schemele foarte mari degradează calitatea output-ului.
Verdict: Raționament-prin-răspuns, câmpuri descriptive, null-uri explicite și scheme concentrate. Obțineți aceste patru corect și acuratețea output-ului structurat crește măsurabil.
Output Structurat cu LLM-uri Locale
Nu aveți nevoie de un provider API pentru output structurat. Motoarele de inferență locale îl suportă prin decodare constrânsă bazată pe gramatică, același mecanism fundamental, rulând pe propriul hardware.
Ollama
Cea mai ușoară cale pentru output structurat local. Ollama acceptă o JSON Schema prin parametrul 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 folosește XGrammar sub capotă pentru decodare constrânsă. Aceeași garanție ca la providerii API: conformitate 100% cu schema.
vLLM și SGLang
Pentru inferență locală de nivel producție, vLLM și SGLang suportă ambele output structurat prin parametrii guided_json și guided_regex. XGrammar este backend-ul implicit, oferind un overhead aproape zero la generarea JSON, de până la 3,5x mai rapid decât motoarele alternative de gramatică.
Outlines
Outlines este librăria Python open-source care a pionierat generarea constrânsă bazată pe gramatică. Funcționează cu orice model Hugging Face și suportă constrângeri JSON Schema, regex și gramatică completă fără context (CFG/EBNF). Este, de asemenea, integrat în vLLM și SGLang ca opțiune de backend gramatical.
Diferența cheie față de providerii API: output-ul structurat local nu are limitări de subset al schemei. Controlați gramatica în totalitate. Dar calitatea modelului variază mai mult; un model local de 7 miliarde de parametri nu va egala GPT-4o sau Claude la sarcini complexe de extracție. Schema va fi întotdeauna validă; calitatea conținutului depinde de model.
Verdict: Ollama pentru dezvoltare, vLLM/SGLang cu XGrammar pentru producție. Output-ul structurat local este suficient de matur pentru majoritatea cazurilor de utilizare, cu mențiunea că modelele mai mici produc conținut de calitate inferioară în cadrul schemei.
Întrebări Frecvente (FAQ)
Ce este output-ul structurat în LLM-uri?
Output-ul structurat este un mecanism care garantează că răspunsul unui LLM se conformează unei JSON Schema predefinite. Spre deosebire de textul simplu sau chiar JSON Mode, output-ul structurat utilizează decodarea constrânsă pentru a asigura că fiecare câmp, tip și constrângere din schema dumneavoastră este respectat – 100% din timp, nu „de obicei”.
Care este diferența dintre JSON Mode și Output-uri Structurate?
JSON Mode garantează JSON sintactic valid, dar nu impune schema dumneavoastră; ați putea obține orice obiect JSON valid. Output-urile Structurate (Strict Mode) garantează conformitatea totală cu schema prin decodare constrânsă. Folosiți Strict Mode pentru producție; JSON Mode este relevant doar când nu aveți o schemă prestabilită.
Care provideri LLM suportă nativ output-ul structurat?
OpenAI (din august 2024), Google Gemini (2024, extins 2026), Anthropic (beta noiembrie 2025, GA început 2026), Cohere și xAI (Grok) suportă toate output-ul structurat nativ. Pe partea locală, Ollama, vLLM și SGLang îl suportă prin decodare constrânsă bazată pe gramatică.
Cum garantează decodarea constrânsă conformitatea cu schema?
JSON Schema este compilată într-o mașină cu stări finite (FSM). La fiecare pas de generare a token-urilor, sunt permise doar token-urile care mențin output-ul pe o cale validă prin FSM; token-urile invalide își au logiții setați la minus infinit. Acest lucru înseamnă că token-urile invalide au zero probabilitate de a fi generate, oferindu-vă o garanție matematică, nu una statistică.
Ar trebui să folosesc output structurat sau function calling?
Folosiți output-ul structurat pentru extracție și clasificare, când doriți date într-o formă specifică. Folosiți function calling pentru fluxuri de lucru agentice, când modelul trebuie să decidă ce acțiune să întreprindă. Multe aplicații de producție folosesc ambele: output structurat pentru extracția datelor și function calling pentru orchestrare.
Pot stream-ui output-ul structurat?
Da. OpenAI suportă streaming cu metoda parse(), iar Instructor oferă create_partial() pentru streaming-ul modelelor Pydantic care se populează câmp cu câmp. Rețineți că chunk-urile individuale de streaming nu sunt valide individual conform schemei; câmpurile se populează incremental.
Ce este librăria Instructor?
Instructor este cea mai populară librărie de output structurat (11K+ stele GitHub, 3M+ descărcări lunare). Înfășoară SDK-urile providerilor cu validare bazată pe Pydantic, retry-uri automate cu feedback de validare și suport pentru streaming. Funcționează cu OpenAI, Anthropic, Gemini, Cohere, Ollama și peste 10 alți provideri.
Funcționează output-ul structurat cu LLM-uri locale?
Da. Ollama suportă output-ul structurat prin parametrul format cu JSON Schema. vLLM și SGLang îl suportă prin parametrii guided_json. Toate trei folosesc XGrammar sau Outlines pentru decodare constrânsă. Garanția de conformitate a schemei este aceeași ca la providerii API; calitatea conținutului depinde de model.
Care sunt greșelile comune de design al schemei?
Primele greșeli: plasarea câmpului de raționament după câmpul de răspuns (modelul decide înainte de a gândi), scheme profund imbricate (4+ niveluri cresc erorile), lipsa descrierilor de câmp (modelul ghicește intenția), lipsa gestionării null-urilor pentru datele opționale (forțează halucinația) și scheme prea mari (50+ câmpuri degradează calitatea).
Adaugă output-ul structurat latență?
Există un overhead de compilare a schemei la prima cerere, de obicei 50-200ms în timp ce se construiește FSM. Cererile ulterioare cu aceeași schemă folosesc un FSM cache-uit și adaugă o latență aproape zero. Pentru majoritatea aplicațiilor, acest lucru este neglijabil comparativ cu timpul total de inferență al modelului.
Pot folosi output-ul structurat cu imagini sau input-uri multimodale?
Da. Output-ul structurat se aplică formatului răspunsului, nu input-ului. Puteți trimite o imagine către GPT-4o sau Gemini cu o schemă de output structurat și puteți primi înapoi o analiză a imaginii conformă cu schema. Acest lucru este puternic pentru fluxurile de lucru de extracție vizuală, extrăgând date structurate din chitanțe, formulare sau imagini de produse.