Wil je AI inzetten op klantdossiers, interne documenten of gevoelige aanvragen zonder dat die bij een externe aanbieder terechtkomen, dan kan een agent op je eigen machine dat doen. Wat Ollama is en hoe je het installeert staat in wat Ollama is en hoe lokale modellen werken. Dit stuk gaat over de volgende stap: een agent bouwen die zelf functies aanroept, helemaal offline.
Update 4 november 2026 Gecontroleerd tegen de huidige Ollama-documentatie (Ollama v0.40.14 van 3 november, de Python-bibliotheek 0.6.3 van 29 september). Het origineel koos
llama3.1en de OpenAI-bibliotheek. Nu gebruikt het voorbeeldqwen3.5:4ben de eigenollama-bibliotheek. De tekst waarschuwt ook voor de standaard contextlengte en voor de cloudmodellen, die je privacybelofte kunnen breken.
Hoe werkt tool calling met Ollama?
Een taalmodel voert zelf niets uit. Bij tool calling beschrijf je in je verzoek welke functies bestaan. Het model antwoordt dan met een gestructureerde aanroep in plaats van tekst: de functienaam en de argumenten. Jouw code voert die functie uit. Het resultaat gaat terug naar het model als bericht met rol tool en het veld tool_name, waarna het model verder redeneert of een eindantwoord geeft (Bron: Ollama docs).
Dat herhaal je in een lus tot het model geen aanroepen meer teruggeeft. Die lus is de agent. Het model kan ook meerdere aanroepen tegelijk teruggeven, dus loop altijd over alle tool_calls en stuur per aanroep één antwoord terug.
Welk model en welke bibliotheek heb je nodig?
Je hebt drie dingen: Ollama, Python en een model dat tools ondersteunt. De Python-bibliotheek installeer je met pip install ollama. De huidige versie is 0.6.3 van 29 september 2026, onder MIT-licentie en voor Python 3.8 of nieuwer (Bron: PyPI).
Kies het model op de eigenschap tools. Qwen 3.5 heeft die, naast vision en thinking. De 4B-variant is zo’n 3,3 tot 4 GB groot met een contextvenster van 256K (Bron: Ollama modelpagina). Dat past op een gewone laptop. Heb je een zware videokaart of veel werkgeheugen, dan is qwen3.8:27b sterker, maar met 18 GB ook een stuk zwaarder (Bron: Ollama modelpagina). Meer over dat model lees je in Qwen 3.8 27B: gratis AI-model dat op je eigen computer draait. Het oude llama3.1 ondersteunt tools nog steeds, maar is een jaar oud.
ollama pull qwen3.5:4b
python3 -m venv venv
source venv/bin/activate
pip install ollama
Hoe bouw je de agent?
Als voorbeeld nemen we een agent die binnenkomende aanvragen triëert. Hij zoekt de klant op aan de hand van het klantnummer, zet de aanvraag in een categorie en schrijft dat weg in een lokaal bestand. Twee gewone Python-functies zijn de tools. De bibliotheek leidt het schema af uit de typehints en de docstring, dus die docstring is wat het model leest om te kiezen.
import json
from ollama import chat
MODEL = "qwen3.5:4b"
KLANTEN = {
"10482": {"naam": "Bakkerij De Gouden Korst", "contract": "Zakelijk Plus"},
"20931": {"naam": "Van Dijk Installatie", "contract": "Basis"},
}
CATEGORIEEN = {"storing", "factuur", "contract", "overig"}
def zoek_klant(klantnummer: str) -> str:
"""Zoek een klant op via het klantnummer en geef naam en contract terug."""
klant = KLANTEN.get(str(klantnummer).strip())
return json.dumps(klant, ensure_ascii=False) if klant else "Onbekend klantnummer"
def zet_in_categorie(categorie: str, samenvatting: str) -> str:
"""Zet de aanvraag in een categorie (storing, factuur, contract of overig) met een samenvatting van één zin."""
if categorie not in CATEGORIEEN:
return f"Ongeldige categorie. Kies uit: {', '.join(sorted(CATEGORIEEN))}"
regel = {"categorie": categorie, "samenvatting": samenvatting}
with open("triage.jsonl", "a", encoding="utf-8") as bestand:
bestand.write(json.dumps(regel, ensure_ascii=False) + "\n")
return "Opgeslagen"
Let op de str(...) in de eerste functie en de controle op toegestane waarden in de tweede. Het officiële voorbeeld van de bibliotheek werkt met een conversie omdat teruggegeven argumenten niet altijd precies bij het schema passen. Een klein model stuurt een klantnummer soms als getal. Een foutmelding als tekst terugsturen helpt het model bovendien om zichzelf te corrigeren.
Dan de lus zelf:
TOOLS = {functie.__name__: functie for functie in (zoek_klant, zet_in_categorie)}
SYSTEEMPROMPT = (
"Je triëert binnenkomende aanvragen. Staat er een klantnummer in de tekst, "
"zoek dan eerst die klant op. Zet de aanvraag daarna in precies één categorie. "
"Meld tot slot in één zin wat je gedaan hebt."
)
def draai_agent(aanvraag: str, max_stappen: int = 6) -> str:
berichten = [
{"role": "system", "content": SYSTEEMPROMPT},
{"role": "user", "content": aanvraag},
]
for _ in range(max_stappen):
antwoord = chat(
model=MODEL,
messages=berichten,
tools=list(TOOLS.values()),
options={"temperature": 0},
)
berichten.append(antwoord.message)
if not antwoord.message.tool_calls:
return antwoord.message.content
for call in antwoord.message.tool_calls:
functie = TOOLS.get(call.function.name)
if functie is None:
uitkomst = f"Onbekende tool: {call.function.name}"
else:
try:
uitkomst = functie(**call.function.arguments)
except Exception as fout:
uitkomst = f"Fout: {fout}"
berichten.append(
{"role": "tool", "tool_name": call.function.name, "content": str(uitkomst)}
)
return "Gestopt: maximaal aantal stappen bereikt."
if __name__ == "__main__":
print(draai_agent("Klantnummer 10482: de pinautomaat in onze winkel valt sinds vanochtend steeds uit."))
Drie dingen in deze lus zijn bewust gekozen. Het assistent-bericht met de aanroepen komt vóór de toolresultaten in berichten, zoals de documentatie voorschrijft. Een onbekende toolnaam of een uitzondering stopt de agent niet maar gaat als tekst terug naar het model. En max_stappen voorkomt dat een model dat in cirkels draait je machine bezig houdt.
Na een run staat er een regel in triage.jsonl met de gekozen categorie en samenvatting. Welke woorden het model kiest, verschilt per run en per model. Meet daarom niet op gevoel: hoe je zo’n agent met vaste testcases controleert, staat in AI-agents evalueren met een LLM-judge, dat ook op Ollama en Qwen 3.5 draait.
Waarom staat mijn contextlengte te laag voor een agent?
Ollama kiest de contextlengte op basis van je videogeheugen: onder 24 GiB start het met 4.096 tokens, tussen 24 en 48 GiB met 32.000, vanaf 48 GiB met 256.000. Voor agents raadt de documentatie minstens 64.000 tokens aan (Bron: Ollama docs). Bij elke ronde in de lus groeit het gesprek met toolresultaten, dus een klein venster loopt snel vol en het model vergeet dan je instructie.
Zet de lengte bij het starten van de server:
OLLAMA_CONTEXT_LENGTH=64000 ollama serve
Een groter venster kost geheugen. Controleer met ollama ps in de kolom PROCESSOR of het model niet deels naar de processor uitwijkt, want dat maakt de agent traag.
Hoe houd je de agent echt offline en privé?
Dat het model lokaal draait, is niet genoeg. Vier punten bepalen of je belofte klopt.
Draai alleen lokale modellen. Ollama zegt dat het je prompts en data niet ziet als je lokaal draait. Bij de optionele cloudmodellen worden prompts en antwoorden wel verwerkt op afstand, volgens Ollama zonder opslag of training (Bron: Ollama docs). Wil je die route uitsluiten, zet dan OLLAMA_NO_CLOUD=1 of "disable_ollama_cloud": true in ~/.ollama/server.json en herstart Ollama. Je verliest daarmee de cloudmodellen en de webzoekfunctie.
Laat Ollama aan je eigen computer vastzitten. Standaard luistert hij op 127.0.0.1:11434. Zet je hem via OLLAMA_HOST open voor je netwerk, dan kan iedereen daar je model gebruiken. Hoe je dat afschermt, lees je in de gids Lokale AI-server afschermen: zo voorkom je LLMjacking.
Beperk wat de tools mogen. Een agent die tekst van buiten leest en daarna iets kan wegschrijven, is gevoelig voor prompt-injectie: een aanvraag kan instructies bevatten. In het voorbeeld kan de agent alleen een regel toevoegen aan één bestand en een klant opzoeken. Geef je een tool de macht om te mailen, te verwijderen of een shell te starten, vraag dan eerst menselijke goedkeuring.
Test het echt. Trek de netwerkkabel eruit of zet wifi uit en draai de agent opnieuw. Werkt hij nog, dan gaat er niets naar buiten.
Kan ik bestaande OpenAI-code hergebruiken?
Ja, voor een agent die je al tegen een cloud-API schreef. Ollama biedt een OpenAI-compatibele API op http://localhost:11434/v1/. Je zet de basis-URL om en vult een willekeurige sleutel in, want die wordt genegeerd (Bron: Ollama docs).
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1/", api_key="ollama")
Chat completions ondersteunt tools, maar tool_choice niet: je kunt het model dus niet dwingen een bepaalde tool te kiezen. Voor opties zoals de contextlengte is de eigen ollama-bibliotheek handiger. De documentatievoorbeelden gebruiken die ook.
Waar liggen de grenzen van een lokale agent?
Kleine modellen maken meer fouten bij het kiezen van tools en het invullen van argumenten dan de grote cloudmodellen. Voor afgebakende taken zoals aanvragen triëren, documenten samenvatten of gegevens ordenen is een model van 4 tot 9 miljard parameters vaak genoeg. Moet de agent lang plannen of veel tools combineren, dan loop je eerder tegen de grens aan. Ga dan een maat omhoog voordat je naar de cloud kijkt.
De winst is privacy en geen kosten per aanroep, de prijs is hardware en het zelf beheren van de omgeving. Wil je meer over lokale modellen, hardware en keuzes op een rij, begin dan bij de hardwaregids lokale LLM’s draaien.
