CrewAI Tools Integration: Let Agents Search, Read, and Actually Do Work
2 min read
An agent without tools is like an engineer with plenty of theory but no keyboard.
Can talk a lot, but cannot ship.
Common built-in tools
Frequently used CrewAI tools include:
SerperDevTool: web searchFileReadTool: read filesFileWriterTool: write filesScrapeWebsiteTool: scrape webpage content
Attach tools to an agent
from crewai import Agent
from crewai_tools import SerperDevTool
search_tool = SerperDevTool()
researcher = Agent(
role="Researcher",
goal="Find trustworthy sources about the topic",
backstory="You validate facts before writing.",
tools=[search_tool],
allow_delegation=False,
verbose=True,
)💡 You can reuse the same
search_toolacross agents. No need to recreate it every time (DRY).
Minimal custom tool template
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
class QueryInput(BaseModel):
keyword: str = Field(description="Search keyword")
class KeywordTool(BaseTool):
name: str = "Keyword Tool"
description: str = "Return a short explanation for a keyword."
args_schema: type[BaseModel] = QueryInput
def _run(self, keyword: str) -> str:
return f"Result for: {keyword}"Four tool design rules
- Do one thing only: if it searches, do not also write files
- Be explicit:
descriptionshould clearly state purpose and input - Validate parameters: use Pydantic schema
- Return stable format: easier for downstream tasks to parse
Common errors
| Symptom | Cause | Fix |
|---|---|---|
| Tool never called | Task prompt does not explicitly require it | Add explicit "use tool first" instruction in task |
| Bad parameter values | args schema is unclear | Add Field(description=...) |
| Hard-to-use output | Free-form text too scattered | Return fixed sections or JSON string |
Next step
After tools, the next focus is output consistency.
Next post shows how to lock format with Pydantic:
👉 Structured Output with Pydantic