Tools
Tools are the capabilities that you provide to your agents, allowing them to perform specific actions or access external services. ToolAgents offers a flexible system for creating and managing tools.
Core Tool Concepts
ToolRegistry
The ToolRegistry is a container for organizing and managing tools:
from ToolAgents import ToolRegistry
# Create a registry
tool_registry = ToolRegistry()
# Add tools
tool_registry.add_tool(your_tool)
tool_registry.add_tools([tool1, tool2, tool3])
# Get a tool by name
calculator_tool = tool_registry.get_tool("calculator")
# Check if a tool exists
has_weather_tool = tool_registry.has_tool("get_weather")
FunctionTool
FunctionTool is the primary way to create tools in ToolAgents. It can wrap Python functions, Pydantic models, or OpenAI-style function specifications:
from ToolAgents import FunctionTool
# Create from a function
function_tool = FunctionTool(your_function)
# Create from a Pydantic model
model_tool = FunctionTool(YourPydanticModel)
# Create from an OpenAI tool spec
openai_tool = FunctionTool.from_openai_tool(openai_tool_spec, implementation_function)
Creating Tools
Function-Based Tools
Create tools from Python functions with type hints and docstrings:
from ToolAgents import FunctionTool
def calculate_age(birth_year: int, current_year: int = 2024) -> int:
"""
Calculate a person's age based on their birth year.
Args:
birth_year: The year the person was born
current_year: The current year (defaults to 2024)
Returns:
The person's age in years
"""
return current_year - birth_year
age_calculator = FunctionTool(calculate_age)
Pydantic Model-Based Tools
Create more complex tools using Pydantic models:
from pydantic import BaseModel, Field
from typing import List, Optional
from ToolAgents import FunctionTool
class SearchTool(BaseModel):
"""
Search for information on a given topic.
"""
query: str = Field(..., description="The search query")
num_results: int = Field(5, description="Number of results to return")
include_snippets: bool = Field(True, description="Whether to include text snippets")
def run(self):
"""Execute the search and return results."""
# Implementation...
results = [f"Result {i} for '{self.query}'" for i in range(self.num_results)]
return results
search_tool = FunctionTool(SearchTool)
OpenAI-Style Tools
Create tools using OpenAI's function calling format:
from ToolAgents import FunctionTool
def translate_text(text, source_language, target_language):
"""Translate text between languages"""
# Implementation...
return f"Translated: {text} from {source_language} to {target_language}"
# OpenAI-style specification
translate_spec = {
"type": "function",
"function": {
"name": "translate_text",
"description": "Translate text from one language to another",
"parameters": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "The text to translate"
},
"source_language": {
"type": "string",
"description": "The source language code (e.g., 'en', 'fr', 'es')"
},
"target_language": {
"type": "string",
"description": "The target language code (e.g., 'en', 'fr', 'es')"
}
},
"required": ["text", "source_language", "target_language"]
}
}
}
translate_tool = FunctionTool.from_openai_tool(translate_spec, translate_text)
Advanced Tool Features
Pre-processors and Post-processors
Add processing steps before and after tool execution:
from ToolAgents import FunctionTool
def database_query(query: str) -> list:
"""Execute a database query"""
# Implementation...
return [{"id": 1, "name": "Example"}]
# Define pre-processor to sanitize input
def sanitize_query(parameters):
parameters["query"] = parameters["query"].strip().replace(";", "")
return parameters
# Define post-processor to format output
def format_results(results):
return {"count": len(results), "data": results}
# Create tool with processors
db_query_tool = FunctionTool(
database_query,
pre_processor=sanitize_query,
post_processor=format_results
)
Tool Documentation
The quality of your tool documentation directly impacts how effectively LLMs will use your tools:
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel, Field
from ToolAgents import FunctionTool
class SortOrder(Enum):
ASCENDING = "asc"
DESCENDING = "desc"
class SortItems(BaseModel):
"""
Sort a list of items in ascending or descending order.
This tool takes a list of comparable items (numbers or strings) and
sorts them according to the specified order. It can handle numerical
or alphabetical sorting.
"""
items: List[str] = Field(
...,
description="The items to sort. Can be numbers or strings. "
"Example: ['apple', 'banana', 'cherry'] or [10, 5, 8, 3]"
)
order: SortOrder = Field(
SortOrder.ASCENDING,
description="The sort order to use. 'asc' for ascending (smallest to largest), "
"'desc' for descending (largest to smallest)."
)
numeric: bool = Field(
False,
description="Whether to treat the items as numbers. If true, '10' will be sorted "
"after '2'. If false, standard string sorting applies."
)
def run(self):
"""
Sort the items and return the sorted list.
Returns:
A list containing the sorted items.
"""
if self.numeric:
# Convert strings to numbers if numeric sorting is requested
converted_items = [float(item) for item in self.items]
else:
converted_items = self.items
# Determine if we should reverse the sort
reverse = (self.order == SortOrder.DESCENDING)
# Perform the sort
sorted_items = sorted(converted_items, reverse=reverse)
return sorted_items
sort_tool = FunctionTool(SortItems)
Common Tool Categories
Data Processing Tools
def filter_data(data: list, condition: str) -> list:
"""
Filter a list of items based on a condition.
Args:
data: List of dictionaries to filter
condition: A Python expression like "item['age'] > 30"
Returns:
Filtered list of items
"""
return [item for item in data if eval(condition, {"__builtins__": {}}, {"item": item})]
filter_tool = FunctionTool(filter_data)
API Integration Tools
class APIRequest(BaseModel):
"""
Make an API request to an external service.
"""
url: str = Field(..., description="The API endpoint URL")
method: str = Field("GET", description="HTTP method: GET, POST, PUT, DELETE")
headers: dict = Field({}, description="HTTP headers to include")
body: Optional[dict] = Field(None, description="Request body for POST/PUT")
def run(self):
"""Execute the API request."""
import requests
if self.method.upper() == "GET":
response = requests.get(self.url, headers=self.headers)
elif self.method.upper() == "POST":
response = requests.post(self.url, headers=self.headers, json=self.body)
# Add other methods as needed
return {
"status_code": response.status_code,
"content": response.json() if response.headers.get("content-type") == "application/json" else response.text
}
api_tool = FunctionTool(APIRequest)
File Operation Tools
def read_file(file_path: str) -> str:
"""
Read the contents of a file.
Args:
file_path: Path to the file to read
Returns:
The contents of the file as a string
"""
with open(file_path, 'r') as file:
return file.read()
def write_file(file_path: str, content: str) -> str:
"""
Write content to a file.
Args:
file_path: Path to the file to write
content: Content to write to the file
Returns:
Confirmation message
"""
with open(file_path, 'w') as file:
file.write(content)
return f"Successfully wrote to {file_path}"
read_tool = FunctionTool(read_file)
write_tool = FunctionTool(write_file)
Best Practices
- Clear Documentation: Provide detailed descriptions of what each tool does
- Proper Typing: Use type hints to specify parameter types and return values
- Error Handling: Implement robust error handling within tools
- Sensible Defaults: Provide default values for optional parameters
- Validation: Use Pydantic's validation capabilities to ensure correct inputs
- Focused Functionality: Keep tools focused on specific tasks
- Consistent Naming: Use clear, consistent naming conventions
- Security Considerations: Validate inputs to prevent injection attacks
- Input Examples: Include examples in parameter descriptions
- Output Documentation: Describe the format and structure of tool outputs