In the CrewAI framework, a Task is a specific assignment completed by an Agent.
Tasks provide all necessary details for execution, such as a description, the agent responsible, required tools, and more, facilitating a wide range of action complexities.
Tasks within CrewAI can be collaborative, requiring multiple agents to work together. This is managed through the task properties and orchestrated by the Crew’s process, enhancing teamwork and efficiency.
CrewAI Enterprise includes a Visual Task Builder in Crew Studio that simplifies complex task creation and chaining. Design your task flows visually and test them in real-time without writing code.
Using YAML configuration provides a cleaner, more maintainable way to define tasks. We strongly recommend using this approach to define tasks in your CrewAI projects.
After creating your CrewAI project as outlined in the Installation section, navigate to the src/latest_ai_development/config/tasks.yaml file and modify the template to match your specific task requirements.
Variables in your YAML files (like {topic}) will be replaced with values from your inputs when running the crew:
Code
Copy
Ask AI
crew.kickoff(inputs={'topic': 'AI Agents'})
Here’s an example of how to configure tasks using YAML:
tasks.yaml
Copy
Ask AI
research_task: description: > Conduct a thorough research about {topic} Make sure you find any interesting and relevant information given the current year is 2025. expected_output: > A list with 10 bullet points of the most relevant information about {topic} agent: researcher guardrail: ensure each bullet contains a minimum of 100 wordsreporting_task: description: > Review the context you got and expand each topic into a full section for a report. Make sure the report is detailed and contains any and all relevant information. expected_output: > A fully fledge reports with the mains topics, each with a full section of information. Formatted as markdown without '```' agent: reporting_analyst markdown: true output_file: report.md
To use this YAML configuration in your code, create a crew class that inherits from CrewBase:
Alternatively, you can define tasks directly in your code without using YAML configuration:
task.py
Copy
Ask AI
from crewai import Taskresearch_task = Task( description=""" Conduct a thorough research about AI Agents. Make sure you find any interesting and relevant information given the current year is 2025. """, expected_output=""" A list with 10 bullet points of the most relevant information about AI Agents """, agent=researcher)reporting_task = Task( description=""" Review the context you got and expand each topic into a full section for a report. Make sure the report is detailed and contains any and all relevant information. """, expected_output=""" A fully fledge reports with the mains topics, each with a full section of information. """, agent=reporting_analyst, markdown=True, # Enable markdown formatting for the final output output_file="report.md")
Directly specify an agent for assignment or let the hierarchical CrewAI’s process decide based on roles, availability, etc.
Understanding task outputs is crucial for building effective AI workflows. CrewAI provides a structured way to handle task results through the TaskOutput class, which supports multiple output formats and can be easily passed between tasks.
The output of a task in CrewAI framework is encapsulated within the TaskOutput class. This class provides a structured way to access results of a task, including various formats such as raw output, JSON, and Pydantic models.
By default, the TaskOutput will only include the raw output. A TaskOutput will only include the pydantic or json_dict output if the original Task object was configured with output_pydantic or output_json, respectively.
Once a task has been executed, its output can be accessed through the output attribute of the Task object. The TaskOutput class provides various ways to interact with and present this output.
# Example tasktask = Task( description='Find and summarize the latest AI news', expected_output='A bullet list summary of the top 5 most important AI news', agent=research_agent, tools=[search_tool])# Execute the crewcrew = Crew( agents=[research_agent], tasks=[task], verbose=True)result = crew.kickoff()# Accessing the task outputtask_output = task.outputprint(f"Task Description: {task_output.description}")print(f"Task Summary: {task_output.summary}")print(f"Raw Output: {task_output.raw}")if task_output.json_dict: print(f"JSON Output: {json.dumps(task_output.json_dict, indent=2)}")if task_output.pydantic: print(f"Pydantic Output: {task_output.pydantic}")
The markdown parameter enables automatic markdown formatting for task outputs. When set to True, the task will instruct the agent to format the final answer using proper Markdown syntax.
# Example task with markdown formatting enabledformatted_task = Task( description="Create a comprehensive report on AI trends", expected_output="A well-structured report with headers, sections, and bullet points", agent=reporter_agent, markdown=True # Enable automatic markdown formatting)
When markdown=True, the agent will receive additional instructions to format the output using:
analysis_task: description: > Analyze the market data and create a detailed report expected_output: > A comprehensive analysis with charts and key findings agent: analyst markdown: true # Enable markdown formatting output_file: analysis.md
Consistent Formatting: Ensures all outputs follow proper markdown conventions
Better Readability: Structured content with headers, lists, and emphasis
Documentation Ready: Output can be directly used in documentation systems
Cross-Platform Compatibility: Markdown is universally supported
The markdown formatting instructions are automatically added to the task prompt when markdown=True, so you don’t need to specify formatting requirements in your task description.
Tasks can depend on the output of other tasks using the context attribute. For example:
Code
Copy
Ask AI
research_task = Task( description="Research the latest developments in AI", expected_output="A list of recent AI developments", agent=researcher)analysis_task = Task( description="Analyze the research findings and identify key trends", expected_output="Analysis report of AI trends", agent=analyst, context=[research_task] # This task will wait for research_task to complete)
Task guardrails provide a way to validate and transform task outputs before they
are passed to the next task. This feature helps ensure data quality and provides
feedback to agents when their output doesn’t meet specific criteria.
Guardrails can be defined in two ways:
Function-based guardrails: Python functions that implement custom validation logic
String-based guardrails: Natural language descriptions that are automatically converted to LLM-powered validation
String-based guardrails allow you to describe validation criteria in natural language. When you provide a string instead of a function, CrewAI automatically converts it to an LLMGuardrail that uses an AI agent to validate the task output.
from crewai import Task# Simple string-based guardrailblog_task = Task( description="Write a blog post about AI", expected_output="A blog post under 200 words", agent=blog_agent, guardrail="Ensure the blog post is under 200 words and includes practical examples")# More complex validation criteriaresearch_task = Task( description="Research AI trends for 2025", expected_output="A comprehensive research report", agent=research_agent, guardrail="Ensure each finding includes a credible source and is backed by recent data from 2024-2025")
research_task: description: Research the latest AI developments expected_output: A list of 10 bullet points about AI agent: researcher guardrail: ensure each bullet contains a minimum of 100 wordsvalidation_task: description: Validate the research findings expected_output: A validation report agent: validator guardrail: confirm all sources are from reputable publications and published within the last 2 years
The LLMGuardrail class is the underlying mechanism that powers string-based guardrails. You can also use it directly for more advanced control:
Code
Copy
Ask AI
from crewai import Taskfrom crewai.tasks.llm_guardrail import LLMGuardrailfrom crewai.llm import LLM# Create a custom LLMGuardrail with specific LLMcustom_guardrail = LLMGuardrail( description="Ensure the response contains exactly 5 bullet points with proper citations", llm=LLM(model="gpt-4o-mini"))task = Task( description="Research AI safety measures", expected_output="A detailed analysis with bullet points", agent=research_agent, guardrail=custom_guardrail)
Note: When you use a string guardrail, CrewAI automatically creates an LLMGuardrail instance using your task’s agent LLM. Using LLMGuardrail directly gives you more control over the validation process and LLM selection.
The output_pydantic property allows you to define a Pydantic model that the task output should conform to. This ensures that the output is not only structured but also validated according to the Pydantic model.
Here’s an example demonstrating how to use output_pydantic:
Code
Copy
Ask AI
import jsonfrom crewai import Agent, Crew, Process, Taskfrom pydantic import BaseModelclass Blog(BaseModel): title: str content: strblog_agent = Agent( role="Blog Content Generator Agent", goal="Generate a blog title and content", backstory="""You are an expert content creator, skilled in crafting engaging and informative blog posts.""", verbose=False, allow_delegation=False, llm="gpt-4o",)task1 = Task( description="""Create a blog title and content on a given topic. Make sure the content is under 200 words.""", expected_output="A compelling blog title and well-written content.", agent=blog_agent, output_pydantic=Blog,)# Instantiate your crew with a sequential processcrew = Crew( agents=[blog_agent], tasks=[task1], verbose=True, process=Process.sequential,)result = crew.kickoff()# Option 1: Accessing Properties Using Dictionary-Style Indexingprint("Accessing Properties - Option 1")title = result["title"]content = result["content"]print("Title:", title)print("Content:", content)# Option 2: Accessing Properties Directly from the Pydantic Modelprint("Accessing Properties - Option 2")title = result.pydantic.titlecontent = result.pydantic.contentprint("Title:", title)print("Content:", content)# Option 3: Accessing Properties Using the to_dict() Methodprint("Accessing Properties - Option 3")output_dict = result.to_dict()title = output_dict["title"]content = output_dict["content"]print("Title:", title)print("Content:", content)# Option 4: Printing the Entire Blog Objectprint("Accessing Properties - Option 5")print("Blog:", result)
In this example:
A Pydantic model Blog is defined with title and content fields.
The task task1 uses the output_pydantic property to specify that its output should conform to the Blog model.
After executing the crew, you can access the structured output in multiple ways as shown.
Dictionary-Style Indexing: You can directly access the fields using result[“field_name”]. This works because the CrewOutput class implements the getitem method.
Directly from Pydantic Model: Access the attributes directly from the result.pydantic object.
Using to_dict() Method: Convert the output to a dictionary and access the fields.
Printing the Entire Object: Simply print the result object to see the structured output.
The output_json property allows you to define the expected output in JSON format. This ensures that the task’s output is a valid JSON structure that can be easily parsed and used in your application.
Here’s an example demonstrating how to use output_json:
Code
Copy
Ask AI
import jsonfrom crewai import Agent, Crew, Process, Taskfrom pydantic import BaseModel# Define the Pydantic model for the blogclass Blog(BaseModel): title: str content: str# Define the agentblog_agent = Agent( role="Blog Content Generator Agent", goal="Generate a blog title and content", backstory="""You are an expert content creator, skilled in crafting engaging and informative blog posts.""", verbose=False, allow_delegation=False, llm="gpt-4o",)# Define the task with output_json set to the Blog modeltask1 = Task( description="""Create a blog title and content on a given topic. Make sure the content is under 200 words.""", expected_output="A JSON object with 'title' and 'content' fields.", agent=blog_agent, output_json=Blog,)# Instantiate the crew with a sequential processcrew = Crew( agents=[blog_agent], tasks=[task1], verbose=True, process=Process.sequential,)# Kickoff the crew to execute the taskresult = crew.kickoff()# Option 1: Accessing Properties Using Dictionary-Style Indexingprint("Accessing Properties - Option 1")title = result["title"]content = result["content"]print("Title:", title)print("Content:", content)# Option 2: Printing the Entire Blog Objectprint("Accessing Properties - Option 2")print("Blog:", result)
In this example:
A Pydantic model Blog is defined with title and content fields, which is used to specify the structure of the JSON output.
The task task1 uses the output_json property to indicate that it expects a JSON output conforming to the Blog model.
After executing the crew, you can access the structured JSON output in two ways as shown.
Accessing Properties Using Dictionary-Style Indexing: You can access the fields directly using result[“field_name”]. This is possible because the CrewOutput class implements the getitem method, allowing you to treat the output like a dictionary. In this option, we’re retrieving the title and content from the result.
Printing the Entire Blog Object: By printing result, you get the string representation of the CrewOutput object. Since the str method is implemented to return the JSON output, this will display the entire output as a formatted string representing the Blog object.
By using output_pydantic or output_json, you ensure that your tasks produce outputs in a consistent and structured format, making it easier to process and utilize the data within your application or across multiple tasks.
import osos.environ["OPENAI_API_KEY"] = "Your Key"os.environ["SERPER_API_KEY"] = "Your Key" # serper.dev API keyfrom crewai import Agent, Task, Crewfrom crewai_tools import SerperDevToolresearch_agent = Agent( role='Researcher', goal='Find and summarize the latest AI news', backstory="""You're a researcher at a large company. You're responsible for analyzing data and providing insights to the business.""", verbose=True)# to perform a semantic search for a specified query from a text's content across the internetsearch_tool = SerperDevTool()task = Task( description='Find and summarize the latest AI news', expected_output='A bullet list summary of the top 5 most important AI news', agent=research_agent, tools=[search_tool])crew = Crew( agents=[research_agent], tasks=[task], verbose=True)result = crew.kickoff()print(result)
This demonstrates how tasks with specific tools can override an agent’s default set for tailored task execution.
In CrewAI, the output of one task is automatically relayed into the next one, but you can specifically define what tasks’ output, including multiple, should be used as context for another task.
This is useful when you have a task that depends on the output of another task that is not performed immediately after it. This is done through the context attribute of the task:
Code
Copy
Ask AI
# ...research_ai_task = Task( description="Research the latest developments in AI", expected_output="A list of recent AI developments", async_execution=True, agent=research_agent, tools=[search_tool])research_ops_task = Task( description="Research the latest developments in AI Ops", expected_output="A list of recent AI Ops developments", async_execution=True, agent=research_agent, tools=[search_tool])write_blog_task = Task( description="Write a full blog post about the importance of AI and its latest news", expected_output="Full blog post that is 4 paragraphs long", agent=writer_agent, context=[research_ai_task, research_ops_task])#...
You can define a task to be executed asynchronously. This means that the crew will not wait for it to be completed to continue with the next task. This is useful for tasks that take a long time to be completed, or that are not crucial for the next tasks to be performed.
You can then use the context attribute to define in a future task that it should wait for the output of the asynchronous task to be completed.
Code
Copy
Ask AI
#...list_ideas = Task( description="List of 5 interesting ideas to explore for an article about AI.", expected_output="Bullet point list of 5 ideas for an article.", agent=researcher, async_execution=True # Will be executed asynchronously)list_important_history = Task( description="Research the history of AI and give me the 5 most important events.", expected_output="Bullet point list of 5 important events.", agent=researcher, async_execution=True # Will be executed asynchronously)write_article = Task( description="Write an article about AI, its history, and interesting ideas.", expected_output="A 4 paragraph article about AI.", agent=writer, context=[list_ideas, list_important_history] # Will wait for the output of the two tasks to be completed)#...
The callback function is executed after the task is completed, allowing for actions or notifications to be triggered based on the task’s outcome.
Code
Copy
Ask AI
# ...def callback_function(output: TaskOutput): # Do something after the task is completed # Example: Send an email to the manager print(f""" Task completed! Task: {output.description} Output: {output.raw} """)research_task = Task( description='Find and summarize the latest AI news', expected_output='A bullet list summary of the top 5 most important AI news', agent=research_agent, tools=[search_tool], callback=callback_function)#...
Once a crew finishes running, you can access the output of a specific task by using the output attribute of the task object:
Code
Copy
Ask AI
# ...task1 = Task( description='Find and summarize the latest AI news', expected_output='A bullet list summary of the top 5 most important AI news', agent=research_agent, tools=[search_tool])#...crew = Crew( agents=[research_agent], tasks=[task1, task2, task3], verbose=True)result = crew.kickoff()# Returns a TaskOutput object with the description and results of the taskprint(f""" Task completed! Task: {task1.output.description} Output: {task1.output.raw}""")
While creating and executing tasks, certain validation mechanisms are in place to ensure the robustness and reliability of task attributes. These include but are not limited to:
Ensuring only one output type is set per task to maintain clear output expectations.
Preventing the manual assignment of the id attribute to uphold the integrity of the unique identifier system.
These validations help in maintaining the consistency and reliability of task executions within the crewAI framework.
You can now specify if a task should create directories when saving its output to a file. This is particularly useful for organizing outputs and ensuring that file paths are correctly structured.
Code
Copy
Ask AI
# ...save_output_task = Task( description='Save the summarized AI news to a file', expected_output='File saved successfully', agent=research_agent, tools=[file_save_tool], output_file='outputs/ai_news_summary.txt', create_directory=True)#...
Check out the video below to see how to use structured outputs in CrewAI:
Tasks are the driving force behind the actions of agents in CrewAI.
By properly defining tasks and their outcomes, you set the stage for your AI agents to work effectively, either independently or as a collaborative unit.
Equipping tasks with appropriate tools, understanding the execution process, and following robust validation practices are crucial for maximizing CrewAI’s potential,
ensuring agents are effectively prepared for their assignments and that tasks are executed as intended.
Assistant
Responses are generated using AI and may contain mistakes.