Naar inhoud
lightbulb Welkom op de nieuwe kennisbank | We hebben de docs volledig vernieuwd met meer dan 160 features. Bekijk wat nieuw isarrow_forward

Gestructureerde JSON van de Gemini API

Laat de Gemini API altijd geldige JSON teruggeven die voldoet aan een opgegeven schema, via response_mime_type en response_schema met Pydantic-modellen.

Waarom gestructureerde output

Taalmodellen genereren standaard vrije tekst. Voor applicaties die data verwerken heb je betrouwbare, parseerbare output nodig. JSON uit vrije tekst halen is fragiel: markdown-codeblokken, extra uitleg, wisselende veldnamen en ontbrekende verplichte velden breken je verwerking.

De Gemini API ondersteunt twee niveaus van gestructureerde output: de JSON-modus (altijd geldige JSON, vrije structuur) en een response schema (JSON dat voldoet aan een schema dat jij bepaalt).

warning

Werk met de huidige SDK

De oude google-generativeai SDK (import google.generativeai as genai) is uitgefaseerd; de ondersteuning eindigde op 30 november 2025. Gebruik de unified google-genai SDK: from google import genai. Installeren doe je met pip install google-genai. Alle voorbeelden hieronder gebruiken die SDK.

JSON-modus inschakelen

De eenvoudigste methode: zet response_mime_type op "application/json".

from google import genai
from google.genai import types
import json
import os

client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Geef een lijst van 5 grote Europese steden met hun land en inwoneraantal.",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
    ),
)

data = json.loads(response.text)
print(data)

Met de JSON-modus krijg je altijd geldige JSON terug, maar het model bepaalt zelf de structuur. Voor voorspelbare verwerking voeg je een schema toe.

Schema definieren met response_schema

Voor een vaste structuur geef je een schema mee. Dat kan als platte JSON Schema-dictionary:

schema = {
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "stad": {"type": "string"},
            "land": {"type": "string"},
            "inwoners": {"type": "integer"},
            "hoofdstad": {"type": "boolean"},
        },
        "required": ["stad", "land", "inwoners", "hoofdstad"],
    },
}

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Geef een lijst van 5 grote Europese steden.",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=schema,
    ),
)

steden = json.loads(response.text)
for stad in steden:
    print(f"{stad['stad']} ({stad['land']}): {stad['inwoners']:,} inwoners")

Pydantic-modellen gebruiken

De Python SDK accepteert Pydantic-modellen direct als schema. Dat is doorgaans de prettigste werkwijze: je krijgt type-validatie, IDE-ondersteuning en compactere code. Bovendien lees je het resultaat direct uit via response.parsed, zonder zelf json.loads te hoeven aanroepen.

from pydantic import BaseModel
from typing import Optional

class Stad(BaseModel):
    naam: str
    land: str
    inwoners: int
    hoofdstad: bool
    bijzonderheid: Optional[str] = None

class StedenLijst(BaseModel):
    steden: list[Stad]
    gegenereerd_op: str

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Geef 5 grote Europese steden.",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=StedenLijst,
    ),
)

result: StedenLijst = response.parsed
for stad in result.steden:
    print(f"{stad.naam}: {stad.inwoners:,}")
lightbulb

Vraag een lijst zonder wrapper-model

Heb je alleen een lijst nodig? Geef dan list[Stad] rechtstreeks als response_schema. Je hoeft geen extra wrapper-klasse te maken: response.parsed is dan meteen een Python-lijst van Stad-objecten.

Enums in schema's

Beperk een veld tot een vaste set waarden met een enum. Een str-gebaseerde Enum of een Literal werkt allebei.

from enum import Enum

class Prioriteit(str, Enum):
    LAAG = "laag"
    MIDDEL = "middel"
    HOOG = "hoog"
    KRITIEK = "kritiek"

class Taak(BaseModel):
    titel: str
    prioriteit: Prioriteit
    geschatte_uren: float
    toewijzing: str

class TakenLijst(BaseModel):
    taken: list[Taak]
    sprint_nummer: int

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=(
        "Maak een sprint-backlog voor een webshop-project. "
        "Genereer 5 taken met realistische schattingen."
    ),
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=TakenLijst,
    ),
)

backlog: TakenLijst = response.parsed

Geneste objecten en arrays

Schema's mogen zo diep genest zijn als nodig. Gemini vult de hele boom in.

class Adres(BaseModel):
    straat: str
    huisnummer: str
    postcode: str
    stad: str
    land: str

class Contactpersoon(BaseModel):
    naam: str
    email: str
    telefoon: Optional[str] = None
    adres: Adres
    rollen: list[str]

class Bedrijf(BaseModel):
    naam: str
    kvk_nummer: str
    website: str
    contactpersonen: list[Contactpersoon]
    sector: str

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Genereer een voorbeeldbedrijf in de IT-sector met 2 contactpersonen.",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=Bedrijf,
    ),
)

bedrijf: Bedrijf = response.parsed

Tekst extraheren met schema

Gestructureerde output is sterk bij het uittrekken van data uit vrije tekst of documenten. Je stuurt de tekst mee en laat Gemini de velden invullen.

class Persartikel(BaseModel):
    kop: str
    datum: Optional[str] = None
    auteur: Optional[str] = None
    samenvatting: str
    kernpunten: list[str]
    sentiment: str
    categorie: str

tekst = """Amsterdam, 15 maart 2026 - Google heeft vandaag aangekondigd...
(lang nieuwsbericht)"""

prompt = f"Extraheer informatie uit dit artikel:

{tekst}"

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=prompt,
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=Persartikel,
    ),
)

artikel: Persartikel = response.parsed

Goede gewoonten voor productie

Een paar punten die je code robuust houden:

  • Valideer altijd na ontvangst. Ook met response_schema is Pydantic-validatie een goed vangnet. Wikkel response.parsed of Model.model_validate_json(response.text) in een try/except en log de ruwe respons bij een fout.
  • Houd schema's zo plat als kan. Heel diep geneste of optionele velden maken de output minder stabiel. Splits desnoods in twee aanroepen.
  • Pin je model op een stabiele versie. Gebruik een vaste naam zoals gemini-2.5-flash in plaats van een latest- of preview-alias, zodat gedrag niet onaangekondigd verandert.
  • Let op modeluitfasering. Gemini 2.0 Flash en 2.0 Flash-Lite zijn op 1 juni 2026 uitgezet. Controleer bij oudere code of het modelnaam-argument nog bestaat en stap zo nodig over op een nieuwer model.
Is response_schema beschikbaar voor alle Gemini-modellen?

Gestructureerde output met response_schema werkt op de huidige modellen, waaronder de Gemini 2.5- en 3.x-reeksen zoals gemini-2.5-flash, gemini-2.5-pro en de nieuwere 3.x-modellen. Oudere of zeer lichte modellen ondersteunen soms alleen response_mime_type zonder schema; raadpleeg de modelpagina van Google voor de actuele lijst.

Wat als het model verplichte velden weglaat?

Met response_schema dwingt Gemini de structuur af, inclusief verplichte velden. Bouw voor productie toch een validatiestap in met Pydantic, zodat een onverwachte respons netjes wordt opgevangen in plaats van je verwerking te breken.

Moet ik response.text zelf parsen?

Niet als je een Pydantic-model als schema gebruikt. De google-genai SDK vult dan response.parsed met een kant-en-klaar object. Geef je een platte JSON Schema-dictionary mee, dan parse je response.text zelf met json.loads.

Kan ik ook XML of andere formaten opvragen?

De gegarandeerde schema-binding werkt alleen voor JSON. Voor andere formaten gebruik je JSON als tussenstap, of je vraagt in de prompt om een specifiek formaat. Die laatste route is minder betrouwbaar.

Werkt gestructureerde output ook in een chatsessie?

Ja. Maak een sessie met client.chats.create en geef per bericht een config mee aan send_message, of stel een vaste config in bij het aanmaken van de chat. De structuur wordt dan voor elk antwoord afgedwongen.

Welk model kies ik het best?

Voor de meeste extractie- en classificatietaken is gemini-2.5-flash een goede, snelle en voordelige keuze. Heb je zwaardere redenering of complexe geneste schema's nodig, kies dan een pro-variant. Pin altijd een stabiele modelnaam in productie.