Structured Outputs: Ako prinútiť LLM vrátiť spoľahlivé dáta

Jazykové modely sú skvelé v generovaní textu — ale v produkčných aplikáciách potrebujete dáta, nie prózu. Structured Outputs je technika, ktorá zaručuje, že model vráti presne taký formát, aký vaša aplikácia očakáva.


1. Problém: LLM ako nespoľahlivý dátový zdroj

Predstavte si aplikáciu, ktorá má extrahovať meno, vek a email zo životopisu. Poprosite GPT-5 alebo Claude, a on vráti... čo vlastne?

  • Niekedy čistý JSON s korektnou štruktúrou.
  • Niekedy JSON s komentárom pred otváracou závorkou.
  • Niekedy Markdown blok obalený v ```json.
  • Niekedy celú vetu: „Samozrejme! Tu sú dáta: {...}".

Každý z týchto prípadov vyžaduje iný parsing. V produkčnom systéme, kde volania idú do tisícov denne, jeden neočakávaný formát stačí na pád celého pipeline.

Structured Outputs rieši práve tento problém: namiesto toho, aby ste v prompte prosili model o správny formát, vynútite ho na úrovni API alebo inference enginu — model fyzicky nemôže odchýliť od schémy.


2. Ako to funguje technicky

Existujú tri hlavné mechanizmy, ktorými poskytovatelia garantujú štruktúrovaný výstup:

2.1 Constrained Decoding (obmedzené dekódovanie)

Najrobustnejší prístup. Inference engine pri každom kroku generovania obmedzí pravdepodobnostné rozdelenie tokenov len na tie, ktoré sú konzistentné s požadovanou schémou. Ak JSON objekt ešte nemá uzatváraciu závorku, model jednoducho nemôže vygenerovať token, ktorý by schému porušil — na úrovni logitov.

Implementujú to napríklad:

  • llama.cpp cez GBNF gramatiky (Grammar-Based Formal Notation)
  • Outlines — open-source Python knižnica pre lokálne modely
  • vLLM s integrovanou JSON Schema podporou
  • OpenAI API od modelu gpt-4o-2024-08-06 cez parameter response_format

2.2 JSON Mode

Jednoduchší variant — model je inštruovaný generovať syntakticky validný JSON, ale bez konkrétnej schémy. Zaručuje, že výstup je parsovateľný, nie že obsahuje správne polia a typy.

2.3 Post-generation Validation + Retry

Najstaršia metóda: vygeneruj, validuj, pri neúspechu opakuj. Pomalé, nespoľahlivé a drahé. Dnes sa používa len ako fallback alebo pre veľmi komplexné schémy.


3. Porovnanie prístupov naprieč providermi

Provider / nástroj Metóda Schéma Garancie
OpenAI GPT-4o+ Constrained decoding JSON Schema (podmnožina) 100 % validný JSON
Anthropic Claude Tool use + post-validation Pydantic / JSON Schema Veľmi vysoká, nie absolútna
Google Gemini 1.5+ response_mime_type + schema Upravený JSON Schema Veľmi vysoká
Ollama + llama.cpp GBNF gramatiky Vlastná gramatika 100 % (constrained)
Outlines (open-source) Constrained decoding Pydantic, JSON Schema, Regex 100 % (constrained)
LangChain .with_structured_output() Závisí od modelu Pydantic model Závisí od backendu

Dôležité: „100 % validný JSON" neznamená „sémanticky správne hodnoty". Model môže vygenerovať validný objekt, kde vek je -5 alebo email neobsahuje @. Validácia obchodnej logiky zostáva na aplikácii.


4. Praktické použitie

4.1 OpenAI API (Python) — Pydantic integrácia

from openai import OpenAI
from pydantic import BaseModel

class Kandidat(BaseModel):
    meno: str
    vek: int
    email: str
    skusenosti_roky: float

client = OpenAI()
completion = client.beta.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[
        {"role": "system", "content": "Extrahuj dáta z životopisu."},
        {"role": "user", "content": zivotopis_text}
    ],
    response_format=Kandidat,
)
kandidat = completion.choices[0].message.parsed
print(kandidat.meno, kandidat.email)

4.2 Anthropic Claude cez tool use

Claude natívne nepodporuje constrained decoding cez API, ale structured outputs možno dosiahnuť definovaním nástroja s požadovanou schémou a vynútením jeho volania cez tool_choice:

import anthropic

client = anthropic.Anthropic()
response = client.messages.create(
    model="claude-opus-4-8",
    tools=[{
        "name": "uloz_kandidata",
        "description": "Ulož extrahované dáta kandidáta",
        "input_schema": {
            "type": "object",
            "properties": {
                "meno": {"type": "string"},
                "vek": {"type": "integer"},
                "email": {"type": "string"}
            },
            "required": ["meno", "vek", "email"]
        }
    }],
    tool_choice={"type": "tool", "name": "uloz_kandidata"},
    messages=[{"role": "user", "content": zivotopis_text}]
)
data = response.content[0].input

4.3 Outlines pre lokálne modely

import outlines

model = outlines.models.transformers("mistralai/Mistral-7B-v0.1")
generator = outlines.generate.json(model, Kandidat)
kandidat = generator("Extrahuj dáta: " + zivotopis_text)

Typické produkčné use cases:

  • Extrakcia entít z dokumentov — faktúry, zmluvy, životopisy, správy
  • Klasifikácia s presnými labeli a skóre namiesto voľného textu
  • Generovanie konfigurácií a workflow definícií pre downstream systémy
  • Multi-step reasoning kde každý krok vracia štruktúrovaný medzivýsledok
  • API wrappery nad LLM pre integráciu s databázami a existujúcimi systémami

5. Limity, riziká a smer vývoja

Obmedzenia schémy u jednotlivých providerov: OpenAI nepodporuje celú špecifikáciu JSON Schema 2020-12 — chýba napríklad anyOf s viac ako dvoma variantmi alebo niektoré kombinácie if/then/else. Pri návrhu komplexných schém je nutné tieto limity poznať vopred.

Sémantická nesprávnosť zostáva reálnym rizikom: Constrained decoding garantuje syntaxu, nie zmysel. Ak model vygeneruje do povinného integer poľa vek hodnotu 0 alebo 999, schéma to prepustí. Pridajte post-validáciu pre hodnoty s obchodným dopadom.

Výkonnostný overhead: Constrained decoding pridáva záťaž na inference strane — typicky 5–15 % pomalší throughput oproti voľnému generovaniu. Pre latency-kritické aplikácie je potrebné tento vplyv zmerať.

Problémy s hĺbkou a rekurziou: Hlboko zanorené objekty (napríklad strom s ľubovoľnou hĺbkou) sú problematické. Väčšina providerov má obmedzenie hĺbky schémy alebo rekurzívne typy úplne nepodporuje.

Vendor lock-in: Každý provider má mierne odlišnú implementáciu a podmnožinu JSON Schema. Abstrakčné vrstvy ako Instructor alebo LangChain .with_structured_output() pomáhajú s prenositeľnosťou, ale pridávajú závislosť.

Kam smeruje budúcnosť: Trend je jednoznačný — štandardizácia okolo JSON Schema draft 2020-12 a hlbšia integrácia so systémami ako MCP, kde structured outputs tvoria základ pre spoľahlivú inter-agent komunikáciu. Constrained decoding sa v roku 2026 stáva de-facto štandardom v akomkoľvek serióznom produkčnom AI pipeline.


Zhrnutie: Structured Outputs transformuje LLM z nepredvídateľného textového generátora na spoľahlivý dátový procesor — čo je nevyhnutný predpoklad pre produkčné AI aplikácie a agentic systémy, kde každý krok pipeline závisí od presného výstupu toho predchádzajúceho.