How to Design Tools for an AI Agent (So It Actually Uses Them)
To design tools an AI agent will actually use correctly, give each tool one job, write the description for a new hire rather than a compiler, constrain the inputs with typed schemas and enums, and return errors that tell the agent what to do next. Agents rarely fail because the model is weak. They fail because the tool list is ambiguous, and the model is picking from your descriptions with nothing else to go on.
TL;DR
- The model chooses tools by reading their names and descriptions. That text is not documentation, it is the interface.
- One tool, one job. A
manage_data(action, payload)tool with twelve branches turns every call into a guess. - Write descriptions that say when to use the tool and when not to, not just what it does.
- Constrain inputs. An enum with four options cannot be hallucinated the way a free-text string can.
- Make errors instructive. "Invalid input" is a dead end. "start_date must be YYYY-MM-DD, got 'last Tuesday'" is a fix.
Why your agent ignores its tools
When an agent picks a tool, it is not reasoning about your codebase. It sees a list of names, descriptions, and parameter schemas, and it predicts which one fits the request. That is the entire decision. Your beautifully implemented function is invisible. The forty characters of description are the whole interface.
This is why tool design is prompt engineering wearing a different hat, and why the debugging instinct most builders bring is wrong. When an agent calls the wrong tool, the reflex is to reach for a better model or bolt more rules onto the system prompt. Usually the actual problem is that two descriptions overlap and the model had no way to tell them apart. You would not blame a new hire for picking wrong between two tools labeled "process the record" and "handle the record." The fix is not a smarter hire.
The anatomy of a tool definition
Every tool definition, whether you write it directly or serve it over MCP, comes down to four parts the model reads before it commits to a call.
Notice which one carries the weight. The name gets skimmed, the schema gets followed, but the description is where the model decides whether this tool is the right one for the request in front of it. Most broken agents have a great implementation behind a description that was written in four seconds.
Rule 1: One tool, one job
The most common mistake is the kitchen-sink tool: one endpoint with an action parameter and a payload that means something different for each action. It feels efficient because it is one function to maintain. For the model it is a maze. It has to pick the right action string, then shape a payload whose valid form depends on that string, with no schema telling it which fields go with which branch.
Split it. list_orders(customer_id) and refund_order(order_id, amount) are two tools the model cannot confuse, each with a schema that describes exactly one shape. Yes, that is more definitions. It is also fewer wrong calls, and wrong calls are the expensive part. A useful test: if you cannot write the tool's description without the word "or," you are looking at two tools.
The same logic applies at the boundary. A tool should map to a decision a person would make, not to your internal service layout. Do not make the agent call get_auth_token then fetch_user_record then parse_profile when what it wanted was get_customer(email). Every extra hop is another chance to drop a thread, and this kind of multi-step chore is exactly the work you should be pushing down into a loop instead of a prompt. My Write Loops Not Prompts guide walks through where that line sits.
Rule 2: Write the description for a new hire, not a compiler
Here is a real description most codebases ship:
search_orders- Searches orders.
That tells the model nothing it could not guess. Compare:
search_orders- Find orders for one customer by email or order ID. Returns up to 50 matches, newest first, with status and total. Use this before any refund or status question so you are working from the live record. Does not cover subscriptions, uselist_subscriptionsfor those.
Everything the model needed to decide is now on the page: the trigger, the limits, the shape of the return, and the escape hatch to the neighboring tool. That last sentence does an unreasonable amount of work. Most wrong-tool calls come from a gap where no tool fits and the model reaches for the nearest thing rather than admit the gap, which is the same failure mode behind AI hallucinations generally. Naming the alternative closes the gap.
Write these in plain sentences. You are not writing a docstring for a linter, you are briefing a capable person who has never seen your system and has to act in the next five seconds.
Rule 3: Constrain inputs and make errors teach
Every free-text parameter is a place the model can invent something. Every enum is a place it cannot. If status accepts only pending, shipped, delivered, or cancelled, say so in the schema. The model will not pass in transit because the schema never offered it. This is the same discipline as pinning down output shape, and it works for the same reason: narrow the space, and there is less room to be wrong.
Then make failure useful. The default error most tools return is a status code and a shrug. An agent that gets "400 Bad Request" has no idea what to change, so it retries the same call, burns tokens, and eventually gives up or fabricates a result. Write errors as instructions:
- Bad:
Error: invalid input - Good:
start_date must be YYYY-MM-DD, got 'last Tuesday'. Convert to a date first. - Bad:
Error: not found - Good:
No order with ID 88123. Use search_orders(email) to find the right ID.
The good versions are a repair path. Your error message is the only feedback channel the agent has at the moment it is most confused, so spend real words there.
Rule 4: Keep the list short
Every tool you add competes for attention with every other tool. At three tools the model picks correctly almost every time. At forty, descriptions start colliding, and each one is also sitting in your context window on every single call, costing tokens whether it gets used or not.
If your agent genuinely needs a wide surface, do not flatten it all into one list. Scope the tools to the task and load only that set, or put a router in front that picks the toolkit before the agent picks the tool. The pattern to avoid is a model reading forty descriptions to find the two that matter. If you are exposing tools over a shared server, the same restraint applies there, and my guide to what an MCP server is covers how that boundary works.
How to test your tools
You do not need a harness for the first pass. Take your tool list, hand it to a model with no other context, and give it ten realistic requests. Ask which tool it would call and with what arguments. Do not let it execute anything, just declare the call.
Include two or three requests that no tool covers. Those are the valuable ones. A well-designed tool list produces "none of these apply." A badly designed one produces a confident call to whatever was closest, which is exactly the bug you would have shipped. Every wrong pick maps to a specific description you can rewrite, and you can rerun the whole thing in a minute after the edit. This is the cheapest feedback loop in agent development and almost nobody runs it.
The bottom line
Your agent is only as good as the tools it can see, and it sees names, descriptions, and schemas. Give each tool one job so there is nothing to guess between. Write the description like you are briefing a new hire who has five seconds to act, including when not to use it and what to use instead. Constrain the inputs so bad calls are impossible rather than merely discouraged. Return errors that name the fix. Then keep the list short enough that the right choice stays obvious.
Do that and most of the mysterious agent failures you have been blaming on the model disappear, because they were never about the model. They were about a tool list nobody proofread.
If you want more field notes on making agents work in production instead of in demos, join the OpusJake newsletter. One practical build per week, no fluff.
How many tools should an AI agent have?
Fewer than you think. Most agents work best with somewhere between three and a dozen tools that each do one job. Past that, the descriptions start overlapping and the model has to guess which of two similar tools you meant. If you need more surface area, group tools by task and load only the relevant set for the job at hand rather than handing the model everything you have.
Why does my agent call the wrong tool?
Almost always because two tool descriptions overlap, or because one description says what the tool does without saying when to use it. The model picks tools by reading the descriptions, so ambiguity there becomes a wrong call at runtime. Rewrite the descriptions so each one states its trigger condition and names the tool to use instead in the cases it does not cover.
Should I use MCP or write my own tool definitions?
Use MCP when the tool is something more than one agent or app will need, since it gives you one server that any MCP client can connect to. Write direct tool definitions when the tool is specific to a single app and nobody else will call it. The design rules are identical either way, because both end up as a name, a description, and a typed schema the model reads.
What makes a good tool description for an AI agent?
It reads like an instruction to a competent new hire on their first day. State what the tool does, when to reach for it, when not to, what it returns, and any constraint that is not obvious from the parameter names. Two or three plain sentences beat a one-line restatement of the function name every time.
How do I test whether my agent's tools are well designed?
Run the tool list past a model with no other context and ask it which tool it would call for ten realistic requests, including a few that no tool covers. Every wrong pick points at a description that needs work, and every time it invents a call for the uncovered cases you have found a missing refusal path.
OpusJake is Jake Schincariol's operating system for building with AI: agents, workflows, prompts, and the free resources behind them. Get the next move every week.