CrewAI Guide: Build AI Agent Teams in Python
CrewAI is a Python framework for orchestrating teams of AI agents, where each agent has a defined role, goal, and set of tools. The framework uses a crew metaphor: you assemble a team, assign tasks, and let the agents collaborate to complete a complex project. CrewAI has rapidly become one of the most popular multi-agent frameworks thanks to its clean API, good documentation, and active community.
Core Concepts
Before writing code, understand the four building blocks:
- Agent: An autonomous entity with a role, goal, backstory, and optionally tools. Think of an agent as a specialist you’re hiring.
- Task: A specific piece of work assigned to an agent, with a description and expected output.
- Tool: A function an agent can call to interact with the outside world — web search, file reading, API calls.
- Crew: The team that brings agents and tasks together, defining the process (sequential or hierarchical).
Installation
pip install crewai
For built-in tools (web search, file reading, etc.):
pip install crewai[tools]
CrewAI uses LangChain under the hood for LLM integration. Set your API key:
export OPENAI_API_KEY="sk-..."
# Or for Anthropic Claude:
export ANTHROPIC_API_KEY="sk-ant-api03-..."
Your First Crew: A Simple Research Team
Let’s build a two-agent crew that researches a topic and writes a summary.
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool
# Optional: web search tool
search_tool = SerperDevTool() # requires SERPER_API_KEY env var
# Define agents
researcher = Agent(
role="Senior Research Analyst",
goal="Uncover cutting-edge developments and provide thorough, accurate research",
backstory="""You are an expert research analyst with 10 years of experience
in technology and AI. You excel at finding reliable sources and synthesizing
complex information into clear insights.""",
verbose=True,
allow_delegation=False,
tools=[search_tool]
)
writer = Agent(
role="Tech Content Writer",
goal="Write engaging, accurate technical content that is accessible to developers",
backstory="""You are a skilled technical writer who transforms complex research
into clear, well-structured articles. You understand developer audiences and
write with precision and clarity.""",
verbose=True,
allow_delegation=False
)
# Define tasks
research_task = Task(
description="""Research the current state of AI coding assistants in 2026.
Focus on: key players, feature comparisons, pricing, and adoption trends.
Provide at least 5 specific findings with supporting details.""",
expected_output="""A detailed research report with 5+ key findings,
specific data points, and source references.""",
agent=researcher
)
writing_task = Task(
description="""Using the research provided, write a comprehensive blog post
about AI coding assistants in 2026. Include:
- An engaging introduction
- Key players and their differentiators
- A comparison table
- Recommendations for different developer types
- A conclusion
Target length: 800-1000 words. Use markdown formatting.""",
expected_output="""A complete, publication-ready blog post in markdown format
with headers, a comparison table, and clear recommendations.""",
agent=writer
)
# Assemble the crew
crew = Crew(
agents=[researcher, writer],
tasks=[research_task, writing_task],
process=Process.sequential, # Tasks run in order
verbose=True
)
# Run it
result = crew.kickoff()
print(result)
Defining Agents with Roles, Goals, and Backstories
The three key fields — role, goal, and backstory — are more important than they might seem. They’re injected directly into the agent’s system prompt and shape how it approaches every task.
Role
Defines the agent’s title and specialty. Keep it specific:
- Bad: “AI Assistant”
- Good: “Python Security Auditor specializing in OWASP Top 10”
Goal
The agent’s primary objective, written as an imperative:
goal="Identify security vulnerabilities in Python code and provide actionable remediation steps"
Backstory
Context that gives the agent its “expertise” and reasoning style:
backstory="""You have 15 years of experience in application security,
have conducted hundreds of penetration tests, and have a deep understanding
of common Python vulnerabilities including SQL injection, XSS, and insecure
deserialization. You think methodically and prioritize findings by severity."""
Well-crafted backstories significantly improve output quality.
Sequential vs Hierarchical Process
CrewAI supports two primary execution patterns:
Sequential Process (Default)
Tasks execute one after another in the order defined. Each task’s output is available to subsequent tasks.
crew = Crew(
agents=[researcher, analyst, writer],
tasks=[research_task, analysis_task, writing_task],
process=Process.sequential
)
Best for: Linear workflows where each step builds on the previous one.
Hierarchical Process
A manager agent orchestrates the other agents, deciding which agent handles which task and in what order. This is more dynamic and suitable for complex, branching workflows.
from crewai import LLM
manager_llm = LLM(model="gpt-4o")
crew = Crew(
agents=[researcher, analyst, writer, reviewer],
tasks=[complex_project_task], # Single high-level task
process=Process.hierarchical,
manager_llm=manager_llm,
verbose=True
)
In hierarchical mode, you typically define a single high-level task and let the manager agent break it down and delegate to specialists.
Adding Tools to Agents
Tools are Python functions that agents can call to interact with external systems.
Built-in CrewAI Tools
from crewai_tools import (
SerperDevTool, # Web search via Serper API
ScrapeWebsiteTool, # Scrape a webpage
FileReadTool, # Read local files
DirectoryReadTool, # List directory contents
CodeInterpreterTool, # Execute Python code
GithubSearchTool # Search GitHub repos
)
# Give an agent multiple tools
data_analyst = Agent(
role="Data Analyst",
goal="Analyze datasets and provide statistical insights",
backstory="Expert data analyst with strong Python and statistics skills.",
tools=[
FileReadTool(),
CodeInterpreterTool()
]
)
Custom Tools
Create any function as a tool using the @tool decorator:
from crewai.tools import tool
import requests
@tool("Get Cryptocurrency Price")
def get_crypto_price(symbol: str) -> str:
"""Fetch the current price of a cryptocurrency by symbol (e.g., BTC, ETH)."""
url = f"https://api.coingecko.com/api/v3/simple/price?ids={symbol}&vs_currencies=usd"
response = requests.get(url)
data = response.json()
return f"{symbol}: ${data.get(symbol, {}).get('usd', 'N/A')}"
# Attach to agent
crypto_analyst = Agent(
role="Crypto Market Analyst",
goal="Monitor and analyze cryptocurrency prices",
backstory="Financial analyst specializing in digital assets.",
tools=[get_crypto_price]
)
Configuring the LLM
By default CrewAI uses OpenAI’s GPT-4. To use Claude:
from crewai import LLM
claude_llm = LLM(
model="claude-opus-4-5",
api_key="sk-ant-api03-..."
)
agent = Agent(
role="Senior Developer",
goal="Write high-quality Python code",
backstory="Experienced software engineer.",
llm=claude_llm
)
Use different models for different agents to balance cost and capability:
# Expensive model for planning
planner = Agent(role="Planner", llm=LLM(model="claude-opus-4-5", ...))
# Cheaper model for routine tasks
formatter = Agent(role="Formatter", llm=LLM(model="claude-haiku-3-5", ...))
Practical Example: Automated Research Pipeline
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
search = SerperDevTool()
scraper = ScrapeWebsiteTool()
researcher = Agent(
role="Lead Researcher",
goal="Find comprehensive information about the given topic from reliable sources",
backstory="Academic researcher with expertise in evaluating source credibility.",
tools=[search, scraper],
verbose=True
)
fact_checker = Agent(
role="Fact Checker",
goal="Verify claims and identify any inaccuracies in the research",
backstory="Experienced journalist known for rigorous fact-checking.",
tools=[search],
verbose=True
)
summarizer = Agent(
role="Executive Summarizer",
goal="Create concise, actionable summaries for decision-makers",
backstory="Former management consultant who excels at distilling complex info.",
verbose=True
)
topic = "The impact of AI agents on software developer productivity in 2026"
crew = Crew(
agents=[researcher, fact_checker, summarizer],
tasks=[
Task(description=f"Research: {topic}", expected_output="Detailed findings", agent=researcher),
Task(description="Fact-check the research findings and flag any unverified claims", expected_output="Verified research with confidence ratings", agent=fact_checker),
Task(description="Create a 300-word executive summary of the verified findings", expected_output="Concise executive summary", agent=summarizer)
],
process=Process.sequential,
verbose=True
)
result = crew.kickoff()
print(result.raw)
Memory and Learning
CrewAI supports memory to help agents learn from past interactions:
crew = Crew(
agents=[...],
tasks=[...],
memory=True, # Enable long-term memory
embedder={
"provider": "openai",
"config": {"model": "text-embedding-3-small"}
}
)
With memory enabled, agents can recall information from previous crew runs, making them more effective over time for recurring tasks.
CrewAI strikes an excellent balance between simplicity and power. For most multi-agent use cases — research pipelines, content generation, code analysis, report generation — it provides exactly the right abstractions without overwhelming complexity.