Blog Post #19: The Theory of Tool Use: What Makes a Good Tool for an Agent?

Imagine handing a power drill to someone who has never seen one before. You don’t give them a manual, the buttons aren’t labeled, and you just say, “Here, use this thing.” The result would be confusion at best, and a hole in the wall at worst. This is what it’s like to give a poorly designed tool to an AI agent.

So far, we’ve discussed how agents can decide to use tools via the ReAct loop. But this brings up a critical question: how does the agent know what tools are available and how to use them? An agent doesn’t “read” your Python code. It reads a textual description of your code.

If that description is vague, ambiguous, or inaccurate, the agent will fail. It might call the wrong tool, provide the wrong arguments, or get stuck in a loop. Therefore, designing a good tool for an agent is an exercise in writing excellent documentation for a machine.

The Agent is the “User” of Your Code

This is the most important mental shift you must make. You are no longer just writing a Python function for another developer to call. You are designing an API for a non-human, highly intelligent, but extremely literal-minded user—the LLM.

When an agent needs to act, its underlying LLM is shown a list of available tools. The LLM’s entire decision is based on the names and descriptions of these tools.

Bad Description: The agent will ignore your tool or use it incorrectly.

Good Description: The agent will reliably select your tool for the right job and provide the correct parameters.

The “user interface” for your agent’s tools are its docstrings and type hints. Let’s break down how to master them.

The Anatomy of a Perfect Tool: The Docstring

The docstring is the instruction manual for your tool. It needs to be crystal clear.

Principle 1: The One-Liner is King

The first line of the docstring should be a concise, active summary of exactly what the tool does. This is often the most important piece of information for the LLM’s initial decision.

Bad: """This function gets some information.""" (Vague and useless)

Good: """Retrieves the current time for a specified timezone.""" (Clear, active, and specific)

Principle 2: Describe Every Parameter in Detail

Don’t assume the agent knows what a parameter means. Explain each one, its expected data type, and provide an example.

Bad: """Args: timezone: the timezone"""

Good: """ Args: timezone (str): The IANA timezone name, e.g., 'America/New_York' or 'Asia/Kolkata'. """

The example is crucial. It gives the LLM a concrete idea of the format it needs to generate.

Principle 3: Explain the Return Value

What should the agent expect to get back when it calls this function? Be explicit about the format and content of the successful return value.

Good: """Returns: A string containing the current time formatted as HH:MM:SS."""

The Secret Weapon: Python Type Hints

While docstrings provide human-readable (and LLM-readable) context, Python’s type hints provide a rigid, unambiguous structure. Modern agentic frameworks are increasingly reliant on type hints to understand your tools, often using them to generate the final description shown to the LLM.

Why Type Hints are Critical:

  • Unambiguity: timezone: str is a machine-readable fact. It’s not open to interpretation like a natural language sentence.
  • Validation: Frameworks can use type hints to validate the LLM’s generated arguments before they are even passed to your function, catching errors early.
  • Structured Data: For complex inputs and outputs (like a JSON object), you can use libraries like Pydantic, which are built entirely on type hints, to define a rigid schema.

Putting It All Together: A Well-Designed Tool

Let’s combine these principles to create a professional, agent-ready tool.

from datetime import datetime
import pytz

def get_current_time(timezone: str) -> str:
    """Retrieves the current time for a specified IANA timezone.

    Args:
        timezone (str): The IANA timezone name to get the current time for,
                      e.g., 'America/New_York' or 'Asia/Kolkata'.

    Returns:
        str: A string containing the current time in the specified timezone,
             formatted as 'HH:MM:SS', or an error message if the
             timezone is invalid.
    """
    try:
        tz = pytz.timezone(timezone)
        current_time = datetime.now(tz)
        return current_time.strftime('%H:%M:%S')
    except pytz.UnknownTimeZoneError:
        logger.error(f"Invalid timezone provided: {timezone}")
        return f"Error: The timezone '{timezone}' is not a valid IANA timezone."

Notice how the type hints (timezone: str and -> str) work together with the detailed docstring to create a perfect, unambiguous description of the tool. The error handling also provides a clean Observation for the agent if it makes a mistake.

High-Level Principles for Good Tool Design

  1. Be Atomic: Prefer several simple, single-purpose tools over one complex tool that does many things. (e.g., get_user_profile and update_user_address are better than one giant manage_user tool).
  2. Be Deterministic: A tool should, as much as possible, produce the same output for the same input.
  3. Handle Errors Gracefully: A tool should never crash the agent. It should catch exceptions and return a helpful error message as a string. The agent can then observe the error and try to correct itself.

Conclusion

The tools you provide to your agent are its only connection to the outside world. The quality of your agent is therefore directly limited by the quality and clarity of its tools. When designing them, remember your user: a very powerful, very literal-minded machine that relies entirely on your descriptions to make its decisions.

By mastering the art of writing clean, well-documented, and strongly-typed functions, you move from being a user of agentic frameworks to a true architect of capable and reliable AI systems.

Author

Debjeet Bhowmik

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com

Leave a Comment