Tool use and function calling in production
Designing the tools an agent can call — schemas, errors, idempotency and permissions — is most of the work.
An agent is only as good as the tools you hand it. Most agent failures we are asked to diagnose are not reasoning failures at all — they are tool design failures.
Narrow beats flexible
Shape
- Flexible tool
- query(table, filter, fields)
- Narrow tools
- find_customer_by_email, list_open_invoices
Model behaviour
- Flexible tool
- Unpredictable call construction
- Narrow tools
- Constrained, repeatable
Authorisation
- Flexible tool
- Hard to scope safely
- Narrow tools
- Enforced per tool, per user
Debugging
- Flexible tool
- Every call is different
- Narrow tools
- A small set of known shapes
| Flexible tool | Narrow tools | |
|---|---|---|
| Shape | query(table, filter, fields) | find_customer_by_email, list_open_invoices |
| Model behaviour | Unpredictable call construction | Constrained, repeatable |
| Authorisation | Hard to scope safely | Enforced per tool, per user |
| Debugging | Every call is different | A small set of known shapes |
Narrow tools beat flexible ones
A single tool that queries any table with any filter looks powerful and produces unpredictable calls. Several specific tools — find_customer_by_email, list_open_invoices — constrain the space and are far more reliable. Design for the model's benefit, not the developer's convenience.
The description is the interface
The model chooses tools from their descriptions. Say what it does, when to use it, when not to, what it returns and what it costs. Ambiguity between two similarly described tools is the most common source of wrong calls.
Errors are instructions
A tool returning 'Error: invalid input' teaches the model nothing. 'Error: date must be YYYY-MM-DD, received 12/05/2026' lets it correct itself on the next turn. Write error messages as if the reader is the one who will retry — because it is.
Assume it will be called twice
Retries, replans and plain confusion mean any tool can be invoked more than once with the same arguments. Anything with side effects needs an idempotency key. This is not a nice-to-have; it is the difference between a retry and a duplicate charge.
Tool design that agents can actually use
Do
- Narrow, specific tools over one flexible query tool
- Descriptions that say when NOT to use it
- Errors that explain how to retry correctly
- Idempotency keys on anything with side effects
Don't
- Rely on the prompt for authorisation
- Two tools with near-identical descriptions
- "Error: invalid input" with no detail
- Assume a tool is called exactly once
Permissions belong in the tool, not the prompt
Never rely on instructions to keep an agent inside its lane. Enforce authorisation in the tool implementation, scoped to the acting user, exactly as you would for a public API — because from a security standpoint that is what it is.
- Scope every call to the authenticated user's permissions
- Rate-limit per agent run, not just per account
- Require explicit approval for irreversible or high-value actions
- Log every invocation with arguments, result and the run that caused it