wat is function calling open ai python voorbeeld

Function calling maakt het mogelijk om taalmodellen gecontroleerd samen te laten werken met externe functies en systemen.

In plaats van alleen tekst te genereren, kan het model bepalen wanneer een functie nodig is en welke parameters daarbij horen.

In dit blog laten we stap voor stap zien hoe function calling werkt met de OpenAI API, van een eenvoudig voorbeeld tot een volledig uitgewerkte implementatie.

Structuur

  1. Wat is function calling?
  2. Waarom is function calling nuttig?
  3. Wanneer gebruik je function calling?
  4. Tutorial function calling
  5. Volledig voorbeeld function calling

1. Wat is function calling?

Function calling is een mechanisme waarbij een taalmodel kan aangeven dat een specifieke functie (tool) aangeroepen moet worden om een vraag te beantwoorden. Het model voert deze functie niet zelf uit, maar levert gestructureerde output waarin staat welke functie gebruikt moet worden en met welke parameters.

De daadwerkelijke uitvoering van de functie gebeurt in je eigen code. Dit zorgt ervoor dat je AI-toepassing controleerbaar, veilig en goed te integreren blijft binnen bestaande systemen.

2. Waarom is function calling nuttig?

Zonder function calling is een taalmodel beperkt tot de tekst die je meegeeft. Zodra informatie nodig is uit een database, API of intern systeem, loop je vast. Function calling lost dit op door het model te laten bepalen welke actie nodig is, terwijl jij bepaalt hoe en waar die actie wordt uitgevoerd.

Dit maakt AI geschikt voor productieomgevingen waarin betrouwbaarheid, voorspelbaarheid en integratie met andere systemen cruciaal zijn.

3. Wanneer gebruik je function calling?

Function calling gebruik je wanneer een antwoord afhankelijk is van externe data of acties. Denk aan het ophalen van orderinformatie, het uitvoeren van controles, het aanpassen van gegevens of het bouwen van AI-agents die meerdere stappen doorlopen.

Zodra AI meer moet doen dan alleen tekst genereren, is function calling vaak de juiste keuze.

4. Tutorial function calling

In deze tutorial laten we stap voor stap zien hoe function calling werkt aan de hand van een voorbeeld waarin een orderstatus wordt opgehaald uit een lokaal (gesimuleerd) systeem.

Setup: OpenAI client

Als je mee wilt doen dien je een eigen OpenAI API key te hebben.

import os
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv("api_key.env")

OPENAI_API_KEY = os.getenv("OPEN_AI_API_KEY")

print(f"Length API key: {len(OPENAI_API_KEY)}")
print(f"Last characters: ...{OPENAI_API_KEY[-30:]}")

client = OpenAI(api_key=OPENAI_API_KEY, base_url="https://api.openai.com/v1/")

print(client)
Length API key: 164
Last characters: ...xtvqYjTUfLU8_RN4xfoZMy0nQDfCkA
<openai.OpenAI object at 0x71529e4b97f0>

Bij tool/function calling werk je altijd in 2 stappen, met 2 API calls:

  1. Een eerste call, waarbij het model bepaalt of/welke tool gebruikt moet worden.
  2. Een tweede call, waarbij het model antwoord geeft op de vraag, gebruik makend van context vanuit de functie/tool.

4.1. Aanmaken te gebruiken tool met functie

We maken een dummy functie aan, die een status teruggeeft voor een ordernummer.

In het echt zou deze functie bijvoorbeeld een API call uit kunnen voeren op een ERP systeem, om daaruit de orderstatus te verkrijgen.

In onderstaande code doen we het volgende:

  • Aanmaken dummy functie get_order_status().
  • Testen van de functie.
def get_order_status(order_id: str) -> str:
    fake_db = {
        "ORD123": "Shipped",
        "ORD456": "Processing",
        "ORD789": "Cancelled",
    }
    return fake_db.get(order_id, "Order not found")

print(get_order_status(order_id="ORD123"))
print(get_order_status(order_id="ORD789"))
print(get_order_status(order_id="ORD999"))
Shipped
Cancelled
Order not found

Je ziet dat de functie op basis van een ordernummer een status teruggeeft.

4.2. Opstellen van tool-schema

Om de OpenAI API te informeren over deze functie (tool), moet een model/schema opgesteld worden.

De eisen hiervan staan in de documentatie.

In onderstaande code doen we het volgende:

  • Aanmaken van een list met tools.
  • Hierin verwerken van de functie get_order_status()
  • We geven onder andere mee:
    • Een omschrijving van de functie.
    • Een omschrinving van de parameters.
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_order_status",
            "description": "Retrieve the status of an order by order ID",
            "parameters": {
                "type": "object",
                "properties": {
                    "order_id": {"type": "string", "description": "The ID of the order"},
                },
                "required": ["order_id"],
            },
        },
    }
]

4.3. Eerste API call: Model tool laten kiezen

Nu we een tool (functie), en schema hebben, kunnen we bij een prompt bepalen of het model de functie wil gebruiken.

In onderstaande code doen we het volgende:

  • Aanmaken prompt, met een vraag over een order.
  • Aanmaken met een lijst met messages, deze vullen we later aan.
  • Genereren van een antwoord met client.chat.completions.create():
    • Met tools=tools verwijzen we naar het schema.
    • Met tool_choice="auto" laten we het model zelf kiezen of de functie gebruikt moet worden.
  • Toevoegen van de output-message aan de lijst messages, dit gebruiken we later.
  • Bekijken het resultaat.
prompt = "Can you tell me the status of order ORD456?"
messages = [{"role": "user", "content": prompt}]

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    temperature=0,
    tools=tools,
    tool_choice="auto",
)

message = response.choices[0].message
messages.append(message)

print(message)
print(message.tool_calls)
ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_D4M5w7SOhxUcSHsMsvYa4qlK', function=Function(arguments='{"order_id":"ORD456"}', name='get_order_status'), type='function')])
[ChatCompletionMessageFunctionToolCall(id='call_D4M5w7SOhxUcSHsMsvYa4qlK', function=Function(arguments='{"order_id":"ORD456"}', name='get_order_status'), type='function')]

In dit resultaat kun je zien dat het antwoord aangeeft dat de tool (functie get_order_status()) gebruikt moet worden.

  • Ook zie je dat het ordernummer daarbij al bepaald is: "ORD456".

  • Dit antwoord is een voorbeeld van structured output.

We hebben nu echter nog geen antwoord op de prompt.

We weten alleen dat het model de functie wil gebruiken.

4.4. Toepassen van functie en samenstellen van messages

Het model heeft bepaald dat de tool (functie get_order_status()) gebruikt moet worden.

In onderstaande code doen we het volgende:

  • Halen de tool call op, de details van het antwoord van het model om de tool te gebruiken.
  • Deze output is een JSON sting, dit zetten we om naar een dictionary met json.loads().
  • We bekijken het resultaat.
import json

tool_call = message.tool_calls[0]
arguments = json.loads(tool_call.function.arguments)
print(arguments)
{'order_id': 'ORD456'}

We zien nu de parameters die het model heeft bepaald, om te gebruiken in de functie.

In onderstaande code doen we het volgende:

  • Ophalen van het "order_id".
  • Aanroepen van de functie voor deze order, en bewaren en bekijken van het resultaat.
order_id = arguments.get("order_id")
result = get_order_status(order_id)

print(f"Order {order_id}: {result}")
Order ORD456: Processing

In onderstaande code doen we het volgende:

  • Voegen een message toe aan de lijst met messages.
    • Dit gebruiken we hierna om met een nieuwe API call een uiteindelijk antwoord op de prompt/vraag te krijgen.
  • We benoemen een nieuwe rol: "role": "tool".
  • We verwijzen naar het ID van de tool call.
  • We geven content mee in JSON formaat: het order id en de status.
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": json.dumps({"order_id": order_id, "status": result}),
})

messages
[{'role': 'user', 'content': 'Can you tell me the status of order ORD456?'},
 ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_D4M5w7SOhxUcSHsMsvYa4qlK', function=Function(arguments='{"order_id":"ORD456"}', name='get_order_status'), type='function')]),
 {'role': 'tool',
  'tool_call_id': 'call_D4M5w7SOhxUcSHsMsvYa4qlK',
  'content': '{"order_id": "ORD456", "status": "Processing"}'}]

4.5. Tweede API call: Beantwoorden van vraag

We hebben nu alle details om de prompt/vraag over de order te beantwoorden. Dit verzameld in variabele messages.

Dit gebruiken we om met een nieuwe API call een antwoord te krijgen.

In onderstaande code doen we het volgende:

  • Genereren van een antwoord met client.chat.completions.create().
  • Daarbij gebruiken we variabele messages, dit bevat:
    • De originele prompt: de vraag over de order.
    • Het antwoord uit de vorige API call: dat de tool (functie get_order_status()) gebruikt moet worden.
    • De details van de order, verkregen door gebruikt te maken van de functie.
  • Bekijken het antwoord.
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    temperature=0.2,
)
print(response.choices[0].message.content)
The status of order ORD456 is currently "Processing."

Je zie dat er nu netjes in menselijke taal antwoord is gegeven op de vraag.

Waarbij de functie is gebruikt om de status van de order op te halen.

5. Volledig voorbeeld

We hebben stap voor stap het toepassen van function calling laten zien.

In onderstaande code doen we het volgende:

  • Volledige uitwerking van de eerdere code.
  • Daarbij gebruik makend van een if-else-statement, om te bepalen of er een tool-call was.
  • En gebruik makend van een for-loop, om eventueel meerdere tool-calls te kunnen behandelen.
import json

# Define tool function
def get_order_status(order_id: str) -> str:
    fake_db = {
        "ORD123": "Shipped",
        "ORD456": "Processing",
        "ORD789": "Cancelled",
    }
    return fake_db.get(order_id, "Order not found")

# Define tool schema
tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Retrieve the status of an order by order ID",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {"type": "string", "description": "The ID of the order"}
            },
            "required": ["order_id"],
        },
    },
}]

# Define prompt
user_message = "Can you tell me the status of order ORD456?"
messages = [{"role": "user", "content": user_message}]

# First API call: let model decide if tool must be used
check_response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
    tool_choice="auto",
)

check_message = check_response.choices[0].message
messages.append(check_message)

# If tool call in message: apply function, get arguments and create tool-message
if check_message.tool_calls:
    for tool_call in check_message.tool_calls:
        if tool_call.function.name == "get_order_status":
            # Get arguments
            arguments = json.loads(tool_call.function.arguments)
            order_id = arguments["order_id"]
            status = get_order_status(order_id)

            # Create tool-message
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps({"order_id": order_id, "status": status}),
            })

    # Second API call: generate final answer
    final_response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        temperature=.2,
    )
    print(final_response.choices[0].message.content)
else:
    # In case no tool call was required
    print(check_message.content)
The status of order ORD456 is currently "Processing."

We zien ook nu weer een goed resultaat.

Dit voorbeeld gebruikt slechts 1 tool/function: voor het ophalen van de status van een order.

Je zou het uit kunnen breiden met meerdere functies, bijvoorbeeld voor:

  • Ophalen van andere orderdetails.
  • Doorvoeren van aanpassingen in een order.
  • Etc.

Bij de eerste API call bepaalt het model dan op basis van het prompt welke functies gebruikt moeten worden. Dit kunnen er dan ook meerdere zijn.

Wil je AI expert worden?

Tijdens onze 5-daagse AI Opleiding of 7-daagse AI Engineer Opleiding leer je het hele AI spectrum kennen; van klassieke machine learning modellen tot generative AI met o.a. ChatGPT. Je leert programmeren in Python zodat je op uiteenlopende vlakken aan de slag kunt met AI. Of ben je op zoek naar een introductie in AI? Bekijk dan onze AI cursus basis eens. We bieden ook AI consultancy aan op allerlei thema’s.

by: