Met de lancering van GPT-5 heeft OpenAI het aanroepen van tools/functies in de API uitgebreid met vrije tool-calls (ruwe tekst, geen JSON), grammaticale beperkingen via Lark/CFG, tool-allowlists en verbeterde redeneerlogica voor toolgebruik. Samen maken deze GPT-5 een echt agentisch model; je kunt API’s, databases en aangepaste tools koppelen aan de Responses API en onderbouwde antwoorden genereren of zelfs workflows automatiseren.
In deze tutorial behandel ik functie-tools, aangepaste tools, grammaticale beperkingen, tool-allowlists en preambles, met codevoorbeelden en heldere uitleg over hoe ze werken en wanneer je ze gebruikt.
Function Calling in GPT-5: Wat & Waarom
Met Function Calling in GPT-5 kun je het model verrijken met de data en acties van je applicatie. Het model kan bepalen wanneer een tool aan te roepen, terwijl jij de logica afhandelt en resultaten teruggeeft voor een definitief, onderbouwd antwoord.
Types Function Calling:
Functie-tools (JSON Schema): Bieden gestructureerde inputs en outputs die het model precies kan aanroepen.
Aangepaste tools (vrij-formaat): Bieden flexibele tekstinputs en -outputs voor ongestructureerde integraties.
Wat is function calling?
GPT-5 ondersteunt zowel gestructureerde functie-tools (met JSON Schema) als aangepaste tools die vrije tekstpayloads accepteren (zoals SQL, scripts of configuraties) voor naadloze integratie met externe runtimes.
Functie-tools worden gedefinieerd met JSON Schema, zodat het model precies begrijpt welke argumenten het moet doorgeven en je strikte invoervalidatie kunt afdwingen. Lees meer in onze OpenAI Function Calling-tutorial.
Waarom function calling gebruiken?
Flexibiliteit: Vrije tools laten het model exact de tekst produceren die jouw systeem nodig heeft, zonder de beperkingen van starre JSON; ideaal voor code, queries of configuraties.
Betrouwbaarheid en controle: Functie-tools dwingen gestructureerde argumenten af, wat de voorspelbaarheid verbetert en parseerfouten vermindert.
Agentische workflows: GPT-5 is ontworpen voor complexe, meerstaps toolgebruik en codetaken, waardoor tool-calling een kernfunctie is.
Hoe werkt function calling?
Stuur een prompt die alle beschikbare tools bevat.
Het model doet een tool-call (met argumenten of vrije tekst).
Je applicatie voert de tool uit (run Python-functie).
Geef de output van de tool terug aan het model.
Het model reageert vervolgens of roept extra tools aan.
Gebruik functie-tools wanneer je strikte validatie en voorspelbare, getypeerde argumenten via JSON Schema wilt.
Gebruik aangepaste tools (vrij-formaat) wanneer je runtime ruwe tekst vereist (zoals scripts, SQL of configuraties) of wanneer je snel wilt itereren zonder schema’s.
Functie-tools (JSON Schema): Verstuur gestructureerde data
Met Functie-tools en JSON Schema krijg je voorspelbare en gestructureerde resultaten van het model. Het model beoordeelt de door jou gedeclareerde tools, bepaalt wanneer het er een gebruikt, stelt JSON-gevalideerde argumenten voor en voert vervolgens de bijbehorende functie in je code uit.
Daarna kun je het model vragen om een antwoord te genereren dat uitsluitend is gebaseerd op de door de tool teruggestuurde data, zodat de output onderbouwd, machineleesbaar en eenvoudig te integreren is.
Dit voorbeeld illustreert enkele kernconcepten:
Tool-ontdekking en argumentgeneratie: Het model selecteert de juiste tool en vult automatisch de JSON-getypeerde argumenten in.
Tool-executieloops: Je applicatie voert de gevraagde tool(s) uit en stuurt de resultaten terug naar het model.
Schema-vormig eindantwoord: Het definitieve antwoord is strikt gebaseerd op de outputs van de tools, wat onnauwkeurigheden minimaliseert en betrouwbaarheid waarborgt.
1. Installatie
Maak een OpenAI-account en genereer een API-sleutel op het platformdashboard. Ga op het dashboard naar de API-sectie, vervolgens “View API keys”, en klik op “Create new secret key”.
Voeg een betaalmethode of credits toe aan je account zodat API-calls kunnen draaien; gebruik wordt afgeschreven van je prepaidtegoed terwijl je verzoeken doet.
Sla je API-sleutel op als een omgevingsvariabele met de naam OPENAI_API_KEY voordat je je app start.
Installeer de officiële OpenAI Python SDK met pip install openai.
2. Tools definiëren
Je geeft een lijst met tools op met een naam, beschrijving en JSON Schema voor parameters. Het schema helpt het model om goedgevormde argumenten aan te leveren.
make_coffee verwacht één stringparameter: coffee_type.
random_coffee_fact neemt geen parameters (leeg object). Deze definities worden doorgegeven via het tools-argument in de API-call zodat het model weet wat beschikbaar is.
import os
from openai import OpenAI
import json
client = OpenAI(api_key = os.environ["OPENAI_API_KEY"])
tools =[{"type":"function","name":"make_coffee","description":"Gives a simple recipe for making a coffee drink.","parameters":{"type":"object","properties":{"coffee_type":{"type":"string","description":"The coffee drink, e.g. espresso, cappuccino, latte"}},"required":["coffee_type"],},},{"type":"function","name":"random_coffee_fact","description":"Returns a fun fact about coffee.","parameters":{"type":"object","properties":{}}}]Mogelijk gemaakt door
3. Tools implementeren
Je implementeert de Python-functies die het werk daadwerkelijk doen:
make_coffee(coffee_type) geeft een beknopte receptstring terug op basis van de gevraagde drank.
random_coffee_fact() geeft een kleine feitjes-payload terug.
Beide retourneren JSON-serialiseerbare dicts, ideaal om terug te voeren aan het model.
defmake_coffee(coffee_type):
recipes ={"espresso":"Grind fine, 18g coffee → 36g espresso in ~28s.","cappuccino":"Brew 1 espresso shot, steam 150ml milk, pour and top with foam.","latte":"Brew 1 espresso shot, steam 250ml milk, pour for silky texture.",}return{"coffee_type": coffee_type,"recipe": recipes.get(coffee_type.lower(),"Unknown coffee type!")}defrandom_coffee_fact():return{"fact":"Coffee is the second most traded commodity in the world, after oil."}Mogelijk gemaakt door
4. Start een gesprek
Start het gesprek met de vraag van de gebruiker: {"role": "user", "content": "How do I make a latte?"}
Het model kan berichten retourneren die een function_call-item bevatten, zoals make_coffee met {"coffee_type":"latte"}. Je moet vervolgens de modelberichten weer toevoegen aan input_list: input_list += response.output. Dit helpt om de gespreksstatus te behouden voor de volgende beurt.
# Track used tools
used_tools =[]
input_list =[{"role":"user","content":"How do I make a latte?"}]
response = client.responses.create(
model="gpt-5",
tools=tools,input=input_list,)
input_list += response.outputMogelijk gemaakt door
5. Voer tool-calls uit en voeg outputs toe
Je moet itereren over response.output en items identificeren waar item.type gelijk is aan "function_call". Parse voor deze items item.arguments en stuur de verzoeken door naar je Python-functies.
Voor de make_coffee-functie roep je deze aan met make_coffee(args["coffee_type"]). Voor de random_coffee_fact-functie roep je gewoon random_coffee_fact() aan.
Na het uitvoeren van de functies voeg je een function_call_output-bericht toe dat het volgende bevat:
call_id (die deze output koppelt aan het verzoek van het model)
output (een JSON-string van je functie-resultaat).
for item in response.output:ifgetattr(item,"type","")=="function_call":
used_tools.append(item.name)
args = json.loads(item.arguments or"{}")if item.name =="make_coffee":
result = make_coffee(args["coffee_type"])elif item.name =="random_coffee_fact":
result = random_coffee_fact()else:
result ={"error":f"Unknown tool {item.name}"}
input_list.append({"type":"function_call_output","call_id": item.call_id,"output": json.dumps(result)})Mogelijk gemaakt door
6. Genereer het eindantwoord
Je doet een tweede client.responses.create-call en geeft de geüpdatete input_list door die nu de tool-outputs bevat.
De variabele used_tools legt de namen vast van tools die in de function calls van het model voorkwamen. We gebruiken deze om te tonen welke tools zijn gebruikt.
final = client.responses.create(
model="gpt-5",
tools=tools,input=input_list,
instructions="Answer using only the tool results.")print("Final output:\n", final.output_text)print("\n--- Tool Usage ---")for t in tools:
status ="USED ✅"if t["name"]in used_tools else"NOT USED ❌"print(f"{t['name']}: {status}")Mogelijk gemaakt door
Omdat de gebruiker naar een latte vroeg, selecteerde het model make_coffee met coffee_type = "latte", jouw code voerde dit uit en het eindantwoord werd uitsluitend opgebouwd uit dat tool-resultaat.
Final output:{"coffee_type":"latte","recipe":"Brew 1 espresso shot, steam 250ml milk, pour for silky texture."}--- Tool Usage ---
make_coffee: USED ✅
random_coffee_fact: NOT USED ❌Mogelijk gemaakt door
Aangepaste tools (vrij-formaat): Verstuur ruwe tekst
Gebruik de vrije, aangepaste tools van GPT-5 om het model ruwe tekst rechtstreeks naar je tool te laten sturen, zoals code, SQL, shell-commando’s of eenvoudige CSV, zonder JSON Schema te vereisen.
Deze mogelijkheid gaat verder dan de oudere, uitsluitend JSON-gebaseerde functieaanroepen en geeft je meer flexibiliteit voor integratie met executors, query-engines of DSL-interpreters.
In de vrij-formaatmodus genereert het model een aangepaste tool-call met een ongestructureerde tekstpayload die je naar je runtime kunt routeren. Je retourneert vervolgens het resultaat dat het model gebruikt om het antwoord aan de gebruiker af te ronden.
We schrijven nu de code die het model in staat stelt de juiste tools te selecteren en ongestructureerde ruwe tekst als output te geven. Deze output gaat vervolgens naar een Python-functie om een resultaat te genereren. Zo kan de gebruiker de ingrediënten opgeven die hij/zij heeft en genereert het model recepten op maat.
In deze voorbeeldcode hebben we:
De OpenAI-client geïnitialiseerd en één aangepaste tool gedefinieerd genaamd meal_planner die ruwe tekstinput accepteert.
De Python-functie plan_meal gemaakt die een kommagescheiden string met ingrediënten neemt en een maaltijdidee retourneert.
Het gesprek gestart met een gebruikersbericht met de beschikbare ingrediënten.
Een eerste model-call gedaan met de instructie aan GPT-5 om de tool aan te roepen met alleen een schone lijst van ingrediënten, en de modeloutput aan de gespreksgeschiedenis toegevoegd.
De uitgegeven aangepaste tool-call gelokaliseerd en de ruwe, kommagescheiden inputstring geëxtraheerd.
De tool uitgevoerd door de lijst door te geven aan plan_meal, en vervolgens het resultaat teruggestuurd naar het model als een function_call_output gekoppeld via call_id.
Een laatste model-call uitgevoerd om het ruwe idee van de tool om te zetten in een korte, stapsgewijze receptuur, en zowel de tool-call-details als de eindoutput geprint.
from openai import OpenAI
import json
import random
client = OpenAI()# --- Custom tool ---
tools =[{"type":"custom","name":"meal_planner","description":"Takes ONLY a comma-separated list of ingredients and suggests a meal idea."}]# --- Fake meal planner ---defplan_meal(ingredients:str)->str:
ideas =[f"Stir-fry: {ingredients} with garlic & soy sauce.",f"One-pot rice: cook {ingredients} together in broth until fluffy.",f"Soup: simmer {ingredients} in stock with herbs.",f"Sheet-pan bake: roast {ingredients} at 200°C for ~20 min."]return random.choice(ideas)# --- Start conversation ---
messages =[{"role":"user","content":"I only have chicken, rice, and broccoli. Any dinner ideas?"}]# 1) Ask model with clear instruction
resp = client.responses.create(
model="gpt-5",
tools=tools,input=messages,
instructions="If the user mentions ingredients, call the meal_planner tool with ONLY a comma-separated list like 'chicken, rice, broccoli'.")
messages += resp.output
# 2) Find the tool call
tool_call =next((x for x in resp.output ifgetattr(x,"type","")=="custom_tool_call"),None)assert tool_call,"No tool call found!"# Get clean CSV input
ingredients_csv = tool_call.input.strip()# 3) Run the tool
meal_result = plan_meal(ingredients_csv)# 4) Send tool output back
messages.append({"type":"function_call_output","call_id": tool_call.call_id,"output": meal_result
})# 5) Final model response
final = client.responses.create(
model="gpt-5",
tools=tools,input=messages,
instructions="Turn the meal idea into a short recipe with 3-4 steps.")print("\n--- Tool Call ---")print("Name:", tool_call.name)print("Input:", ingredients_csv)print("Output:", meal_result)print("\n--- Final Output ---\n", final.output_text)Mogelijk gemaakt door
Als resultaat kregen we statistieken over de gebruikte tools, inclusief installatie, input en output. Bovendien geeft de eindoutput een compleet recept hoe je de maaltijd maakt.
--- Tool Call ---
Name: meal_planner
Input: chicken, rice, broccoli
Output: One-pot rice: cook chicken, rice, broccoli together in broth until fluffy.
--- Final Output ---
One-Pot Chicken, Rice & Broccoli
- Season bite-size chicken pieces with salt and pepper; sear in a little oil in a pot until lightly browned.
- Add 1 cup rinsed rice and 2 cups broth (or water + salt). Bring to a boil, then cover and simmer on low for12 minutes.
- Scatter 2 cups small broccoli florets on top, cover, and cook 5-7 more minutes until rice is fluffy and broccoli is tender.
- Rest 5 minutes off heat, fluff, and adjust seasoning. Optional: stir in a knob of butter or a splash of soy.Mogelijk gemaakt door
GPT-5 ondersteunt nu contextvrije grammatica (CFG) om te zorgen dat outputformaten strikt worden gecontroleerd.
Door een grammatica, zoals SQL of een domeinspecifieke taal (DSL), toe te passen op zijn antwoorden, garandeert GPT-5 dat de outputs consequent de vereiste structuur volgen. CFG is vooral belangrijk voor geautomatiseerde processen en kritieke workflows.
GPT-5 kan grammatica’s in formaten zoals Lark gebruiken om de outputs van de tool tijdens generatie te beperken. Deze benadering van constrained decoding verhoogt de betrouwbaarheid door format-drift te voorkomen en structurele consistentie te waarborgen.
We schrijven nu de code waarin het model een tool selecteert en ALLEEN een grammatica-geldige rekenkundige uitdrukking output; deze uitdrukking wordt vervolgens in Python geëvalueerd, het resultaat wordt teruggegeven aan het gesprek en het eindantwoord wordt duidelijk in natuurlijke taal gepresenteerd.
In deze voorbeeldcode hebben we:
De OpenAI-client geïnitialiseerd en een aangepaste tool math_solver gedefinieerd die ALLEEN een grammatica-geldige rekenkundige uitdrukking mag outputten (Lark CFG).
Het gesprek gestart met een wiskundevraag in natuurlijke taal van de gebruiker.
Een eerste model-call gedaan met de instructie aan GPT-5 om math_solver aan te roepen met een uitdrukking die aan de grammatica voldoet.
De uitgegeven tool-call gelokaliseerd en de ruwe uitdrukkingsstring uit de tool-payload geëxtraheerd.
De uitdrukking lokaal geëvalueerd in een beperkte omgeving om een concreet resultaat te produceren.
Het toolresultaat teruggegeven aan het gesprek, gekoppeld via de oorspronkelijke call_id.
Een laatste model-call uitgevoerd om het geëvalueerde resultaat duidelijk in natuurlijke taal te presenteren.
from openai import OpenAI
import json
client = OpenAI()# --- Local fake evaluator ---defeval_expression(expr:str)->str:try:# Evaluate safely using Python's eval on restricted globals
result =eval(expr,{"__builtins__":{}},{})returnf"{expr} = {result}"except Exception as e:returnf"Error evaluating expression: {e}"# --- Custom tool with grammar constraint ---
tools =[{"type":"custom","name":"math_solver","description":"Solve a math problem by outputting ONLY a valid arithmetic expression.","format":{"type":"grammar","syntax":"lark","definition":r"""
start: expr
?expr: term
| expr "+" term -> add
| expr "-" term -> sub
?term: factor
| term "*" factor -> mul
| term "/" factor -> div
?factor: NUMBER
| "(" expr ")"
%import common.NUMBER
%ignore " "
"""},}]# --- User asks ---
msgs =[{"role":"user","content":"What is (12 + 8) * 3 minus 5 divided by 5?"}]# 1) First model call: GPT-5 must emit a grammar-valid expression
resp = client.responses.create(
model="gpt-5",
tools=tools,input=msgs,
instructions="Always call the math_solver tool with a grammar-valid arithmetic expression like '(12 + 8) * 3 - 5 / 5'.")
msgs += resp.output
tool_call =next(
x for x in resp.output
ifgetattr(x,"type","")in("custom_tool_call","tool_call","function_call"))
expr =getattr(tool_call,"input","")orgetattr(tool_call,"arguments","")print("\n=== Grammar-Constrained Expression ===")print(expr)# 2) Run the local evaluator
tool_result = eval_expression(expr)print("\n=== Tool Execution Result ===")print(tool_result)# 3) Return tool output
msgs.append({"type":"function_call_output","call_id": tool_call.call_id,"output": tool_result
})# 4) Final pass: GPT-5 presents answer nicely
final = client.responses.create(
model="gpt-5",input=msgs,
tools=tools,
instructions="Present the evaluated result clearly in natural language.")print("\n=== Final Output ===")print(final.output_text)Mogelijk gemaakt door
Zoals je ziet, heeft het model de tool geselecteerd en vervolgens een grammatica-beperkte uitdrukking gegenereerd. Daarna gaat deze door de Python-functie om het antwoord te genereren. Uiteindelijk hebben we een net antwoord in natuurlijke taal.
=== Grammar-Constrained Expression ===(12 + 8) * 3 - 5 / 5=== Tool Execution Result ===(12 + 8) * 3 - 5 / 5=59.0=== Final Output ===59Mogelijk gemaakt door
Tool-allowlists: Beperk veilig wat het model kan gebruiken
Met de instelling allowed_tools kun je het model beperken tot een veilige selectie van tools uit je volledige toolset. Dit verhoogt de voorspelbaarheid en voorkomt ongewenste tool-calls, terwijl het model binnen de toegestane set flexibel blijft.
Je kunt het model laten kiezen uit toegestane tools of vereisen dat het er één gebruikt, vergelijkbaar met “force tool”-gedrag in andere stacks, en in lijn met best practices voor orkestratie van tool-calls.
We schrijven nu de code waarin we één tool toestaan, het model alleen die tool laten aanroepen, deze uitvoeren, de resultaten terugvoeren en vervolgens een beknopte samenvatting voor de gebruiker produceren.
Opmerking: Maak een gratis Firecrawl-account aan, genereer een API-sleutel, sla deze op als omgevingsvariabele FIRECRAWL_API_KEY en installeer de Firecrawl Python SDK met pip install firecrawl-py.
In deze voorbeeldcode hebben we:
Een volledige toolset gedefinieerd met zowel dummy_web_search als firecrawl_search.
Het model beperkt tot alleen firecrawl_search via tool_choice = { type: "allowed_tools", mode: "required", tools: [...] }.
De eerste model-call uitgevoerd, de tool-naam en argumenten vastgelegd en deze voor de zichtbaarheid geprint.
Wanneer firecrawl_search wordt aangeroepen, de argumenten gedeserialiseerd, Firecrawl uitgevoerd, de respons omgezet naar een JSON-serialiseerbare dict en de veilige datapayload geëxtraheerd.
De toolresultaten teruggevoerd naar het gesprek via function_call_output gekoppeld met call_id, en vervolgens een laatste model-call gedaan om samen te vatten in 3–4 bullets met Markdown-links.
Een fallback-tak opgenomen die de dummytool zou draaien (al voorkomt de allowlist dit in deze run).
Het uiteindelijke antwoord in natuurlijke taal geprint.
from openai import OpenAI
from firecrawl import Firecrawl
import json
import os
client = OpenAI()
firecrawl = Firecrawl(api_key=os.environ["FIRECRAWL_API_KEY"])# --- Full toolset ---
tools =[{"type":"function","name":"dummy_web_search","description":"A fake web search that always returns static dummy results.","parameters":{"type":"object","properties":{"query":{"type":"string"},"limit":{"type":"integer"}},"required":["query"]},},{"type":"function","name":"firecrawl_search","description":"Perform a real web search using Firecrawl.","parameters":{"type":"object","properties":{"query":{"type":"string"},"limit":{"type":"integer"}},"required":["query"]},},]# --- Dummy implementation ---defdummy_web_search(query, limit=3):return{"query": query,"results":[f"[Dummy] Result {i+1} for '{query}'"for i inrange(limit)]}# --- User asks ---
messages =[{"role":"user","content":"Find me the latest info about the stock market."}]# --- Restrict to Firecrawl only ---
resp = client.responses.create(
model="gpt-5",
tools=tools,input=messages,
instructions="Only the firecrawl_search tool is allowed. Do not use dummy_web_search.",
tool_choice={"type":"allowed_tools","mode":"required",# force Firecrawl"tools":[{"type":"function","name":"firecrawl_search"}],},)for item in resp.output:ifgetattr(item,"type","")in("function_call","tool_call"):print("\n--- Tool Call ---")print("Tool name:", item.name)print("Arguments:", item.arguments)if item.name =="firecrawl_search":
args = json.loads(item.arguments)# Firecrawl returns a SearchData object → convert it
results_obj = firecrawl.search(
query=args["query"],
limit=args.get("limit",3),)# 🔥 Convert to JSON-serializable dictifhasattr(results_obj,"to_dict"):
results = results_obj.to_dict()elifhasattr(results_obj,"dict"):
results = results_obj.dict()else:
results = json.loads(results_obj.json())ifhasattr(results_obj,"json")else results_obj
print("\n--- Firecrawl Raw Results ---")print(json.dumps(results, indent=2)[:500])# ✅ Extract only the data portion for summarization
safe_results = results.get("data", results)# Feed back to GPT
messages += resp.output
messages.append({"type":"function_call_output","call_id": item.call_id,"output": json.dumps(safe_results)# now safe})# Final pass
final = client.responses.create(
model="gpt-5",
tools=tools,input=messages,
instructions="Summarize the Firecrawl search results into 3-4 bullet points with clickable [Title](URL) links.")print("\n--- Final Natural Language Answer ---")print(final.output_text)elif item.name =="dummy_web_search":
args = json.loads(item.arguments)
results = dummy_web_search(args["query"], args.get("limit",3))print("\n--- Dummy Web Search Results ---")print(json.dumps(results, indent=2))Mogelijk gemaakt door
Het selecteerde de Firecrawl-zoekfunctie en gebruikte die om de eindrespons in markdownformaat te genereren.
Preambles: Vertel het model hoe tools aan te roepen
Preambles zijn korte toelichtingen die het model genereert vóór het aanroepen van een tool, om de reden voor de call te verduidelijken. Ze vergroten transparantie, bouwen vertrouwen bij gebruikers en verbeteren de debugbaarheid in complexe workflows. Je schakelt ze in met een eenvoudige instructie zoals “leg uit voordat je een tool aanroept”, meestal zonder merkbare vertraging toe te voegen.
We schrijven nu de code waarin het model eerst een korte regel “Preamble:” genereert die uitlegt waarom het een tool aanroept, vervolgens de tool aanroept, jij deze lokaal uitvoert, het resultaat terugstuurt en het model een duidelijk eindantwoord produceert.
In deze voorbeeldcode hebben we:
De OpenAI-client geïnitialiseerd en een strikt getypeerde functie-tool (medical_advice) met JSON Schema gedefinieerd.
Een systeem-instructie toegevoegd die het model vraagt om vóór elke tool-call een eenregelige “Preamble:” te outputten.
Het gesprek gestart met een symptoomvraag van de gebruiker.
De eerste model-call gedaan om zowel de preamble als de tool-call met argumenten te verkrijgen.
De tool geëxtraheerd en lokaal uitgevoerd om advies te genereren.
De tooloutput teruggestuurd naar het model, gekoppeld via call_id.
Een laatste model-call uitgevoerd zodat GPT‑5 het resultaat presenteert als een beknopt en gebruiksvriendelijk antwoord.
from openai import OpenAI
import json
import random
client = OpenAI()# --- Fake tool implementation ---defmedical_advice(symptom:str):
remedies ={"headache":"You can take acetaminophen (paracetamol) or ibuprofen, rest in a quiet room, and stay hydrated.","cough":"Drink warm fluids, use honey in tea, and consider over-the-counter cough syrup.","fever":"Use acetaminophen to reduce fever, stay hydrated, and rest. See a doctor if >39°C.",}return{"advice": remedies.get(symptom.lower(),"Please consult a healthcare provider for guidance.")}# --- Tool definition ---
tools =[{"type":"function","name":"medical_advice","description":"Provide safe, general over-the-counter advice for common symptoms.","parameters":{"type":"object","properties":{"symptom":{"type":"string"}},"required":["symptom"],"additionalProperties":False},"strict":True,}]# --- Messages (system preamble instruction) ---
messages =[{"role":"system","content":"Before you call a tool, explain why you are calling it in ONE short sentence prefixed with 'Preamble:'."},{"role":"user","content":"What should I take for a headache?"}]# 1) First call: expect preamble + tool call
resp = client.responses.create(model="gpt-5",input=messages, tools=tools)print("=== First Response ===")for item in resp.output:
t =getattr(item,"type",None)if t =="message":# Extract just the model's text
content =getattr(item,"content",None)
text =Noneifisinstance(content,list):
text ="".join([c.text for c in content ifhasattr(c,"text")])elif content:
text =str(content)if text:# ✅ Only print onceprint(text)if t in("function_call","tool_call","custom_tool_call"):print("Tool:",getattr(item,"name",None))print("Args:",getattr(item,"arguments",None))# Extract tool call
tool_call =next(x for x in resp.output ifgetattr(x,"type",None)in("function_call","tool_call","custom_tool_call"))
messages += resp.output
# 2) Execute tool locally
args = json.loads(getattr(tool_call,"arguments","{}"))
symptom = args.get("symptom","")
tool_result = medical_advice(symptom)# 3) Return tool result
messages.append({"type":"function_call_output","call_id": tool_call.call_id,"output": json.dumps(tool_result)})# 4) Final model call → natural answer
final = client.responses.create(model="gpt-5",input=messages, tools=tools)print("\n=== Final Answer ===")print(final.output_text)Mogelijk gemaakt door
Je ziet dat het vóór het aanroepen van de tool uitlegt waarom de tool wordt aangeroepen. Dit is goed voor observability en debugging.
Samenvatting
GPT-5 is OpenAI’s meest geavanceerde model tot nu toe, met name uitblinkend in coderen en agent-gebaseerde workflows. De nieuwste API-functies maken het mogelijk om van begin tot eind eenvoudig productierijpe systemen te ontwikkelen.
In deze tutorial heb je geleerd hoe je:
Gestructureerde outputs retourneert met Functie-tools en JSON Schema voor betrouwbare downstream-automatisering.
Vrije uitvoer mogelijk maakt met Aangepaste tools (ruwe tekst), zodat het model code, SQL, shellscripts en CSV-bestanden kan genereren, niet alleen JSON-calls.
Formaten beperkt met Lark-grammaticale constraints wanneer precisie cruciaal is, zoals bij wiskunde, SQL of domeinspecifieke talen (DSL’s).
Toegang tot tools beperkt met allowlists (of door één tool af te dwingen) om veiligheid, controle en determinisme te vergroten.
Transparantie verbetert met korte preambles, zodat het model uitlegt waarom het een specifieke tool aanroept, wat helpt bij observability en debugging.
Als gecertificeerd data scientist haal ik met passie het maximale uit de nieuwste technologie om innovatieve machinelearning-toepassingen te bouwen. Met een sterke achtergrond in spraakherkenning, data-analyse en -rapportage, MLOps, conversationele AI en NLP heb ik mijn vaardigheden aangescherpt in het ontwikkelen van intelligente systemen die echt impact maken. Naast mijn technische expertise ben ik ook een sterke communicator met een talent om complexe concepten terug te brengen tot heldere, beknopte taal. Daardoor ben ik uitgegroeid tot een veelgelezen blogger over data science, waar ik mijn inzichten en ervaringen deel met een groeiende community van data-professionals. Op dit moment richt ik me op contentcreatie en redactie, waarbij ik met large language models werk aan krachtige en aansprekende content die zowel bedrijven als individuen helpt het beste uit hun data te halen.
Begin je reis met het ontwikkelen van AI-gestuurde applicaties met de OpenAI API. Leer over de functionaliteit achter populaire AI-toepassingen zoals ChatGPT.
Begin met het maken van AI-systemen met modellen van OpenAI. Leer hoe je de OpenAI API kunt gebruiken om de GPT- en Whisper-modellen van OpenAI aan te sturen.
Met de lancering van GPT-5 heeft OpenAI het aanroepen van tools/functies in de API uitgebreid met vrije tool-calls (ruwe tekst, geen JSON), grammaticale beperkingen via Lark/CFG, tool-allowlists en verbeterde redeneerlogica voor toolgebruik. Samen maken deze GPT-5 een echt agentisch model; je kunt API’s, databases en aangepaste tools koppelen aan de Responses API en onderbouwde antwoorden genereren of zelfs workflows automatiseren.
In deze tutorial behandel ik functie-tools, aangepaste tools, grammaticale beperkingen, tool-allowlists en preambles, met codevoorbeelden en heldere uitleg over hoe ze werken en wanneer je ze gebruikt.
Function Calling in GPT-5: Wat & Waarom
Met Function Calling in GPT-5 kun je het model verrijken met de data en acties van je applicatie. Het model kan bepalen wanneer een tool aan te roepen, terwijl jij de logica afhandelt en resultaten teruggeeft voor een definitief, onderbouwd antwoord.
Types Function Calling:
Wat is function calling?
GPT-5 ondersteunt zowel gestructureerde functie-tools (met JSON Schema) als aangepaste tools die vrije tekstpayloads accepteren (zoals SQL, scripts of configuraties) voor naadloze integratie met externe runtimes.
Functie-tools worden gedefinieerd met JSON Schema, zodat het model precies begrijpt welke argumenten het moet doorgeven en je strikte invoervalidatie kunt afdwingen. Lees meer in onze OpenAI Function Calling-tutorial.
Waarom function calling gebruiken?
Hoe werkt function calling?
Bron: Function calling - OpenAI API
Wanneer Functie- vs. Aangepaste tools gebruiken
Functie-tools (JSON Schema): Verstuur gestructureerde data
Met Functie-tools en JSON Schema krijg je voorspelbare en gestructureerde resultaten van het model. Het model beoordeelt de door jou gedeclareerde tools, bepaalt wanneer het er een gebruikt, stelt JSON-gevalideerde argumenten voor en voert vervolgens de bijbehorende functie in je code uit.
Daarna kun je het model vragen om een antwoord te genereren dat uitsluitend is gebaseerd op de door de tool teruggestuurde data, zodat de output onderbouwd, machineleesbaar en eenvoudig te integreren is.
Dit voorbeeld illustreert enkele kernconcepten:
1. Installatie
pip install openai.2. Tools definiëren
Je geeft een lijst met tools op met een naam, beschrijving en JSON Schema voor parameters. Het schema helpt het model om goedgevormde argumenten aan te leveren.
make_coffeeverwacht één stringparameter:coffee_type.random_coffee_factneemt geen parameters (leeg object). Deze definities worden doorgegeven via hettools-argument in de API-call zodat het model weet wat beschikbaar is.3. Tools implementeren
Je implementeert de Python-functies die het werk daadwerkelijk doen:
make_coffee(coffee_type)geeft een beknopte receptstring terug op basis van de gevraagde drank.random_coffee_fact()geeft een kleine feitjes-payload terug.Beide retourneren JSON-serialiseerbare dicts, ideaal om terug te voeren aan het model.
4. Start een gesprek
Start het gesprek met de vraag van de gebruiker: {
"role": "user", "content": "How do I make a latte?"}Het model kan berichten retourneren die een
function_call-item bevatten, zoalsmake_coffeemet {"coffee_type":"latte"}. Je moet vervolgens de modelberichten weer toevoegen aaninput_list: input_list += response.output. Dit helpt om de gespreksstatus te behouden voor de volgende beurt.5. Voer tool-calls uit en voeg outputs toe
Je moet itereren over
response.outputen items identificeren waaritem.typegelijk is aan"function_call". Parse voor deze itemsitem.argumentsen stuur de verzoeken door naar je Python-functies.Voor de
make_coffee-functie roep je deze aan metmake_coffee(args["coffee_type"]). Voor derandom_coffee_fact-functie roep je gewoonrandom_coffee_fact()aan.Na het uitvoeren van de functies voeg je een
function_call_output-bericht toe dat het volgende bevat:call_id(die deze output koppelt aan het verzoek van het model)output(een JSON-string van je functie-resultaat).6. Genereer het eindantwoord
Je doet een tweede
client.responses.create-call en geeft de geüpdateteinput_listdoor die nu de tool-outputs bevat.De variabele
used_toolslegt de namen vast van tools die in de function calls van het model voorkwamen. We gebruiken deze om te tonen welke tools zijn gebruikt.Omdat de gebruiker naar een latte vroeg, selecteerde het model
make_coffeemetcoffee_type = "latte", jouw code voerde dit uit en het eindantwoord werd uitsluitend opgebouwd uit dat tool-resultaat.Aangepaste tools (vrij-formaat): Verstuur ruwe tekst
Gebruik de vrije, aangepaste tools van GPT-5 om het model ruwe tekst rechtstreeks naar je tool te laten sturen, zoals code, SQL, shell-commando’s of eenvoudige CSV, zonder JSON Schema te vereisen.
Deze mogelijkheid gaat verder dan de oudere, uitsluitend JSON-gebaseerde functieaanroepen en geeft je meer flexibiliteit voor integratie met executors, query-engines of DSL-interpreters.
In de vrij-formaatmodus genereert het model een aangepaste tool-call met een ongestructureerde tekstpayload die je naar je runtime kunt routeren. Je retourneert vervolgens het resultaat dat het model gebruikt om het antwoord aan de gebruiker af te ronden.
We schrijven nu de code die het model in staat stelt de juiste tools te selecteren en ongestructureerde ruwe tekst als output te geven. Deze output gaat vervolgens naar een Python-functie om een resultaat te genereren. Zo kan de gebruiker de ingrediënten opgeven die hij/zij heeft en genereert het model recepten op maat.
In deze voorbeeldcode hebben we:
meal_plannerdie ruwe tekstinput accepteert.plan_mealgemaakt die een kommagescheiden string met ingrediënten neemt en een maaltijdidee retourneert.plan_meal, en vervolgens het resultaat teruggestuurd naar het model als eenfunction_call_outputgekoppeld viacall_id.Als resultaat kregen we statistieken over de gebruikte tools, inclusief installatie, input en output. Bovendien geeft de eindoutput een compleet recept hoe je de maaltijd maakt.
Grammaticale beperkingen (Lark): Beperk tool-outputs
GPT-5 ondersteunt nu contextvrije grammatica (CFG) om te zorgen dat outputformaten strikt worden gecontroleerd.
Door een grammatica, zoals SQL of een domeinspecifieke taal (DSL), toe te passen op zijn antwoorden, garandeert GPT-5 dat de outputs consequent de vereiste structuur volgen. CFG is vooral belangrijk voor geautomatiseerde processen en kritieke workflows.
GPT-5 kan grammatica’s in formaten zoals Lark gebruiken om de outputs van de tool tijdens generatie te beperken. Deze benadering van constrained decoding verhoogt de betrouwbaarheid door format-drift te voorkomen en structurele consistentie te waarborgen.
We schrijven nu de code waarin het model een tool selecteert en ALLEEN een grammatica-geldige rekenkundige uitdrukking output; deze uitdrukking wordt vervolgens in Python geëvalueerd, het resultaat wordt teruggegeven aan het gesprek en het eindantwoord wordt duidelijk in natuurlijke taal gepresenteerd.
In deze voorbeeldcode hebben we:
math_solvergedefinieerd die ALLEEN een grammatica-geldige rekenkundige uitdrukking mag outputten (Lark CFG).math_solveraan te roepen met een uitdrukking die aan de grammatica voldoet.call_id.Zoals je ziet, heeft het model de tool geselecteerd en vervolgens een grammatica-beperkte uitdrukking gegenereerd. Daarna gaat deze door de Python-functie om het antwoord te genereren. Uiteindelijk hebben we een net antwoord in natuurlijke taal.
Tool-allowlists: Beperk veilig wat het model kan gebruiken
Met de instelling
allowed_toolskun je het model beperken tot een veilige selectie van tools uit je volledige toolset. Dit verhoogt de voorspelbaarheid en voorkomt ongewenste tool-calls, terwijl het model binnen de toegestane set flexibel blijft.Je kunt het model laten kiezen uit toegestane tools of vereisen dat het er één gebruikt, vergelijkbaar met “force tool”-gedrag in andere stacks, en in lijn met best practices voor orkestratie van tool-calls.
We schrijven nu de code waarin we één tool toestaan, het model alleen die tool laten aanroepen, deze uitvoeren, de resultaten terugvoeren en vervolgens een beknopte samenvatting voor de gebruiker produceren.
Opmerking: Maak een gratis Firecrawl-account aan, genereer een API-sleutel, sla deze op als omgevingsvariabele
FIRECRAWL_API_KEYen installeer de Firecrawl Python SDK metpip install firecrawl-py.In deze voorbeeldcode hebben we:
dummy_web_searchalsfirecrawl_search.firecrawl_searchviatool_choice = { type: "allowed_tools", mode: "required", tools: [...] }.firecrawl_searchwordt aangeroepen, de argumenten gedeserialiseerd, Firecrawl uitgevoerd, de respons omgezet naar een JSON-serialiseerbare dict en de veilige datapayload geëxtraheerd.function_call_outputgekoppeld metcall_id, en vervolgens een laatste model-call gedaan om samen te vatten in 3–4 bullets met Markdown-links.Het selecteerde de Firecrawl-zoekfunctie en gebruikte die om de eindrespons in markdownformaat te genereren.
Preambles: Vertel het model hoe tools aan te roepen
Preambles zijn korte toelichtingen die het model genereert vóór het aanroepen van een tool, om de reden voor de call te verduidelijken. Ze vergroten transparantie, bouwen vertrouwen bij gebruikers en verbeteren de debugbaarheid in complexe workflows. Je schakelt ze in met een eenvoudige instructie zoals “leg uit voordat je een tool aanroept”, meestal zonder merkbare vertraging toe te voegen.
We schrijven nu de code waarin het model eerst een korte regel “Preamble:” genereert die uitlegt waarom het een tool aanroept, vervolgens de tool aanroept, jij deze lokaal uitvoert, het resultaat terugstuurt en het model een duidelijk eindantwoord produceert.
In deze voorbeeldcode hebben we:
medical_advice) met JSON Schema gedefinieerd.“Preamble:”te outputten.call_id.Je ziet dat het vóór het aanroepen van de tool uitlegt waarom de tool wordt aangeroepen. Dit is goed voor observability en debugging.
Samenvatting
GPT-5 is OpenAI’s meest geavanceerde model tot nu toe, met name uitblinkend in coderen en agent-gebaseerde workflows. De nieuwste API-functies maken het mogelijk om van begin tot eind eenvoudig productierijpe systemen te ontwikkelen.
In deze tutorial heb je geleerd hoe je:
Wil je meer leren over wat je kunt doen met de verschillende tools van OpenAI? Dan raad ik onze OpenAI Fundamentals skill track en de cursus Working with the OpenAI API aan.