Vergelijking van gestructureerde output bij populaire LLM-leveranciers: OpenAI, Gemini, Anthropic, Mistral en AWS Bedrock

Ietwat afwijkende API's vereisen een speciale aanpak.

Inhoud

Hieronder volgt een vergelijking van de ondersteuning voor gestructureerde output (betrouwbaar JSON terugkrijgen) bij populaire LLM-aanbieders, plus minimale Python-voorbeelden

gekleurde balken staand

We hebben eerder gekeken hoe je gestructureerde output kunt aanvragen bij de LLM die op Ollama is gehost. Zodra JSON weer via de verbinding loopt, behandelt validatie van gestructureerde LLM-output in Python die standhoudt het parseren, Pydantic-controles, herpogingen en tests in je service. Hier bekijken we hoe je hetzelfde kunt aanvragen bij andere aanbieders.

TL;DR-matrix

Aanbieder Native “JSON-modus” JSON-Schema-afdwinging Typische instelling Opmerkingen
OpenAI Ja Ja (eersteklas) response_format={"type":"json_schema", ...} Werkt via de Responses API of Chat Completions; kan ook function calling gebruiken.
Google Gemini Ja Ja (eersteklas) response_schema= + response_mime_type="application/json" Retourneert strikt gevalideerd JSON als schema is ingesteld.
Anthropic (Claude) Indirect Ja (via Tool Use met JSON-schema) tools=[{input_schema=...}] + tool_choice Forceer het model om je gedefinieerde tool te “aanroepen”; levert schema-gestalte argumenten op.
Mistral Ja Gedeeltelijk (alleen JSON; geen server-side schema) response_format={"type":"json_object"} Zorgt voor JSON, maar je valideert client-side tegen je schema.
AWS Bedrock (platform) Verschilt per model Ja (via Tool/Converse-schema) toolConfig.tools[].toolSpec.inputSchema Bedrock’s Converse API valideert tool-input tegen een JSON-schema.

Gestructureerde LLM-output — Algemene informatie

Gestructureerde LLM-output verwijst naar het vermogen van grote taalmodellen (LLM’s) om reacties te genereren die strikt voldoen aan een vooraf gedefinieerd, specifiek formaat of structuur, in plaats van vrij tekst te produceren. Deze gestructureerde output kan in formaten zoals JSON, XML, tabellen of sjablonen, waardoor de data machine-leesbaar, consistent en makkelijk parsebaar is door software voor gebruik in verschillende toepassingen.

Gestructureerde outputs verschillen van traditionele LLM-outputs, die doorgaans open-eind, natuurlijke taaltekst genereren. In plaats daarvan dwingen gestructureerde outputs een schema of formaat af, zoals JSON-objecten met gedefinieerde sleutels en waardetypes, of specifieke klassen in de output (bijv. meerkeuze-antwoorden, sentimentklassen of database-regelformaten). Deze aanpak verbetert betrouwbaarheid, vermindert fouten en hallucinaties, en vereenvoudigt integratie in systemen zoals databases, API’s of workflows.

De generatie van gestructureerde outputs in LLM’s omvat vaak technieken zoals:

  • Het specificeren van gedetailleerde prompt-instructies om het model te begeleiden bij het produceren van output in het gewenste formaat.
  • Het gebruik van validatie- en parsehulpmiddelen zoals Pydantic in Python om te waarborgen dat de output overeenkomt met het schema.
  • Soms het afdwingen van decoderingsbeperkingen op basis van grammatica of eindige statemachine om token-niveau-naleving van het formaat te garanderen.

Voordelen van gestructureerde LLM-outputs omvatten:

  • Machine-leesbaarheid en gemakkelijke integratie.
  • Verminderde variabiliteit en fouten.
  • Verbeterde voorspelbaarheid en verificerbaarheid voor taken die consistente dataformaten vereisen.

Uitdagingen omvatten het ontwerpen van effectieve schemas, het afhandelen van complexe genestelde data, en potentiële beperkingen in redeneervermogen in vergelijking met vrij tekstgeneratie.

Over het algemeen maakt gestructureerde output LLM’s nuttiger in toepassingen die precieze, geformatteerde data vereisen in plaats van uitsluitend mens-leesbare tekst.

Python-voorbeelden voor gestructureerde output

Alle fragmenten extraheren evenement-info als JSON: {title, date, location}. Vervang keys/modellen zoals je wilt.

1) OpenAI — JSON Schema (strikt)

from openai import OpenAI
import json

client = OpenAI()

schema = {
    "name": "Evenement",
    "schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "date":  {"type": "string", "description": "YYYY-MM-DD"},
            "location": {"type": "string"}
        },
        "required": ["title", "date", "location"],
        "additionalProperties": False
    },
    "strict": True
}

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}
    ],
    response_format={"type": "json_schema", "json_schema": schema},
)

data = json.loads(resp.choices[0].message.content)
print(data)

OpenAI’s Structured Outputs-functie dwingt dit schema af op de serverside.


2) Google Gemini — response schema + JSON MIME

import google.generativeai as genai
from google.genai import types

# Configureer met je API-sleutel
# genai.configure(api_key="your-api-key")

schema = types.Schema(
    type=types.Type.OBJECT,
    properties={
        "title": types.Schema(type=types.Type.STRING),
        "date": types.Schema(type=types.Type.STRING),
        "location": types.Schema(type=types.Type.STRING),
    },
    required=["title", "date", "location"],
    additional_properties=False,
)

resp = genai.generate_content(
    model="gemini-2.0-flash",
    contents="Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'",
    generation_config=genai.GenerationConfig(
        response_mime_type="application/json",
        response_schema=schema,
    ),
)

print(resp.text)  # al geldige JSON volgens schema

Gemini zal strikt JSON retourneren dat voldoet aan response_schema.


3) Anthropic (Claude) — Tool Use met JSON-schema

from anthropic import Anthropic
import json

client = Anthropic()

tool = {
    "name": "extract_event",
    "description": "Return event details.",
    "input_schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "date": {"type": "string"},
            "location": {"type": "string"}
        },
        "required": ["title", "date", "location"],
        "additionalProperties": False
    }
}

msg = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=256,
    tools=[tool],
    tool_choice={"type": "tool", "name": "extract_event"},  # forceer schema
    messages=[{"role": "user", "content":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)

# Claude zal de tool "aanroepen"; pak de args (die overeenkomen met je schema)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))

Claude heeft geen algemene “JSON-modus”-schakelaar; in plaats daarvan geeft Tool Use met een input_schema je gevalideerde, schema-gestalte argumenten (en je kunt het gebruik ervan forceren).


4) Mistral — JSON-modus (client-side validatie)

from mistralai import Mistral
import json

client = Mistral()

resp = client.chat.complete(
    model="mistral-large-latest",
    messages=[{"role":"user","content":
        "Return JSON with keys title, date (YYYY-MM-DD), location for: "
        "'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
    response_format={"type": "json_object"}  # garandeert geldige JSON
)

data = json.loads(resp.choices[0].message.content)
print(data)
# Tip: valideer `data` lokaal tegen je Pydantic/JSON Schema.

Mistral’s json_object dwingt JSON-vorm af (niet je exacte schema) — valideer client-side.


5) AWS Bedrock — Converse API Tool-schema (model-onafhankelijk)

import boto3, json

bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0"

tools = [{
    "toolSpec": {
        "name": "extract_event",
        "inputSchema": {
            "json": {
                "type": "object",
                "properties": {
                    "title": {"type": "string"},
                    "date": {"type": "string"},
                    "location": {"type": "string"}
                },
                "required": ["title","date","location"],
                "additionalProperties": False
            }
        }
    }
}]

resp = bedrock.converse(
    modelId=model_id,
    toolConfig={"tools": tools},
    toolChoice={"tool": {"name": "extract_event"}},  # forceer schema
    messages=[{"role":"user","content":[{"text":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)

# Haal toolUse-content op
tool_use = next(
    c["toolUse"] for c in resp["output"]["message"]["content"] if "toolUse" in c
)
print(json.dumps(tool_use["input"], indent=2))

Bedrock valideert tool-input tegen je JSON-schema en veel gehoste modellen (bijv. Claude) ondersteunen dit via Converse.


Praktische richtlijnen en validatie

  • Als je de sterkste serverside garanties wilt: OpenAI gestructureerde outputs of Gemini response schema.
  • Als je al op Claude/Bedrock zit: definieer een Tool met een JSON-schema en forceer het gebruik; lees de argumenten van de tool als je getypeerde object.
  • Als je Mistral gebruikt: schakel json_object in en valideer lokaal (bijv. met Pydantic).

Validatiepatroon (werkt voor ze allemaal)

from pydantic import BaseModel, ValidationError

class Event(BaseModel):
    title: str
    date: str
    location: str

try:
    event = Event.model_validate(data)  # `data` van elke aanbieder
except ValidationError as e:
    # afhandelen / opnieuw proberen / vraag model om te fixen met e.errors()
    print(e)

Abonneren

Ontvang nieuwe berichten over systemen, infrastructuur en AI-engineering.