Lesson 09 CrewAI Intro
Theme:

CrewAI Intro

Lesson 09 · Building Your Own Agents · ~12 min read

1. The multi-agent metaphor

In Modules 2–4, the “agent” was always one LLM in a loop, accumulating tool results until it had an answer. Tools multiplied; agents didn’t. What if the right abstraction for some problems is not one agent with many tools but several agents with distinct roles, each doing what they do best, exchanging artefacts?

This is the CrewAI thesis. Borrowed (deliberately) from how human teams work: a researcher gathers material, a writer drafts, an editor polishes. Each person has a specialty. The work flows through them. CrewAI gives this shape first-class primitives — Agent, Task, Crew, Process — instead of asking you to encode it as a graph (LangGraph) or as handoff metadata (OpenAI Agents SDK).

Whether the metaphor helps depends on the shape of your problem. For one-role + many-tools work, CrewAI is overkill — the Claude Agent SDK from Module 2 is cleaner. For genuine multi-step collaboration where each step benefits from its own persona and context, CrewAI is the cleanest expression in 2026. Section 7 turns that intuition into a decision matrix.

2. Roles, goals, backstories: persona-as-prompt

A CrewAI Agent is constructed with three string fields that together define its persona:

CrewAI concatenates these into the system prompt for every LLM call this agent makes. There is nothing magical here — backstory is just a structured place to put system-prompt content. The value is the discipline: by forcing you to write a role + goal + backstory per agent, CrewAI makes the team’s division of labour explicit in code. You can’t sneak two responsibilities into one agent without it being obvious in the constructor call.

Why teams like this in practice

This is the most common reason people like CrewAI even when they could have used a simpler framework: it makes the team shape readable. A new engineer reading agents=[researcher, writer, reviewer] understands the system at a glance — no graph diagram required, no handoff metadata to chase across files.

3. Tasks: the unit of work

A Task is what an agent does. The constructor fields are deliberately small:

A task is a description, an output spec, an owner, and its dependencies — nothing more. Everything you might call “control flow” lives in the Crew’s Process, not in individual tasks. That separation is what keeps a 3-task crew readable and a 10-task crew still approachable.

4. Crews and processes

A Crew ties everything together — agents, tasks, and the process that orchestrates them:

crew = Crew(
    agents=[researcher, writer, reviewer],
    tasks=[research_task, write_task, review_task],
    process=Process.sequential,
    verbose=True,
)
result = crew.kickoff(inputs={"topic": "..."})

Two process shapes ship in CrewAI today:

crew.kickoff(inputs={...}) is the entry point; inputs becomes the substitution dict for task description placeholders. The return value is the last task’s output, but every task’s output is also accessible afterwards via crew.tasks[N].output, which is invaluable when you want to log intermediate artefacts (research findings, draft text) separately from the final review.

5. Tools, attached per-agent

CrewAI has its own @tool decorator that mirrors what M2’s Claude Agent SDK shipped: turn a Python function into something an agent can call, with a docstring as the description. The big difference is where tools attach: in CrewAI, tools are bound to specific agents via tools=[...] on the Agent constructor, not globally to a crew.

researcher = Agent(
    role="...", goal="...", backstory="...",
    tools=[web_search, web_fetch],
    llm="anthropic/claude-3-5-sonnet-latest",
)
writer = Agent(
    role="...", goal="...", backstory="...",
    tools=[],  # writer has no tools — it works from research context only
    llm="anthropic/claude-3-5-sonnet-latest",
)

This per-agent attachment is one more way CrewAI enforces role specialisation: the writer cannot call web_search even if it wanted to. If a downstream task needs research output, it gets it through context=[research_task], not by calling tools itself. The split mirrors how human teams police scope.

6. Model routing via LiteLLM

CrewAI delegates model calls to LiteLLM, which means the llm= field on every Agent accepts a provider-prefixed model string:

LiteLLM reads the matching env var (ANTHROPIC_API_KEY, OPENAI_API_KEY, …) and routes the call. A CrewAI crew can mix models across agents — for example, a cheap model for the researcher and a more capable model for the writer — by setting llm= differently per agent. That’s a real cost lever once you ship.

For this course, every agent uses "anthropic/claude-3-5-sonnet-latest" so the Module 6 cross-framework cost/latency comparison is fair (same model family as Modules 1–4). Resist the temptation to mix models during the lab — you’ll pull that lever in Lesson 11.

7. When to pick CrewAI (and when not to)

A short decision matrix the reader will revisit in Module 6.

Pick CrewAI when:

Don’t pick CrewAI when:

The multi-agent tax is real

Three agents means at minimum three LLM calls per kickoff — often more, once you count the manager (in hierarchical mode) and any retries. If your problem can be solved by one agent with the right tools, one agent will be cheaper, faster, and easier to debug. Reach for CrewAI when the team shape itself is the abstraction you need, not because “multi-agent” sounds impressive.

This is the framing L10 builds on: the planner + worker + reviewer crew is the canonical sweet-spot demo, and it’s exactly the shape you’ll port across frameworks in Module 6’s cross-framework scorecard.

References