
LLM gestructureerde uitvoer is het mechanisme dat garandeert dat de reactie van een taalmodel voldoet aan een vooraf gedefinieerd schema -- niet alleen geldig JSON, maar schema-geldig JSON met precies de velden, typen en beperkingen die je hebt opgegeven. Alle grote providers ondersteunen dit nu native, en het heeft veranderd hoe productie-LLM-applicaties worden gebouwd.
Snelle Samenvatting: Gestructureerde Uitvoer in Één Oogopslag
Als je weinig tijd hebt, hier is het landschap in 2026:
| Aspect | Details |
|---|---|
| Wat het is | Schema-afgedwongen reacties van LLM's -- gegarandeerde structuur, geen "best effort" |
| Wie het ondersteunt | OpenAI, Anthropic, Gemini, Cohere, xAI (Grok), plus lokaal via Ollama/vLLM |
| Sleutelmechanisme | Constrained decoding -- ongeldige tokens worden gemaskeerd vóór sampling |
| JSON-modus vs. Strict-modus | JSON-modus = alleen geldige syntaxis. Strict-modus = volledige schema-conformiteit |
| Python-bibliotheek | Pydantic (BaseModel + Field) voor schemadefinitie |
| TypeScript-bibliotheek | Zod (z.object + .describe) voor schemadefinitie |
| Beste startaanpak | OpenAI met Pydantic of Zod via native SDK |
| Beste productiebibliotheek | Instructor (Python) of native SDK (TypeScript) |
| Grootste valkuil | Het redenering-veld NA het antwoordveld plaatsen -- model beslist voor het denken |
| Latentie-overhead | 50-200ms bij eerste aanroep (schema-compilatie), daarna gecached |
Laten we nu elk stuk uiteenzetten.
Wat Zijn LLM Gestructureerde Uitvoeren?
Gestructureerde uitvoer is het verschil tussen hopen dat een LLM geldig JSON teruggeeft en dit garanderen. Wanneer je gestructureerde uitvoer inschakelt, kan het model fysiek geen tokens produceren die je schema schenden. Je definieert een JSON Schema (of Pydantic model, of Zod schema), geeft het door aan de API, en krijgt elke keer een reactie terug die ermee overeenkomt.
Waarom is dit belangrijk? Vóór gestructureerde uitvoer schreven ontwikkelaars fragiele regex-parsers, wikkelten elke LLM-aanroep in try/catch JSON.parse-blokken, en hadden nog steeds te maken met "bijna correcte" reacties -- geldig JSON waarbij een veld ontbrak of het verkeerde type had. Die hele klasse fouten is verdwenen.
Er zijn drie niveaus van structuurafdwinging, en ze vertegenwoordigen een duidelijke evolutie:
- Prompt engineering -- "Geef JSON terug met deze velden." Onbetrouwbaar. Het model kan 80-90% van de tijd conformeren.
- JSON-modus -- Garandeert syntactisch geldig JSON, maar dwingt je schema niet af. Je kunt
{"foo": "bar"}ontvangen terwijl je{"name": string, "age": number}verwachtte. - Strict-modus / Constrained decoding -- Garandeert 100% schema-conformiteit. Het model kan letterlijk geen ongeldige tokens uitvoeren. Dit is wat "gestructureerde uitvoer" betekent in 2026.
Vanaf begin 2026 ondersteunen OpenAI, Anthropic en Google Gemini alle native gestructureerde uitvoer. Het ecosysteem is geconvergeerd.
Verdict: Als je LLM-reacties in productie parseert met regex of JSON.parse, doe je het op de moeilijke manier. Native gestructureerde uitvoer elimineert die hele klasse van fouten.
JSON-modus vs. Strict-modus: Wat Is Er Eigenlijk Veranderd?
Dit onderscheid verwarrt veel ontwikkelaars omdat de namen vergelijkbaar klinken. Dat zijn ze niet.
| Functie | JSON-modus | Strict-modus (Gestructureerde Uitvoeren) |
|---|---|---|
| API-parameter | type: "json_object" | type: "json_schema" met strict: true |
| Garandeert geldig JSON | Ja | Ja |
| Garandeert schema-conformiteit | Nee | Ja |
| Mechanisme | Post-hoc token bias | Constrained decoding (FSM) |
| Kan onverwachte velden teruggeven | Ja | Nee |
| Kan vereiste velden weglaten | Ja | Nee |
| Typehandhaving | Geen | Volledig (string, number, array, etc.) |
| Wanneer te gebruiken | Je hebt van tevoren geen schema | Alles in productie |
De tijdlijn: OpenAI introduceerde JSON-modus eind 2023. Het was een stap voorwaarts, maar ontwikkelaars realiseerden zich snel dat "geldig JSON" niet genoeg was -- ze hadden schema-geldig JSON nodig. In augustus 2024 lanceerde OpenAI Structured Outputs met Strict Mode, dat constrained decoding gebruikt om schema-conformiteit te garanderen. Tegen 2025-2026 had elke grote provider dezelfde aanpak overgenomen.
JSON-modus heeft nog een klein gebruiksscenario: wanneer je echt de vorm van de reactie van tevoren niet weet en gewoon enig geldig JSON voor ongestructureerde verkenning wilt. Maar dat is zeldzaam in productie.
Verdict: Gebruik Strict-modus voor alles in productie. JSON-modus is effectief verouderd voor schema-gebonden gebruiksscenario's. Als je een schema hebt (en dat zou je moeten hebben), gebruik type: "json_schema" met strict: true.
Hoe Werkt Constrained Decoding Eigenlijk?
Hier is het mechanisme dat 100% schema-conformiteit mogelijk maakt -- niet 99,9%, maar letterlijk 100%.
Wanneer je een JSON Schema naar een provider stuurt met Strict Mode ingeschakeld, wordt het schema gecompileerd tot een eindige toestandsmachine (FSM). Deze FSM vertegenwoordigt elk geldig pad door je schema. Bij elke token-generatiestap controleert de inferentie-engine welke tokens de uitvoer op een geldig pad zouden houden en welke niet. Ongeldige tokens krijgen hun logits ingesteld op negatief oneindig vóór sampling, wat betekent dat ze een nulkans hebben om geselecteerd te worden.
<!-- IMAGE: constrained-decoding diagram showing FSM token masking during structured output generation -->Denk eraan als autocomplete op steroïden. Als het model zojuist {"rating": heeft uitgevoerd en je schema zegt dat rating een integer is, zijn de enige toegestane volgende tokens cijfertokens. Aanhalingstekens, letters, haakjes -- allemaal gemaskeerd. Het model kan geen "vijf" uitvoeren, ook al "wil" het dat.
Dit is hetzelfde kernconcept dat wordt gebruikt door XGrammar (de engine achter vLLM, SGLang en de meeste lokale inferentieservers) en Outlines (de open-source Python-bibliotheek voor beperkte generatie). De API-providers hebben het gewoon in hun inferentie-infrastructuur geïntegreerd.
Er is één afweging om te kennen: de eerste aanvraag met een nieuw schema leidt tot een compilatielatentie (typisch 50-200ms) terwijl de FSM wordt gebouwd. Volgende aanvragen met hetzelfde schema gebruiken een gecached FSM en voegen bijna nul overhead toe. Er is ook een subtiele kwaliteitsoverweging -- het beperken van het tokenvocabulaire kan soms de uitvoerkwaliteit verminderen voor creatieve of vrije-formaatsvelden, dus houd je schema's gericht op echt gestructureerde gegevens.
Verdict: Constrained decoding is wat "werkt meestal" scheidt van "werkt altijd." Het is de engineering die gestructureerde uitvoer productieklaar maakt.
Multi-Provider Implementatie: OpenAI, Anthropic en Gemini
Hier is iets dat geen van de andere gidsen je laat zien: dezelfde extractietaak geïmplementeerd voor alle drie grote providers. We extraheren een gestructureerde productbeoordeling uit ongestructureerde tekst.
Het Pydantic-schema (gedeeld tussen alle providers):
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 Implementatie
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 direct
)
review = response.choices[0].message.parsed # Getypeerd ProductReview objectOpenAI's implementatie is het meest volwassen. De parse()-methode accepteert een Pydantic model direct en geeft een getypeerd object terug. Eén beperking: OpenAI's Strict Mode ondersteunt een subset van JSON Schema -- geen $ref, beperkte anyOf, en alle velden moeten vereist zijn met additionalProperties: false.
Anthropic Implementatie
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's native gestructureerde uitvoer gebruikt output_config.format met een JSON Schema. Het bereikte GA begin 2026. Anthropic ondersteunt ook het oudere patroon van het definiëren van een "nep"-tool en extraheren via tool_use -- dat werkt nog steeds, maar native gestructureerde uitvoer is schoner voor pure extractie.
Gemini Implementatie
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 direct
}
)
import json
review = ProductReview(**json.loads(response.text))Gemini ondersteunt Pydantic models direct in de Python SDK via response_schema. Een unieke functie: Gemini respecteert propertyOrdering in het schema, zodat je de velduitvoervolgorde kunt bepalen (nuttig voor het redenering-eerst patroon).
Providervergelijking
| Functie | OpenAI | Anthropic | Gemini |
|---|---|---|---|
| API-parameter | response_format | output_config.format | response_schema |
| Schema-invoer | Pydantic of JSON Schema | JSON Schema | Pydantic of JSON Schema |
| Strict-modus | strict: true | Impliciet met json_schema | Impliciet |
| Streaming | Ja (partieel JSON) | Ja | Ja |
| Weigeringsbehandeling | message.refusal-veld | Foutreactie | Foutreactie |
| Tool-use alternatief | Ja | Ja (originele methode) | Ja |
| Schema-compilatiecache | Ja (server-side) | Ja | Ja |
| Eigenschapsvolgorde | Geen native ondersteuning | Nee | Ja (propertyOrdering) |
Verdict: OpenAI heeft de meest gepolijste DX met zijn parse()-methode. Anthropic biedt de capabelste onderliggende modellen. Gemini's eigenschapsvolgorde is uniek nuttig. Alle drie doen het werk -- kies op basis van je bestaande providerrelatie.
Pydantic Patronen voor Python-ontwikkelaars
Pydantic is de de-facto standaard voor het definiëren van gestructureerde uitvoerschema's in Python. Hier zijn de patronen die ertoe doen.
Basisschema met Beschrijvingen
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")Die description-strings zijn niet alleen voor documentatie -- ze worden deel van het JSON Schema dat naar het model wordt gestuurd en beïnvloeden direct wat het model genereert. Beschouw ze als prompt engineering binnen het schema.
Geneste Modellen
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 # Genest model
key_products: list[str] = Field(description="Top 3 products or services")Houd nesting op maximaal 2-3 niveaus. Diep geneste schema's verhogen foutpercentages en vertragen schema-compilatie.
Het Redenering-Eerst Patroon
Dit is het meest impactvolle schema-ontwerppatroon. Plaats een reasoning-veld vóór je antwoordvelden:
# Slecht -- model verbindt zich aan een antwoord voor het nadenkt
class ClassificationBad(BaseModel):
category: Literal["spam", "ham"]
confidence: float
# Goed -- model redeneert eerst door het probleem
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's genereren tokens van links naar rechts. Als category eerst komt, kiest het model een categorie en rationaliseert het dan. Als reasoning eerst komt, werkt het model door het probleem en verbindt het zich dan aan een categorie. Het is chain-of-thought ingebakken in het schema.
JSON Schema Export
# Genereer het JSON Schema voor elk Pydantic model
schema = ProductReview.model_json_schema()
# Geef dit door aan elke provider die rauw JSON Schema accepteertVerdict: Pydantic + beschrijvende velden + redenering-eerst volgorde is de Python driebond voor gestructureerde uitvoer. Beheers deze drie patronen en je handelt 90% van de gebruiksscenario's af.
Zod Patronen voor TypeScript-ontwikkelaars
Zod is het TypeScript-equivalent van Pydantic -- en het is even centraal voor gestructureerde uitvoer workflows.
Basisschema met Beschrijvingen
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"),
});
// TypeScript-type automatisch afleiden
type ProductReview = z.infer<typeof ProductReview>;Net als Pydantic's Field(description=...), wordt Zod's .describe() deel van het JSON Schema en stuurt de uitvoer van het model.
Integratie met 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; // Getypeerd!Integratie met 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 volledig getypeerd als ProductReviewDe Vercel AI SDK gebruikt Zod native met generateObject(), waardoor het de schoonste TypeScript-integratie is. Het werkt met OpenAI, Anthropic, Gemini en andere providers via een uniforme API.
JSON Schema Conversie
import { zodToJsonSchema } from "zod-to-json-schema";
const jsonSchema = zodToJsonSchema(ProductReview);
// Gebruik met elke provider die rauw JSON Schema accepteertVerdict: Zod + .describe() + de Vercel AI SDK is de TypeScript stack voor gestructureerde uitvoer. Als je in het Node/Next.js ecosysteem zit, is dit de weg van de minste weerstand.
Gestructureerde Uitvoer vs. Functie-aanroepen: Wanneer Gebruik Je Wat?
Dit is een van de meest voorkomende bronnen van verwarring. Beide betreffen schema's, beide geven gestructureerde gegevens terug -- maar ze lossen verschillende problemen op.
Gestructureerde uitvoer zegt: "Geef me gegevens in deze exacte vorm." Het is voor extractie, classificatie en opmaak. Je trekt gestructureerde informatie uit ongestructureerde tekst.
Functie-aanroepen (tool use) zegt: "Hier zijn acties die je kunt uitvoeren -- beslis welke je uitvoert en geef de argumenten op." Het is voor agent workflows waarbij het model uit meerdere tools kiest en acties activeert.
De verwarring is historisch begrijpelijk. Anthropic's originele "gestructureerde uitvoer" was letterlijk functie-aanroepen -- je definieerde een nep-tool genaamd extract_review en greep de argumenten. Dat werkt nog steeds, maar native gestructureerde uitvoer is eenvoudiger voor pure extractie.
| Scenario | Beste Aanpak | Waarom |
|---|---|---|
| Gegevens uit tekst extraheren | Gestructureerde uitvoer | Direct, lagere latentie, één schema |
| In categorieën classificeren | Gestructureerde uitvoer | Één reactie, één schema |
| Agent beslist welk tool te gebruiken | Functie-aanroepen | Model kiest uit meerdere tools |
| Meerstaps-orchestratie | Functie-aanroepen | Sequentiële tool-aanroepen |
| Gegevens extraheren EN volgende actie besluiten | Beide | Gestructureerde uitvoer voor extractie, functie-aanroepen voor orchestratie |
Gestructureerde uitvoer drijft de tool-aanroep pipelines in AI-agent systemen. Bekijk onze gids over AI-agents voor bedrijven voor hoe deze passen in productie workflows.
Verdict: Gebruik gestructureerde uitvoer wanneer je de vorm van de gegevens kent. Gebruik functie-aanroepen wanneer het model een actie moet kiezen. In de praktijk gebruiken de meeste applicaties beide -- gestructureerde uitvoer voor data-extractie en functie-aanroepen voor agent-orchestratie.
Productiepatronen: Fouten, Retries en Streaming
Gestructureerde uitvoer werkend krijgen in een demo is eenvoudig. Het betrouwbaar houden in productie vereist het afhandelen van drie dingen: weigeringen, validatiefouten en streaming.
Weigeringsbehandeling
Soms weigert een model je gevraagde uitvoer te genereren -- typisch omdat beveiligingsfilters de invoer hebben gemarkeerd. In dit geval geven gestructureerde uitvoer API's niet je schema terug. Ze geven een weigering terug.
response = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=messages,
response_format=ProductReview,
)
# Controleer ALTIJD op weigering voordat je toegang krijgt tot geparseerde inhoud
if response.choices[0].message.refusal:
print(f"Model refused: {response.choices[0].message.refusal}")
else:
review = response.choices[0].message.parsedAls je de weigeringscontrole overslaat en probeert toegang te krijgen tot .parsed bij een weigering, krijg je None en een verwarrende downstream-fout. Controleer eerst, altijd.
Retry Patronen met Validatiefeedback
Schema-conformiteit wordt gegarandeerd door constrained decoding, maar semantische correctheid niet. Het model kan {"rating": 1, "sentiment": "positive"} teruggeven -- geldig schema, tegenstrijdige inhoud. Daar komen validatie + retries van pas.
import instructor
client = instructor.from_openai(OpenAI())
# Instructor behandelt retries automatisch
review = client.chat.completions.create(
model="gpt-4o",
response_model=ProductReview,
max_retries=3, # Retries met validatiefout feedback
messages=[
{"role": "user", "content": review_text}
],
)Instructor geeft de validatiefout terug aan het model bij retry, zodat het zichzelf kan corrigeren. Voor handmatige retry-patronen zonder 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
# Voer hier aanvullende semantische validatie uit
break
except ValidationError as e:
messages.append({"role": "assistant", "content": str(response)})
messages.append({"role": "user", "content": f"Validation error: {e}. Fix it."})Streaming Gestructureerde Uitvoer
Voor grote gestructureerde reacties -- lange arrays, veel velden, complexe geneste objecten -- laat streaming je progressief partiële resultaten renderen.
import instructor
client = instructor.from_openai(OpenAI())
# Partiële resultaten streamen terwijl velden worden ingevuld
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:
# Velden worden één voor één ingevuld terwijl tokens streamen
if partial_review.summary:
print(f"Summary so far: {partial_review.summary}")Één valkuil: individuele streaming-chunks zijn op zichzelf niet schema-geldig. Het reasoning-veld kan ingevuld zijn terwijl rating nog None is. Plan je UI dienovereenkomstig -- toon een laadstatus voor niet-ingevulde velden.
Verdict: Weigeringscontroles zijn niet onderhandelbaar. Retries met validatiefeedback vangen semantische fouten op. Streaming is het waard voor elke reactie die meer dan een paar seconden duurt.
Vergelijking van Gestructureerde Uitvoer Bibliotheken
Je kunt gestructureerde uitvoer gebruiken via native API's, maar bibliotheken voegen validatie, retries, streaming en multi-provider ondersteuning toe. Hier is het landschap.
Instructor is de meest populaire optie met 11K+ GitHub-sterren en 3M+ maandelijkse downloads. Het wikkelt OpenAI, Anthropic, Gemini, Cohere, Ollama en meer met een uniforme Pydantic-gebaseerde interface. Kernfuncties: automatische retries met validatiefeedback, streaming via create_partial(), en eenvoudige setup (instructor.from_openai(client)). Als je een Python-team bent, begin hier.
BAML neemt een andere aanpak: schema-eerst via een aangepaste DSL. Je definieert schema's in .baml-bestanden en auto-genereert clients voor Python, TypeScript, Ruby en meer. Zijn SAP-algoritme (schema-aligned parsing) gaat op een elegante manier om met rommelige modeluitvoer. Het beste voor cross-language teams of wanneer je contracten wilt tussen je LLM-laag en applicatielaag. Afweging: extra buildstap en een nieuwe syntaxis om te leren.
LangChain biedt .with_structured_output(schema) voor provideronafhankelijke gestructureerde uitvoer. Handig als je al in het LangChain-ecosysteem zit. Afweging: het is een zware afhankelijkheid, en de abstractie kan provider-specifieke functies verbergen die je mogelijk nodig hebt.
Native API's -- directe aanroepen met response_format / output_config -- vereisen geen afhankelijkheden buiten de provider-SDK. Je krijgt volledige controle en volledige zichtbaarheid. Het beste voor eenvoudige gebruiksscenario's of teams die minimale abstractie prefereren.
| Bibliotheek | Talen | Providers | Auto Retries | Streaming | GitHub Sterren | Leercurve |
|---|---|---|---|---|---|---|
| Instructor | Python, TS | 15+ | Ja | Ja | 11K+ | Laag |
| BAML | Python, TS, Ruby, Go | Alle (DSL-agnostisch) | Ja | Ja | 7K+ | Gemiddeld |
| LangChain | Python, TS | 20+ | Gedeeltelijk | Ja | 100K+ | Gemiddeld-Hoog |
| Native API's | Elk | 1 per SDK | Nee | Ja | N/A | Laag |
De juiste bibliotheek voor gestructureerde uitvoer kiezen maakt deel uit van een bredere AI-stack beslissing. We analyseren de volledige stack in onze Best AI Stack voor SaaS gids.
Bekijk onze Beste Bibliotheken voor LLM Gestructureerde Uitvoeren [binnenkort] voor een diepgaande vergelijking van Instructor, BAML, Mirascope en meer.
Verdict: Begin met Instructor voor Python, native API's voor TypeScript. Ga naar BAML als je cross-language schema-contracten nodig hebt. Vermijd LangChain alleen voor gestructureerde uitvoer -- dat is overdreven.
Best Practices voor Schema-ontwerp (en Veelvoorkomende Fouten)
Je schema-ontwerp heeft direct invloed op de uitvoerkwaliteit. Hier zijn de patronen die ertoe doen en de fouten die je nauwkeurigheid kosten.
Redenering Vóór Antwoorden Plaatsen
We hebben dit behandeld in de Pydantic-sectie, maar het verdient herhaling omdat het de meest impactvolle ontwerpbeslissing is:
# Vóór: model raadt het antwoord, rationaliseert het dan
class Bad(BaseModel):
answer: str
reasoning: str
# Na: model denkt eerst, verbindt zich dan
class Good(BaseModel):
reasoning: str = Field(description="Think step by step")
answer: strLLM's genereren van links naar rechts. Veldvolgorde is promptvolgorde. Redenering eerst betekent dat het model door het probleem moet werken voordat het zich verbindt aan een antwoord.
De Anti-patroon Tabel
| Fout | Probleem | Oplossing |
|---|---|---|
| Redenering-veld na antwoord | Model beslist voor het nadenkt | Redenering voor antwoord verplaatsen |
| Diep genest (4+ niveaus) | Hogere foutpercentage, langzamere compilatie | Afvlakken tot 2-3 niveaus |
| Geen veldbeschrijvingen | Model raadt wat je wilt | .describe() / Field(description=...) toevoegen |
| Ontbrekende null-behandeling | Model hallucineert een waarde om het veld te vullen | Optional / .nullable() gebruiken |
| Overgrote schema's (50+ velden) | Compilatietimeout, kwaliteitsverslechtering | Opsplitsen in meerdere aanroepen |
| Vage enum-opties | Model kiest de verkeerde categorie | Specifieke, niet-overlappende opties gebruiken |
Nulls Expliciet Behandelen
Als een veld mogelijk geen gegevens in de brontekst heeft, maak het dan optioneel. Het forceren van een vereist veld wanneer gegevens niet bestaan, leidt tot hallucinatie:
class PersonInfo(BaseModel):
name: str # Altijd aanwezig
email: Optional[str] = Field(None, description="Email if mentioned, null otherwise")
phone: Optional[str] = Field(None, description="Phone if mentioned, null otherwise")Schema's Gefocust Houden
Eén schema per taak. Probeer niet alles in één enkel massief schema te extraheren. Als je 50+ velden nodig hebt, splits dan op in meerdere extractieaanroepen. OpenAI's Strict Mode heeft praktische limieten op schema-complexiteit, en zelfs wanneer het werkt, verslechteren zeer grote schema's de uitvoerkwaliteit.
Verdict: Redenering-eerst, beschrijvende velden, expliciete nulls en gefocuste schema's. Krijg deze vier goed en je nauwkeurigheid bij gestructureerde uitvoer stijgt meetbaar.
Gestructureerde Uitvoer met Lokale LLM's
Je hebt geen API-provider nodig voor gestructureerde uitvoer. Lokale inferentie-engines ondersteunen het via grammatica-gebaseerde constrained decoding -- hetzelfde fundamentele mechanisme, draaiend op je eigen hardware.
Ollama
Het eenvoudigste pad voor lokale gestructureerde uitvoer. Ollama accepteert een JSON Schema via de format-parameter:
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 gebruikt XGrammar intern voor constrained decoding. Dezelfde garantie als de API-providers: 100% schema-conformiteit.
vLLM en SGLang
Voor productiekwaliteit lokale inferentie ondersteunen vLLM en SGLang beide gestructureerde uitvoer via guided_json en guided_regex parameters. XGrammar is het standaard backend, dat bijna nul overhead levert bij JSON-generatie -- tot 3,5x sneller dan alternatieve grammatica-engines.
Outlines
Outlines is de open-source Python-bibliotheek die grammatica-gebaseerde beperkte generatie pioneered. Het werkt met elk Hugging Face model en ondersteunt JSON Schema, regex en volledige contextvrije grammatica (CFG/EBNF) beperkingen. Het is ook geïntegreerd in vLLM en SGLang als een grammatica-backend optie.
Het sleutelverschil met API-providers: lokale gestructureerde uitvoer heeft geen schema-subset beperkingen. Je beheert de grammatica volledig. Maar modelkwaliteit varieert meer -- een lokaal 7B parameter model zal niet overeenkomen met GPT-4o of Claude op complexe extractietaken. Het schema zal altijd geldig zijn; de inhoudskwaliteit hangt af van het model.
Verdict: Ollama voor ontwikkeling, vLLM/SGLang met XGrammar voor productie. Lokale gestructureerde uitvoer is volwassen genoeg voor de meeste gebruiksscenario's, met de kanttekening dat kleinere modellen content van lagere kwaliteit produceren binnen het schema.
FAQ
Wat is gestructureerde uitvoer in LLM's?
Gestructureerde uitvoer is een mechanisme dat garandeert dat de reactie van een LLM voldoet aan een vooraf gedefinieerd JSON Schema. In tegenstelling tot platte tekst of zelfs JSON-modus, gebruikt gestructureerde uitvoer constrained decoding om ervoor te zorgen dat elk veld, type en beperking in je schema wordt nageleefd -- 100% van de tijd, niet "meestal".
Wat is het verschil tussen JSON-modus en Gestructureerde Uitvoeren?
JSON-modus garandeert syntactisch geldig JSON maar dwingt je schema niet af -- je kunt elk geldig JSON-object ontvangen. Gestructureerde Uitvoeren (Strict Mode) garanderen volledige schema-conformiteit via constrained decoding. Gebruik Strict Mode voor productie; JSON-modus is alleen relevant wanneer je van tevoren geen schema hebt.
Welke LLM-providers ondersteunen gestructureerde uitvoer native?
OpenAI (sinds augustus 2024), Google Gemini (2024, uitgebreid 2026), Anthropic (bèta november 2025, GA begin 2026), Cohere en xAI (Grok) ondersteunen alle native gestructureerde uitvoer. Aan de lokale kant ondersteunen Ollama, vLLM en SGLang het via grammatica-gebaseerde constrained decoding.
Hoe garandeert constrained decoding schema-conformiteit?
Het JSON Schema wordt gecompileerd tot een eindige toestandsmachine (FSM). Bij elke token-generatiestap zijn alleen tokens toegestaan die de uitvoer op een geldig pad door de FSM houden -- ongeldige tokens krijgen hun logits ingesteld op negatief oneindig. Dit betekent dat ongeldige tokens een nulkans hebben om gegenereerd te worden, wat je een wiskundige garantie geeft, geen statistische.
Moet ik gestructureerde uitvoer of functie-aanroepen gebruiken?
Gebruik gestructureerde uitvoer voor extractie en classificatie -- wanneer je gegevens in een specifieke vorm wilt. Gebruik functie-aanroepen voor agent-workflows -- wanneer het model moet beslissen welke actie te nemen. Veel productieapplicaties gebruiken beide: gestructureerde uitvoer voor data-extractie en functie-aanroepen voor orchestratie.
Kan ik gestructureerde uitvoer streamen?
Ja. OpenAI ondersteunt streaming met de parse()-methode, en Instructor biedt create_partial() voor het streamen van Pydantic-modellen die veld voor veld worden ingevuld. Houd er rekening mee dat individuele streaming-chunks niet individueel schema-geldig zijn -- velden worden incrementeel ingevuld.
Wat is de Instructor-bibliotheek?
Instructor is de meest populaire bibliotheek voor gestructureerde uitvoer (11K+ GitHub-sterren, 3M+ maandelijkse downloads). Het wikkelt provider-SDK's met Pydantic-gebaseerde validatie, automatische retries met validatiefeedback en streaming-ondersteuning. Het werkt met OpenAI, Anthropic, Gemini, Cohere, Ollama en 10+ andere providers.
Werkt gestructureerde uitvoer met lokale LLM's?
Ja. Ollama ondersteunt gestructureerde uitvoer via de format-parameter met JSON Schema. vLLM en SGLang ondersteunen het via guided_json parameters. Alle drie gebruiken XGrammar of Outlines voor constrained decoding. De schema-conformiteitsgarantie is dezelfde als bij API-providers; inhoudskwaliteit hangt af van het model.
Wat zijn veelvoorkomende schema-ontwerpfouten?
De belangrijkste fouten: het redenering-veld na het antwoordveld plaatsen (model beslist voor het nadenkt), diep geneste schema's (4+ niveaus verhogen fouten), ontbrekende veldbeschrijvingen (model raadt de bedoeling), geen null-behandeling voor optionele gegevens (dwingt hallucinatie af), en overgrote schema's (50+ velden verslechteren de kwaliteit).
Voegt gestructureerde uitvoer latentie toe?
Er is een schema-compilatie-overhead bij de eerste aanvraag -- typisch 50-200ms terwijl de FSM wordt gebouwd. Volgende aanvragen met hetzelfde schema gebruiken een gecached FSM en voegen bijna nul latentie toe. Voor de meeste applicaties is dit te verwaarlozen vergeleken met de totale model-inferentietijd.
Kan ik gestructureerde uitvoer gebruiken met afbeeldingen of multimodale invoer?
Ja. Gestructureerde uitvoer is van toepassing op het reactie-formaat, niet de invoer. Je kunt een afbeelding sturen naar GPT-4o of Gemini met een gestructureerd uitvoerschema en een schema-conforme analyse van de afbeelding terugkrijgen. Dit is krachtig voor visuele extractie-workflows -- gestructureerde gegevens extraheren uit bonnen, formulieren of productafbeeldingen.