Level: Advanced Updated: August 2026

Tool Use — tools for agents

A good agent is only as good as the tools you gave it. How to design tools the model understands, calls correctly, and doesn't break. The practical guide.

In the Structured Outputs & Tool Use guide we saw the basic mechanics of function calling. Here we go deeper into design — how to build tools an AI agent can actually use successfully, which is the art that separates an agent that works from one that gets stuck.

The agent loop — a reminder

An agent runs in a loop: the model gets a goal + a list of tools, decides which to call, the code runs them and returns results, and repeats until the task is done.

while not done:
    response = model.generate(messages, tools=TOOLS)
    if response.tool_calls:
        for call in response.tool_calls:
            result = run_tool(call.name, call.input)   # your code runs it
            messages.append(tool_result(call.id, result))
    else:
        done = True   # the model finished and returned a final answer

The tools are the model's "hands." If they're poorly designed — the agent will choose wrong, send wrong parameters, or get into loops.

Designing a good tool — 6 principles

  1. Clear name and description. The description is the tool's "prompt." get_order_status with the description "returns an order's status by order number" is far better than lookup with no explanation. Write when to use it and when not to.
  2. Few, well-defined parameters. Each parameter with a description, a type and an enum where possible. Fewer parameters = fewer errors.
  3. One tool = one task. Don't build a mega-tool that does ten things by a flag. Split into focused tools.
  4. Concise results. Return only what the model needs. Don't return 5,000 lines of JSON — filter/summarize (see Context Engineering).
  5. Limit the number of tools. Too many tools confuse it. If there are many, group by context or use dynamic retrieval.
  6. Consistent naming. The same convention for all tools — it's easy for the model to learn the pattern.
lightbulb
The key insight

Most "agent failures" are actually tool-design failures — a vague description or a bloated result. Improve the tools before you blame the model.

Error handling — don't let a tool crash the agent

A tool that fails should return a clear error message to the model, not crash. The model can read the error and try differently:

def run_tool(name, args):
    try:
        return TOOLS[name](**args)
    except Exception as e:
        # return the error to the model as a result, don't raise
        return {"error": str(e), "hint": "check the parameters and try again"}

Human-in-the-loop — for dangerous tools

Not every action should run automatically. Tools that perform an irreversible action (sending an email to a customer, making a payment, deleting data) need human approval before running. Design the flow so the agent proposes the action, and a human approves.

Orchestrating multiple tools

When a task requires a sequence of tools (search → filter → act), the model manages the order. For this to work:

Security — tools are an attack surface

A tool gives the model the ability to act in the real world — and that's dangerous if the model is "influenced" by prompt injection:

rocket_launch

Next step

Build a full agent, connect tools in a standard way with MCP, and secure it.