All guides
AI Agents9 min read
By Leeor MeirovitzLast updated:

Tool Use: How AI Agents Act on the Real World Safely

An engineer reviewing an AI agent's tool call log on a screen in a working office

TL;DR

  • Tool use (also called function calling) is how an AI agent does something instead of just describing it - the model picks a tool, fills in typed arguments, and your code runs the action.
  • The single most useful safety line is read versus write: read tools are cheap to get wrong, write tools change the world, so the guards live almost entirely on the write side.
  • Ship safety as layers - clear tool design, argument validation, allowlists, scoped credentials, dry-run and human approval for anything irreversible, plus full logging of every call.

What is tool use (function calling) in an AI agent?

A language model on its own can only produce text. It can tell you it would send the email, refund the order, or restart the server, but it can't actually do any of it. Tool use is the bridge. You hand the model a list of tools it's allowed to call, each with a name, a description, and a typed schema for its arguments. When the model decides a tool fits the task, it doesn't run anything itself - it emits a structured request that says 'call send_email with these arguments.' Your code receives that request, runs the real function, and passes the result back into the conversation.

That round trip is the whole mechanic, and it's worth being precise about who does what. The model chooses and fills in. Your code executes. The two are deliberately separated, because the model is a prediction engine and your code is where you put the locks. Anyone who's shipped an agent learns this fast - the moment the model is one step removed from the actual action, you have somewhere to stand and say no.

Function calling and tool use are the same idea under two names. The format differs slightly between model providers, but the shape is constant: a declared interface, a model-generated call, a runtime that validates and runs it. Everything else in this article is about making that runtime trustworthy.

  • The model proposes a tool call; it never executes the tool directly.
  • Each tool is declared with a name, a plain-language description, and a typed argument schema.
  • Your runtime validates the proposed call, runs it, and feeds the result back to the model.
  • Function calling and tool use are interchangeable terms for this pattern.
  • Because execution sits in your code, that's exactly where every guard belongs.

How does the model decide which tool to call and with what arguments?

The model picks a tool the same way it picks the next word - by pattern, from the context you gave it. The tool's name and description are the strongest signals. A tool called 'get_customer_orders' with a description that says 'returns the last 90 days of orders for a customer ID' tells the model exactly when to reach for it. A tool called 'process' with no description is a coin flip. The model is reading your tool list like documentation, so write it like documentation.

Arguments come from the schema plus whatever's in the conversation. If your schema declares a required 'order_id' as a string and an optional 'reason' as an enum, the model will try to fill those from what the user said and what earlier tool calls returned. This is also where it goes wrong: the model can hallucinate an argument that looks plausible, mislabel a type, or invent an ID that was never mentioned. The schema constrains the shape but not the truth, which is why validation in your code is non-negotiable later on.

One first-hand note. The biggest single improvement we've seen on agent reliability isn't a smarter model - it's better tool descriptions. Rename a vague tool, add one sentence about when not to use it, and the wrong-tool rate drops noticeably. The model is doing its best with the labels you wrote. Better labels, better decisions.

  • Tool names and descriptions are the primary signal for tool selection.
  • Arguments are inferred from the schema plus the conversation and prior results.
  • Models can hallucinate plausible-but-wrong arguments, so the schema is a shape guarantee, not a truth guarantee.
  • A 'when not to use this' line in the description cuts down wrong-tool calls.
  • Clearer descriptions beat a bigger model for selection accuracy in our experience.

What makes a good tool for an agent to use?

A good tool is narrow, named for what it does, and honest about what it returns. Narrow scope is the part teams underrate. A single 'manage_account' tool that can read, update, suspend, and delete is a tool the model will eventually misuse, because the difference between those actions is buried in an argument rather than in the tool itself. Split it. Four small tools - 'get_account', 'update_account_email', 'suspend_account', 'delete_account' - give the model clearer choices and give you per-action control over which ones need approval.

Typed schemas do real work here. Use enums instead of free text when the set of valid values is known. Mark required fields as required. Set sensible bounds - a 'limit' that maxes out at 100, a 'date' that has to parse. Every constraint you put in the schema is a constraint the model tries to respect before your code even runs, which means fewer bad calls to catch. Think of the schema as the first line of defence, not just paperwork.

Error messages are the part people forget, and they matter more for agents than for humans. When a tool fails, the message goes straight back to the model, which then decides what to do next. 'Error 400' tells it nothing. 'order_id 99 not found - confirm the ID from get_customer_orders before retrying' tells it how to recover. Write errors as instructions to the next attempt, because that's literally how they get used.

  • Keep each tool narrow - one clear action per tool, not a multi-purpose switch.
  • Use typed schemas with enums, required flags, and bounds to constrain calls up front.
  • Name tools for the action so intent is visible without reading arguments.
  • Write error messages as recovery instructions the model can act on.
  • Splitting broad tools lets you apply different guards to read versus destructive actions.

Why does the read-vs-write distinction matter so much?

This is the line that organises everything else. Read tools fetch information - look up an order, search a knowledge base, check a calendar. If the model calls a read tool with the wrong arguments, the worst case is usually a useless result and a wasted call. Write tools change state - send the message, move the money, update the record, delete the row. A wrong write tool call has consequences that don't undo themselves. Same mechanism, completely different blast radius.

Once you sort your tools into these two buckets, your safety budget almost sorts itself. Read tools can run freely, maybe with rate limits and scoped access so a curious agent can't page through your entire database. Write tools get the real machinery: validation, allowlists, confirmation steps, approval gates, idempotency. You stop spreading caution evenly and concentrate it where a mistake actually costs something.

A practical decision framework we use: for every tool, ask 'if the model called this with the worst plausible arguments, what breaks, and can I undo it in under a minute?' Read tools almost always pass. Write tools that fail that test - the irreversible ones - are the tools that need a human in the loop. That one question routes most of your design decisions without a meeting.

  • Read tools fetch state; a wrong call usually just wastes a turn.
  • Write tools change state; a wrong call can be expensive or irreversible.
  • Let read tools run freely under rate limits and scoped access.
  • Concentrate validation, approval, and idempotency on the write side.
  • Decision test: worst plausible arguments - what breaks, and can you undo it fast?

What safety patterns keep agent tool use under control?

The patterns that hold up in production are old infrastructure ideas applied to a new caller. Start with allowlists. The agent should only be able to call tools you explicitly registered, and where a tool takes an open-ended target - a URL, a table name, a recipient domain - that target should be checked against a list of approved values rather than trusted as typed. An allowlist of what's permitted beats a blocklist of what's forbidden every time, because you can't enumerate everything that could go wrong.

Then scope the credentials. The agent's database token should be read-only if the agent only reads. Its email key should send from one address, not the whole domain. Least privilege means that even when the model does something unexpected, the credentials physically can't reach beyond their grant. Pair that with rate limits so a confused loop can't fire a thousand calls in a minute, and with idempotency keys so that if a write gets retried after a timeout you get one refund, not three.

Dry-run and confirm are the two patterns that save you most often. A dry-run mode lets a write tool report exactly what it would do without doing it - 'this would refund 240 dollars to order 99' - which you can show to a person or check programmatically before committing. For anything destructive or irreversible, that preview becomes a hard stop until a human approves. None of these are exotic. They're the same discipline you'd apply to any system that can act on its own, pointed at a caller that improvises.

  • Allowlist both the tools and the open-ended targets they accept.
  • Scope credentials to least privilege - read-only tokens, single-sender keys.
  • Rate-limit tool calls so a loop can't cause runaway damage.
  • Use idempotency keys so retried writes don't double-execute.
  • Add a dry-run preview for write tools and gate irreversible actions behind approval.

How do you validate arguments before a tool actually runs?

Schema validation and business validation are two different jobs, and you need both. The schema catches shape problems - missing required field, wrong type, value outside the declared enum. Most runtimes reject these automatically, and you should let them, returning a clear error so the model can correct itself. But a call can be perfectly well-formed and still wrong. An 'order_id' that's a valid string but doesn't exist. A refund amount that parses fine but exceeds the order total. A recipient that matches the email format but isn't a customer.

That second layer is yours to write, and it runs in your code after the schema passes and before the action commits. Confirm the IDs exist. Check the amounts against real limits. Verify the actor is allowed to do this to this record. Treat every argument as if it came from an unpredictable source, because it did. The model isn't malicious, but it's improvising from text, and 'looks plausible' is not the same as 'is correct.'

When validation fails, fail loud and useful. Send back the specific reason and, where you can, the path to fixing it. Because the error returns to the model, a good message often lets the agent self-correct on the next turn without a human touching it. A bad message sends it into a retry loop guessing at what went wrong. The validation layer is where you turn the model's optimism into something you can actually trust.

  • Let schema validation reject shape errors automatically and return a clear reason.
  • Add business validation in your code: existence, limits, permissions, consistency.
  • Run all checks after the schema passes but before the action commits.
  • Treat every argument as untrusted input, even from a well-behaved model.
  • Make failure messages specific so the agent can self-correct on the next turn.

When should a human approve an agent's action?

The rule we keep coming back to is reversibility. If an action can be cleanly undone in a moment, the agent can usually take it on its own - reading data, drafting a reply, updating a low-stakes field. If an action can't be undone, or undoing it is expensive or embarrassing, a human should sign off before it happens. Sending money, deleting records, emailing customers in bulk, changing production config - these are the ones you gate, every time.

Approval works best as a pause, not a roadblock. The agent does all the reasoning, assembles the exact call, runs the dry-run, and presents a clean summary: here's what I want to do, here's the data, approve or reject. The human reviews a finished proposal instead of doing the work, which keeps most of the speed of automation while putting a person on the trigger of the actions that matter. Done well, this is the difference between an agent you can deploy and a demo you can't.

Tune the threshold to the cost of being wrong, and let it move. Early on, gate more than you think you need to - watch what the agent proposes, build trust, then loosen the gates on the actions that have proven safe. We've never regretted starting cautious. We have regretted the opposite. You can always remove a gate; you can't un-send the email it would have caught.

  • Gate any action that's irreversible, costly, or hard to walk back.
  • Let the agent fully prepare the call so the human approves a finished proposal.
  • Keep low-stakes, reversible actions automatic to preserve speed.
  • Set the approval threshold by the cost of a wrong action, not by tool count.
  • Start with more gates and loosen them as specific actions earn trust.

How do you stay observable over every tool call?

You can't trust what you can't see. Every tool call an agent makes should be logged with the tool name, the full arguments, the result or error, a timestamp, and the trace that ties it to a session and user. When something goes sideways - and on a long enough timeline it will - this log is the difference between 'we know exactly what it did and why' and a shrug. Treat tool-call logging as a feature of the system, not an afterthought you bolt on after the first incident.

Good observability also feeds the design loop. Patterns show up in the logs that you'd never guess from testing: a tool the model keeps calling with the same wrong argument, an error message that triggers a retry storm, a write that fires more often than the business expects. Each of those is a fix - rename the tool, rewrite the error, tighten the schema. The agents that get more reliable over time are the ones whose owners actually read the logs.

Set alerts on the signals that matter rather than watching everything. Spikes in error rates, write-tool calls above a normal baseline, repeated failed approvals, any call that trips an allowlist. You don't need to monitor every read. You do need to know immediately when a write tool starts behaving in a way it shouldn't, because that's where a quiet problem turns into a loud one.

  • Log every call with tool name, arguments, result or error, timestamp, and trace ID.
  • Tie logs to a session and user so any action can be reconstructed.
  • Mine the logs for wrong-argument patterns and retry storms, then fix the tool.
  • Alert on error spikes, allowlist trips, and abnormal write volume - not every read.
  • Treat logging as core system design, not a post-incident add-on.

Start here

If you're building your first agent that acts on real systems, don't try to land every pattern at once. Begin by listing your tools and sorting each into read or write. That one sort tells you where almost all your effort goes. Give read tools scoped, least-privilege access and let them run. Then take your write tools one at a time and add the guards in order: a typed schema, argument validation in your code, an allowlist for any open-ended target, and a dry-run preview.

For the write tools that are irreversible - money, deletion, anything customer-facing at scale - put a human approval step in front of them before you ship, and wire up logging on day one so you can see every call from the first run. Start with the gates tighter than feels necessary. It's far easier to loosen a gate once an action has earned trust than to recover from one that never had a gate at all.

This is the work we do with teams moving agents from demo to production - turning a model that can propose actions into a system you can actually let loose on real infrastructure. If you're at that step and want a second set of eyes on where the guards should sit, that's a conversation worth having before the first write tool goes live.

  • Sort every tool into read or write before anything else.
  • Give read tools scoped access and let them run freely.
  • Add guards to write tools in order: schema, validation, allowlist, dry-run.
  • Put human approval in front of irreversible actions before launch.
  • Turn on tool-call logging from the very first run, not after an incident.

Want this built for your business?

We map the highest-leverage place to start and ship a first live system within two weeks.

Book a strategy call

Common questions

What is the difference between tool use and function calling?

There isn't a real difference - they're two names for the same pattern. The model is given a set of declared functions or tools, it generates a structured request to call one with specific arguments, and your code validates and runs it. Different providers use slightly different formats and names, but the mechanic is identical: the model proposes, your code executes.

Can an AI agent run a tool by itself without my code?

No. The model only ever produces a structured request that says which tool it wants and what arguments to pass. Nothing happens until your runtime receives that request and chooses to execute it. That separation is the whole reason tool use can be made safe - your code is the layer that validates, gates, and logs every action the model proposes.

How do I stop an agent from calling a tool with wrong or invented arguments?

Use two layers. A typed schema with enums, required fields, and bounds catches shape errors automatically. Then add business validation in your code that confirms IDs exist, amounts stay within limits, and the actor is permitted. Treat every argument as untrusted input, and return specific error messages so the model can self-correct on its next turn.

Which agent actions should require human approval?

Gate anything irreversible or expensive to undo - sending money, deleting records, bulk customer emails, production config changes. The test is reversibility: if a wrong action can be cleanly undone in under a minute, the agent can usually handle it alone. If not, a human should approve a finished proposal before it runs. Start with more gates and loosen them as actions prove safe.

What is a dry-run in the context of agent tool use?

A dry-run mode lets a write tool report exactly what it would do without committing the action - for example, 'this would refund 240 dollars to order 99.' You can show that preview to a person for approval or check it programmatically before executing. It's one of the most effective safety patterns because it surfaces the real effect of a call while it's still reversible.

There isn't a real difference - they're two names for the same pattern. The model is given a set of declared functions or tools, it generates a structured request to call one with specific arguments, and your code validates and runs it. Different providers use slightly different formats and names, but the mechanic is identical: the model proposes, your code executes.

Ask AI about X18 Global

“What does X18 Global (x18global.com) do for enterprise AI and automation - and can you summarise their guide "Tool Use: How AI Agents Act on the Real World Safely"?”