04. Tool Definition
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
descriptionon each property is mandatory. The model reads it to decide what to pass.- Use
enumto limit choices when the model should pick from a known set. - Set
defaultvalues so omitting an optional argument does not crash the tool. - Mark required properties in the
requiredarray.
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}")
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.