
Agent tool calling best practices: waarom je agent de verkeerde tool kiest
Agent tool calling best practices zijn het verschil tussen een werkende demo en een agent die in productie stilletjes de verkeerde tool aanroept. Het engineeringteam van Anthropic mat dat één herschreven beschrijving een toolresultaat van 206 tokens terugbracht naar 72, en Claude Code begrenst elk toolantwoord nu hard op 25.000 tokens omdat het tokenlek reëel is. Je agent faalt op vier manieren: verkeerde tool, verkeerde argumenten, op hol geslagen loops en tokenverlies. En voor elk daarvan bestaat een fix die je deze week nog kunt shippen.
Belangrijkste leerpunten:
- Agent tool calling faalt op precies vier manieren: verkeerde tool, verkeerde argumenten, op hol geslagen loops en tokenverlies.
- Toolbeschrijvingen zijn de enige instructie die het model ziet op het moment van selectie, dus die lossen de meeste verkeerde-tool-aanroepen op.
- Platte, taakgerichte schema's met gevalideerde inputs elimineren de meeste fouten met verkeerde argumenten.
- Beknopte toolantwoorden en een eval-loop bij elke wijziging houden tokenkosten en regressies meetbaar.
Waarom faalt agent tool calling in productie?
Agent tool calling faalt op vier manieren: het model kiest de verkeerde tool, schrijft verkeerde argumenten, draait rond in een op hol geslagen loop of lekt tokens door te vette antwoorden. Elke fout raakt een andere stap van de aanroep-loop, dus de volgorde van fixen maakt uit. Begin bij de selectie, want een verkeerde toolkeuze vergiftigt elke stap daarna.
| Foutmodus | Waar in de loop | Practice die het oplost | Inspanning |
|---|---|---|---|
| Verkeerde tool | Model kiest uit de toollijst | 1 (beschrijvingen) + 4 (namespacing, filteren) | Laag |
| Verkeerde argumenten | Model schrijft de tool_call-JSON | 2 (platte schema's) + 6 (validatie) | Laag-middel |
| Op hol geslagen loop | tool_result gaat terug naar het model | 3 (atomaire tools) + 7 (menselijke gates) | Middel |
| Tokenverlies | tool_result keert terug naar het contextvenster | 5 (beknopte resultaten) + 8 (eval-loop) | Laag-middel |
Het volledige recept in één overzicht:
| Practice | Fout die het oplost | Inspanning |
|---|---|---|
| 1. Schrijf beschrijvingen waar het model iets mee kan | Verkeerde tool | Laag |
| 2. Houd schema's plat en taakgericht | Verkeerde argumenten | Laag |
| 3. Bundel meerstaps reeksen tot atomaire tools | Op hol geslagen loops | Middel |
| 4. Namespace, snoei en filter tools dynamisch | Verkeerde tool | Middel |
| 5. Geef beknopte, signaalrijke resultaten terug | Tokenverlies | Laag |
| 6. Valideer elke aanroep en laat foutmeldingen lesgeven | Verkeerde argumenten | Middel |
| 7. Zet een mens voor destructieve acties | Op hol geslagen loops, veiligheid | Middel |
| 8. Draai een eval-loop bij elke toolwijziging | Alle vier, als regressies | Middel |
Werk ze in deze volgorde af. Practice 1 en 2 kosten een middag en halen de meeste verkeerde-tool- en verkeerde-argumentfouten weg die je nu ziet. Een toolbeschrijving is geen documentatie. Het is de enige instructie die het model krijgt op het moment van selectie.
Fase 1: ontwerp tools die het model echt kan gebruiken
De goedkoopste betrouwbaarheidswinst bij agent tool calling zit in je tooldefinities, niet in je prompts of je modelkeuze. Het model leest nooit je API-docs of je README. Het ziet een naam, een beschrijvingstekenreeks en een JSON-schema, en beslist alleen op basis daarvan. Krijg die drie goed en de selectienauwkeurigheid verbetert voordat je ook maar iets anders aanraakt.
Practice 1: schrijf beschrijvingen waar het model iets mee kan
Schrijf toolbeschrijvingen als instructies voor het model, niet als API-documentatie. Een beschrijving die een menselijke ontwikkelaar tevreden stelt ("REST-wrapper voor de users-endpoint") geeft het model niets om op te beslissen. Anthropic's engineering-gids over tools schrijven en hun best practices voor tooldefinities pushen hetzelfde patroon: zeg wanneer je de tool gebruikt, wat hij teruggeeft en wanneer je hem NIET gebruikt.
{
"name": "get_user",
"description": "Fetches a user profile. Use ONLY when you already have a user_id. Do NOT use to search or list users; call search_users instead. Returns name, email, plan. Errors if user_id is not a valid UUID."
}tegenover de versie die de meeste teams shippen:
{
"name": "get_user",
"description": "Gets a user."
}Twee regels doen hier het meeste werk. Ten eerste: geef parameters een naam waarvan de betekenis ondubbelzinnig is: user_id, nooit user of id, want user nodigt het model uit om een naam of e-mailadres te sturen waar een UUID hoort. Ten tweede: benoem uitsluitingen expliciet. "Do NOT use to search users" voorkomt meer verkeerde-tool-aanroepen dan welke hoeveelheid positieve beschrijving dan ook, omdat modellen overlappende tools veel vaker door elkaar halen dan dat ze één duidelijk afgebakende tool verkeerd begrijpen. Voor de mechanismen op providerniveau, hoe deze definities bij de API's van OpenAI, Anthropic en Google aankomen, zie onze multi-provider function calling-gids.
Practice 2: houd schema's plat en taakgericht
Houd inputschema's plat, met elk veld dat de taak echt nodig heeft en geen enkel veld dat hij niet nodig heeft. Geneste objecten met optionele vertakkingen zijn de broedplaats van fouten met verkeerde argumenten: het model moet een structuur raden waarvan het nooit voorbeelden ziet. De OpenAI function calling-gids accepteert willekeurige JSON-schema's, maar toegestaan is niet hetzelfde als betrouwbaar.
{
"name": "create_ticket",
"parameters": {
"type": "object",
"properties": {
"ticket": {
"type": "object",
"properties": {
"details": {
"type": "object",
"properties": {
"title": { "type": "string" },
"meta": { "type": "object" }
}
}
}
}
}
}
}Vlak het af tot de taak:
{
"name": "create_ticket",
"parameters": {
"type": "object",
"properties": {
"title": { "type": "string" },
"priority": { "type": "string", "enum": ["low", "medium", "high"] },
"assignee_id": { "type": "string" }
},
"required": ["title", "priority"]
}
}Enums winnen van vrije tekst voor elk veld met een begrensde verzameling waarden. Required-arrays winnen van alles wat optioneel is. Als het model een veld bijna altijd nodig heeft, maak het dan required in het toolschema, zelfs als je API het optioneel noemt. Je spiegelt niet je API. Je ontwerpt een oppervlak dat één specifiek model correct kan invullen.
Fase 2: beheer de toolset, niet alleen de tools
Losse toolkwaliteit schiet tekort zodra een agent meer dan een handvol tools draagt, want selectiefouten groeien met de lengte van de lijst die het model leest.
Practice 3: bundel meerstaps API-reeksen tot atomaire tools
Vouw elke vaste reeks API-aanroepen om tot één atomaire tool. Anthropic's engineering-post gebruikt schedule_event en get_customer_context als voorbeeld: één aanroep die het hele werk doet wint van drie aanroepen die de agent elke keer correct moet ketenen. Elke schakel in een keten is weer een beurt waarin het model kan vastlopen, verkeerd kan herproberen of in een loop kan terechtkomen.
# What the agent does WITHOUT an atomic tool: 3 calls, 3 chances to fail
calendar = call_tool("list_calendars", {})
free = call_tool("find_free_slot", {"calendar_id": calendar["items"][0]["id"], "duration": 30})
call_tool("create_event", {"calendar_id": calendar["items"][0]["id"], "start": free["start"]})
# One atomic tool: the sequence lives in your code, not the model's head
call_tool("schedule_event", {"duration": 30, "attendees": ["[email protected]"]})De vuistregel: als het model B altijd na A moet aanroepen, zijn A en B één tool in twee vermommingen.
Practice 4: namespace, snoei en filter tools dynamisch
Geef elke toolnaam een namespace en laat elke agent alleen de subset zien die zijn huidige taak nodig heeft. Generieke namen botsen zodra je twee integraties koppelt. Stel je een agent voor die aan twee MCP-servers hangt die allebei een tool search aanbieden: twee identieke werkwoorden, niet uit elkaar te houden. Anthropic documenteert meetbare eval-winst door prefix-namespacing:
| Voor | Na (prefix) | Na (suffix) |
|---|---|---|
search | asana_projects_search | search_asana_projects |
create | asana_tasks_create | create_asana_tasks |
search (tweede server) | github_repos_search | search_github_repos |
Snoeien is net zo belangrijk als naamgeving. Een supportagent heeft zijn billing-tools niet geladen nodig terwijl hij een wachtwoordvraag beantwoordt. Het planner-worker-patroon, waarin een planner een taak routeert naar een worker die alleen de relevante tools laadt, is de standaardoplossing; LangGraph's how-to over dynamisch tools laden loopt de implementatie door. Hoeveel tools is te veel? Hanteer 5-10 per agent als werkgebied, niet als wet: de nauwkeurigheid zakt als de lijst groeit, en het middel is filteren, niet een groter model. Als je de routing- en filterlaag zelf kiest, vergelijk dan je opties in ons overzicht van de beste function calling-bibliotheken.
Fase 3: beheers wat terugkomt en wat naar buiten gaat
De loop loopt in twee richtingen en de meeste teams engineeren alleen de uitgaande helft. Wat je tools teruggeven bepaalt hoeveel van het contextvenster de volgende beurt haalt, en wat je validatie afwijst bepaalt of het model van zijn fouten leert of ze herhaalt.
Practice 5: geef beknopte, signaalrijke resultaten terug
Geef het kleinste resultaat terug waar het model iets mee kan, met mensleesbare identificatoren in plaats van kale ID's. Anthropic's engineering-post beschrijft een tool waarvan het standaardresultaat 206 tokens telde; een beknopte response_format-instelling bracht hetzelfde resultaat terug naar 72 tokens, grofweg een derde van de omvang. Vermenigvuldig dat met tientallen aanroepen per taak en het bepaalt of je agent überhaupt klaar komt.
// Before: 206 tokens (shape per Anthropic's documented example)
{
"status": "success",
"data": {
"id": "8f14e45f-ceea-3f9c-a2f3-90c1b5e0a7d2",
"object": "task", "created_at": "2026-07-02T09:14:00Z",
"updated_at": "2026-07-11T16:40:12Z", "completed_at": null,
"assignee": {"id": "c9a1...f2", "object": "user"},
"projects": [{"id": "b7d3...91", "object": "project"}],
"permalink": "https://app.asana.com/0/.../f"
}
}
// After: 72 tokens
{ "task": "Fix login redirect", "assignee": "Dana Kim", "project": "Web App", "due": "2026-07-20" }Nog twee details uit dezelfde bron: Anthropic ondersteunt een response_format-enum (detailed versus concise) op tooldefinities, zodat je de gewenste vorm kunt declareren in plaats van de vuurslang te parsen. En Claude Code begrenst toolantwoorden op 25.000 tokens, een hard plafond dat opgeblazen resultaten hoe dan ook afkapt. Anthropic rapporteert ook, als hun bevinding, dat het omzetten van UUID's naar semantische namen retrieval-hallucinaties meetbaar verminderde. Daarom zegt de "after"-payload hierboven "Dana Kim" en niet c9a1...f2. Vette antwoorden zijn ook een kostenprobleem; zie onze gids om LLM API-kosten te verlagen voor het volledige plaatje.
Practice 6: valideer elke aanroep en laat foutmeldingen het model lesgeven
Valideer elke toolaanroep server-side en geef foutmeldingen terug die de oplossing bevatten. Martin Fowler's stuk over function calling formuleert het bot: vertrouw nooit op de output van het model. Het stuurt strings waar enums horen en verzint ID's die niet bestaan.
def create_ticket(args):
if args.get("priority") not in {"low", "medium", "high"}:
return {"error": f"priority must be one of: low, medium, high. Got '{args.get('priority')}'. Pass priority='medium' for normal issues."}
if not is_valid_uuid(args.get("assignee_id")):
return {"error": "assignee_id must be a UUID. Call list_team_members to get valid IDs, then retry."}
return db.create_ticket(**args)De foutmelding is het hele spel. Vergelijk:
# Unhelpful: the model retries the same bad call
{"error": "invalid input"}
# Helpful: the model knows exactly what to change
{"error": "priority must be one of: low, medium, high. Got 'urgent'. Use 'high'."}Elke validatiefout die je tool teruggeeft is een prompt die je schrijft voor de volgende poging van het model. Foutmeldingen die de beperking benoemen en naar de corrigerende tool wijzen, maken van een retry-loop een één-schot-herstel. Dit is ook je eerste verdedigingslinie op beveiligingsgebied; onze LLM guardrails-gids behandelt het diepgaand.
Fase 4: hoe maak je het veilig en daarna meetbaar?
Veiligheid en meting zijn dezelfde fase, want een destructieve actie zonder gate en een ongemeten regressie duiken allebei op als incidenten die je niet zag aankomen. Zet een gate voor acties die niet ongedaan gemaakt kunnen worden en instrumenteer daarna alles, zodat de volgende toolwijziging een beslissing is met bewijs erachter, geen hoop.
Practice 7: zet een mens voor destructieve acties
Scheid lees-tools van schrijf-tools en zet een menselijke bevestigingsgate op alles wat destructief is. De tool-annotaties van de MCP-specificatie bestaan precies hiervoor: destructiveHint markeert tools die destructieve updates uitvoeren en openWorldHint vlagt tools die externe systemen raken, zodat clients om bevestiging kunnen vragen vóór uitvoering. Gebruik ze.
De foutmodus is niet hypothetisch. Laurent Kubaski documenteerde een geval in zijn tool-calling-artikel van juli 2025, met het oorspronkelijke rapport gelinkt, waarin een gebruiker Copilot in Excel vroeg om iets te doen met rij 4 en de agent in plaats daarvan rij 8 bewerkte. Er stond geen bevestigingsgate tussen de verkeerde rij en de schrijfactie. De fix is het patroon dat AWS documenteert voor Bedrock Agents: de agent bereidt de actie voor, geeft hem terug ter goedkeuring en voert pas uit nadat een mens bevestigt. Cursor doet hetzelfde voor bestandswijzigingen. Beperk credentials tot read-only waar lezen alles is wat de taak nodig heeft, en behandel bevestigingsgates als onderdeel van je injection-oppervlak, het onderwerp van onze gids over prompt injection-preventie.
Practice 8: draai een eval-loop bij elke toolwijziging
Draai een kleine evaluatiesuite vóór en na elke toolwijziging en lees de metrieken in een vaste volgorde. De optimalisatiegids van Paragon stelt een raamwerk van vier metrieken voor dat het overnemen waard is:
| Metriek (per Paragon) | Wat het vangt | Hoe te meten |
|---|---|---|
| Toolcorrectheid | Verkeerde-tool-aanroepen | Riep de agent de juiste tool aan voor de taak? |
| Inputnauwkeurigheid | Verkeerde argumenten | Waren de argumenten geldig en compleet? |
| Taakvoltooiing | End-to-end-falen | Werd het doel van de gebruiker bereikt? |
| Taakefficiëntie | Tokenverlies, loops | Aantal aanroepen en tokens? |
Anthropic's tool evaluation cookbook, gebouwd op echte Slack- en Asana-MCP-evals, laat zien hoe goede en slechte eval-taken eruitzien:
# Weak: vague, many valid paths, impossible to score
"Use the Asana tools to organize some work."
# Strong: one correct tool, checkable arguments, binary outcome
"Create a task titled 'Renew TLS cert' in project 'Infra' assigned to [email protected], due 2026-08-15. Expect exactly one create_task call with those four fields."Onze interpretatie, expliciet als zodanig gelabeld: de gepubliceerde cijfers geven je de volgorde om in te werken. Controleer eerst toolcorrectheid, want Anthropic's eigen metingen laten zien dat beschrijvings- en naamgevingswijzigingen die direct verplaatsen (de 206-naar-72-token-herschrijving, de UUID-naar-naam-hallucinatiebevinding) en bewaar taakefficiëntie voor het laatst, omdat die vooral fouten weerspiegelt die de eerste drie metrieken al vingen. Ontwerp voor de starterssuite 15-30 taken, twee of drie per tool, elk met één verwachte aanroep en een binaire slaagvoorwaarde. Die omvang is genoeg om een regressie van een beschrijvingsherschrijving te vangen zonder een week labelwerk, en we lezen de Slack- en Asana-opzet van het cookbook als bewijs dat een suite van deze omvang het bedoelde startpunt is, geen shortcut. De diepere mechanica staan in onze gids over AI-agents evalueren in productie, en als je eval-resultaten zeggen dat de tools zelf prima zijn maar de orkestratie niet, dan is dat het moment om je frameworkkeuze opnieuw af te zetten tegen de beste AI-agent-frameworks.
Agent tool calling vs MCP: wat is het verschil?
MCP is een transport- en registrystandaard, geen betrouwbaarheidslaag, dus dezelfde acht practices gelden of je tools nu via MCP binnenkomen of inline gedefinieerd zijn. Native tool calling is het contract tussen model en provider: hoe het model een tool_call uitzendt en een tool_result leest. MCP standaardiseert hoe tools het model bereiken; het doet niets aan de vraag of het model de juiste kiest.
| Native tool calling regelt | MCP voegt toe | Geen van beide regelt |
|---|---|---|
| Berichtformaat van tool_call / tool_result | Een gedeeld protocol zodat elke client elke server bereikt | Kwaliteit van beschrijvingen |
| Provider-specifieke schema's | Tool-discovery en registry | Schemaontwerp, validatie |
| Onderhandeling over parallelle aanroepen | Annotaties zoals destructiveHint | Menselijke gates, evals, antwoordhygiëne |
Een MCP-server die een tool search aanbiedt met de beschrijving "searches things" faalt identiek aan een inline functie die hetzelfde gedefinieerd is. Fix eerst de definitie, maak je daarna pas druk over het transport. Onze Model Context Protocol-gids dekt de protocolkant van begin tot eind.
Hoe Techsy deze acht practices toepast
Bij elke agent-build voor een klant dwingen we drie hiervan af voordat er ook maar iets anders scheep gaat: beschrijvingen geschreven als instructies (Practice 1), validatiegates op elke schrijf-tool (Practice 6) en een eval-suite die vóór de deploy draait, niet na een incident (Practice 8). Die drie dekken verkeerde-tool-aanroepen, verkeerde-argument-aanroepen en de regressies die beide opnieuw introduceren, en daar begon elk productie-agentincident dat we gedebugd hebben. De andere vijf practices volgen als de agent groeit. Is je agent voorbij het demostadium en kiest hij de verkeerde tools, vraag dan een gratis consult aan en we vertellen je welke van de acht je als eerste moet fixen.
Over de auteur
Mert Batur is medeoprichter van Techsy.io, waar het team AI-agents, automatiseringssystemen en voice/SDR-pipelines scheept voor B2B-klanten. Hij schrijft over de LLM-toolingstack die het Techsy-team daadwerkelijk in productie gebruikt. Verbind op LinkedIn.
Veelgestelde vragen
Wat is agent tool calling?
Agent tool calling is het mechanisme waarbij een LLM beslist om een externe functie aan te roepen, een gestructureerde tool_call uitzendt en wacht tot jouw code een tool_result teruggeeft waarover hij kan redeneren. Het is wat een chatmodel verandert in een agent die databases kan bevragen, API's kan aanroepen en acties kan ondernemen: het model kiest de tool en de argumenten, jouw executor voert ze uit.
Hoe werkt de agent tool calling-loop?
De loop heeft vijf stappen: het gebruikersverzoek bereikt het model, het model selecteert een tool en schrijft een tool_call, jouw executor voert hem uit, een tool_result gaat terug naar het model en het model antwoordt of doet een nieuwe aanroep. Die cyclus herhaalt zich tot de taak klaar is. De vier foutmodi in deze gids zitten elk op een specifieke stap van deze loop.
Waarom kiest mijn agent de verkeerde tool?
Meestal omdat twee tools overlappen en hun beschrijvingen niet zeggen welke welke is. Het model selecteert alleen op naam en beschrijving, dus "gets a user" tegenover "finds users" leest als inwisselbaar. Los het op met uitsluitingsregels ("do NOT use to search"), namen met een namespace en minder tools in de context. Kubaski's vier-modellen-test liet zien dat zelfs sterke modellen verkeerd routeren bij dubbelzinnige lijsten.
Hoe dwing ik een tool calling-agent om zijn output te structureren?
Beperk het schema, niet de prompt. Gebruik enums voor begrensde velden, required-arrays voor alles wat de taak nodig heeft en platte objecten in plaats van geneste. Voor het eindantwoord, in plaats van de toolaanroep, dwingen providerfuncties zoals OpenAI's structured outputs en Anthropic's tool-choice-modi een specifieke vorm af. Onze gids over gestructureerde uitvoer behandelt beide paden met code.
Agent tool calling vs MCP: wat is het verschil?
Native tool calling is het contract tussen jouw code en één modelprovider: het berichtformaat van tool_call en tool_result. MCP is een protocollaag die standaardiseert hoe tools ontdekt en afgeleverd worden bij elke compatibele client. MCP verandert de leidingen, niet de betrouwbaarheid. Een slecht beschreven tool faalt op dezelfde manier via beide paden, zoals onze Model Context Protocol-gids uitlegt.
Hoeveel tools is te veel voor een LLM-agent?
Hanteer 5-10 tools per agent als werkgebied, niet als wet. De selectienauwkeurigheid zakt als de zichtbare lijst groeit, zeker wanneer namen of beschrijvingen overlappen. De fix is niet een groter model maar filteren: laad alleen de subset die de huidige taak nodig heeft, met een planner-worker-splitsing. Geef alles een namespace zodat twee integraties nooit allebei een kale search aanbieden.
Wat is het beste model voor tool calling?
Er is geen enkelvoudig antwoord en gepubliceerde benchmarks verouderen snel in dit veld. Frontier-modellen van OpenAI, Anthropic en Google halen allemaal elementaire tool-use-taken, terwijl kleinere modellen met goed ontworpen tools taken vaak bijna net zo vaak voltooien tegen een fractie van de tokenkosten. Bouw de eval-suite van 15-30 taken uit Practice 8 en test kandidaten tegen je eigen tools.
Hoe verlaag ik de tokenkosten van tool calling?
Beperk wat terugkomt. Geef beknopte, signaalrijke resultaten terug in plaats van rauwe API-payloads: Anthropic documenteerde een tokenreductie van 206 naar 72 door één response_format-wijziging. Zet UUID's om naar namen, laat velden weg die het model nooit gebruikt en onthoud dat elk toolresultaat bij elke volgende beurt opnieuw het contextvenster ingaat. Minder aanroepen, via atomaire tools, schrapt hele resultaten van de rekening.
Hoe evalueer ik de kwaliteit van tool calling?
Score vier metrieken op volgorde: toolcorrectheid (juiste tool?), inputnauwkeurigheid (geldige argumenten?), taakvoltooiing (doel bereikt?) en taakefficiëntie (aantal tokens en aanroepen?). Schrijf 15-30 taken, elk met één verwachte specifieke aanroep met controleerbare argumenten en een binaire slaagvoorwaarde. Draai de suite vóór en na elke toolwijziging, zodat een beschrijvingsherschrijving nooit ongemeten scheep gaat.
Conclusie
Diagnoseer voordat je optimaliseert. Je agent kiest de verkeerde tool om een van vier redenen, en drie van de acht practices hierboven, beschrijvingen, platte schema's en filteren, lossen de selectiefouten op die de meeste productie-incidenten veroorzaken. Begin daar, want ze kosten een middag en zij zijn de reden dat dit probleem überhaupt oplosbaar is. Houd validatiefoutmeldingen informatief, zet een mens voor alles wat destructief is en draai de eval-loop bij elke wijziging, zodat je meet voordat je van model wisselt. Het verkeerde-tool-probleem is geen modelprobleem. Het is een tool-ontwerpprobleem en het ontwerp is van jou.