AI coding

Naming Tools So a Model Picks the Right One

Antonio Evans11 min read

A close-up of a printed tool schema on a desk, with three human hands using colored markers to circle the tool name, underline the description, and bracket the enum labels.
Key points

Key points

  1. 1A model selects a tool by matching the user's wording against the tool name, its description text and its enum labels, so those fields are the real documentation the model sees.
  2. 2Distinctive, verb-led names and descriptions that say when a tool applies and when it does not reduce wrong-tool picks more than adding parameters or restructuring the JSON.
  3. 3Enum labels that mean something without surrounding context prevent argument-level mistakes and keep generated payloads valid on the first try.
  4. 4An audit of names, descriptions, enum labels and tool responses, run as a repeatable checklist, catches the selection errors that schema validation alone cannot.

The three fields the model actually reads

A tool schema carries two different kinds of content. The JSON structure says what a valid call looks like: property names, types, required keys, nesting. The natural-language surface says what the tool is for and when to reach for it. Models use both, but selection lives almost entirely in the second one. When a model decides whether to call a tool at all, and which of several candidates fits, it is matching the user's sentence against the name string, the description block and the enum values it can see.

The mechanics are ordinary function calling. You describe available tools as schemas in the request, the model decides whether to call one, and it returns structured arguments that your application executes (OpenAI's function calling guide). The same pattern appears across providers with small syntax differences: in the Anthropic API the schema arrives under input_schema; in OpenAI's it sits under parameters inside a function object (Prefect's MCP vs function calling comparison). That portability gap is one reason the Model Context Protocol exists at all: a server publishes tools once and any compatible client discovers them at runtime, so the same names and descriptions travel across hosts (MCP specification overview).

That runtime discovery makes the wording more important, not less. With function calling you control the tool list on every request. With MCP, tools arrive from a server you may not have written, and the client surfaces whatever name, title and description that server publishes (MCP resources and discovery patterns). The protocol itself treats tool descriptions as untrusted material and asks hosts to get explicit consent before invoking anything (MCP security principles). In other words: the model reads the description, but you should not assume it is honest or well written.

Here is the decision rule that follows. If a request could plausibly match two tools, the fix is almost never in the JSON Schema. It is in the name, the description or the enum. Rewrite those three first, re-run your test prompts, and only then look at parameters.

Why names do the heavy lifting

Names are short, high-salience tokens that the model has seen millions of times in tool-calling training data. A good name behaves like a compressed instruction.

The strongest evidence here is a schema-alignment study rather than an opinion. Researchers at Seoul National University found that small language models fail at tool use largely through schema misalignment: given tools with unfamiliar naming conventions, models hallucinate plausible but nonexistent tool names that reflect naming patterns internalized during pretraining. Their fix, called PA-Tool, was to rename tool components to match pretraining conventions, with no retraining of the model at all. On the MetaTool and RoTBench benchmarks the rename produced improvements of up to 17 percent and cut schema misalignment errors by 80 percent (the PA-Tool paper, ACL version). A naming change, not an architecture change, moved the failure rate that far.

Four naming rules do most of that work.

Lead with a verb. search_tickets, create_refund, fetch_invoice describe an action. tickets, refunds, billing describe a domain. Verbs map cleanly onto the imperative form of user requests.

Make sibling names differ in the first word. If you expose get_order_status and get_order_status_v2, you have built a coin flip. Distinguish by verb and object: check_order_status versus fetch_order_history.

Avoid internal jargon and abbreviations. crm_lookup_v3 means nothing to a model that has not seen your internal wiki. find_customer_by_email means something immediately.

Keep names consistent across one server. Mixed conventions (stripe_charge, DoRefund, invoices.list) tell the model you have no scheme, and it guesses.

NameVerdictWhy
get_weatherGoodVerb first, one clear object
weather_api_callWeakReads as infrastructure, not intent
handleTicketsWeakVague verb, camel case mixes conventions
search_closed_ticketsGoodVerb plus a scoped object
tixBadAbbreviation only an insider parses
refund_and_notifyRiskyTwo actions behind one name; split it

The last row is a common trap. Names that bundle several effects force the model to reason about side effects it cannot verify. One name, one verb, one outcome.

If you are wiring several models, including smaller ones, into one tool surface, testing candidate names against the model you actually deploy matters more than elegance. Quanta Inference exposes text, image, video, audio and embedding models through one OpenAI-compatible API key, which makes it practical to replay the same set of test prompts against more than one endpoint before you settle on a naming scheme.

Writing descriptions that exclude

A description has one job beyond describing: it must tell the model what this tool is not for. Most schema bugs come from descriptions that only enumerate capabilities, leaving adjacency to be guessed.

The PA-Tool finding above has a practical corollary. Models carry priors about how tool descriptions read, so descriptions that follow the patterns seen in training data are easier to route. Short declarative sentences with an explicit boundary beat adjectives.

Consider a booking agent with three tools. A first draft:

"description": "Manages hotel bookings, cancellations and modifications."

That single sentence invites the model to use it for every booking-adjacent request, including refunds it cannot perform. A paired version:

"description": "Create a new hotel reservation. Use when the user gives a hotel,
check-in and check-out date and wants a new booking.
Do not use to change or cancel an existing booking; use modify_booking or
cancel_booking instead."

Under the hood the two tools may call the same endpoint. The description is what separates them.

A few content rules are worth standardizing across a toolset:

  • Open with the action, in plain English, not a noun phrase. "Create a new hotel reservation" beats "Hotel reservation creation utility."
  • State when to use it, referencing the kind of user request it serves.
  • State when not to use it, and name the alternative tool explicitly. This single sentence is the highest-yield edit in most schemas.
  • Describe preconditions, such as required identifiers the user must supply first.
  • Say what it returns, briefly, so the model knows whether follow-up calls are needed.
  • Avoid marketing language and absolute words like "always" or "unlimited," which push the model toward over-triggering.

Note what is not on the list: JSON formatting detail. The structural schema already covers types. Repeat natural-language constraints only where the model should reason about them.

There is also a security dimension to how descriptions are written and read. OWASP documents MCP tool poisoning as an attack in which a malicious server exposes normal-looking tool names and descriptions, then returns responses carrying hidden instructions that land in the model's context and are treated as trusted (OWASP on MCP tool poisoning). The attack works because descriptions are reviewed once at connect time while responses are not. Your naming standard does not stop that, but a discipline of describing tools with explicit scope, plus a response-format contract, gives you a place to hang the runtime checks covered later.

Enum labels that stand alone

Enums are where models make argument-level mistakes, and those mistakes are often harder to spot than wrong-tool calls because the request succeeds and returns a plausible answer for the wrong slice of data.

The rule: a label should be unambiguous when read alone, outside the tool description and outside the user's sentence. open and closed pass. 1 and 2 fail. pending is borderline because it means different things in ticket systems and in payment flows; pending_customer_reply does not.

Compare two ways to express the same filter on a support tool:

WeakStrongReason
status: ["open", "closed"]status: ["awaiting_agent", "awaiting_customer", "resolved", "archived"]Each label states who owes the next action
priority: [1, 2, 3]priority: ["low", "medium", "high", "urgent"]Words map to user phrasing
range: ["d", "w", "m"]range: ["last_day", "last_week", "last_month"]No decoding required
type: ["a", "b"]type: ["bug", "feature_request"]Self-describing domain terms

Three practices follow from the table.

Pad the space between labels. If two labels can describe the same request, a model will split between them unpredictably. high and urgent overlap; either drop one or write the boundary into a description.

Prefer self-describing words to codes. Codes require a lookup table, and models perform that lookup unreliably, especially when the same code appears in two tools with different meanings. The schema-matching literature makes the broader point: when systems must match schema elements using names and descriptions alone, both must carry the meaning on their face (LLM-Matcher).

Constrain output shape when possible. The same argument applies to the model's response, not just its input: enforcing a defined structure up front removes a whole class of parse failures downstream (Agenta's guide to structured outputs). A fixed schema for tool arguments and results is the preconditions; clean enum labels are what make the arguments readable.

One more habit worth adopting: derive enum labels from the wording your users actually type. If analytics shows people ask for "the last 30 days," not "month to date," label the option accordingly. Names are a matching surface, and matching improves when both sides use the same vocabulary.

An audit that catches the errors schema validation misses

Structural validation proves a tool call is well formed. It cannot prove the right tool was chosen. The gaps that survive validation are things like: a model calling get_order_status when it needed get_shipping_status, an enum value that is valid but semantically wrong, or a tool selected for an operation the user was never authorized to perform. These show up as plausible, wrong answers, which is why code review and unit tests rarely catch them.

Run this audit on any toolset before release and after any prompt or model change. Each item is a yes or no, and a single no is a field to rewrite, not a discussion.

#CheckPass looks like
1Every name begins with a verbfetch_, create_, search_ prefixes throughout
2No two names share a first word unless they share an objectDistinct first tokens across siblings
3Every description names the tool's inverse"Do not use for X; use Y instead" appears where ambiguity exists
4Every enum value reads correctly with no description attachedA new engineer can pick the right value unaided
5Descriptions are free of marketing or absolute languageNo "always," "unlimited," "best"
6Each tool has a test prompt set5 to 10 phrasings per tool, including near-misses
7Near-miss prompts are documented as expected refusalsPrompts the tool must not match are listed
8Response format is constrained where feasibleStructured output or a fixed schema, per OWASP guidance
9External tools are allowlistedUsers cannot point the agent at arbitrary servers
10Runtime restrictions live outside the promptAccess control enforced at tool execution, not instructions

Items 8 to 10 come straight from the defensive guidance around tool servers: constrain response format, isolate privileged tools, enforce restrictions server-side and require explicit confirmation for sensitive operations (OWASP). They are part of a naming audit because a well-named tool that is over-privileged is still a liability.

The test-prompt set in item 6 is where the audit earns its keep. Write them as one small file so they can run as a regression suite:

CASES = [
    # (user prompt, expected tool, must_not_be)
    ("Show my last three orders", "recent_orders", "search_tickets"),
    ("Refund order 1042", "refund_order", "modify_booking"),
    ("Where is my package", "get_shipping_status", "check_order_status"),
]

Run every case against each model you deploy and record mismatches. A failed case points at exactly one of three fields. If the correct tool never fired, the name or the description's "when to use" sentence is weak. If two tools split the votes, their descriptions lack a boundary or their enums overlap. If the tool fired but the argument is wrong, the enum labels are doing too little work.

Worked example: three tools to one

A support agent has three poorly named tools, and the mismatch rate on the queue is high. First pass, the schema as received:

[
  {"name": "tickets", "description": "Ticket utility."},
  {"name": "handleTicket", "description": "Handles tickets."},
  {"name": "ticket_update", "description": "Updates a ticket status."}
]

Every prompt about tickets is a coin flip. The names share a stem, two descriptions are circular, and no description states a boundary. The rewrite separates on verb and object, and each description carries a "do not use" line:

[
  {"name": "search_tickets",
   "description": "Find tickets by status or priority. Use when the user wants a list of matching tickets. Do not use to change a ticket; use update_ticket_status instead.",
   "parameters": {"type": "object", "properties": {
     "status": {"type": "string", "enum": ["awaiting_agent","awaiting_customer","resolved","archived"]},
     "priority": {"type": "string", "enum": ["low","medium","high","urgent"]}}}},
  {"name": "update_ticket_status",
   "description": "Change the status of one existing ticket, identified by its numeric id. Do not use to list tickets or to add comments.",
   "parameters": {"type": "object", "properties": {
     "ticket_id": {"type": "integer"},
     "status": {"type": "string", "enum": ["awaiting_agent","awaiting_customer","resolved","archived"]}},
    "required": ["ticket_id","status"]}},
  {"name": "add_ticket_comment",
   "description": "Attach a written comment to one existing ticket. Use when the user wants to leave a note or reply. Do not use to change status.",
   "parameters": {"type": "object", "properties": {
     "ticket_id": {"type": "integer"},
     "body": {"type": "string"}},
    "required": ["ticket_id","body"]}}
]

Nothing in the JSON structure changed except the enum breadth. The fix is entirely in the prose. A reader can verify the improvement without a benchmark: for the prompt "close ticket 1042," only update_ticket_status contains both the action and the identifier, and its description says which tool to use instead when the user wants a list.

When a team is maintaining a dozen such toolsets across business lines, the manual audit does not scale linearly. Putting a named domain expert on the tool surface, with the skill library behind it, is one way to keep the vocabulary consistent as tools are added. Quanta Experts reads the local context, does the work and hands back a finished deliverable, which fits a review pass over schemas and test prompts.

When the protocol changes the answer

The same naming rules apply whether tools are defined inline for a function-calling API or discovered at runtime from an MCP server, but the failure modes differ.

With inline function calling you own the whole surface: names, descriptions, enums, execution and the dispatch loop. That control makes a naming audit straightforward, though it also means you rewrite tool definitions per provider if you switch vendors (Prefect). With MCP, a server publishes its tools and a client surfaces them, so your leverage is split between the server author and the host. The protocol's conventions put human-readable identity in title and a short functional summary in description, alongside the machine-facing name, and that split is deliberate (MCP prompts reference). Clients increasingly use the descriptive fields for discovery and ranking, which means a server that leaves description thin underperforms however good its endpoint is.

The time-to-value comparison makes the choice concrete. Writing an API integration takes days of auth setup and field mapping; connecting an MCP server takes minutes, and the assistant assembles the calls per question instead of running a fixed script (Mitiga's MCP vs API breakdown). For exploration, MCP wins. For a deterministic nightly job, the API wins. Neither is a substitute for naming discipline, because both end up presenting a text description to a model.

The practical consequence for schema authors is a decision rule about where to invest. If the tool surface is small and stable, spend the time on descriptions once and add a regression prompt set. If the surface is large or changes often, invest in the names and the enum vocabulary, because those are the parts that survive a rewrite of the wrapper. Teams that keep a skill per domain, installed into a coding agent or applied by a named expert, get this for the cost of maintaining the skill text rather than the whole integration. Quanta Skills is the library that library runs on.

FAQ

FAQ

Does the tool name matter more than the description?

Yes, in practice, because the name is short, high-salience and matched directly against the user's wording, and it is the field most often wrong. A study of schema misalignment on small models found that renaming tool components to match familiar conventions raised tool-use accuracy by up to 17 percent and cut alignment errors by 80 percent, with no model training at all (PA-Tool). Descriptions do the finer routing between adjacent tools, so treat the name as the headline and the description as the qualification.

How many tools should one agent have before I split them up?

There is no universal number, but the signal to watch is cross-matching in your test set: if adding a tool causes previously correct prompts to route to the new one, the surface is too crowded for the model you are using. Splitting by business domain, with each toolset naming its own vocabulary, is usually better than shrinking descriptions to make room. Re-run the same prompt set after the split.

Should I put "do not use" instructions in descriptions?

Yes, deliberately and specifically. A sentence that names the alternative tool ("Do not use to cancel; use cancel_booking") is often the single most effective edit in a schema, because it removes the adjacency that models otherwise resolve by guessing. Keep it to one or two lines, name the exact alternative tool and avoid vague exclusions like "do not use incorrectly."

Are enum labels a security concern or just a usability one?

Both. Labels that overlap produce valid-but-wrong arguments, which look like correct answers and quietly pull the wrong data. Separately, tool responses themselves are a known attack channel: a malicious server can return text carrying hidden instructions that the model follows, so formats and access controls need to be enforced at runtime, not just in the description (OWASP). Label clarity fixes the first problem; structured responses and execution-layer controls fix the second.

How do I test whether my names work without a benchmark suite?

Build a small file of test prompts: five to ten phrasings per tool, plus near-miss prompts the tool must not match. Send them through the model you actually deploy, log which tool fired and compare against the expected one. Twenty to thirty cases run by hand will expose the worst collisions in an afternoon, and the same file becomes a regression check for every schema change after that.

Sources

Sources

  1. Function calling | OpenAI API
  2. MCP vs Function Calling: When to Use Which - Prefect
  3. Specification
  4. Resources
  5. Don't Adapt Small Language Models for Tools
  6. Don't Adapt Small Language Models for Tools
  7. MCP Tool Poisoning | OWASP Foundation
  8. LLM-Matcher: A Name-Based Schema Matching Tool ...
  9. The guide to structured outputs and function calling with LLMs - Agenta-AI
  10. Prompts
  11. MCP vs API: When to Use Each (and Why You Need Both) - Mitiga.io
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles