TAI BUI
Back to curriculum
BuildPython

CrewAI: Role-Based Crews and Flows

CrewAI is a role-based multi-agent framework built on four primitives (Agent, Task, Crew, Process) and two shapes: Crews for autonomous collaboration, Flows for event-driven, deterministic control. The docs are blunt about which to reach for first: "for any production-ready application, start with a Flow."

TIME: ~75 minutesPREREQUISITES: Phase 14 · 12 (Workflow Patterns), Phase 14 · 14 (Actor Model)

Learning Objectives

  • Name CrewAI's four primitives (Agent, Task, Crew, Process) and what each owns.
  • Distinguish Sequential, Hierarchical, and the planned Consensus process; pick one per workload.
  • Distinguish Crews (autonomous role-based) from Flows (event-driven deterministic), and explain the docs' production recommendation.
  • Wire tools with the `@tool` decorator and `BaseTool` subclass; reason about structured outputs vs free text.
  • Name the four CrewAI memory types and when each pays off.
  • Implement a stdlib three-agent crew (researcher, writer, editor) that produces a brief.
  • Spot the four CrewAI failure modes: prompt-bloat, manager-LLM tax, brittle handoffs, Crew-as-prod.

The Problem

Teams adopting multi-agent frameworks tend to hit the same wall. "Autonomous collaboration" looks great in a demo. Then a customer files a bug and you need deterministic replay. Finance asks what an LLM-routed crew costs per run. On-call wants to know which agent stalled at 3 AM.

A free-form, LLM-routed crew answers none of those cleanly. A pure DAG answers all of them, but it loses the exploratory shape a brainstorming agent needs.

CrewAI splits the difference openly. Crews handle collaborative, role-based, exploratory work. Flows handle event-driven, code-owned, auditable production. One framework, two shapes, and you pick per surface.

Warm-up0/2
1. Which kind of workflow is easiest to replay when debugging a failed run?Warm-up
2. In the actor model, how do independent actors communicate?Warm-up

The Concept

CrewAI is a Python framework for building multi-agent systems out of role-based agents. It has a small surface of four primitives and two top-level shapes, Crews and Flows. This section covers both, then tools, memory, and where the whole thing breaks.

Four primitives

Memorize these four and the rest is config.

  • Agent. role + goal + backstory + tools + (optional) llm. The backstory is load-bearing: it shapes tone, judgment, and when the agent stops. Tools are functions the agent can call (more below).
  • Task. description + expected_output + agent + (optional) context + (optional) output_pydantic. A reusable unit of work. expected_output is the contract, context lists the upstream tasks whose outputs get passed in, and output_pydantic forces a structured shape.
  • Crew. The container. It owns the list of agents, the list of tasks, the process, and optional memory, verbose, and manager_llm settings.
  • Process. The execution strategy: Sequential, Hierarchical, or Consensus (planned). It sets the shape of the run.

Agents never see each other directly. Tasks reference agents, the Crew sequences tasks, and the Process decides who picks the next task. That is the whole mental model.

Validated against CrewAI 0.86 (2026-05). Newer versions may rename or merge process types; check the CrewAI Processes docs before relying on a specific shape.

Sequential vs Hierarchical vs Consensus

  • Sequential. Tasks run in declaration order, and the output of task N is available as context to task N+1. It is the cheapest and most predictable option. Use it when the order is fixed.
  • Hierarchical. A manager Agent (a separate LLM call) routes between specialists. CrewAI spawns the manager from your manager_llm config or a default. Each round the manager picks the next task, and it can refuse or re-route. Use it when you have four or more specialists and the order genuinely depends on prior output.
  • Consensus. Planned, and not implemented in the public API today. The docs reserve the name for a future voting-based process, so do not rely on it.

Hierarchical adds manager LLM calls on top of the specialist calls, and each manager call carries the task list plus prior outputs. Token cost grows faster than the call count, so pay for it only when you need the routing.

Crews vs Flows

A Crew is LLM-driven autonomy: the framework picks the shape of the run at runtime. A Flow is an event-driven graph you own, where @start marks the entry and @listen(topic) marks a step that fires when another step emits that topic. Each Flow step is plain Python, and it can call a Crew internally. The docs lead with this split in 2026.

  • Crew fits research, brainstorming, first drafts, and anywhere the path is part of the answer. It is cheap to prototype and hard to replay or test.
  • Flow fits production. It is observable, testable, and deterministic.

The docs' 2026 production recommendation is to start with a Flow, then fold Crews in as Crew.kickoff() calls from inside Flow steps when autonomy earns its cost. The Flow gives you the audit trail and the Crew gives you the exploration. Compose them instead of picking one.

Tool integration

There are three ways to give an Agent a tool. Pick the simplest one that fits.

  1. @tool decorator. A pure function becomes a tool. The signature is the schema and the docstring is the description the LLM sees. Best for one-off helpers.

    python
    from crewai.tools import tool
     
    @tool("Search the web")
    def search(query: str) -> str:
        """Return top results for the query."""
        return run_search(query)
  2. BaseTool subclass. A class-based tool with an explicit args schema, async support, and retries. Use it when the tool holds state (a client, a cache) or needs structured args.

    python
    from crewai.tools import BaseTool
    from pydantic import BaseModel
     
    class SearchArgs(BaseModel):
        query: str
        limit: int = 10
     
    class SearchTool(BaseTool):
        name = "web_search"
        description = "Search the web and return top results."
        args_schema = SearchArgs
     
        def _run(self, query: str, limit: int = 10) -> str:
            return self.client.search(query, limit=limit)
  3. Built-in toolkits. CrewAI ships first-party adapters: SerperDevTool, FileReadTool, DirectoryReadTool, CodeInterpreterTool, RagTool, WebsiteSearchTool. One import wires each one up.

Structured outputs use Pydantic. Pass output_pydantic=MyModel on the Task, and CrewAI validates the LLM response against the model, then either coerces it or retries. Pair that with a tight expected_output string. Free text is fine for drafts, but structured outputs are what downstream Flows can actually consume.

Memory hooks

CrewAI ships four memory types, and a Crew can enable all four at once.

Validated against CrewAI 0.86 (2026-05). Recent releases route everything through a unified Memory system that wraps these four stores. The conceptual model below still holds, but the public class surface may collapse to a single Memory entry-point in newer versions; check CrewAI memory docs for the current API.

  • Short-term. A conversation buffer within a single run, wiped when the run ends.
  • Long-term. Persisted across runs in a vector DB (Chroma by default, swappable) and retrieved by similarity to the current task.
  • Entity. Per-entity facts, like "Customer X is on the enterprise plan." Keyed by entity rather than by similarity, and it survives across runs.
  • Contextual. Assembly-time retrieval. It pulls relevant memory at the moment the Agent needs it instead of preloading.

Enable memory on the Crew with memory=True or per-type config. It is backed by an embeddings provider you configure (OpenAI by default, swappable to local). Memory is one of the places CrewAI earns its keep against thinner frameworks, since pure LangGraph makes you wire each of these yourself.

When CrewAI fits

  • Three to six agents with named roles and a collaborative workflow: drafting, reviewing, planning, brainstorming.
  • Routing where the LLM's judgment about the next step is part of the value (Hierarchical).
  • Teams that would rather read role + goal + backstory than a graph definition.

When CrewAI does not fit

  • Deterministic DAGs with strict ordering. Use LangGraph (Lesson 13). The graph is the right abstraction there, and CrewAI's role framing is friction.
  • Sub-second latency budgets. Hierarchical adds round trips, and even Sequential serializes prompts that carry backstories and prior outputs.
  • Single-agent loops. Skip the framework. An agent loop (Lesson 1) plus a tool registry is shorter.

The short version of the framework landscape is that CrewAI sits in the "collaborative role-based" corner. Lessons 13 to 18 cover the alternatives: LangGraph, AutoGen, the OpenAI Agents SDK, the Claude Agent SDK, and Agno/Mastra.

Dependency shape

CrewAI is independent of LangChain, supports Python 3.10 to 3.13, and uses uv. For star count, see crewAIInc/crewAI (snapshot as of 2026-05). AWS Bedrock integration is documented. Vendor benchmarks report a substantial speedup vs LangGraph on QA workloads, but the methodology (dataset, hardware, evaluation metric) is not published, so treat framework-vendor numbers as directional only.

Where this pattern goes wrong

  • Prompt-bloat from backstories. A 2000-word backstory per agent across a five-agent crew burns the context budget before the first tool call. Keep backstories under 200 words, and reuse phrases across agents instead of repeating house style five times.
  • Manager-LLM token tax. Hierarchical adds a manager LLM call before every specialist call. On a five-task crew that is six LLM calls instead of five, and the manager call carries the full task list plus prior outputs. Switch to Sequential unless routing depends on output.
  • Brittle handoffs. Task N's expected_output is "an outline". Task N+1 reads it as context and tries to parse three sections, but the LLM produced four, so the downstream Agent ad-libs. Put output_pydantic on Task N so Task N+1 reads a typed object instead of free text.
  • Crew-as-prod. A free-form Crew shipped to production without a Flow wrapper. Output variability is high, replay is impossible, and on-call cannot diff a bad run against a good one. Wrap it in a Flow.
Check: The Concept0/32
1. In CrewAI, what is an Agent?Define
2. In CrewAI, what is a Task?Define
3. What is a Task's `expected_output`?Define
4. In CrewAI, what is a Crew?Define
5. What does a Crew's Process decide?Define
6. What is the status of CrewAI's Consensus process, per the lesson?Define
7. What is a CrewAI Flow?Define
8. What is an Agent's backstory used for?Define
9. What does the `@tool` decorator do?Define
10. What is a `BaseTool` subclass?Define
11. What are the three ways to give a CrewAI Agent a tool, per the lesson?Define
12. What is the manager LLM in a Hierarchical process?Define
13. Which of these is NOT one of the four memory types CrewAI ships?Define
14. What is entity memory?Define
15. What is long-term memory in CrewAI?Define
16. What is contextual memory?Define
17. Agents in a crew never see each other directly. How does work move from one to the next?Explain
18. When is Hierarchical process worth picking over Sequential?Explain
19. Why does Hierarchical cost more than Sequential on the same five tasks?Explain
20. What is the difference between a Crew and a Flow?Explain
21. Why do the docs recommend starting production with a Flow that calls `Crew.kickoff()` inside its steps?Explain
22. Why does the lesson caution against using a free-form Crew in production?Explain
23. A tool must hold an API client and a cache. Why use a `BaseTool` subclass instead of `@tool`?Explain
24. What does passing output_pydantic=MyModel on a Task do, per the lesson?Explain
25. What separates short-term memory from long-term memory in a Crew?Explain
26. What is backstory bloat and how does the lesson recommend handling it?Explain
27. Why should a framework vendor's reported speedup over LangGraph on QA workloads be treated as directional only?Explain
28. Task N's `expected_output` is "an outline". Task N+1 expects three sections, but the LLM produced four and the downstream agent invents content. What fixes the cause?Analyze
29. A five-task crew has a fixed order. After a switch to Hierarchical, runs cost more and take longer with no quality gain. What explains this?Analyze
30. You are shipping a customer-facing service where support must replay any bad run, but drafting the reply benefits from several role-based agents. Which design fits?Design
31. A brief goes through research, drafting and editing in a fixed order, with three specialists and a tight budget. Which Process should you pick?Design
32. A support crew must always know that Customer X is on the enterprise plan, found by customer rather than by how similar a new ticket looks. Which memory fits?Design

Build It

code/main.py implements stdlib versions (plus numpy for the memory mock) of both shapes plus a three-agent crew.

What's in it:

  • Agent and Task dataclasses matching CrewAI's surface.
  • SequentialCrew.kickoff(inputs) runs tasks in declaration order, threading outputs through as context.
  • HierarchicalCrew.kickoff(topic) adds a manager Agent that picks the next specialist each round and stops at "done".
  • Flow with @start and @listen(topic) decorators, a tiny event loop, and a trace.
  • tool(name), a decorator mirroring CrewAI's @tool shape.
  • Memory with short_term, long_term, and entity stores. Mocked similarity is cosine similarity over hashed token vectors, the one place the file imports numpy.
  • Mock LLM responses are hardcoded strings keyed off role plus input prefix. No network, fully deterministic.

The demo is a researcher, writer, and editor crew producing a brief on "agent engineering 2026". The researcher pulls (mocked) sources, the writer drafts, and the editor tightens. The same crew then runs through a Flow to show the deterministic shape.

Run it:

bash
python3 code/main.py

The trace covers five things: a sequential crew threading outputs through context; a hierarchical crew with manager picks (researcher, writer, editor, then "done"); a flow running the same three steps with explicit topics (researched, drafted, edited); tool calls routed through @tool; and long-term memory surviving across two kickoffs.

The Crew trace is fluid, and the manager could in principle re-order. The Flow trace is fixed. That contrast is the lesson.

Check: Build It0/5
1. In main.py, `SequentialCrew.kickoff({"topic": "agent engineering 2026"})` runs the researcher, writer and editor tasks, and the researcher is given the `search` tool. What is the first line returned?Apply
2. In main.py, a `HierarchicalCrew` has the three specialists and the demo manager, with `max_steps=5`. How many entries does `kickoff` return?Apply
3. In main.py's Flow demo, `on_edited` returns None after the `edited` topic. How many entries does `flow.kickoff` put in the trace?Apply
4. In main.py's demo, one `Memory` is shared by the sequential crew, the hierarchical crew, the Flow, and a second sequential crew. What does `len(memory.long_term)` print at the end?Apply
5. In main.py, `_researcher("agent engineering 2026", [], memory)` is called with an empty tools list. What does it return?Apply

Use It

  • CrewAI Flow for production, even when the Flow is a single step that calls Crew.kickoff(). The Flow gives you the audit boundary.
  • CrewAI Crew (Sequential) for collaborative work with a clear order, especially first drafts and review loops.
  • CrewAI Crew (Hierarchical) when routing depends on output and you have four or more specialists.
  • LangGraph (Lesson 13) for explicit state machines, durable resume, and strict ordering.
  • AutoGen v0.4 (Lesson 14) for actor-model concurrency and fault isolation.
  • OpenAI Agents SDK (Lesson 16) for OpenAI-first products with handoffs and guardrails.
  • Claude Agent SDK (Lesson 17) for Claude-first products with subagents and a session store.

Ship It

outputs/skill-crew-or-flow.md picks Crew vs Flow for a task and scaffolds the minimal implementation. It hard-rejects Crew-without-backstory, Flow-without-explicit-topics, and Hierarchical with only two specialists.

Author's Note

Default to a Flow and let a Crew earn its place inside one. A Flow with a single step that calls Crew.kickoff() already gives you the audit boundary, and you can loosen it later if autonomy turns out to pay for itself. A free-form Crew in production is the failure mode this lesson warns about, and a Flow wrapper is the fix.

Treat the role-based framing as an interface to your prompts, not decoration. Keep each backstory short, test a few variants, and freeze the one you pick. And reach for Hierarchical only when you can say why a fixed order won't work. If you can't, the manager call is a tax you are paying for the look of sophistication.

Pitfalls

  • Backstory as flavor. It shapes outputs. Test three variants per agent, since the variance is real, then pick one and freeze it.
  • Skipping expected_output. Without a contract per task, downstream tasks pick up whatever the LLM produced. The Crew runs and the audit fails.
  • Memory always-on. Long-term memory writes on every run, so the vector DB grows and retrieval gets noisy. Scope writes to tasks where the fact is persistent.
  • Manager prompt drift. Hierarchical's manager prompt is implicit. If routing gets weird, dump it in verbose mode and read it.
  • Tool side effects in Crews. A Crew can call a tool more times than you expect. POST, DELETE, and payment calls belong in a Flow step, never in a Crew tool.
Check: Pitfalls0/5
1. Per the lesson's dedicated Pitfalls section, what should you do about backstory variance and missing expected_output contracts?Explain
2. Per the lesson's Pitfalls section, what is the fix for 'tool side effects in Crews' and 'memory always-on'?Explain
3. A Crew agent has a tool that charges a customer's card, and one run charged the same customer three times. What is the cause and the fix?Analyze
4. A Crew has had long-term memory enabled for months. Retrieval now returns loosely related notes and the vector DB keeps growing. Which pitfall is this?Analyze
5. A Hierarchical crew starts routing oddly and skips the editor. The manager prompt is implicit. What is the first debugging step?Analyze

Exercises

  1. Convert the Sequential crew to a Flow. Count the touchpoints where variability drops. Note where readability dropped.
  2. Add entity memory to the crew: facts about a customer persist across kickoffs. Verify retrieval pulls the right entity.
  3. Implement a Hierarchical process where the manager refuses to route to the editor until the writer's output has at least three paragraphs. Trace the retry.
  4. Wire a BaseTool subclass for a (mocked) web search. Compare the trace shape vs the @tool decorator version.
  5. Add output_pydantic=Brief to the editor task, where Brief has title, summary, sections. Make the writer task output malformed JSON once; verify CrewAI's retry behavior in the trace.
  6. Read CrewAI's docs intro. Port the toy to the real crewai API. Which guarantees did the stdlib version skip?
  7. Wire AgentOps or Langfuse (Lesson 24) to a real run. Which traces did you miss in the stdlib version?

Key Terms

TermWhat people sayWhat it actually means
Agent"Persona"Role + goal + backstory + tools
Task"Unit of work"Description + expected output + assignee + optional structured output
Crew"Agent team"Container for Agents + Tasks + Process
Process"Execution strategy"Sequential / Hierarchical / Consensus (planned)
Flow"Deterministic workflow"Event-driven, code-owned, testable
Backstory"Persona prompt"Tone and judgment shaper for the Agent
@tool"Function tool"Decorator that turns a function into a tool the Agent can call
BaseTool"Class tool"Class-based tool with args schema, retries, async support
Entity memory"Per-entity facts"Memory scoped to a customer / account / issue
Long-term memory"Cross-run memory"Vector-backed memory that survives between kickoffs
Contextual memory"Just-in-time retrieval"Memory pulled at the moment the Agent needs it
Manager LLM"Router agent"Extra LLM in Hierarchical process that picks the next task
expected_output"Task contract"String that tells the Agent (and audit) what shape to return

Further Reading

Code

Ships With