What is BaseTool?
BaseTool is the object-oriented tool surface in CrewAI: you declare name and description as class attributes so the LLM sees a stable tool catalog entry, define args_schema as a Pydantic model for structured inputs, and implement _run for synchronous execution with optional _arun for asyncio-native backends. The framework wraps exceptions, feeds results back into the agent loop, and respects caching when enabled on the owning Agent.
Reach for BaseTool instead of the @tool decorator when you need persistent state (database pools, OAuth sessions), inheritance to share behavior across several tools, or custom validation hooks that are awkward to express as a single function. Keep descriptions short but intention-revealing — the model chooses tools based on this text more than on the class name.
Security-wise, BaseTool runs in the same process as your crew. Treat _run like a network-facing handler: validate paths, enforce authz, and never let the model supply raw SQL without parameterization. Combine with @before_tool_call_crew hooks for global gates when multiple tools share policy.
When to Use
Stateful integrations, shared base classes for a family of tools, or anything that fits OOP better than @tool.
Use Cases
- • Internal APIs
- • Custom data sources
- • Compound tools with shared setup
Key Features
- ✓ Pydantic args_schema
- ✓ Sync + async bodies
- ✓ Reusable across agents
When NOT to Use
One-off pure functions — use @tool for less boilerplate.
Notes
args_schema quality
Rich Field descriptions become part of the tool schema the model sees. Invest in them — they reduce malformed calls more than long prose in the class docstring.
Async backends
If your integration is natively async, implement _arun and keep _run thin or raise NotImplementedError. Mixing blocking calls inside async loops stalls the whole event loop.
Caching side effects
Agent-level caching deduplicates identical tool inputs. Tools that perform writes or time-sensitive reads should document whether caching is safe; callers may need cache=False on the agent.
Import
from crewai.tools import BaseTool
Key Parameters
| Parameter | Type | Default | Purpose |
|---|---|---|---|
| name | str | — | Tool name presented to the agent. |
| description | str | — | Helps the agent decide when to call it. |
| args_schema | type[BaseModel] | — | Pydantic input schema. |
Code Examples
Stateful counter tool
from pydantic import BaseModel, Field
from crewai.tools import BaseTool
class TickInput(BaseModel):
delta: int = Field(default=1, ge=1, le=10)
class CounterTool(BaseTool):
name = 'counter'
description = 'Increment an in-memory counter'
args_schema = TickInput
def __init__(self):
super().__init__()
self._value = 0
def _run(self, delta: int) -> str:
self._value += delta
return f'value={self._value}'
HTTP GET tool sketch
import requests
from pydantic import BaseModel, HttpUrl
from crewai.tools import BaseTool
class FetchInput(BaseModel):
url: HttpUrl
class HttpGetTool(BaseTool):
name = 'http_get'
description = 'Fetch text from an allowlisted HTTPS URL'
args_schema = FetchInput
def _run(self, url: HttpUrl) -> str:
if not str(url).startswith('https://api.internal/'):
raise ValueError('URL not allowlisted')
return requests.get(str(url), timeout=10).text[:8000]
Self-contained agent + tool
from pydantic import BaseModel, Field
from crewai import Agent
from crewai.tools import BaseTool
class StepInput(BaseModel):
delta: int = Field(default=1, ge=1, le=5)
class StepTool(BaseTool):
name = 'step_counter'
description = 'Increment an internal counter by delta'
args_schema = StepInput
_value = 0
def _run(self, delta: int) -> str:
StepTool._value += delta
return f'value={StepTool._value}'
agent = Agent(
role='Demo',
goal='Call the counter',
backstory='You only use tools when asked.',
tools=[StepTool()],
)
Common Mistakes
❌ Missing args_schema
✅ Define a Pydantic model for typed inputs.
❌ Vague description strings like 'Does stuff'
✅ Describe exact inputs, outputs, and side effects so the model schedules the tool intentionally.
BaseTool FAQ
What is BaseTool in CrewAI?
Subclass-this base for custom tools — defines name, description, args_schema, _run, _arun. BaseTool is the object-oriented tool surface in CrewAI: you declare name and description as class attributes so the LLM sees a stable tool catalog entry, define args_schema as a Pydantic model for structured inputs, and implement _run for synchronous execution with optional _arun for asyncio-native backends. The framework wraps exceptions, feeds results back into the agent loop, and respects caching when enabled on the owning Agent. Reach for BaseTool instead of the @tool de…
Which package defines the CrewAI class BaseTool?
DevShelfHub maps BaseTool to Python module crewai.tools (package path crewai.tools in this reference). Pin your installed crewai version and match imports to the snippet on this page.
When should I use BaseTool?
Stateful integrations, shared base classes for a family of tools, or anything that fits OOP better than @tool.
When should I avoid using BaseTool?
One-off pure functions — use @tool for less boilerplate.
How do I import BaseTool in Python?
from crewai.tools import BaseTool
Where can I explore more CrewAI API reference pages?
Open the CrewAI API reference index on DevShelfHub to search 58 classes, 30 methods, and 16 decorators, each with runnable examples, parameters, common mistakes, and cross-links.