AI agents

How to Design Tools an AI Agent Can Actually Use

Most reports of a model calling the wrong tool are really reports of a badly written tool description. Here is the contract, the schema rules, and the error text that fixes it.

On this page
  1. What makes a tool usable by an agent
  2. The Five P Tool Contract
  3. One tool per outcome, not one per endpoint
  4. Error messages are prompts
  5. Schema rules that remove whole bug classes
  6. Writes need idempotency and two phases
  7. The tool schema tax
  8. Testing a tool description

What makes a tool usable by an agent

The short answer

A tool is usable by an agent when its description alone lets a competent stranger call it correctly on the first attempt, with no access to your codebase, no way to ask a question, and no memory of yesterday. That is the entire design brief. Nearly every complaint that a model called the wrong tool, invented an argument or looped on an error turns out to be a description problem rather than a model problem, and it is fixable in an afternoon.

This gets neglected because tool descriptions look like documentation, so they get written last and reviewed by nobody. They are not documentation. They are the part of the prompt that decides what the agent does, and the only instruction it has at the moment it chooses an action.

  • Every turnHow often your full tool schema set is resent and billed, in every run.
  • 0Identifiers an agent should ever construct itself. Every ID comes from an earlier tool result.
  • 2Phases an irreversible write needs: a prepare that previews, and a commit that acts.
  • 1:1The wrapping ratio to avoid. One tool per API endpoint is the commonest tool design mistake.

The Five P Tool Contract

Every tool description should carry the same five parts in the same order. Consistency matters as much as content: twelve tools written to one template compare cleanly, and twelve written in twelve styles force the model to guess what the differences mean.

Framework

The Five P Tool Contract

Write every tool to these five headings. If a heading is empty, that is a finding about the tool, not a reason to drop the heading.

01
Purpose

One sentence naming the user-visible outcome, then one sentence naming what the tool does not do. The negative sentence is the part people skip and it is the part that prevents the overlap bug, where two similarly named tools both sound correct and the model picks by coin toss.

02
Provenance

For every argument, state where the value must come from. Say plainly that order_id comes from search_orders and must never be constructed. This single habit removes the largest class of agent bug, because a model under pressure to produce an identifier will produce one that matches your format perfectly and refers to nothing.

03
Preconditions

What must be true before the call is valid, expressed as a check the agent can perform with another tool. Not a warning, an instruction: call get_order and read status first. Preconditions written as prose advice get ignored; written as a prior tool call they get followed.

04
Postconditions

What changes in the world and what the return value actually proves. The distinction between queued and completed belongs here, because an agent that reads a queued response as done will report success for money that has not moved.

05
Prescribed recovery

For each named error class, the next action: retry once with a corrected argument, call a different tool, or escalate. Generic advice to handle errors gracefully produces the apology loop. Naming the error and the response produces recovery.

Read it back with one question in mind: could someone who has never seen your system call this correctly first time. If they would need to ask you anything, the model will guess instead, and the guess will be confident.

One tool per outcome, not one per endpoint

Wrapping your REST API one to one is the fastest way to build a tool set and the most reliable way to make an agent slow and error prone. Endpoints are shaped for programmers who read documentation and hold state across calls. Tools should be shaped for the outcome someone wants.

One tool per endpointOne tool per outcome
Tool count for a mid-sized systemForty or moreEight to twelve
Turns to finish a typical taskFive or six, chaining IDsTwo or three
Where the business rules liveIn the model's head, rediscovered each runIn the tool, tested once
When the API changesEvery affected tool description shiftsThe tool absorbs it, the description holds
Typical failureRight tool, wrong argument, wrong orderClean error the agent can act on
Reviewing the tool listNobody can hold forty in their headA person reads it in two minutes

The pattern that carries most of the benefit is search then act. Provide one lookup tool that takes a human-shaped query and returns the records with the fields the next action needs, including their identifiers. Then provide action tools that require those identifiers. The agent never has to invent an ID because there is always a tool that hands it one, and your validator can reject any identifier that did not appear in an earlier result. That check is covered further in controlling what an agent is allowed to do.

Error messages are prompts

Whatever a tool returns lands in the model's context and shapes the next decision. That makes error text prompt engineering with a different job title, and it is the most valuable writing in the whole system, because the agent reads it at the exact moment it is stuck.

What the tool returnsWhat the agent does nextWhat to return instead
500 Internal Server ErrorRetries the identical call until the turn cap firesBilling service unavailable, transient. Wait 2s, retry once, then escalate.
400 Bad RequestChanges an argument at random and tries againdate_from must be an ISO 8601 date. Received 1st of last month. Today is 2026-08-26.
An empty arrayConcludes the customer does not exist and stopsNo orders matched. Searched by email only. Retry with order_number or postcode.
nullReads it as success and reports the task doneAn explicit state field with a reason. Never a bare null from a write.
Permission deniedTries a neighbouring tool that also failsYour role cannot refund over 500. Use request_refund_approval instead.
200 OKAssumes the money has movedRefund RF-123 created, state pending, settles in about 3 working days. Verify with get_refund.
The right-hand column costs an hour to write and removes entire categories of agent failure. It is the cheapest reliability work available.
Never return a stack trace or a raw upstream body

A stack trace tells the model nothing actionable and can carry internal hostnames, query fragments and occasionally customer data straight into a context window that gets logged, replayed and sometimes sent to a provider. Map upstream failures to a small set of named error codes, each with a prescribed recovery, and keep the raw detail in your own trace where a human can find it.

Schema rules that remove whole bug classes

The schema is a contract the model cannot argue with, so put as much of the constraint there as possible and leave the description for what a schema cannot express. Each rule below corresponds to a bug that stops occurring once the rule is applied.

  • Enumerate anything enumerable. An enum of five reason codes is checkable. A free-text reason field produces sixty variants in a month and no reporting.
  • Stay one level deep. Models fill flat objects far more reliably than nested ones. If you need nesting, you probably need a second tool.
  • Make almost nothing optional. Every optional field is an invitation to invent a value that seems helpful. Required and validated beats optional and hopeful.
  • Ban negative booleans. A field called exclude_inactive gets set wrong roughly half the time. Use status with values active, inactive and all.
  • Absolute dates only, and say what day it is. Put the current date in the system prompt and reject relative strings at the boundary with an error naming the expected format.
  • Put units in the field name. Fields called amount_minor_units and timeout_seconds prevent an argument nobody notices until a refund is a hundred times too large.
  • Pattern-match identifier fields. A regex on order_id catches an invented ID at the schema layer, before it reaches your database.
  • Cap and paginate returns. A four thousand token result is charged again on every remaining turn of the run. Return the fields the next action needs plus a cursor, not the whole record.

The last rule is the one with a running cost attached. Return size is not a one-off charge, it is a subscription paid for the rest of the run, which is why trimming tool output is usually a bigger saving than changing model. The mechanism is set out in what an AI agent actually is.

A tool written to the Five P contract, ready to adaptyaml
# tools/refund_order_line.yaml
# Authored in YAML, serialised to the provider's JSON tool schema at build time.
# Every section below maps to one part of the Five P contract.

name: refund_order_line

description: |
  PURPOSE
  Issues a refund for ONE line on ONE order and returns the refund record.
  It does not cancel the order, does not refund shipping, and does not email
  the customer. Use cancel_order and send_customer_email for those.

  PROVENANCE
  order_id            must come from a search_orders or get_order result in
                      this run. Never construct or infer it.
  line_id             must come from the lines array of that same order.
  amount_minor_units  integer, order currency, minor units. Must be less than
                      or equal to line.refundable_minor_units from get_order.
  reason_code         one of the enum values. Free text belongs in note.
  idempotency_key     one stable string per intended refund. Reusing it returns
                      the original refund instead of creating a second one.

  PRECONDITION
  Order status must be delivered or shipped. Call get_order and read status
  before calling this tool.

  POSTCONDITION
  Creates a refund in state pending. Money moves later. The return value proves
  the refund was created, not that it settled. Confirm with get_refund.

  ON ERROR
  amount_exceeds_refundable  read refundable_minor_units from get_order and
                             retry once with a valid amount.
  order_not_refundable       stop and escalate. Do not try another tool.
  upstream_unavailable       wait 2 seconds, retry once, then escalate.

input_schema:
  type: object
  additionalProperties: false
  required: [order_id, line_id, amount_minor_units, reason_code, idempotency_key]
  properties:
    order_id:           { type: string, pattern: "^ORD-[0-9]{8}$" }
    line_id:            { type: string, pattern: "^LN-[0-9]{4}$" }
    amount_minor_units: { type: integer, minimum: 1 }
    reason_code:
      type: string
      enum: [damaged, not_as_described, late_delivery, goodwill, duplicate_charge]
    note:               { type: string, maxLength: 280 }
    idempotency_key:    { type: string, minLength: 8 }

returns: |
  { "refund_id": "RF-00012345", "state": "pending",
    "amount_minor_units": 1299, "currency": "GBP",
    "expected_settlement": "3 working days",
    "verify_with": "get_refund(refund_id)" }

Writes need idempotency and two phases

Read tools can be retried freely. Write tools cannot, and an agent will retry, because retrying is what a model does when a response looks ambiguous. Design every write assuming it will be called twice with the same intent, once because of a timeout and once because the model was not sure the first one worked.

  1. Make the idempotency key an argumentNot a header your code adds

    The key belongs in the schema so the model generates one per intent rather than per call. If your code generates it, a retry produces a fresh key and a second refund.

  2. Store the key and replay the original resultServer side

    A repeated key returns the first result, including the same identifier and the same state. The agent then sees a consistent world instead of two conflicting truths.

  3. Split irreversible actions into prepare and commitThe pattern worth the extra turn

    Prepare returns a preview with a short-lived token: the amount, the record, what will change. Commit takes only that token. A human can approve between the two without anybody building an approval system.

  4. Return the resulting state, never OKOne line, large effect

    The response should say what the record now is, and name the tool that verifies it. An agent given a verification path uses it. An agent given OK reports success.

  5. Tag every write with the run identifierFor the bad day

    When a run fails between two writes, you need to find the first one to compensate for it. Without a run tag, that search is manual and slow at exactly the wrong moment.

Two APIs, no transaction

If a task writes to a CRM and then to billing, there is no transaction spanning both, whatever the framework implies. You get two options and you must pick one before launch: a compensating action that reverses the first write, or an approval gate placed before either write happens. The retry mechanics that sit underneath this are covered in rate limits, retries and backoff.

The tool schema tax

Every tool description is sent to the model on every turn, whether or not the agent uses that tool. A large tool set is therefore a fixed tax on every run, and it also lowers accuracy, because more similar-sounding options make the choice harder. Both costs point the same way.

What your tool list costs per day

Estimate schema tokens by counting characters in your rendered tool definitions and dividing by about four. Put your own input price in rather than a rate quoted anywhere, because those change.

0Tokens per run spent describing tools
0Percent of input tokens that is tool schema
0Tokens per run after grouping
0Saved per day by grouping

Run it with your real tool count before you argue about model pricing. The number that usually surprises people is the share output: on an endpoint-shaped tool set, a large fraction of every prompt is spent describing tools the agent will never call on this task. Grouping by outcome cuts the tax and the error rate together.

Testing a tool description

Tool descriptions are prose that controls behaviour, so they need tests like any other behaviour. The test is cheap: give a model nothing but your tool list and a phrased request, and check which tool it picks and which arguments it fills. No agent loop, no database, no waiting.

Terms used precisely here
Tool schema
The machine-readable declaration of a tool's name, arguments, types and constraints, sent to the model alongside its description on every turn so it can produce a valid call.
Provenance rule
An instruction stating where an argument's value must come from, usually that an identifier must appear in an earlier tool result in the same run and may never be constructed by the model.
Idempotency key
A stable string supplied with a write so that repeating the same call returns the original result instead of performing the action twice. Generated once per intent, not once per attempt.
Two-phase write
A write split into a prepare call that returns a preview and a short-lived token, and a commit call that takes only that token, so an irreversible action can be reviewed before it happens.
Tool surface
The complete set of tools exposed to an agent in one run. It defines both the token cost of every turn and the outer limit of the damage a bad run can do.
Tool review, run before the agent goes near production
0 of 8 done

That last item is the one people resist. A tool nobody calls is not free: it is a permanent tax on every prompt and one more option to choose wrongly. The tool set is usually the part of a build that gets postponed, and it is the first thing we rewrite in AI agent development.

Questions readers ask next

How many tools should one agent have?
Enough to finish the task and no more, which in practice usually means eight to twelve grouped by outcome rather than forty grouped by endpoint. The limit is not a hard technical one, it is that every extra tool costs tokens on every turn and adds a similar-sounding option at the moment of choice. If two tools need a paragraph to distinguish, merge them.
Should tool descriptions be long or short?
Long enough to remove ambiguity, short enough that you would read all of them. Provenance rules and error handling earn their tokens because they prevent whole failure classes. Marketing language, restating the tool name, and explaining what the underlying service is do not, and they get resent on every turn of every run.
Why does the agent keep inventing identifiers?
Because you asked it for one and gave it no way to get a real one. A model completing a pattern will produce something that matches your format and refers to nothing. The fix has three parts: a lookup tool that returns identifiers, a provenance line in every description saying IDs must come from a prior result, and a validator that rejects any identifier not seen earlier in the run.
Do I need MCP or a specific framework to define tools well?
No. The transport matters far less than the contract. Whether tools are declared through a provider's native format, a protocol like MCP, or plain functions in your own loop, the same five parts decide whether an agent can use them. Pick the transport your stack supports and spend the saved time writing the descriptions and error text.
How do I stop an agent calling a write tool it should not?
Do not rely on the description. Enforce it in code: check permissions and thresholds in the validator before execution, keep write tools out of the tool set entirely for runs that should be read-only, and require an approval token for anything irreversible. A prompt is a preference, and a validator is the only thing that holds when the input is unusual.
What is the single highest-value change to an existing tool set?
Rewriting the error messages. It takes about an hour, needs no schema migration, and removes the apology loop, the random argument change and most silent successes in one pass. Second is adding provenance lines for identifier arguments. Both are prose changes, which is why they get postponed and why they keep paying off.
Cite this

ChatGPTalker. "How to Design Tools an AI Agent Can Actually Use." chatgptalker.com, 2026-08-26. https://chatgptalker.com/guides/designing-tools-for-agents/

Rather have it built than read about it?

Send the process you want automated. You get a scoped plan back, with the build shape, the stack and a realistic timeline.

Start a project