# Batch-requests met de Gemini API [[TOC]] ## Wanneer gebruik je batch-verwerking Batch-verwerking is de juiste keuze als je: - Honderden tot miljoenen prompts wilt verwerken - Geen real-time antwoord nodig hebt (resultaat mag tot 24 uur later komen) - Kosten wilt minimaliseren (50 procent korting op input- en outputtokens) - Rate limit-problemen wilt vermijden bij grote volumes Typische use cases: een hele productcatalogus verrijken, samenvattingen genereren voor een archief, een kennisbank embedden, of classificaties draaien op grote datasets. :::info title="Sinds 2026 een native Batch API" Eerder had de Gemini Developer API geen eigen batch-endpoint voor tekstgeneratie en moest je parallelle calls bouwen. Sinds begin 2026 is er een echte Batch-modus via `client.batches`. Dit artikel gebruikt die native aanpak; de parallelle methode staat hieronder als alternatief voor wie wel real-time resultaten nodig heeft. ::: ## De juiste SDK en modellen Gebruik de nieuwe, unified `google-genai` SDK (`from google import genai`). De oude `google-generativeai` SDK is gedeprec8 en krijgt geen nieuwe features meer. ```bash pip install google-genai ``` Gangbare modellen in 2026 zijn `gemini-2.5-flash` (snel en goedkoop) en `gemini-3.5-flash` (nieuwer). Voor embeddings gebruik je `gemini-embedding-001`. Controleer de officiele modellenpagina van Google voor de actuele lijst, want modelnamen wisselen regelmatig. ## Een batch-job aanmaken met inline requests Voor kleinere batches (inputpayload onder 20 MB) geef je de requests direct mee: ```python from google import genai client = genai.Client() producten = [ {"id": "P001", "naam": "Draadloze muis"}, {"id": "P002", "naam": "Mechanisch toetsenbord"}, {"id": "P003", "naam": "4K monitor 27 inch"}, ] inline_requests = [ { "contents": [ {"role": "user", "parts": [{"text": f"Schrijf een korte productomschrijving voor: {p['naam']}"}]} ] } for p in producten ] batch_job = client.batches.create( model="gemini-2.5-flash", src=inline_requests, config={"display_name": "productomschrijvingen"}, ) print(f"Aangemaakt: {batch_job.name}") ``` ## Een batch-job aanmaken met een JSONL-bestand Voor grote batches (tot 2 GB inputbestand) upload je een JSON Lines-bestand. Elke regel is een volledige request met een eigen `key`, zodat je resultaten later kunt terugkoppelen aan je brondata: ```python import json from google import genai from google.genai import types client = genai.Client() producten = [ {"id": "P001", "naam": "Draadloze muis"}, {"id": "P002", "naam": "Mechanisch toetsenbord"}, ] with open("requests.jsonl", "w") as f: for p in producten: regel = { "key": p["id"], "request": { "contents": [ {"role": "user", "parts": [{"text": f"Categoriseer dit product: {p['naam']}"}]} ] }, } f.write(json.dumps(regel) + " ") uploaded = client.files.upload( file="requests.jsonl", config=types.UploadFileConfig(display_name="batch-requests", mime_type="jsonl"), ) batch_job = client.batches.create( model="gemini-2.5-flash", src=uploaded.name, config={"display_name": "product-classificatie"}, ) ``` ## Voortgang monitoren Een batch-job doorloopt verschillende statussen. Pollen doe je met `client.batches.get()`: ```python import time completed_states = { "JOB_STATE_SUCCEEDED", "JOB_STATE_FAILED", "JOB_STATE_CANCELLED", "JOB_STATE_EXPIRED", } job = client.batches.get(name=batch_job.name) while job.state.name not in completed_states: print(f"Status: {job.state.name}") time.sleep(30) job = client.batches.get(name=batch_job.name) print(f"Eindstatus: {job.state.name}") ``` De belangrijkste statussen: | Status | Betekenis | | --- | --- | | `JOB_STATE_PENDING` | Wacht om verwerkt te worden | | `JOB_STATE_RUNNING` | Wordt verwerkt | | `JOB_STATE_SUCCEEDED` | Succesvol afgerond | | `JOB_STATE_FAILED` | Mislukt (bekijk de foutdetails) | | `JOB_STATE_CANCELLED` | Door jou geannuleerd | | `JOB_STATE_EXPIRED` | Liep langer dan 48 uur en is verlopen | ## Resultaten ophalen De uitvoer komt terug als inline responses (bij inline requests) of als bestand (bij JSONL-invoer): ```python job = client.batches.get(name=batch_job.name) if job.state.name == "JOB_STATE_SUCCEEDED": if job.dest and job.dest.file_name: inhoud = client.files.download(file=job.dest.file_name) for regel in inhoud.decode("utf-8").splitlines(): resultaat = json.loads(regel) print(resultaat.get("key"), resultaat.get("response")) elif job.dest and job.dest.inlined_responses: for i, response in enumerate(job.dest.inlined_responses): if response.response: print(f"Antwoord {i + 1}: {response.response.text}") ``` ## Een job annuleren Een lopende job stop je direct, al gegenereerde uitvoer blijft beschikbaar: ```python client.batches.cancel(name=batch_job.name) ``` ## Batch embeddings Embeddings hebben hun eigen methode, `create_embeddings`, met hetzelfde job-model: ```python from google import genai client = genai.Client() teksten = [ "Artificiele intelligentie verandert de wereld", "Machine learning is een onderdeel van AI", "Neurale netwerken zijn geinspireerd op het menselijk brein", ] inline_requests = [{"content": t} for t in teksten] job = client.batches.create_embeddings( model="gemini-embedding-001", src={"inlined_requests": inline_requests}, config={"display_name": "kennisbank-embeddings"}, ) print(f"Embedding-job: {job.name}") ``` :::tip title="Begin klein" Test je request-formaat eerst met twee of drie inline requests voordat je een bestand van duizenden regels indient. Een verkeerd JSONL-schema laat de hele job falen en kost je een polling-ronde van soms uren. ::: ## Alternatief: parallelle calls voor real-time werk Heb je toch synchrone resultaten nodig (bijvoorbeeld in een interactieve flow), dan zijn begrensde parallelle calls de beste keuze. Let op: dit valt onder de normale, niet-verlaagde tarieven en je raakt sneller rate limits. ```python import asyncio from google import genai client = genai.Client() async def generate_for_item(item: dict, semaphore: asyncio.Semaphore) -> dict: async with semaphore: try: response = await client.aio.models.generate_content( model="gemini-2.5-flash", contents=f"Schrijf een productomschrijving voor: {item['naam']}", ) return {"id": item["id"], "tekst": response.text, "status": "ok"} except Exception as e: return {"id": item["id"], "tekst": None, "status": str(e)} async def process_batch(items: list, concurrency: int = 5) -> list: semaphore = asyncio.Semaphore(concurrency) return await asyncio.gather(*(generate_for_item(i, semaphore) for i in items)) results = asyncio.run(process_batch(producten)) for r in results: print(f"{r['id']}: {r['status']}") ``` :::warn title="Respecteer rate limits" Begrens gelijktijdige requests met een `Semaphore`. Vijf tot tien gelijktijdige requests is veilig op een gratis tier; meer is mogelijk met een betaald account. Bouw exponentiele back-off in voor `RESOURCE_EXHAUSTED`-fouten zodat je niet harder blijft proberen dan toegestaan. ::: ## Vertex AI Batch Prediction Werk je binnen Google Cloud met grote, herhaalbare pipelines, dan biedt Vertex AI Batch Prediction dezelfde 50 procent korting met diepere integratie: input en output via Cloud Storage of BigQuery, IAM-rechten en monitoring binnen je project. De Gemini Batch API is doorgaans eenvoudiger om mee te starten; Vertex AI loont als je al in dat ecosysteem zit. :::faq ### Heeft de Gemini API echt een native batch-endpoint? Ja. Sinds begin 2026 maak je batch-jobs aan met `client.batches.create()` in de `google-genai` SDK. Een aparte parallelle-call-constructie is daarvoor niet meer nodig. ### Hoeveel goedkoper is batch-verwerking? Batch-jobs kosten 50 procent minder dan synchrone calls, voor zowel input- als outputtokens. De afspraak is dat resultaten binnen 24 uur klaar zijn, in de praktijk vaak veel sneller. ### Welke SDK moet ik gebruiken? De nieuwe unified `google-genai` SDK, geimporteerd als `from google import genai`. De oude `google-generativeai` SDK is gedeprec8; bestaande code migreer je via de officiele migratiegids van Google. ### Werkt batch-modus ook voor embeddings? Ja, via `client.batches.create_embeddings()` met een embeddingmodel zoals `gemini-embedding-001`. Je geeft inline requests of een geupload bestand mee, net als bij tekstgeneratie. ### Hoe ga ik om met gedeeltelijk mislukte batches? Geef elke request een unieke `key` mee. In de uitvoer koppel je per regel de status terug aan je brondata en dien je alleen de mislukte items opnieuw in. ### Wanneer kies ik dan nog parallelle calls? Alleen als je echt real-time antwoorden nodig hebt. Dat valt onder de normale tarieven en loopt sneller tegen rate limits aan, dus voor grote, niet-urgente volumes is de Batch API vrijwel altijd beter. :::