AI Agent Tool Design: Schemas, Descriptions and Safe Retries
A tool is the interface between an agent and your systems. This guide covers one job per tool, descriptions and schemas, useful errors, idempotent retries, and how to test tool selection.
Tool design for AI agents is interface design. The agent can only use your systems as well as your tools let it.
Most “agent failures” I see trace back to a vague tool description, an unclear error, or a retry that ran an action twice. The model gets blamed. The tool was the problem.
Here is how I design tools so agents pick them correctly, recover from errors, and never pay an invoice twice.
Tool Design for AI Agents Starts With the Interface
A tool is a function the agent can call: look up a customer, search a log, create a ticket, issue a refund. The model sees a name, a description, and a schema. That is the whole interface. It cannot read your code or ask a coworker what a field means.
Anthropic’s engineering team makes this point in its post on writing tools for agents, and an earlier piece on building effective agents puts it well: invest as much effort in the agent-computer interface as you would in a human-computer interface.
The same piece gives a good test. Put yourself in the model’s shoes. Is it obvious how to use this tool from the description and parameters alone? If you would need to think carefully, the model will guess.
The payoff is real. Anthropic reports that precise refinements to tool descriptions helped Claude Sonnet 3.5 reach top results on the SWE-bench Verified benchmark. Descriptions are not decoration. They are a main lever.
New to how agents call tools? Start with the AI agent architecture guide. If your tools sit behind a server, see what MCP is and how to build an MCP server. The rules below apply either way.
One Job per Tool
Give each tool one clear job. Then make that job match a real step in the workflow, not a row in your database.
Two failure modes pull in opposite directions. Too fine: ten tiny tools the agent must chain in order, where each hop can go wrong. Too broad: one tool with a mode parameter that does five things, so the description turns into a manual.
Anthropic recommends a few thoughtful tools aimed at high-impact workflows. Their examples are useful:
- Instead of
list_users,list_events, andcreate_event, build oneschedule_eventtool that finds availability and books the slot. - Instead of
read_logs, buildsearch_logs, which returns only relevant lines with some context. - Instead of
get_customer_by_id,list_transactions, andlist_notes, buildget_customer_context.
That is consolidation, and it works for reads. For writes, I add one rule of my own: split tools by risk, not just by function.
| Tool class | Example | Rule |
|---|---|---|
| Read | search_invoices | Safe to call freely and retry |
| Reversible write | add_ticket_note | Allowed, logged |
| Irreversible write | send_payment, delete_record | Separate tool, narrow scope, approval or hard limits |
Do not hide a destructive action behind a flag on a read tool. Keep it separate so you can gate it, log it, and remove it alone. This also makes least-privilege permissions easy to apply: you can grant the read tool and withhold the write tool.
OpenAI’s function calling guide adds two habits worth copying. Do not make the model fill in arguments your code already knows: if you hold the order_id, submit_refund() should not ask for it. And if two functions are always called in sequence, merge them.
Descriptions and Examples
How do you write a good tool description? Write it the way you would brief a new hire. Anthropic suggests exactly that: make implicit context explicit, including query formats, niche terms, and how resources relate.
A good description answers five questions:
- What does this tool do?
- When should the agent use it?
- When should it not, and which tool should it use instead?
- What does each parameter mean, and in what format?
- What does it return?
Anthropic’s agent guide says a good tool definition often includes example usage, edge cases, input format requirements, and clear boundaries from other tools. Here is a compact example:
{
"name": "lookup_invoice",
"description": "Find one invoice by its invoice number. Use when the user gives an invoice number like 'INV-20418'. Do not use to search by vendor or date; use search_invoices for that. Returns status, amount in USD cents, vendor name, and due date. Returns not_found if no match.",
"input_schema": {
"type": "object",
"properties": {
"invoice_number": {
"type": "string",
"pattern": "^INV-[0-9]{5}$",
"description": "Invoice number, for example INV-20418"
}
},
"required": ["invoice_number"]
}
}
Schema habits that prevent mistakes
- Name parameters without ambiguity. Anthropic’s example: use
user_id, notuser. - Use enums and patterns so invalid values cannot be expressed. OpenAI’s example of a bad design is
toggle_light(on: bool, off: bool), which allows nonsense calls. - Make mistakes hard. Anthropic calls this poka-yoke. Their team found a model made errors with relative file paths once the agent moved directories. When they changed the tool to require absolute paths, the model used it flawlessly.
- Return names, not only IDs. Anthropic found that resolving opaque UUIDs into meaningful language significantly improves precision in retrieval tasks and cuts hallucinations.
- Control response size. Use pagination, filters, truncation, and sensible defaults so one call does not flood the context window. A
response_formatoption withconciseanddetailedvalues is a clean way to let the agent choose.
Errors the Agent Can Act On
An agent reads your error message and decides what to do next. A stack trace gives it nothing to work with. An actionable message gives it a next step.
Anthropic says to prompt-engineer error responses to communicate specific, actionable improvements instead of opaque codes or tracebacks.
| Bad error | Better error |
|---|---|
Error 400 | invoice_number must look like INV-20418. You sent '20418'. Try again with the INV- prefix. |
Not found | No invoice INV-20418. Use search_invoices with the vendor name to find similar numbers. |
Permission denied | This agent cannot approve amounts over $5,000. Escalate to a human approver. |
Timeout | The payment service did not answer. The payment may or may not have been sent. Call get_payment_status before trying again. |
That last row matters most. A timeout on a write is ambiguous, and the message should say so.
If you use MCP, the specification separates two error types. Protocol errors cover things like unknown tools and invalid arguments. Tool execution errors are returned inside the tool result with isError: true, and cover API failures, bad input data, and business logic errors. Put your helpful text in the second kind, because that is what the model reads and can reason about.
The same spec says servers must validate all tool inputs, apply access controls, and rate limit calls, and that clients should treat tool annotations as untrusted unless they come from a trusted server. Never let a description or a hint stand in for a real permission check.
Idempotency and Verify-Before-Retry
How do you retry safely? Do not retry a write until you know whether the first call worked.
The AWS Builders’ Library says it plainly: retries are selfish, and APIs with side effects are not safe to retry unless they provide idempotency. An idempotent call can run many times and have the same effect as running once.
Agents make this worse because they retry on their own. A model that sees a timeout will often call the tool again. If the first call went through, you now have two payments or two tickets.
Use two defenses together.
1. Idempotency keys. The caller sends a unique key with each write. The server stores the result under that key. A retry with the same key returns the saved result and does not repeat the action. Stripe documents this pattern: retries with the same key return the saved response, even when the first response was a 500 error, and reusing a key with different parameters returns an error. Stripe notes GET and DELETE are idempotent by definition. There is also an IETF draft for a standard Idempotency-Key header. It is still a draft, not a finished standard.
Generate the key in your tool code, not in the model. Build it from the stable identity of the action, such as the invoice number plus the payment run ID. The model should never invent it.
2. Verify before retry. Give every write tool a matching read tool, and tell the agent to check state after an uncertain result.
The retry rule I use:
- Write tool fails or times out.
- Agent calls the status tool (
get_payment_status). - If the action happened, report success. Do not retry.
- If it did not, retry once with the same idempotency key.
- If it is still unclear, stop and escalate to a human.
Cap retries at two or three. After that, an error that says “escalate” beats a fourth blind attempt. For hand-offs, see how to escalate to a human cleanly.
How Many Tools Is Too Many
There is no magic number, but the trend is clear: more tools means more confusion.
Anthropic notes that too many or overlapping tools can distract agents from efficient strategies. OpenAI’s function calling guide suggests aiming for fewer than 20 functions available at the start of a turn, and calls this a soft suggestion. Treat 20 as a loose ceiling to test against, not a rule.
Research points the same way. The RAG-MCP paper describes how models struggle as external tools multiply, from prompt bloat and selection complexity. In their MCP stress test, retrieving only the relevant tool descriptions raised selection accuracy to 43.13%, against 13.62% for the baseline. That is one benchmark, not a law, but it shows the direction.
What to do when the list grows:
- Merge overlapping tools. If two tools could both answer a request, the model will pick wrongly some of the time.
- Use namespaces. Group by service and resource, like
asana_searchandjira_search. Anthropic found that prefix versus suffix naming had non-trivial effects on its evaluations, and that effects vary by model. So test your own scheme. - Give each agent only the tools its job needs. A short list per workflow beats fifty tools on one agent.
My test for tool overload: if two descriptions are hard to tell apart, merge or rename them before adding a third.
How to Test Tool Selection
You cannot judge tool design by reading it. Run it.
Anthropic recommends evaluation tasks grounded in real-world use, with realistic data. Avoid toy sandboxes. Track more than accuracy: runtime, number of tool calls, token use, and tool errors. Redundant calls or repeated errors point to a tool design problem.
A simple selection test:
- Write 20 to 30 real requests from the workflow, including ambiguous ones.
- For each, write down the correct tool and the correct arguments.
- Run each request several times.
- Record which tool the agent picked, and which arguments it sent.
- For wrong picks, find which description caused the confusion. Change that text and rerun.
Look for pairs of tools that get confused with each other. Those descriptions need work. Add a few traps too: requests that should trigger no tool, and requests that should be refused. I cover how to build and score this kind of test in my guide to AI agent evaluation.
A tool review checklist
Run this on every tool before it ships:
- One job, named after a workflow step
- Read and write actions split; irreversible actions in their own tool
- Description says what, when, when not, and what it returns
- Parameters named without ambiguity; enums and patterns used
- Output returns names and key fields, not raw IDs or huge dumps
- Errors say what went wrong and what to try next
- Write tools take an idempotency key generated in code
- A status tool exists for every write tool
- Retry cap set, with escalation after the cap
- Tool selection tested on real requests, several runs each
- Inputs validated and permissions checked in code
Bottom Line
Treat every tool as a product with one user: the model.
Give each tool one job, a description with boundaries, and errors that say what to do next. Make writes idempotent, and check state before any retry.
Next step: pick your three most-used tools and run the checklist above. Fix the descriptions first. It is the cheapest change with the biggest effect.
FAQ
How do I write a good tool description? Describe the tool as you would to a new hire. State what it does, when to use it, when not to, what each parameter means, and what it returns. Add an example and name the tool to use instead for nearby cases.
How many tools is too many? OpenAI suggests aiming for fewer than 20 functions available at once, as a soft guideline. The real answer comes from testing. If the agent starts picking the wrong tool, or two descriptions look alike, you have too many or too much overlap.
How do I return errors the agent can use?
Say what went wrong, what the agent sent, and what to try next. Avoid bare codes and stack traces. With MCP, return the message in the tool result with isError: true so the model can read it.
How do I retry safely? Never retry a write blindly. Use an idempotency key made in your code, check the state with a status tool after any timeout, retry at most once or twice, and escalate to a human if the result is still unclear.
How do I test tool selection? Write 20 to 30 real requests with the correct tool and arguments for each. Run them several times and record what the agent picks. Fix the descriptions behind any wrong choices, then rerun.
Three Ways to Work With TMA
Need an agent built? We deploy production AI agents in your infrastructure. Working pilot. Real data. Measurable ROI. → Schedule Demo
Want to co-build a product? We’re not a dev agency. We’re co-builders. Shared cost. Shared upside. → Partner with Us
Want to join the Guild? Ship pilots, earn bounties, share profit. Community + equity + path to exit. → Become an AI Architect
Need this implemented?
We design and deploy enterprise AI agents in your environment with measurable ROI and production guardrails.
About the Author
Chase Dillingham
Founder & CEO, TrainMyAgent
Chase Dillingham is the founder and CEO of TrainMyAgent. He spent 15+ years as an enterprise architect deploying production systems. Now he builds AI agent platforms that deliver measurable ROI.
Connect with Chase Dillingham on LinkedIn