Skip to content

Tool Calling

Tool calling (ook bekend als function calling) geeft AI modellen de mogelijkheid om externe functies aan te roepen. Dit is nuttig voor:

  • Realtime data ophalen (weer, stocks, etc.)
  • Acties uitvoeren (emails versturen, database queries)
  • Berekeningen uitvoeren
  • Externe API's aanroepen

De tool calling flow

Tool calling is een multi-step conversatie:

  1. Request met tools - Stuur een request met tool definities
  2. Tool call ontvangen - Model retourneert welke tool het wil aanroepen
  3. Tool uitvoeren - Jouw code voert de tool uit
  4. Resultaat terugsturen - Stuur het resultaat als tool message
  5. Finale response - Model geeft antwoord met de tool output

Belangrijk

De server voert tools niet uit. Jouw applicatie is verantwoordelijk voor het uitvoeren van de tools en het terugsturen van de resultaten.

Tool definitie

Een tool wordt gedefinieerd met een JSON schema:

python
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Haal het huidige weer op voor een locatie",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "Stad en land, bijv. Amsterdam, Nederland"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "Temperatuur eenheid"
                    }
                },
                "required": ["location"]
            }
        }
    }
]

Tool definitie velden

VeldTypeBeschrijving
typestringAltijd "function"
function.namestringNaam van de functie
function.descriptionstringBeschrijving wanneer de tool te gebruiken
function.parametersobjectJSON Schema voor de parameters

Basis voorbeeld

python
from vondr import VondrClient
import json

client = VondrClient()

# Definieer de tool
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Haal het huidige weer op voor een locatie",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "Stad naam"}
            },
            "required": ["location"]
        }
    }
}]

# Stuur request met tools
response = client.chat(
    messages=[{"role": "user", "content": "Wat is het weer in Amsterdam?"}],
    tools=tools
)

choice = response.choices[0]

# Check of het model een tool wil aanroepen
if choice.message.tool_calls:
    tool_call = choice.message.tool_calls[0]
    print(f"Model wil {tool_call.function.name} aanroepen")
    print(f"Met argumenten: {tool_call.function.arguments}")

Complete tool calling flow

Het volgende voorbeeld toont de volledige flow: request, tool uitvoering, en finale response.

python
from vondr import VondrClient
import json

client = VondrClient()

def get_weather(location: str) -> dict:
    """Jouw implementatie van de weather functie"""
    # In productie zou je hier een echte API aanroepen
    return {"temperature": 18, "condition": "bewolkt", "location": location}

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Haal het huidige weer op",
        "parameters": {
            "type": "object",
            "properties": {"location": {"type": "string"}},
            "required": ["location"]
        }
    }
}]

messages = [{"role": "user", "content": "Wat is het weer in Amsterdam?"}]

# Stap 1: Eerste request
response = client.chat(messages=messages, tools=tools)
choice = response.choices[0]

if choice.message.tool_calls:
    tool_call = choice.message.tool_calls[0]

    # Stap 2: Voer de tool uit
    args = json.loads(tool_call.function.arguments)
    result = get_weather(**args)

    # Stap 3: Voeg assistant message en tool result toe aan history
    messages.extend([
        {
            "role": "assistant",
            "content": None,
            "tool_calls": [{
                "id": tool_call.id,
                "type": "function",
                "function": {
                    "name": tool_call.function.name,
                    "arguments": tool_call.function.arguments
                }
            }]
        },
        {
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(result)
        }
    ])

    # Stap 4: Krijg finale response
    final_response = client.chat(messages=messages, tools=tools)
    print(final_response.choices[0].message.content)
    # Output: "Het weer in Amsterdam is 18°C en bewolkt."

Tool choice

Met tool_choice bepaal je hoe het model met tools omgaat:

python
# Auto (standaard) - Model kiest zelf of het tools gebruikt
response = client.chat(
    messages=messages,
    tools=tools,
    tool_choice="auto"
)

# Required - Model moet een tool aanroepen
response = client.chat(
    messages=messages,
    tools=tools,
    tool_choice="required"
)

# Specifieke tool forceren
response = client.chat(
    messages=messages,
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "get_weather"}}
)

tool_choice opties

WaardeBeschrijving
"auto"Model kiest zelf of het een tool aanroept (standaard)
"none"Model mag geen tools aanroepen
"required"Model moet minimaal één tool aanroepen
{"type": "function", "function": {"name": "..."}}Forceer een specifieke tool

Meerdere tools

Je kunt meerdere tools beschikbaar stellen:

python
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Haal het huidige weer op voor een locatie",
            "parameters": {
                "type": "object",
                "properties": {"location": {"type": "string"}},
                "required": ["location"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "Voer een wiskundige berekening uit",
            "parameters": {
                "type": "object",
                "properties": {"expression": {"type": "string"}},
                "required": ["expression"]
            }
        }
    }
]

# Model kiest de juiste tool gebaseerd op de vraag
response = client.chat(
    messages=[{"role": "user", "content": "Wat is 25 * 4?"}],
    tools=tools
)
# Model zal de calculate tool kiezen

Response object

Bij een tool call bevat de response:

python
# Check of er tool calls zijn
if response.choices[0].message.tool_calls:
    for tool_call in response.choices[0].message.tool_calls:
        print(f"ID: {tool_call.id}")
        print(f"Type: {tool_call.type}")  # "function"
        print(f"Naam: {tool_call.function.name}")
        print(f"Argumenten: {tool_call.function.arguments}")  # JSON string

# finish_reason is "tool_calls" bij een tool aanroep
print(response.choices[0].finish_reason)  # "tool_calls"

Tool call velden

VeldTypeBeschrijving
idstringUnieke identifier voor deze call
typestringAltijd "function"
function.namestringNaam van de aangeroepen tool
function.argumentsstringJSON string met de argumenten

Tool dispatcher patroon

Voor meerdere tools kun je een dispatcher gebruiken:

python
from vondr import VondrClient
import json

client = VondrClient()

# Registreer je tool functies
tool_functions = {
    "get_weather": lambda location: {"temp": 18, "location": location},
    "calculate": lambda expression: {"result": eval(expression)},
    "search": lambda query: {"results": [f"Result for: {query}"]},
}

def execute_tool(name: str, arguments: dict):
    """Voer een tool uit op basis van naam."""
    if name not in tool_functions:
        return {"error": f"Onbekende tool: {name}"}
    return tool_functions[name](**arguments)

# Na het ontvangen van een tool call
if choice.message.tool_calls:
    for tool_call in choice.message.tool_calls:
        args = json.loads(tool_call.function.arguments)
        result = execute_tool(tool_call.function.name, args)

        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(result)
        })

Best practices

1. Duidelijke beschrijvingen

Geef tools en parameters heldere beschrijvingen zodat het model weet wanneer ze te gebruiken:

python
{
    "name": "search_products",
    "description": "Zoek producten in de catalogus op basis van naam, categorie of prijs. Gebruik dit wanneer de gebruiker vraagt naar producten of wil winkelen.",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "Zoekterm voor productnaam of beschrijving"
            },
            "category": {
                "type": "string",
                "enum": ["elektronica", "kleding", "boeken"],
                "description": "Productcategorie om in te zoeken"
            },
            "max_price": {
                "type": "number",
                "description": "Maximum prijs in euro's"
            }
        },
        "required": ["query"]
    }
}

2. Valideer argumenten

Check altijd de argumenten voordat je de tool uitvoert:

python
def get_weather(location: str) -> dict:
    if not location or len(location) < 2:
        return {"error": "Ongeldige locatie"}

    # Voer de tool uit...

3. Geef duidelijke foutmeldingen

Retourneer nuttige foutmeldingen als tool output:

python
try:
    result = execute_tool(name, args)
except ValueError as e:
    result = {"error": f"Ongeldige invoer: {e}"}
except Exception as e:
    result = {"error": f"Tool uitvoering mislukt: {e}"}

4. Minimale tools

Gebruik alleen tools die relevant zijn voor de huidige taak. Te veel tools kan het model verwarren.

5. Idempotent waar mogelijk

Maak tools die veilig opnieuw uitgevoerd kunnen worden bij retries.

Foutafhandeling

python
import json

if choice.message.tool_calls:
    tool_call = choice.message.tool_calls[0]

    try:
        args = json.loads(tool_call.function.arguments)
        result = execute_tool(tool_call.function.name, args)
        content = json.dumps(result)
    except json.JSONDecodeError:
        content = json.dumps({"error": "Ongeldige argumenten van model"})
    except KeyError as e:
        content = json.dumps({"error": f"Ontbrekend argument: {e}"})
    except Exception as e:
        content = json.dumps({"error": str(e)})

    # Stuur resultaat (of fout) terug
    messages.append({
        "role": "tool",
        "tool_call_id": tool_call.id,
        "content": content
    })

Asynchrone versie

python
from vondr import AsyncVondrClient
import json

client = AsyncVondrClient()

async def async_get_weather(location: str) -> dict:
    # Async API call
    return {"temperature": 18, "location": location}

response = await client.chat(
    messages=[{"role": "user", "content": "Wat is het weer in Amsterdam?"}],
    tools=tools
)

if response.choices[0].message.tool_calls:
    tool_call = response.choices[0].message.tool_calls[0]
    args = json.loads(tool_call.function.arguments)

    # Async tool uitvoering
    result = await async_get_weather(**args)

    messages.extend([
        {
            "role": "assistant",
            "content": None,
            "tool_calls": [{
                "id": tool_call.id,
                "type": "function",
                "function": {
                    "name": tool_call.function.name,
                    "arguments": tool_call.function.arguments
                }
            }]
        },
        {
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(result)
        }
    ])

    final_response = await client.chat(messages=messages, tools=tools)
    print(final_response.choices[0].message.content)