CrewAICrewAI 1.15 · Python 3.10 to 3.13
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
35 small wins to finish your pathNext lesson →

Your first crew: agents and tasks

A crew is a team that runs a list of tasks with a list of agents and returns one result; kickoff starts it.

Last updated: 28 Sep, 2026 · CrewAI 1.15

ShopLLM from the custom-LLM lesson answers messages. An agent wraps it with a job, a task says what the job is, and a crew runs them together.

ShopLLM answers messages. An agent wraps it with a job description, in three parts CrewAI requires: a role, a goal and a backstory.

Project files used on this pageThis lesson builds on a project from earlier lessons. The code below imports this file. Click a file to see its code, or follow the link to the lesson that wrote it. To run the code yourself, keep it in the same folder.
View the code here
shop_llm.py
import os
import re

from crewai import BaseLLM

os.environ["CREWAI_DISABLE_TELEMETRY"] = "true"
os.environ["CREWAI_TRACING_ENABLED"] = "false"
os.environ["CREWAI_DISABLE_VERSION_CHECK"] = "true"


class ShopLLM(BaseLLM):
    def call(self, messages, tools=None, **kwargs):
        if isinstance(messages, str):
            messages = [{"role": "user", "content": messages}]
        text = messages[-1]["content"]
        orders = re.findall(r"\b[A-Z]\d+\b", text)
        if orders:
            return f"I have no way to look up {orders[0]} yet."
        return "Hello. Which order is this about?"

An agent

Example
from crewai import Agent
from shop_llm import ShopLLM

agent = Agent(
    role="Support agent",
    goal="Answer customers of a small online shop",
    backstory="You have worked the shop's support desk for years.",
    llm=ShopLLM(model="shop"),
)

print(agent.role)

Nothing ran yet. The agent is a description of a worker; it needs a task.

A task and a crew

Example
from crewai import Crew, Task

task = Task(
    description="Answer the customer: Where is my order A17?",
    expected_output="One short, friendly sentence.",
    agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])

result = crew.kickoff()
print(result.raw)

A task has a description of the work and an expected_output saying what finished looks like, and names the agent that does it. The crew takes lists of agents and tasks. kickoff runs the tasks and returns a CrewOutput, whose raw is the last task's answer as text.

Reading each task's output

Example
result = crew.kickoff()

for output in result.tasks_output:
    print(output.agent, "|", output.raw)

tasks_output keeps one result per task, each tagged with the role of the agent that produced it. With one task there is one entry; a crew of two agents has two.

An agent, a task and the crew that runs them
inputsresultrunscallsYour codekickoff()Crewagents and tasksTaskdescription, outputAgentrole, goal, backstoryShopLLMdecides the reply
Hover or tap a piece to see what it is and which lesson built it.
Trace one kickoff

Pick one to watch it run, step by step.

The crew holds the lists; the task says what to do and who does it; the agent turns that into messages for the model. A run this small has four moving parts, and you wrote one of them.

An agent with no model

Example
from crewai import Agent

agent = Agent(
    role="Support agent",
    goal="Answer customers of a small online shop",
    backstory="You have worked the shop's support desk for years.",
)
print(agent.llm.model)

Leaving out llm makes CrewAI choose a hosted OpenAI model. The installed 1.15 selects gpt-4.1-mini here, printed above; the choice can change between versions, and the Agents page of the documentation still names an older default, so pass llm= yourself rather than depend on it. Creating the agent works. Running it is where the key is needed:

Example
from crewai import Agent, Crew, Task
import shop_llm

agent = Agent(role="Support agent", goal="Answer customers", backstory="You work the desk.")
task = Task(description="Where is my order A17?", expected_output="One sentence.", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()

CrewAI tried the call three times before giving up, and printed a warning line for each failed call. import shop_llm is there only for its three settings, so the failed run sends nothing. Every agent below passes llm= explicitly.

What kickoff hands back

  • kickoff returns a CrewOutput; its raw is the last task's answer as text.
  • tasks_output holds one entry per task, each tagged with the role of the agent that produced it.
  • Leaving out llm still builds the agent; the missing key only bites at kickoff.

raw vs tasks_output

AttributeHoldsReach for it when
result.rawthe last task's answer as textyou want the final reply
result.tasks_outputone output per taskyou need each step's result
output.agentthe role that produced ityou trace who did what

When a crew earns its place

  • The work has more than one step, and each step has a clear owner.
  • You want one result out, with the steps in between recorded.
  • Different steps need different tools or different instructions.
Watch out
Omitting llm makes CrewAI reach for a hosted model, so a run with no key fails at kickoff, not at Agent(...). Pass llm= to every agent to stay offline.
Try it yourself
  • Change the task's description to ask about C40 and run the crew again.
  • Delete expected_output from the task and read the error.
  • Print result.tasks_output[0].description.

This is what real progress feels like.