Vizuara AI Agents Bootcamp Day 9
CrewAI: A simple yet powerful platform for building multi-agent frameworks
CrewAI is a framework for orchestrating multiple AI agents to work together on complex projects. Think of it as assembling a team of AI specialists – each with a defined role – and assigning them tasks in a structured workflow to achieve a larger goal.
In this post, we’ll introduce the basic building blocks of CrewAI (Agents, Tasks, and Crews) and walk through two example projects to see how it works in practice.
By the end, you should understand how to set up a multi-agent team with CrewAI, how to define tasks for each agent, and how to choose a workflow (sequential vs. hierarchical, etc.) that fits your project.
Table of Contents
(1) Understanding the Basics: Agents, Tasks, and Crews
(2) Project 1: Multi-Agent Content Creation (Research & Article Writing)
(3) Project 2: AI-Powered Customer Outreach Campaign
(4) Workflow Structures: Sequential vs. Hierarchical (and Beyond)
(5) Day 9 wrap up
(1) Understanding the Basics: Agents, Tasks, and Crews
Before diving into the examples, let’s clarify what Agents, Tasks, and Crews mean in CrewAI:
Agents: An Agent is essentially an autonomous AI entity with a specific role and goal. You can think of each agent as a team member with its own expertise. When creating an agent in CrewAI, you define its role (what it is supposed to be), its goal (what it should accomplish), and even a backstory or context that guides its behavior. For example, you might have an agent whose role is “Content Writer” with the goal “Write an insightful article on a given topic.” Agents operate independently but can collaborate by passing information via tasks and crew workflows.
Tasks: A Task in CrewAI is a specific unit of work assigned to an agent – like an assignment with instructions and an expected outcome. Tasks include details such as a description (what needs to be done), an expected_output (the criteria or format for completion), and the agent responsible for that task. In other words, a task tells an agent what to do (and sometimes how or with what tools) and defines what a successful result looks like. By breaking a project into tasks, we give each agent clear instructions and outputs to aim for.
Crews: A Crew is the container that brings agents and tasks together into a coordinated workflow. You can think of it as the project team. When you form a crew, you provide the list of agents and the list of tasks, and you specify how those tasks should be executed (the process or workflow). The crew manages the overall execution: making sure each task is handed off to the right agent, in the right order (or coordinated by a manager agent, as we’ll see). The default workflow is sequential (one task after another), but CrewAI also supports more complex processes like hierarchical delegation. Essentially, the Crew defines who will do which tasks, and in what order or structure.
With these basics in mind, let’s apply them to two projects to see how CrewAI works in practice.
(2) Project 1: Multi-Agent Content Creation (Research & Article Writing)
Scenario: You want to research and write a blog article using multiple AI agents, each specializing in a part of the workflow. We’ll set up three agents – a Content Planner, a Content Writer, and an Editor – and assign them tasks to collaborate on producing a final article. This will illustrate a simple sequential crew where each agent’s output feeds into the next task.
Defining the Agents (Roles, Goals, Backstories)
First, we create our agents. Each agent has a clear role and goal, and we can optionally give them a backstory to provide context or style. The backstory is a prompt that informs the agent’s persona or perspective. Here are the three agents for our project:
Content Planner – Role: plans the article’s content outline. Goal: “Plan engaging and factually accurate content on {topic}.” Backstory: Imagine this agent as a knowledgeable strategist who gathers information and outlines what the writer should cover.
Content Writer – Role: writes the article draft. Goal: “Write an insightful, factual opinion piece about {topic}.” Backstory: This agent is a writer who will base their writing on the planner’s outline, providing objective insights and clearly marking opinions as opinions.
Editor – Role: reviews and polishes the article. Goal: “Edit the blog post to align with the organization’s style.” Backstory: This agent is an editor ensuring the content meets quality standards and balance.
In code, defining an agent is straightforward. We use the Agent
class from CrewAI and pass in the role, goal, backstory, and some settings:
from crewai import Agent
planner = Agent(
role="Content Planner",
goal="Plan engaging and factually accurate content on {topic}",
backstory="You're planning a blog article about the topic: {topic}. Your outline will help the writer.",
allow_delegation=False,
verbose=True
)
Above, we defined the Content Planner agent. We would similarly define the writer
and editor
agents with their respective roles, goals, and backstories (for brevity, those are not shown here, but they follow the same structure). The allow_delegation=False
means these agents won’t delegate their tasks to sub-agents (not needed in our simple setup), and verbose=True
just means the agent will log its thinking process verbosely (useful for debugging or learning).
Defining Tasks for Each Agent
Next, we break down the project into tasks. Each task will correspond to one step of our article writing process and will be handled by one of our agents:
Planning Task: The Content Planner will research the topic and produce an outline/plan.
Writing Task: The Content Writer will take the outline and draft the article.
Editing Task: The Editor will review the draft and make final improvements.
When creating tasks in CrewAI, we provide a description (which can include multi-step instructions), an expected output description, and assign the task to an agent. In our case, the tasks might look like:
from crewai import Task
plan_task = Task(
description=(
"1. Research the latest trends, key players, and news about {topic}.\n"
"2. Identify the target audience and their interests.\n"
"3. Develop a detailed outline (intro, key points, conclusion) for a blog post on {topic}.\n"
"4. Include relevant data, sources, and SEO keywords."
),
expected_output="A comprehensive content plan with an outline, audience analysis, SEO keywords, and references.",
agent=planner
)
write_task = Task(
description=(
"Using the content plan, craft a compelling blog post on {topic}.\n"
"Ensure an engaging introduction, insightful body sections, and a strong conclusion.\n"
"Incorporate the provided SEO keywords naturally and maintain a consistent tone."
),
expected_output="A well-written blog article draft (in markdown) with clear sections (each 2-3 paragraphs).",
agent=writer
)
edit_task = Task(
description="Proofread and edit the draft for grammatical errors and ensure it aligns with the brand voice and journalistic best practices.",
expected_output="A polished final article, ready for publication, in markdown format.",
agent=editor
)
Each task’s description
provides the instruction to the agent (notice we can include numbered steps or multiple requirements), and expected_output
describes what we expect back. For example, the plan_task tells the planner to research the topic and come up with an outline (with specific points to include), and we expect as output a “content plan document” that includes an outline, audience analysis, keywords, etc. We assign agent=planner
so CrewAI knows the Content Planner agent should execute that task. Likewise, the writing task is assigned to the writer, and editing to the editor.
Forming the Crew and Workflow
Now that we have our agents and tasks, we need to assemble them into a Crew. The crew will manage running these tasks in order. In this project, the tasks are inherently sequential – the writing depends on the plan, and editing depends on the draft – so we’ll use the default sequential process (one after the other). We just need to list the tasks in the execution order:
from crewai import Crew
crew = Crew(
tasks=[plan_task, write_task, edit_task],
agents=[planner, writer, editor],
verbose=False # (set True to see detailed logs)
)
Here we create a crew with our three tasks and three agents. By default, Crew
will run in a sequential process, meaning it will execute plan_task
first, then write_task
, then edit_task
in sequence. (If we wanted a different order or parallel execution, we could specify a process
parameter, which we’ll discuss later, but for now sequential is straightforward.) The crew ensures that each task output can feed into the next as needed. In a sequential workflow, the order of tasks in the list matters – they will be run in that order.
Finally, to run the project, we “kick off” the crew with the necessary input. For instance, if our {topic}
placeholder should be "Artificial Intelligence", we would call something like:
crew.kickoff(topic="Artificial Intelligence")
This would start the workflow. Under the hood, CrewAI will prompt each agent in turn to do its task. For example, the Content Planner agent would likely use its prompt to search for trends and outline the article. Once it finishes, its output (say, an outline with sections and bullet points of key info) can be passed as context to the Content Writer agent, which then writes the article draft following that outline. Finally, the Editor agent receives the draft and edits it as instructed.
Each agent works autonomously on its task, but the crew ties their work together sequentially. The result at the end of crew.kickoff
would be a final article (the output of the edit task). We won’t delve into the full generated text, but conceptually, you got the Content Planner’s plan, the Writer’s draft, and the Editor’s polished version, all through one coordinated multi-agent process.
The final agent output converted into markdown looks something like this:
This first project demonstrates a simple sequential crew where tasks are dependent and handled one-by-one. Now, let’s look at a slightly more advanced scenario involving tools and a sales-oriented project.
(3) Project 2: AI-Powered Customer Outreach Campaign
Scenario: Imagine you have a list of potential sales leads and you want to automate the research and initial outreach emails. We’ll create a small crew of two agents: a Sales Researcher (to profile a lead) and a Sales Outreach Writer (to draft personalized outreach content). This project will show how agents can use tools (like web search and file reading) to gather information, and how a custom tool can be integrated. We’ll also again use a sequential process for simplicity, but with richer tasks.
Agents with Sales Roles and Goals
For this campaign, we define two agents:
Sales Representative Agent – Role: Lead profiler. Goal: “Identify high-value leads that match our ideal customer profile.” Backstory: This agent acts like a diligent sales researcher, combing through data to find information about a lead (company background, key people, recent news, etc.). It’s equipped to use external resources to build a profile.
Lead Sales Representative Agent – Role: Outreach specialist. Goal: “Nurture leads with personalized, compelling communications.” Backstory: This agent is like a senior salesperson who crafts customized messages that resonate with the client’s context and needs.
We create these similarly with the Agent
class. For example, the Sales Researcher agent in code might be:
sales_rep_agent = Agent(
role="Sales Representative",
goal="Identify high-value leads that match our ideal customer profile",
backstory=(
"As part of CrewAI's sales team, your mission is to scour data and find valuable leads. "
"You analyze information to unearth opportunities others might overlook. "
"Your work paves the way for meaningful engagements and drives growth."
),
allow_delegation=False,
verbose=True
)
And the lead outreach agent (lead_sales_rep_agent
) would be defined similarly (with a backstory emphasizing engaging potential clients). Now we have our two sales-focused agents ready.
Equipping Agents with Tools
One powerful feature of CrewAI is that agents can be given tools to extend their capabilities. Tools are like apps or skills an agent can use – e.g., searching the web, reading files, analyzing text, etc.. CrewAI comes with some built-in tools, and you can create custom ones. In this project, our Sales Rep agent will need to gather information, so we’ll use a few existing tools:
SerperDevTool – a Google Search tool (allowing the agent to perform web searches).
DirectoryReadTool – a tool to list or read files in a directory (we might use this to retrieve internal resources, like documents about sales strategies or lead information).
FileReadTool – a tool to read the content of a specific file (for example, to open a file with detailed instructions or data on the lead).
We will also demonstrate a custom tool: a simple sentiment analysis tool that always returns "positive" (for teaching purposes), to show how easy it is to extend CrewAI with new tools.
First, we import and initialize the tools we need:
from crewai_tools import SerperDevTool, DirectoryReadTool, FileReadTool
# Initialize built-in tools
serper_dev_tool = SerperDevTool() # Web search tool
directory_read_tool = DirectoryReadTool(directory="./instructions") # Tool to read a local 'instructions' folder
file_read_tool = FileReadTool() # Tool to read file contents
Now, let’s create a custom tool for sentiment analysis. CrewAI allows custom tools by subclassing a BaseTool and implementing a _run
method for the tool’s logic. For simplicity, our sentiment tool will just return "positive"
for any input text:
from crewai.tools import BaseTool
class SentimentAnalysisTool(BaseTool):
name: str = "Sentiment Analysis Tool"
description: str = "Analyzes the sentiment of text to ensure communications are positive."
def _run(self, text: str) -> str:
# Dummy sentiment analysis: always returns "positive"
return "positive"
sentiment_analysis_tool = SentimentAnalysisTool()
This toy tool doesn’t actually analyze text (it’s hardcoded to positive), but it shows how one might integrate a custom analytic tool into CrewAI’s ecosystem. In a real scenario, _run
could call an NLP library or API to get sentiment.
Creating Tasks that Use Tools
Now we define the tasks for our outreach campaign. We have two main tasks:
Lead Profiling Task: The Sales Rep agent will research a given lead (a company or person). The task description will instruct the agent to gather information about the lead’s industry, key people, recent developments, and identify how our product might fit their needs. We’ll equip this task with the search and file-reading tools so the agent can pull in information from the web and internal documents. The expected output is a detailed report on the lead.
Personalized Outreach Task: The Lead Sales Rep agent will use the insights from the profile to craft a personalized outreach campaign (e.g., a set of email drafts or messages) targeting a key decision-maker at the lead’s company. This task will use the web search (perhaps to gather any additional context or news) and the sentiment analysis tool (to check or enforce positivity in tone). The expected output is a series of tailored outreach emails.
Here’s how we define these tasks with CrewAI’s Task
class:
lead_profiling_task = Task(
description=(
"Conduct an in-depth analysis of {lead_name}, a company in the {industry} sector that recently showed interest in our solutions. "
"Compile a detailed profile focusing on key decision-makers, recent business developments, and potential needs that align with our offerings.\n"
),
expected_output=(
"A comprehensive report on {lead_name} with company background, key personnel, recent milestones, and identified needs. "
"Highlight how our solutions can provide value and suggest personalized engagement strategies."
),
tools=[serper_dev_tool, directory_read_tool, file_read_tool],
agent=sales_rep_agent
)
personalized_outreach_task = Task(
description=(
"Using the insights from the {lead_name} profile, craft a personalized outreach campaign aimed at {key_decision_maker} (the {position} of {lead_name}). "
"Address their recent {milestone} and how our solutions support their goals. Ensure the tone matches {lead_name}'s company culture and values.\n"
),
expected_output=(
"A series of personalized email drafts tailored to {lead_name}, specifically for {key_decision_maker}. "
"Each draft should connect our solutions to their recent achievements and future goals, with an engaging yet professional tone."
),
tools=[serper_dev_tool, sentiment_analysis_tool],
agent=lead_sales_rep_agent
)
Notice how we included the tools
parameter for each task, listing the tools the agent can use for that task. For the lead_profiling_task, we gave the Sales Rep agent access to serper_dev_tool
(web search), directory_read_tool
and file_read_tool
(to read internal files). This means when the agent is performing the task, it can call out to these tools – for example, doing a Google search query to find news about {lead_name}, or opening an internal knowledge base file for {industry} insights. Similarly, the personalized_outreach_task for the lead sales agent has the search tool (perhaps to quickly fact-check something or find an appropriate reference to the lead’s recent milestone) and the sentiment analysis tool (which could be used to analyze the drafted emails and ensure they have a positive tone).
The placeholders like {lead_name}
, {industry}
, {key_decision_maker}
, etc., will be filled in when we run the crew (just like {topic}
was in Project 1). For example, we might call crew.kickoff(lead_name="Acme Corp", industry="finance", key_decision_maker="Jane Doe", position="CEO", milestone="IPO")
– and the tasks’ descriptions will be formatted with those values.
Assembling the Crew and Running the Campaign
With agents and tasks ready, we form the crew for the outreach project:
crew = Crew(
tasks=[lead_profiling_task, personalized_outreach_task],
agents=[sales_rep_agent, lead_sales_rep_agent],
memory=True,
verbose=False
)
We pass both tasks and both agents into the crew. Here we set memory=True
, which enables CrewAI to keep a shared memory of what happened in previous tasks. This is useful in sequential flows – for instance, the output of the lead profiling task can be stored and made available to the outreach task. (In practice, CrewAI may automatically pass along context or you can specify context variables, but enabling memory ensures nothing is lost between tasks.) We still use the default sequential process, so the crew will run the lead profiling first, then the outreach task second.
To start the process, you would call crew.kickoff()
with the specific lead’s details as arguments (as mentioned above). The Sales Rep agent would then execute the lead profiling: likely performing searches about the company, reading any internal instruction files for that industry, and composing a profile report. Once done, the Lead Sales Rep agent takes over with the outreach task, using the profile’s findings (from memory) to write personalized emails. The sentiment tool might be invoked to check each draft’s tone (in our simple tool’s case, it will always return "positive", but it shows how an agent can call a tool as part of its reasoning to, say, adjust language).
The final agent output converted into markdown looks something like this:
This project highlights how CrewAI lets agents use external tools to augment their abilities (searching web, reading files, analyzing text, etc.), and how tasks can be richer, multi-step instructions. We still kept a linear order (profile then outreach), which is intuitive for this scenario. However, CrewAI can do more than just straight sequences – it also supports different workflow structures.
(4) Workflow Structures: Sequential vs. Hierarchical (and Beyond)
So far, both examples used a sequential process: tasks executed one after the other in a fixed order. CrewAI also offers a hierarchical process and other advanced workflows. It’s important to understand the difference, because choosing the right structure can make your multi-agent system more effective for the problem at hand.
(a) Sequential Workflows
Sequential process: tasks are executed one after another in a straight line.
In a sequential workflow, each task runs in sequence, and typically the output of one task becomes the context for the next. The crew executes tasks in the order they were listed, not moving on until the current task is complete. This is exactly what we did in our projects – plan → write → edit, or profile → outreach. It’s a straightforward pipeline where each step builds on the previous one. S
(b) Hierarchical Workflows
Hierarchical process: a manager agent delegates tasks to other agents (like a team leader coordinating sub-tasks).
A hierarchical workflow introduces a manager agent (or a manager LLM) that oversees the project. Instead of executing tasks in a predetermined order, the manager decides what tasks need to be done, when, and by whom. This is analogous to a project manager in a company: the manager might break a goal into sub-tasks, assign those tasks to the most suitable agents, and then review or integrate the results. In CrewAI’s hierarchical process, the manager agent can dynamically plan and delegate tasks to the other agents in the crew and validate their outputs. This is powerful for complex or open-ended projects.
(c) Hybrid Workflows
Hybrid process: combining sequential and hierarchical elements – e.g., a leader agent assigns parallel tasks to two agents, then a reviewer agent combines their outputs.
CrewAI is flexible enough to allow hybrid structures, which mix sequential and hierarchical patterns. A hybrid workflow might have multiple agents working in parallel on different tasks, and then a subsequent step to integrate their results. For instance, imagine a manager agent assigns two researchers to investigate different aspects of a topic simultaneously (hierarchical delegation with parallel branches), and then after they finish, a third agent sequentially takes those findings and synthesizes them into a report.
(d) Parallel and Asynchronous Workflows
Parallel tasks: two agents (A and B) working simultaneously from a common start.
Not every project is a neat one-thing-after-another. Sometimes, you can do many things at once. Parallel workflows allow multiple tasks (or multiple agents’ tasks) to execute simultaneously, independent of each other. For example, you might have two agents researching different subtopics at the same time to save time, rather than one after the other. CrewAI supports this kind of parallelism via its kickoff methods – for instance, crew.kickoff_for_each()
will execute tasks for each agent in parallel, and crew.kickoff_async()
will start tasks asynchronously (not waiting for one to finish before starting the next).
(5) Day 9 wrap up
In Day 9 of the Vizuara AI Agents Bootcamp, we introduced CrewAI by breaking down its core concepts – Agents, Tasks, and Crews – and walking through two example projects. We saw that:
Agents are the independent AI actors with specific roles, goals, and even backstories to guide their behavior.
Tasks are the actionable assignments we give to agents, complete with instructions and expected outputs (and optionally tools to help them along).
Crews bring agents and tasks together, defining how the tasks are executed (sequentially, or via a manager agent in a hierarchical setup, etc.) to accomplish an overall objective.
See you in Day 10! 👋