Tasks: Describing the Work

An agent is a capability; a task is the assignment — and the two fields that define a task, its description and its expected output, are where you turn "a smart agent" into "the specific result I need."

If an agent is who does the work, a task is what the work is. Tasks are how you translate a goal into a concrete, checkable assignment, and the discipline of describing them well — especially their expected output — is what makes a crew produce what you actually wanted rather than something plausible-but-off. This third post in the CrewAI series covers tasks.

What a task is

A task is a specific assignment given to an agent, defined primarily by two fields:

from crewai import Task

research = Task(
    description=(
        "Research the top regulatory changes affecting {industry} this year. "
        "Focus on changes that take effect within 12 months."
    ),
    expected_output=(
        "A markdown list of 3-5 changes. For each: the rule, its effective date, "
        "and one sentence on its impact. Cite a source for each."
    ),
    agent=researcher,
)

The task is assigned to an agent (agent=), or in a hierarchical crew left for the manager to delegate. A crew is fundamentally a set of these tasks, executed in an order determined by its process.

expected_output is the field that decides quality

The single most important habit with CrewAI tasks: write a precise expected_output. Because LLM agents will happily produce something, the difference between a useful result and a vague one is usually how clearly you specified what the output should be. “A summary” gets you an unpredictable blob; “a markdown list of exactly 5 items, each under 20 words, with a source URL” gets you something consistent and usable downstream.

expected_output does double duty. It steers the agent toward the right shape, and it gives you a checkable definition of done — a specification you can evaluate against. Treat it the way you’d treat an API response schema: the more precisely you define the shape, the more reliably you get it. This is the task-level version of the constrained-output discipline that runs through good AI engineering.

Passing data in and structuring data out

Tasks aren’t static text. Two mechanisms make them dynamic and reliable:

Structured output is worth reaching for whenever a task’s result feeds something automated. It turns “the agent usually returns roughly the right shape” into “the result is a validated object,” which is the difference between a demo and a system.

Context: tasks building on tasks

Tasks in a crew rarely stand alone — later tasks build on earlier ones. CrewAI lets a task receive the output of previous tasks as context, so a “write the report” task can consume the “research the topic” task’s findings. This is how a sequential crew forms a pipeline: research → analyze → write, each task grounded in the last. Designing that context flow deliberately — which prior outputs each task needs — is part of designing a good crew, and it keeps each agent focused on its step with exactly the inputs it requires rather than the whole history.

Task design principles

A few habits separate crews that work from crews that flail:

Get these right and the crew’s behavior becomes predictable; get them wrong and you’ll be debugging vague outputs with no clear notion of what “correct” even was.

Key takeaways

Further reading

Sources & References