Building Custom Tools
Building Custom Tools
Section titled “Building Custom Tools”While CrewAI comes with a robust toolkit, real-world applications often require unique integrations—proprietary internal APIs, specific database queries, or complex data transformations. This is where Custom Tools shine.
Two Ways to Build
Section titled “Two Ways to Build”CrewAI offers two primary methods for creating custom tools:
- The
@toolDecorator: Quick, function-based, ideal for simple logic. - Subclassing
BaseTool: Object-oriented, supports complex arguments and validation, ideal for production.
Method 1: The @tool Decorator
Section titled “Method 1: The @tool Decorator”For simple functions, you can decorate a Python function. The docstring is critical here—it becomes the description the Agent reads to understand when to use the tool.
from crewai.tools import tool
@tool("Calculate Length")def calculate_length(text: str) -> int: """Returns the length of the text provided.""" return len(text)
# Usage in Agentagent = Agent(..., tools=[calculate_length])Method 2: Subclassing BaseTool (Recommended)
Section titled “Method 2: Subclassing BaseTool (Recommended)”For robust applications, we subclass BaseTool. This allows us to define a strict schema for the inputs using Pydantic. If the LLM tries to call your tool with missing or wrong data types, CrewAI will catch the error and ask the LLM to correct itself automatically.
Defining the Schema
Section titled “Defining the Schema”First, we define what inputs our tool expects using a Pydantic model.
from pydantic import BaseModel, Field
class CustomAPIToolInput(BaseModel): query: str = Field(..., description="The search query to send to the API") limit: int = Field(5, description="Max number of results to return")Implementing the Tool Logic
Section titled “Implementing the Tool Logic”Next, we implement the tool class, linking the schema and defining the _run method.
from crewai.tools import BaseToolfrom typing import Typeimport requests
class CustomSearchTool(BaseTool): name: str = "Internal Knowledge Search" description: str = ( "Useful for searching the company's internal documentation. " "Always use this before asking the user." ) args_schema: Type[BaseModel] = CustomAPIToolInput
def _run(self, query: str, limit: int = 5) -> str: # Your custom logic here response = requests.get( "https://api.internal.company/search", params={"q": query, "limit": limit} ) if response.status_code == 200: return response.text else: return f"Error fetching data: {response.status_code}"
# Instantiate and usecustom_tool = CustomSearchTool()Best Practices
Section titled “Best Practices”- Descriptive Names: The
nameanddescriptionare part of the prompt. Be specific. - Type Hinting: Always type hint your
_runmethod arguments. - Error Handling: Return clear error strings rather than raising exceptions directly if you want the Agent to try again or handle the failure gracefully.