CrewAI — role-based crews
Roles, tasks, and processes in CrewAI, and when a role-based crew beats a hand-built LangGraph.
Why this matters
CrewAI is the most beginner-friendly multi-agent framework — you describe agents as roles with goals and backstories, give them tasks, and CrewAI handles delegation. It is hugely popular in 2026 for cross-functional agent teams (research + analysis + writing + QA). It pairs especially well with stakeholders who can read and edit the role definitions.
Learning objectives
- Define agents, tasks, and crews.
- Pick between sequential and hierarchical processes.
- Use built-in tools (web search, file I/O) and custom tools.
- Wire CrewAI memory and human input.
- Know when to switch to LangGraph.
1. The CrewAI mental model
- Agent — a role/goal/backstory plus tools and an LLM.
- Task — a description, expected output, and (optionally) the agent who must do it.
- Crew — agents + tasks + a
Process(sequential or hierarchical).
Install:
uv add crewai crewai-tools2. Sequential crew (the easiest)
import os
from crewai import Agent, Task, Crew, Process, LLM
from crewai_tools import SerperDevTool, FileWriterTool
llm = LLM(model="openai/gpt-4.1-mini") # CrewAI uses litellm under the hood
researcher = Agent(
role="Senior Research Analyst",
goal="Find facts and citations on the topic",
backstory="A diligent analyst with a love for primary sources.",
tools=[SerperDevTool()], # web search
llm=llm,
verbose=True,
)
writer = Agent(
role="Tech Writer",
goal="Turn research into a 400-word post",
backstory="A clear, concise tech writer.",
tools=[FileWriterTool()],
llm=llm,
verbose=True,
)
t1 = Task(
description="Research the topic '{topic}'. Return 6 bullet points with citations.",
expected_output="A bulleted list of 6 facts with sources.",
agent=researcher,
)
t2 = Task(
description="Write a 400-word, engaging post for a developer audience using the research.",
expected_output="A markdown file `post.md`.",
agent=writer,
output_file="post.md",
context=[t1], # explicit dependency
)
crew = Crew(
agents=[researcher, writer],
tasks=[t1, t2],
process=Process.sequential,
verbose=True,
)
result = crew.kickoff(inputs={"topic": "Agentic AI in 2026"})
print(result.raw)Key points:
inputs={"topic": ...}substitutes{topic}placeholders.context=[t1]makest2aware oft1's output.output_file=writes to disk automatically.
3. Hierarchical crew (with a manager)
In hierarchical mode, you do not assign agents to tasks. The manager decides at runtime.
crew = Crew(
agents=[researcher, writer], # workers only — do NOT include the manager here
tasks=[t1, t2], # tasks may omit `agent=`
process=Process.hierarchical,
manager_llm="openai/gpt-4.1-mini", # OR pass manager_agent=...
planning=True, # crew plans before execution
verbose=True,
)
# OR with a custom manager agent:
manager = Agent(
role="Project Manager",
goal="Deliver the report on time at high quality",
backstory="An experienced PM who delegates effectively.",
allow_delegation=True,
llm=llm,
)
crew = Crew(
agents=[researcher, writer],
tasks=[t1, t2],
process=Process.hierarchical,
manager_agent=manager, # ← do NOT also put `manager` in `agents=...`
planning=True,
)Hard rules to remember:
- The manager agent must not be in
agents=...and must not have its own tools — CrewAI gives itDelegateWorkToolandAskQuestionToolautomatically. allow_delegation=Truebelongs on the manager only.- Workers are usually
allow_delegation=False.
4. Custom tools (with Pydantic schemas)
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
class FetchArgs(BaseModel):
url: str = Field(..., description="URL to fetch")
class FetchTool(BaseTool):
name: str = "fetch_page"
description: str = "Download a webpage and return text."
args_schema: type[BaseModel] = FetchArgs
def _run(self, url: str) -> str:
import httpx
return httpx.get(url, timeout=10).text[:5000]Drop FetchTool() into any agent's tools=[...].
5. Memory and human input
crew = Crew(
agents=[...], tasks=[...],
process=Process.sequential,
memory=True, # short-term + long-term memory enabled
embedder={"provider": "openai", "config": {"model": "text-embedding-3-small"}},
)For human input on a specific task:
t_review = Task(
description="Review the draft. Point out 3 issues.",
expected_output="3 bulleted issues",
agent=writer,
human_input=True, # CLI prompts the user before this task completes
)For a UI-driven workflow you usually wrap CrewAI in a FastAPI/Streamlit and capture human input through your own forms instead.
6. Async, batching, training
crew.kickoff_async(inputs=...)for async runs.crew.kickoff_for_each(inputs_list=...)for batches (parallelism per worker count).crew.train(n_iterations=5, inputs=...)to gather feedback and refine prompts (CrewAI's lightweight optimisation).
7. When to choose CrewAI vs LangGraph
| Need | Pick |
|---|---|
| Linear or hierarchical pipelines, business-readable code | CrewAI |
| Custom routing, cycles, HIL, sub-graphs, evals | LangGraph |
| Production observability with checkpointers and time-travel | LangGraph |
| Quick PoC for stakeholders | CrewAI |
It is fine — and common — to combine. Use LangGraph as the production backbone and embed a CrewAI crew as one node when a sub-task is naturally a "crew."
8. CrewAI Flows (the LangGraph competitor)
In late 2024 CrewAI added Flows — a state machine layer (similar to LangGraph) that you can use with or without a Crew. Decorators: @start, @listen, @router. If you really like CrewAI's syntax and want graph control, look at Flows. For deeply complex agent topologies, LangGraph still pulls ahead in 2026.
Hands-on lab (5 hours)
Build a product-launch crew:
market_research(web search).competitor_analysis(search + structured comparison).messaging_writer(drafts taglines and copy).qa_reviewer(proofreads).
Requirements:
- Use hierarchical process with a custom
Project Manageragent. - Add a custom
FetchToolfor pulling competitor websites. - Memory on; export final files to
out/. - Wrap in a FastAPI endpoint
POST /launchthat takes{topic, competitors: [..]}. - Document one experiment where you swap the manager LLM (gpt-4.1-mini ↔ claude-opus-4-7) and report the cost/quality difference.
Common pitfalls
- Putting the manager into
agents=...— the runtime misroutes tasks. - Tools on the manager — never. The manager only delegates.
- No
expected_output— tasks complete unpredictably. - Forgetting
context=[t1]— later tasks miss earlier output. - Using
Process.hierarchicalwithoutmanager_llmormanager_agent— runtime error.
Self-check
- What does
Process.hierarchicalactually change at runtime? - Why must the manager not have tools?
- How do
context=[...]task dependencies differ from a graph edge? - When do you reach for CrewAI Flows over a plain Crew?
- How does CrewAI handle memory under the hood?
References
Sign in to save your progress and earn badges.