
Struktureret LLM-output er den mekanisme, der garanterer, at en sprogmodels svar overholder et foruddefineret skema – ikke blot gyldig JSON, men skema-valid JSON med de nøjagtige felter, typer og begrænsninger, du har specificeret. Alle store udbydere understøtter nu dette nativt, og det har ændret måden, produktionsklare LLM-applikationer bygges på.
Hurtigt overblik: Strukturerede outputs ved første øjekast
Hvis du har travlt, er her landskabet i 2026:
| Aspekt | Detaljer |
|---|---|
| Hvad det er | Skematvungne svar fra LLM'er, garanteret struktur, ikke "best effort" |
| Hvem understøtter det | OpenAI, Anthropic, Gemini, Cohere, xAI (Grok) samt lokalt via Ollama/vLLM |
| Nøglemekanisme | Begrænset afkodning, ugyldige tokens maskeres før sampling |
| JSON Mode vs. Strict Mode | JSON Mode = kun gyldig syntaks. Strict Mode = fuld skemaoverholdelse |
| Python-bibliotek | Pydantic (BaseModel + Field) til skemadefinition |
| TypeScript-bibliotek | Zod (z.object + .describe) til skemadefinition |
| Bedste starttilgang | OpenAI med Pydantic eller Zod via det native SDK |
| Bedste produktionsbibliotek | Instructor (Python) eller native SDK (TypeScript) |
| Største faldgrube | At placere reasoning-feltet EFTER svarfeltet; modellen beslutter sig, før den tænker |
| Latens-overhead | 50-200 ms ved første kald (schemakompilering), cachelagret bagefter |
Lad os nu dykke ned i hver enkelt del.
Hvad er strukturerede LLM-outputs?
Struktureret output er forskellen mellem at håbe, at en LLM returnerer gyldig JSON, og at garantere det. Når du aktiverer struktureret output, kan modellen fysisk ikke producere tokens, der overtræder dit skema. Du definerer et JSON-skema (eller en Pydantic-model eller et Zod-skema), sender det til API'en og modtager et svar, der matcher det hver eneste gang.
Hvorfor betyder det noget? Før struktureret output skrev udviklere skrøbelige regex-parsere, indpakgede hvert LLM-kald i try/catch JSON.parse-blokke og håndterede stadig svar, der var "næsten rigtige" – gyldig JSON, der manglede et felt eller havde forkert type. Hele denne klasse af bugs er væk.
Der er tre niveauer af strukturhåndhævelse, og de repræsenterer en klar udvikling:
- Prompt engineering: "Returnér venligst JSON med disse felter." Upålideligt. Modellen adlyder måske 80-90 % af gangene.
- JSON Mode: Garanterer syntaktisk gyldig JSON, men håndhæver ikke dit skema. Du kunne få
{"foo": "bar"}, når du forventede{"name": string, "age": number}. - Strict Mode / Begrænset afkodning: Garanterer 100 % skemaoverholdelse. Modellen kan bogstaveligt talt ikke outputte ugyldige tokens. Det er hvad "struktureret output" betyder i 2026.
Primo 2026 understøtter OpenAI, Anthropic og Google Gemini alle nativt struktureret output. Økosystemet er konvergeret.
Konklusion: Hvis du parser LLM-svar med regex eller JSON.parse i produktion, gør du det på den svære måde. Natif struktureret output eliminerer hele den fejlmulighed.
JSON Mode vs. Strict Mode: Hvad ændrede sig egentlig?
Denne distinktion forvirrer mange udviklere, fordi navnene lyder ens. Det er de ikke.
| Funktion | JSON Mode | Strict Mode (Strukturerede Outputs) |
|---|---|---|
| API-parameter | type: "json_object" | type: "json_schema" med strict: true |
| Garanterer gyldig JSON | Ja | Ja |
| Garanterer skemaoverholdelse | Nej | Ja |
| Mekanisme | Token-bias efterfølgende | Begrænset afkodning (FSM) |
| Kan returnere uventede felter | Ja | Nej |
| Kan udelade påkrævede felter | Ja | Nej |
| Typehåndhævelse | Ingen | Fuld (string, number, array osv.) |
| Hvornår skal det bruges | Du har ikke et skema på forhånd | Alt i produktion |
Tidslinjen: OpenAI introducerede JSON Mode i slutningen af 2023. Det var et skridt fremad, men udviklere indså hurtigt, at "gyldig JSON" ikke var nok; de havde brug for skema-valid JSON. I august 2024 lancerede OpenAI Structured Outputs med Strict Mode, som bruger begrænset afkodning til at garantere skemaoverholdelse. I 2025-2026 havde alle store udbydere adopteret samme tilgang.
JSON Mode har stadig et snævert use case: Når du virkelig ikke kender formen på svaret på forhånd og blot ønsker noget gyldigt JSON til ustruktureret udforskning. Men det er sjældent i produktion.
Konklusion: Brug Strict Mode til alt i produktion. JSON Mode er effektivt udfaset til skemabundne use cases. Hvis du har et skema (og det bør du have), skal du bruge type: "json_schema" med strict: true.
Hvordan fungerer begrænset afkodning egentlig?
Her er mekanismen, der muliggør 100 % skemaoverholdelse – ikke 99,9 %, men bogstaveligt talt 100 %.
Når du sender et JSON-skema til en udbyder med Strict Mode aktiveret, kompileres skemaet til en endelig tilstandsmaskine (FSM). Denne FSM repræsenterer hver gyldig sti gennem dit skema. Ved hvert token-genereringstrin tjekker inferensmotoren, hvilke tokens der vil holde outputtet på en gyldig sti, og hvilke der ikke vil. Ugyldige tokens får deres logits sat til negativ uendelig før sampling, hvilket betyder, at de har nul sandsynlighed for at blive valgt.
<!-- IMAGE: constrained-decoding diagram showing FSM token masking during structured output generation -->Tænk på det som autocomplete på steroider. Hvis modellen lige har outputtet {"rating":, og dit skema siger, at rating er et heltal, er de eneste tilladte tokens derefter cifre. Anførselstegn, bogstaver, klammer – alt er maskeret. Modellen kan ikke outputte "five", selvom den "vil" det.
Dette er den samme kernemekanisme, som bruges af XGrammar (motoren bag vLLM, SGLang og de fleste lokale inferensservere) og Outlines (det open source Python-bibliotek til begrænset generering). API-udbyderne har blot integreret det i deres inferensinfrastruktur.
Der er én trade-off, du skal være opmærksom på: Den første anmodning med et nyt skema påfører en kompilering-latens (typisk 50-200 ms), mens FSM'en bygges. Efterfølgende anmodninger med samme skema bruger en cachelagret FSM og tilføjer næsten intet overhead. Der er også en subtil kvalitetsbetragtning: Begrænsning af token-vokabularet kan lejlighedsvis reducere outputkvaliteten for kreative eller frie felter, så hold dine skemaer fokuserede på virkelig strukturerede data.
Konklusion: Begrænset afkodning er det, der adskiller "virker normalt" fra "virker altid." Det er den ingeniørmæssige løsning, der gør struktureret output produktionsklar.
Implementering på tværs af udbydere: OpenAI, Anthropic og Gemini
Her er noget, ingen andre guider viser dig: Den samme ekstraktionsopgave implementeret på tværs af alle tre store udbydere. Vi vil udtrække en struktureret produktanmeldelse fra ustruktureret tekst.
Pydantic-skemaet (delt på tværs af alle udbydere):
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-implementering
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 objectOpenAIs implementering er den mest modne. Metoden parse() accepterer en Pydantic-model direkte og returnerer et typet objekt. Én begrænsning: OpenAIs Strict Mode understøtter et undersæt af JSON Schema; ingen $ref, begrænset anyOf, og alle felter skal være påkrævede med additionalProperties: false.
Anthropic-implementering
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)Anthropics native strukturerede output bruger output_config.format med et JSON-skema. Det nåede GA (generel tilgængelighed) i begyndelsen af 2026. Anthropic understøtter også det ældre mønster med at definere et "falsk" værktøj og udtrække via tool_use; det virker stadig, men native struktureret output er renere til ren ekstraktion.
Gemini-implementering
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 understøtter Pydantic-modeller direkte i Python-SDK'et via response_schema. En unik funktion: Gemini respekterer propertyOrdering i skemaet, så du kan kontrollere rækkefølgen af felt-output (nyttigt til reasoning-first-mønsteret).
Sammenligning af udbydere
| Funktion | OpenAI | Anthropic | Gemini |
|---|---|---|---|
| API-parameter | response_format | output_config.format | response_schema |
| Skema-input | Pydantic eller JSON Schema | JSON Schema | Pydantic eller JSON Schema |
| Strict mode | strict: true | Implicit med json_schema | Implicit |
| Streaming | Ja (delvis JSON) | Ja | Ja |
| Håndtering af afvisning | message.refusal-felt | Fejlrespons | Fejlrespons |
| Alternativ til tool-use | Ja | Ja (original metode) | Ja |
| Caching af schemakompilering | Ja (server-side) | Ja | Ja |
| Egenskabsrækkefølge | Ingen native understøttelse | Nej | Ja (propertyOrdering) |
Konklusion: OpenAI har den mest polerede DX med sin parse()-metode. Anthropic tilbyder de mest capable underliggende modeller. Geminis egenskabsrækkefølge er unikt nyttig. Alle tre får jobbet gjort; vælg baseret på dit eksisterende forhold til udbyderen.
Pydantic-mønstre for Python-udviklere
Pydantic er de facto-standarden for at definere skemaer til struktureret output i Python. Her er de mønstre, der betyder noget.
Grundlæggende skema med beskrivelser
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")Disse description-strenge er ikke kun til dokumentation; de bliver en del af det JSON-skema, der sendes til modellen, og påvirker direkte, hvad modellen genererer. Tænk på dem som prompt engineering inden i skemaet.
Nestede modeller
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")Hold nesting til maks. 2-3 niveauer. Dybt nestede skemaer øger fejlprocenten og forsinker schemakompileringen.
Reasoning-first-mønsteret
Dette er det enkeltstående mest impactful skemadesignmønster. Placér et reasoning-felt før dine svarfelter:
# 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'er genererer tokens fra venstre mod højre. Hvis category kommer først, vælger modellen en kategori og rationaliserer den bagefter. Hvis reasoning kommer først, arbejder modellen sig gennem problemet og forpligter sig derefter til en kategori. Det er chain-of-thought bagt ind i skemaet.
Eksport af JSON Schema
# Generate the JSON Schema for any Pydantic model
schema = ProductReview.model_json_schema()
# Pass this to any provider that accepts raw JSON SchemaKonklusion: Pydantic + beskrivende felter + reasoning-first-rækkefølge er den pythoniske trifecta for struktureret output. Behersk disse tre mønstre, og du kan håndtere 90 % af use cases.
Zod-mønstre for TypeScript-udviklere
Zod er TypeScript-ækvivalenten til Pydantic, og det er lige så centralt for workflows med struktureret output.
Grundlæggende skema med beskrivelser
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>;Ligesom Pydantics Field(description=...) bliver Zods .describe() en del af JSON-skemaet og guider modellens output.
Integration med 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!Integration med 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 bruger Zod nativt med generateObject(), hvilket gør det til den reneste TypeScript-integration. Det virker med OpenAI, Anthropic, Gemini og andre udbydere gennem en samlet API.
Konvertering til JSON Schema
import { zodToJsonSchema } from "zod-to-json-schema";
const jsonSchema = zodToJsonSchema(ProductReview);
// Use with any provider that accepts raw JSON SchemaKonklusion: Zod + .describe() + Vercel AI SDK er stacken til struktureret output i TypeScript. Hvis du befinder dig i Node/Next.js-økosystemet, er dette vejen med mindst modstand.
Struktureret output vs. Function Calling: Hvornår bruger du hvad?
Dette er en af de mest almindelige kilder til forvirring. Begge involverer skemaer, begge returnerer strukturerede data, men de løser forskellige problemer.
Struktureret output siger: "Giv mig data i denne præcise form." Det er til ekstraktion, klassificering og formatering. Du trækker struktureret information ud af ustruktureret tekst.
Function calling (tool use) siger: "Her er handlinger, du kan udføre; beslut hvilken der skal køres, og angiv argumenterne." Det er til agent-workflows, hvor modellen vælger mellem flere værktøjer og udløser handlinger.
Forvirringen giver mening historisk set. Anthropics oprindelige "strukturerede output" var bogstaveligt talt function calling; du definerede et falsk værktøj kaldet extract_review og greb argumenterne. Det virker stadig, men native struktureret output er simplere til ren ekstraktion.
| Scenario | Bedste tilgang | Hvorfor |
|---|---|---|
| Udtræk data fra tekst | Struktureret output | Direkte, lavere latens, ét skema |
| Klassificér i kategorier | Struktureret output | Ét svar, ét skema |
| Agent, der beslutter hvilket værktøj der skal kaldes | Function calling | Modellen vælger mellem flere værktøjer |
| Multi-step orkestrering | Function calling | Sekventielle værktøjskald |
| Udtræk data OG beslut næste handling | Begge | Struktureret output til ekstraktion, function calling til orkestrering |
Struktureret output driver tool-calling-pipelines i AI-agent-systemer. Se vores guide til AI-agenter til virksomheder for at se, hvordan disse passer ind i produktionsworkflows.
Konklusion: Brug struktureret output, når du ved, hvilken form dataene skal have. Brug function calling, når modellen skal vælge en handling. I praksis bruger de fleste applikationer begge dele: struktureret output til dataekstraktion og function calling til agent-orkestrering.
Produktionsmønstre: Fejl, genforsøg og streaming
Det er nemt at få struktureret output til at virke i en demo. At holde det pålideligt i produktion kræver håndtering af tre ting: afvisninger, valideringsfejl og streaming.
Håndtering af afvisninger
Nogle gange nægter en model at generere det ønskede output, typisk fordi sikkerhedsfiltre har flagget inputtet. Når dette sker, returnerer strukturerede output-API'er ikke dit skema. De returnerer en afvisning.
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.parsedHvis du springer afvisningskontrollen over og prøver at tilgå .parsed på en afvisning, får du None og en forvirrende downstream-fejl. Tjek altid først.
Genforsøgsmønstre med valideringsfeedback
Skemaoverholdelse garanteres af begrænset afkodning, men semantisk korrekthed gør det ikke. Modellen kan returnere {"rating": 1, "sentiment": "positive"} – gyldigt skema, men modsigende indhold. Det er her, validering + genforsøg kommer ind i billedet.
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 fodrer valideringsfejlen tilbage til modellen ved genforsøg, så den kan selvkorrigeres. Til manuelle genforsøgsmønstre uden 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 af struktureret output
Til store strukturerede svar, lange arrays, mange felter eller komplekse nestede objekter, lader streaming dig renderne delvise resultater progressivt.
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}")Én faldgrube: Individuelle streaming-chunks er ikke skema-valide alene. reasoning-feltet kan være udfyldt, mens rating stadig er None. Planlæg din UI derefter; vis en loading-state for udfyldte felter.
Konklusion: Afvisningskontroller er ikke-forhandlingsbare. Genforsøg med valideringsfeedback fanger semantiske fejl. Streaming er det værd for ethvert svar, der tager mere end et par sekunder.
Sammenligning af biblioteker til struktureret output
Du kan bruge struktureret output gennem native API'er, men biblioteker tilføjer validering, genforsøg, streaming og understøttelse af flere udbydere. Her er landskabet.
Instructor er den mest populære option med 11K+ GitHub-stjerner og 3M+ månedlige downloads. Det wrapper OpenAI, Anthropic, Gemini, Cohere, Ollama og mere med en samlet Pydantic-baseret grænseflade. Nøglefunktioner: Automatiske genforsøg med valideringsfeedback, streaming via create_partial() og lynsimpel opsætning (instructor.from_openai(client)). Hvis du er et Python-team, så start her.
BAML tager en anden tilgang: skema-first via et custom DSL. Du definerer skemaer i .baml-filer og autogenererer klienter til Python, TypeScript, Ruby og mere. Dens SAP-algoritme (schema-aligned parsing) håndterer rodede modeloutputs elegant. Bedst til teams på tværs af sprog eller når du vil have kontrakter mellem dit LLM-lag og applikationslag. Trade-off: Ekstra build-step og ny syntaks at lære.
LangChain tilbyder .with_structured_output(schema) til udbyder-uafhængigt struktureret output. Bekvemt, hvis du allerede er i LangChain-økosystemet. Trade-off: Det er en tung afhængighed, og abstraktionen kan skjule udbyderspecifikke funktioner, du måske har brug for.
Native API'er, direkte kald med response_format / output_config, kræver nul afhængigheder ud over udbyderens SDK. Du får fuld kontrol og fuld synlighed. Bedst til simple use cases eller teams, der foretrækker minimal abstraktion.
| Bibliotek | Sprog | Udbydere | Auto-genforsøg | Streaming | GitHub-stjerner | Lerningskurve |
|---|---|---|---|---|---|---|
| Instructor | Python, TS | 15+ | Ja | Ja | 11K+ | Lav |
| BAML | Python, TS, Ruby, Go | Alle (DSL-agnostic) | Ja | Ja | 7K+ | Mellem |
| LangChain | Python, TS | 20+ | Delvis | Ja | 100K+ | Mellem-Høj |
| Native API'er | Enhver | 1 pr. SDK | Nej | Ja | N/A | Lav |
Valg af det rette bibliotek til struktureret output er en del af en bredere beslutning om AI-stack. Vi gennemgår hele stacken i vores Guide til den bedste AI-stack til SaaS.
Se vores Bedste biblioteker til LLM-strukturerede outputs [kommer snart] for en dybdegående sammenligning af Instructor, BAML, Mirascope og mere.
Konklusion: Start med Instructor til Python, native API'er til TypeScript. Skift til BAML, hvis du har brug for skema-kontrakter på tværs af sprog. Undgå LangChain kun til struktureret output; det er overkill.
Best practices for skemadesign (og almindelige fejl)
Dit skemadesign påvirker outputkvaliteten direkte. Her er de mønstre, der betyder noget, og de fejl, der koster dig nøjagtighed.
Placér reasoning før svar
Vi dækkede dette i Pydantic-sektionen, men det tåler gentagelse, da det er designbeslutningen med højest 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'er genererer fra venstre mod højre. Feltrækkefølge er prompt-rækkefølge. Reasoning først betyder, at modellen skal arbejde sig gennem problemet, før den forpligter sig til et svar.
Anti-mønster-tabel
| Fejl | Problem | Løsning |
|---|---|---|
| Reasoning-felt efter svar | Modellen beslutter sig, før den tænker | Flyt reasoning før svar |
| Dybt nested (4+ niveauer) | Højere fejlrate, langsommere kompilering | Flad ud til 2-3 niveauer |
| Ingen feltbeskrivelser | Modellen gætter, hvad du vil have | Tilføj .describe() / Field(description=...) |
| Manglende null-håndtering | Modellen hallucinerer en værdi for at fylde feltet | Brug Optional / .nullable() |
| Overdreven store skemaer (50+ felter) | Kompileringstimeout, kvalitetsforringelse | Opdel i flere kald |
| Vage enum-options | Modellen vælger forkert kategori | Brug specifikke, ikke-overlappende options |
Håndtér nulls eksplicit
Hvis et felt muligvis ikke har data i kildeteksten, skal du gøre det valgfrit. At tvinge et påkrævet felt, når data ikke findes, fører til hallucination:
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")Hold skemaer fokuserede
Ét skema per opgave. Prøv ikke at udtrække alt i et enkelt massivt skema. Hvis du har brug for 50+ felter, skal du opdele det i flere ekstraktionskald. OpenAIs Strict Mode har praktiske grænser for skemakompleksitet, og selv når det virker, forringer meget store skemaer outputkvaliteten.
Konklusion: Reasoning-first, beskrivende felter, eksplicitte nulls og fokuserede skemaer. Få disse fire ting rigtigt, og din nøjagtighed ved struktureret output stiger mærkbart.
Struktureret output med lokale LLM'er
Du behøver ikke en API-udbyder for struktureret output. Lokale inferensmotorer understøtter det gennem grammatikbaseret begrænset afkodning – den samme fundamentale mekanisme, der kører på din egen hardware.
Ollama
Den nemmeste vej til lokalt struktureret output. Ollama accepterer et JSON-skema via parameteren 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 bruger XGrammar under motorhjelmen til begrænset afkodning. Samme garanti som API-udbyderne: 100 % skemaoverholdelse.
vLLM og SGLang
Til produktionsklar lokal inferens understøtter både vLLM og SGLang struktureret output gennem parametrene guided_json og guided_regex. XGrammar er standard-backenden, der leverer næsten nul overhead på JSON-generering, op til 3,5x hurtigere end alternative grammatikmotorer.
Outlines
Outlines er det open source Python-bibliotek, der pionerede grammatikbaseret begrænset generering. Det virker med enhver Hugging Face-model og understøtter JSON-skema, regex og fulde kontekstfrie grammatikbegrænsninger (CFG/EBNF). Det er også integreret i vLLM og SGLang som en grammar-backend-option.
Den vigtigste forskel fra API-udbydere: Lokalt struktureret output har ingen begrænsninger for skemaundersæt. Du kontrollerer grammatikken fuldstændigt. Men modelkvaliteten varierer mere; en lokal model med 7 milliarder parametre vil ikke matche GPT-4o eller Claude på komplekse ekstraktionsopgaver. Skemaet vil altid være valid; indholdets kvalitet afhænger af modellen.
Konklusion: Ollama til udvikling, vLLM/SGLang med XGrammar til produktion. Lokalt struktureret output er modent nok til de fleste use cases, med den caveat at mindre modeller producerer indhold af lavere kvalitet inden for skemaet.
FAQ
Hvad er struktureret output i LLM'er?
Struktureret output er en mekanisme, der garanterer, at en LLM's svar overholder et foruddefineret JSON-skema. I modsætning til almindelig tekst eller endda JSON Mode bruger struktureret output begrænset afkodning til at sikre, at hvert felt, hver type og hver begrænsning i dit skema overholdes – 100 % af tiden, ikke "normalt".
Hvad er forskellen mellem JSON Mode og Strukturerede Outputs?
JSON Mode garanterer syntaktisk gyldig JSON, men håndhæver ikke dit skema; du kan få ethvert gyldigt JSON-objekt. Strukturerede Outputs (Strict Mode) garanterer fuld skemaoverholdelse gennem begrænset afkodning. Brug Strict Mode til produktion; JSON Mode er kun relevant, når du ikke har et skema på forhånd.
Hvilke LLM-udbydere understøtter struktureret output nativt?
OpenAI (siden august 2024), Google Gemini (2024, udvidet 2026), Anthropic (beta november 2025, GA begyndelsen af 2026), Cohere og xAI (Grok) understøtter alle native struktureret output. På den lokale side understøtter Ollama, vLLM og SGLang det gennem grammatikbaseret begrænset afkodning.
Hvordan garanterer begrænset afkodning skemaoverholdelse?
JSON-skemaet kompileres til en endelig tilstandsmaskine (FSM). Ved hvert token-genereringstrin er kun tokens, der holder outputtet på en gyldig sti gennem FSM'en, tilladt; ugyldige tokens får deres logits sat til negativ uendelig. Det betyder, at ugyldige tokens har nul sandsynlighed for at blive genereret, hvilket giver dig en matematisk garanti, ikke en statistisk én.
Skal jeg bruge struktureret output eller function calling?
Brug struktureret output til ekstraktion og klassificering, når du vil have data i en bestemt form. Brug function calling til agent-workflows, når modellen skal beslutte, hvilken handling der skal tages. Mange produktionsapplikationer bruger begge dele: struktureret output til dataekstraktion og function calling til orkestrering.
Kan jeg streame struktureret output?
Ja. OpenAI understøtter streaming med metoden parse(), og Instructor leverer create_partial() til streaming af Pydantic-modeller, der udfyldes felt for felt. Husk, at individuelle streaming-chunks ikke er individuelt skema-valide; felter udfyldes inkrementelt.
Hvad er Instructor-biblioteket?
Instructor er det mest populære bibliotek til struktureret output (11K+ GitHub-stjerner, 3M+ månedlige downloads). Det wrapper udbyder-SDK'er med Pydantic-baseret validering, automatiske genforsøg med valideringsfeedback og streaming-understøttelse. Det virker med OpenAI, Anthropic, Gemini, Cohere, Ollama og 10+ andre udbydere.
Virker struktureret output med lokale LLM'er?
Ja. Ollama understøtter struktureret output via parameteren format med JSON-skema. vLLM og SGLang understøtter det gennem guided_json-parametre. Alle tre bruger XGrammar eller Outlines til begrænset afkodning. Garantien for skemaoverholdelse er den samme som hos API-udbydere; indholdskvaliteten afhænger af modellen.
Hvad er almindelige fejl i skemadesign?
De største fejl: At placere reasoning-feltet efter svarfeltet (modellen beslutter sig, før den tænker), dybt nestede skemaer (4+ niveauer øger fejl), manglende feltbeskrivelser (modellen gætter intention), ingen null-håndtering for valgfrie data (tvinger hallucination) og overdrevent store skemaer (50+ felter forringer kvaliteten).
Tilføjer struktureret output latens?
Der er et overhead for schemakompilering ved den første anmodning, typisk 50-200 ms, mens FSM'en bygges. Efterfølgende anmodninger med samme skema bruger en cachelagret FSM og tilføjer næsten nul latens. For de fleste applikationer er dette ubetydeligt sammenlignet med den samlede models inferenstid.
Kan jeg bruge struktureret output med billeder eller multimodale inputs?
Ja. Struktureret output gælder for svar-formatet, ikke inputtet. Du kan sende et billede til GPT-4o eller Gemini med et skema for struktureret output og få tilbage en skema-compliant analyse af billedet. Dette er kraftfuldt til visuelle ekstraktionsworkflows, f.eks. udtrækning af strukturerede data fra kvitteringer, formularer eller produktbilleder.