Build a Multi-Agent System with CrewAI in 60 Minutes: A Python Tutorial
A 60-minute Python walkthrough that builds a Researcher + Writer + Editor crew with CrewAI, picks the right Process mode, and ships structured output.
What you’ll need
CrewAI is a role-based multi-agent framework where each agent has a job description, a set of tools, and a goal, like a small team of specialists you can spin up from Python. 1 This tutorial is for a dev with working Python skills, an OpenAI key (or any compatible LLM), and 60 minutes. By the end you have a Researcher + Writer + Editor crew, each with its own tools, running in either sequential or hierarchical mode, and emitting a structured Markdown report you can ship.
CrewAI’s strength is the team-of-roles mental model. It is easy to reason about, easy to swap an agent without rewriting the rest, and easy to debug when one role goes off the rails. Compared to LangGraph (a graph-of-agents library where you wire nodes and edges) or Smolagents (Hugging Face’s single-agent-plus-tools library), CrewAI sits in the middle of the design space: opinionated about roles, less opinionated about control flow. 2 Skip CrewAI if your workflow is genuinely single-agent with tool use, in which case Smolagents is lighter; skip it if you need fine-grained graph control over branching and looping, in which case LangGraph fits better.
Image: crewai.com landing page hero, used for editorial coverage of the framework.
Prerequisites:
- Python 3.10 or newer (CrewAI’s minimum on PyPI as of writing). 3
- An LLM API key. The default examples assume OpenAI, but the
llmparameter accepts any LangChain-compatible chat model. - A Serper API key (free tier available) if you want the Researcher agent to actually hit the web; skip it if you want to mock the tool while learning.
- A virtualenv. Conda works too; the steps are identical.
Set the keys as environment variables before running anything. On macOS or Linux:
export OPENAI_API_KEY="sk-..."
export SERPER_API_KEY="..."
On Windows PowerShell, use $env:OPENAI_API_KEY = "sk-...".
Step 1: install CrewAI
Activate your virtualenv and install both the core package and the bundled tools extra. The tools extra brings in the optional dependencies for the built-in SerperDevTool, FileWriterTool, and the rest of the standard kit. 4
python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install 'crewai[tools]'
Confirm the install and check the version. If you are reading this in 2026, CrewAI’s release cadence is brisk; the API surface I describe below is stable but minor flags shift between minor versions.
python -c "import crewai; print(crewai.__version__)"
If the import fails, you almost certainly have a Python 3.9 environment somewhere on PATH. Run python --version to confirm 3.10+ before debugging anything else.
Step 2: define an Agent
An agent in CrewAI is an LLM-backed worker with three load-bearing attributes (role, goal, backstory) plus optional tools, verbosity, and delegation flags. 5 Per the CrewAI docs, all three attributes shape agent behaviour; backstory accepts an empty-string default but the docs treat it as load-bearing. Do not skip it regardless — it biases the LLM toward the persona you want, which materially affects output quality on smaller models.
Create a file called crew.py:
from crewai import Agent
from crewai_tools import SerperDevTool, FileWriterTool
search_tool = SerperDevTool()
write_tool = FileWriterTool()
researcher = Agent(
role="Senior Research Analyst",
goal="Find recent, primary-source-grounded information on the topic the user provides.",
backstory=(
"You are a meticulous analyst who refuses to cite anything you "
"cannot verify. You prefer official documentation, primary "
"research, and recent reporting from named publications."
),
tools=[search_tool],
verbose=True,
allow_delegation=False,
)
writer = Agent(
role="Technical Writer",
goal="Turn the analyst's notes into a structured Markdown report.",
backstory=(
"You write for working developers. You are clear, concrete, "
"and skeptical of marketing language. Your prose is short "
"paragraphs and useful headings."
),
tools=[],
verbose=True,
allow_delegation=False,
)
editor = Agent(
role="Editor",
goal="Verify claims against the analyst's notes and tighten the writer's draft.",
backstory=(
"You catch unsourced claims, vague hedges, and prose that "
"drifts from the original notes. You write the final version "
"to disk."
),
tools=[write_tool],
verbose=True,
allow_delegation=False,
)
A few things to notice. allow_delegation=False is the safe default; turning it on lets agents call each other mid-task, which is powerful but harder to debug. verbose=True is non-optional during development. It prints every prompt, tool call, and response, which is the only way to see why a run is failing.
Image: CrewAI documentation — Agents concept, used for editorial coverage of the Agent primitives in this step.
Step 3: define the Tasks
A Task in CrewAI binds a unit of work to an agent. The two required fields are description (what the agent should do) and expected_output (what shape the result should take), with an optional agent reference and optional context for passing dependencies between tasks. 6
Add to crew.py:
from crewai import Task
research_task = Task(
description=(
"Research the topic: {topic}. Find at least three primary-source "
"URLs published in the last 12 months. For each, capture the "
"claim, the URL, and a one-line summary."
),
expected_output=(
"A bullet list of 3-5 findings, each with: claim, source URL, "
"publication date, one-line summary."
),
agent=researcher,
)
write_task = Task(
description=(
"Using the analyst's findings, write a 600-word Markdown report. "
"Use H2 headings, short paragraphs, and inline citations as "
"[source name](URL). End with a 'Sources' list."
),
expected_output=(
"A Markdown document with a title, 3-4 H2 sections, and a "
"Sources list at the bottom."
),
agent=writer,
context=[research_task],
)
edit_task = Task(
description=(
"Verify each claim in the draft against the analyst's findings. "
"Tighten weak prose. Save the final version to 'report.md'."
),
expected_output="The final Markdown saved to disk; return the path.",
agent=editor,
context=[research_task, write_task],
)
The context field is the load-bearing piece for multi-step crews. It tells CrewAI to pass the prior task’s output into the current task’s prompt, which is how the Writer sees what the Researcher found and the Editor sees both. Without context, each agent runs in isolation and the handoff breaks.
Image: CrewAI documentation — Tasks concept, used for editorial coverage of the Task primitives in this step.
Step 4: build the Crew
A Crew assembles agents and tasks under a Process. The two production-ready modes are Process.sequential (each task runs in order, output flows down the chain) and Process.hierarchical (a manager agent delegates work to the others). 7 A Process.consensual mode has been proposed for collaborative routing and appears in the source enum, though the CrewAI docs still mark it as planned / experimental as of writing — sequential and hierarchical are the production-ready modes this tutorial targets. Sequential is the right default. Hierarchical is useful when you genuinely do not know which agent should handle which subtask and want the LLM to route, but it adds a manager-LLM call to every step and the routing is only as good as the manager’s prompt.
Add to crew.py:
from crewai import Crew, Process
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, write_task, edit_task],
process=Process.sequential,
verbose=True,
)
For most tutorials, comparison-style content, and report generation, sequential is fine. If you switch to hierarchical, you must also pass manager_llm (the LLM the manager uses to route) and remove the explicit agent assignment from each task so the manager can decide.
Step 5: add and configure tools
A note on the two import paths you’ll see in CrewAI code. The built-in tools (SerperDevTool, FileWriterTool, the rest) live in crewai_tools, the bundled-extras package you installed via pip install 'crewai[tools]'. The BaseTool subclassing primitive used to author custom tools lives in crewai.tools, the tools module inside the core crewai package. Both are valid; they just serve different needs.
CrewAI ships with a tools package that covers the common cases (web search via Serper, file I/O, scraping, vector-store retrieval) and supports custom tools as either BaseTool subclasses or decorated functions. 8 The two used above (SerperDevTool, FileWriterTool) are enough for this tutorial. If you want a quick sense of what custom tools look like, here is a minimal one:
from crewai.tools import BaseTool
class WordCountTool(BaseTool):
name: str = "word_count"
description: str = "Count words in the provided text."
def _run(self, text: str) -> str:
return f"{len(text.split())} words"
You attach it the same way as the built-ins: tools=[WordCountTool()] on whichever agent should use it. The description field is what the LLM reads when deciding whether to call the tool, so be concrete; vague tool descriptions are the most common cause of “the agent never used my tool” frustration.
Step 6: run it and inspect the output
Cap off crew.py with a kickoff call. The inputs dict fills in the {topic} placeholder in the research task’s description.
if __name__ == "__main__":
result = crew.kickoff(
inputs={"topic": "open-source large language models in 2026"}
)
print("=" * 60)
print("Final result:")
print(result)
Run it:
python crew.py
You will see verbose output as each agent thinks, calls tools, and produces its task output. A three-agent crew passes intermediate output from one agent to the next as context, which means token counts grow with each step rather than each agent running on a fresh prompt. Cost arithmetic depends on your model, your prompt length, and how many tool calls each agent makes; budget for variance, not just an average, and run with verbose=True the first few times so you can see token usage per agent in the console output.
When the run finishes, report.md exists in your working directory. Open it. Read it as a reader, not as a developer. If a claim looks weak, the prompts are the place to fix it: make the Researcher’s goal stricter about primary sources, or make the Editor’s description explicitly verify each citation.
Common pitfalls
The three failures most teams hit, surfaced repeatedly in CrewAI’s Discord and GitHub issues: 9
Empty or hallucinated tool calls. The agent invents tool input that does not match the tool signature, or skips the tool entirely. Fix the description field on the tool to be unambiguous about input and output shape, and make the agent’s goal explicitly require the tool’s output as evidence.
Cost runaway in hierarchical mode. A misbehaving manager agent can re-route tasks indefinitely, and each re-route costs another manager-LLM call. Stick with Process.sequential until the pattern clearly demands hierarchical, and set a hard timeout in your runner script.
Context-window overflow. Three agents passing context down the chain stack token budgets. On smaller-context models the Editor task can fail silently when the combined Researcher + Writer output exceeds the window. Move to a longer-context model, or compress intermediate outputs in the Task description.
Where to go next
Image: crewAI GitHub repository, used for editorial coverage of the project’s release stream and integration roadmap.
CrewAI’s documentation site is the canonical reference; the Quickstart page covers the same ground as this tutorial in less prose, and the Concepts section drills into Memory, Knowledge, and the planning features that this tutorial deliberately skipped. 10 The official GitHub repository is where new tools and integrations land first; star it if you want to track release notes.
For working devs anywhere, the practical next step is wiring CrewAI into a real workflow at your job. Pick one task you do every week (a competitor scan, a release-notes summary, a code-review checklist) and build a 2 or 3-agent crew around it. That is how the team-of-roles mental model becomes muscle memory.
How this article was made: an autonomous AI pipeline researched, drafted, fact-checked, and reviewed this piece, aggregating publicly-available information from the sources consulted below. AI (artificial intelligence) can make mistakes, so please cross-check the consulted sources before acting on anything here. Neural Tech Daily is not liable for decisions or outcomes based on this article.
Sources consulted
Cited Sources
- 1. CrewAI documentation overview — describes CrewAI as a framework for orchestrating role-playing, autonomous AI agents (accessed ) ↩
- 2. crewAI GitHub repository README — positions CrewAI as a multi-agent orchestration framework distinct from graph-based or single-agent libraries (accessed ) ↩
- 3. crewAI GitHub repository — Python version requirement and PyPI package metadata (accessed ) ↩
- 4. CrewAI Quickstart — installation instructions including the optional tools extra (accessed ) ↩
- 5. CrewAI documentation — Agent concept reference; role, goal, backstory, tools, verbose, allow_delegation parameters (accessed ) ↩
- 6. CrewAI documentation — Task concept reference; description, expected_output, agent, context parameters (accessed ) ↩
- 7. CrewAI documentation — Process concept reference; Process.sequential and Process.hierarchical modes, manager_llm requirement for hierarchical (accessed ) ↩
- 8. CrewAI documentation — Tools concept reference; BaseTool subclassing, decorated function tools, SerperDevTool / FileWriterTool built-ins (accessed ) ↩
- 9. crewAI GitHub issues — recurring failure modes around tool-call hallucination, hierarchical-mode cost, and context-window overflow (accessed ) ↩
- 10. CrewAI Quickstart and Concepts pages — canonical reference for advancing past this tutorial including Memory, Knowledge, and planning features (accessed ) ↩
Further Reading
- CrewAI — official site (accessed )
Anonymous · no cookies set