DS DevShelfHub Projects · AI tools
Tutorials / CrewAI / Reference / Classes / BaseTool
Class tools

BaseTool: Reference Guide

By DevShelfHub

Subclass-this base for custom tools — defines name, description, args_schema, _run, _arun.

See the CrewAI API reference index, CrewAI introduction, and core concepts for surrounding context.

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

python
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

python
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

python
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

python
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.