# Gestructureerde JSON van de Gemini API [[TOC]] ## 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). :::warn title="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"`. ```python 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: ```python 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. ```python 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:,}") ``` :::tip title="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. ```python 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. ```python 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. ```python 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. :::faq ### 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. :::