04. Tool Definition

Chapter 4 of 16 · 15 min

A tool requires four things: a name, a human-readable description, an input schema, and an implementation. The input schema follows JSON Schema draft 2020-12 and tells the model what arguments are available and what types they expect.

Writing tool descriptions

The description is the most impactful part of tool definition. It must be specific enough that the model can distinguish this tool from others. Avoid vague language.

def create_web_search_tool(base_url: str = "https://api.example.com/search"):
    return Tool(
        name="web_search",
        description=(
            "Search the web for information about a given query. "
            "Returns up to 10 results with title, URL, and snippet. "
            "Use for factual lookup, news, product information, or any "
            "question requiring current external data."
        ),
        input_schema={
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": (
                        "The search query. Use specific terms. "
                        "Avoid questions; use keyword phrases instead."
                    ),
                    "minLength": 2
                },
                "num_results": {
                    "type": "integer",
                    "description": "Number of results to return (default: 5, max: 10)",
                    "default": 5
                }
            },
            "required": ["query"]
        }
    )

Schema constraints

  • description on each property is mandatory. The model reads it to decide what to pass.
  • Use enum to limit choices when the model should pick from a known set.
  • Set default values so omitting an optional argument does not crash the tool.
  • Mark required properties in the required array.

Tool naming conventions

Names should be lowercase with underscores. Avoid names that are too generic like "search" or "get"—use "web_search" or "db_query" to prevent collisions.

Testing tool definitions

Validate your schemas before deployment by running JSON Schema validators:

from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "properties": {
        "query": {"type": "string", "minLength": 2}
    },
    "required": ["query"]
}

# Test valid input
try:
    validate(instance={"query": "weather in NYC"}, schema=schema)
    print("Valid")
except ValidationError as e:
    print(f"Invalid: {e.message}")

# Test invalid input
try:
    validate(instance={"query": "a"}, schema=schema)
except ValidationError as e:
    print(f"Correctly caught invalid input: {e.message}")
EXERCISE

Define a tool that fetches a specific file from local disk. Write the schema, test it with a valid and invalid path, and verify the tool implementation returns the file contents or an appropriate error message.