Guide 06 · 6 min read

Designing a tool set

More tools is not more capability. Learn how to choose a small menu, name and describe each tool so the model picks the right one, and hide the mess behind wrappers.

Once you know how schemas work, the next question is bigger: which tools should the model get at all? It is easy to keep adding tools whenever something is missing. This guide explains why that slowly makes an agent worse, and how to design a menu the model can use well.

01

The menu is a user interface, and the user is a model

When you design a screen for people, you think about what they can see, what the labels say, and how many buttons there are. A tool menu is the same thing, with a different reader. The model looks at the list of tools, decides which one fits, and fills in the arguments. Every call it makes starts from that menu.

So all the usual design rules apply. Clear labels. Few choices. No two buttons that do nearly the same thing. A model has no way to ask you what you meant, and it cannot try a button to see what it does. It gets the names and descriptions and has to decide.

02

Why a bigger menu makes things worse

Adding a tool feels like adding capability. Often it does the opposite.

  • More choices means more wrong choices. With twelve tools, the model has more ways to pick badly. Each extra tool is another thing to confuse with the right one.
  • Overlap creates coin flips. If search_code, find_in_repo, and lookup all search, the model picks one more or less at random, and may pick the one that is slightly broken.
  • Every schema costs tokens, every call. The whole menu is sent on every step. Twelve long descriptions can use a real fraction of a small budget before the model has done anything.
  • Behavior becomes harder to predict. A run might use one tool one day and its near-twin the next. That makes traces harder to read and results harder to repeat.

None of this means "fewer is always better". A menu that is too small leaves the model unable to do the job. The aim is the smallest menu that still covers what the task needs, and no smaller.

03

A messy menu, and a clean one

Here is a menu a team might end up with while building a support-desk agent. Every tool was added for a reason at the time.

before
1find_ticket(id)           get_ticket(ticket_id)2search_tickets(text)      lookup(query)3list_tickets_by_user(u)   tickets_for_customer(customer)4read_ticket_notes(id)     get_notes(id, limit)

Eight tools, and really three jobs: fetch one ticket, search for tickets, and read a ticket's notes. Two tools per job, with slightly different argument names and, probably, slightly different behavior.

Collapsed, the menu becomes:

after
1get_ticket(ticket_id)                     one ticket, in full2search_tickets(text, customer=None)       matching tickets, one line each3get_notes(ticket_id, limit=20)            the notes on one ticket

Three tools, one for each job, with no overlap. The "by user" tools disappeared because they were search_tickets with a filter. That is the main move in menu design: merge things that differ only by an argument.

04

Principles for each tool

One tool, one job

A tool should be easy to describe in a single sentence that does not contain the word "and". If it is hard to say what a tool is for, the model will find it hard to decide when to use it.

Names say what it does

Prefer plain verbs and nouns: search_tickets, get_notes. Avoid names that could mean several things, such as lookup, fetch, handle, or process. Use one naming pattern across the set, so that the model can predict it. If one tool says ticket_id and another says id for the same thing, you invite mistakes.

Descriptions separate the neighbors

Where two tools are close, say how they differ and when to prefer each. "Use get_ticket when you already have an id. Use search_tickets when you only have words." That one sentence prevents most confusion.

Arguments are few and obvious

Prefer a couple of well-named arguments to many optional ones. If you find yourself adding a fifth or sixth argument, ask whether this is really two tools.

Results look the same everywhere

When tools in a set return results in a consistent format, one line per item with the same labeled fields, the model learns it once and reads every result easily. Mixed formats make it work harder.

05

Wrappers: hide the mess, keep the power

You often cannot change the underlying functions. They may come from a library, or a legacy system, or a teammate. But the model does not have to see them. You can put a wrapper between the model and the real functions.

A wrapper is a small function you write that you present to the model in place of the underlying ones. It can:

  • have a better name and description,
  • accept arguments in a friendlier shape,
  • fill in safe defaults,
  • call whichever underlying function is right for the request,
  • and return results in a clean, consistent format.
wrapper.py
1def search_tickets(text: str, customer: str | None = None) -> str:2    """One entry point that hides two messy back-end calls."""3    if customer:4        rows = backend.tickets_for_customer(customer)5        rows = [r for r in rows if text.lower() in r.lower()]6    else:7        rows = backend.lookup(text)8    return "\n".join(rows[:20]) or "No matching tickets."

Behind the wrapper you can keep all the original tools. The model only sees the one you designed. The menu stays small and the capabilities do not shrink.

You also need a dispatcher: a function that takes the name and arguments the model sent and routes them to the right wrapper. Keep it simple, and make it return a clear error message for a name it does not recognize.

06

Test the menu like you would test code

You cannot tell whether a menu is good by reading it. You find out by watching a model use it.

  1. Read real traces. Which tools did the model call? Did it ever call a near-twin of the one you wanted? Did it call a tool with the wrong arguments?
  2. Look for confusion. If two tools appear in similar situations, they probably overlap. Merge them or sharpen the descriptions.
  3. Look for dead weight. A tool that is never called is costing tokens on every step. Consider removing it.
  4. Check coverage. Walk through every kind of task. Is there a job that no tool can do? Then the menu is too small.
  5. Change one thing at a time. Rename one tool, or merge one pair, and compare the traces. That way you know what helped.

07

A note on limits

Some systems cap the number of tools you may expose, and that is a useful discipline. A hard cap forces the question you should be asking anyway: which of these tools actually earn their place?

Be sure to know how your platform treats the cap. If exceeding it fails the entire submission, check the count first, in code, before anything else runs.

08

Where this shows up

Problem 07 hands you a pile of overlapping, awkwardly named functions and a limit on how many the model may see. You will not be rewarded for a cleverer prompt over the same mess. You will be rewarded for deciding what the model is allowed to call, naming it so that it is hard to misuse, and doing the plumbing behind the scenes.

Sign in to Harness Dojo

Save your progress, submit to the hidden set, and track your solved problems.