跳转到主要内容

文档索引

获取完整文档索引: https://docs.crewai.com.cn/llms.txt

在深入了解之前,请使用此文件来浏览所有可用页面。

概述

在 CrewAI 框架中,Task(任务)是由 Agent(智能体)完成的特定工作分配。 任务提供了执行所需的所有必要细节,例如描述、负责的智能体、所需工具等,从而支持广泛的复杂操作。 CrewAI 中的任务可以是协作性的,需要多个智能体共同完成。这通过任务属性进行管理,并由 Crew(团队)的流程进行编排,从而增强团队协作和效率。
CrewAI AMP 在 Crew Studio 中包含了一个可视化任务构建器,简化了复杂任务的创建和链式连接。您可以直观地设计任务流,并在不编写代码的情况下进行实时测试。任务构建器截图可视化任务构建器支持:
  • 拖拽式任务创建
  • 可视化任务依赖关系和流程
  • 实时测试和验证
  • 轻松共享和协作

任务执行流程

任务可以通过两种方式执行
  • 序列式 (Sequential):任务按照定义的顺序执行
  • 层级式 (Hierarchical):根据智能体的角色和专业知识分配任务
执行流程在创建团队 (Crew) 时定义
代码
crew = Crew(
    agents=[agent1, agent2],
    tasks=[task1, task2],
    process=Process.sequential  # or Process.hierarchical
)

任务属性

属性参数类型描述
描述description (描述)str对任务内容的清晰、简洁说明。
预期输出expected_output (预期输出)str对任务完成情况的详细描述。
名称 (可选)name (名称)Optional[str]任务的名称标识符。
智能体 (可选)agent (智能体)Optional[BaseAgent]负责执行任务的智能体。
工具 (可选)tools (工具)List[BaseTool]智能体在此任务中被限制使用的工具/资源。
上下文 (可选)context (上下文)Optional[List["Task"]]其他任务,其输出将被用作当前任务的上下文。
异步执行 (可选)async_execution (异步执行)Optional[bool]任务是否应异步执行。默认为 False。
人工输入 (可选)human_input (人工输入)Optional[bool]任务是否需要人工审核智能体的最终答案。默认为 False。
Markdown (可选)markdown (Markdown 格式)Optional[bool]任务是否应指示智能体返回采用 Markdown 格式的最终答案。默认为 False。
配置 (可选)config (配置)Optional[Dict[str, Any]]特定于任务的配置参数。
输出文件 (可选)output_file (输出文件)Optional[str]用于存储任务输出的文件路径。
创建目录 (可选)create_directory (创建目录)Optional[bool]如果 output_file 的目录不存在,是否创建该目录。默认为 True。
输出 JSON (可选)output_json (输出 JSON)Optional[Type[BaseModel]]用于构建 JSON 输出的 Pydantic 模型。
输出 Pydantic (可选)output_pydantic (输出 Pydantic)Optional[Type[BaseModel]]用于任务输出的 Pydantic 模型。
回调 (可选)callback (回调)Optional[Any]任务完成后执行的函数/对象。
护栏 (可选)guardrail (护栏)Optional[Callable]在进入下一个任务之前,用于验证任务输出的函数。
护栏列表 (可选)guardrails (护栏列表)Optional[List[Callable]]在进入下一个任务之前,用于验证任务输出的护栏列表。
护栏最大重试次数 (可选)guardrail_max_retries (护栏最大重试次数)Optional[int]当护栏验证失败时的最大重试次数。默认为 3。
任务属性 max_retries 已弃用,将在 v1.0.0 中移除。请改用 guardrail_max_retries 来控制护栏验证失败时的重试尝试。

创建任务

在 CrewAI 中创建任务有两种方式:使用 YAML 配置(推荐)直接在代码中定义 使用 YAML 配置提供了一种更简洁、更易于维护的任务定义方式。我们强烈建议在您的 CrewAI 项目中使用此方法来定义任务。 按照安装部分概述的步骤创建 CrewAI 项目后,导航至 src/latest_ai_development/config/tasks.yaml 文件,并根据您的具体任务需求修改模板。
YAML 文件中的变量(如 {topic})在运行团队时会被输入值所替换
代码
crew.kickoff(inputs={'topic': 'AI Agents'})
以下是使用 YAML 配置任务的示例
tasks.yaml
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

reporting_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
要在代码中使用此 YAML 配置,请创建一个继承自 CrewBase 的团队类
crew.py
# src/latest_ai_development/crew.py

from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool

@CrewBase
class LatestAiDevelopmentCrew():
  """LatestAiDevelopment crew"""

  @agent
  def researcher(self) -> Agent:
    return Agent(
      config=self.agents_config['researcher'], # type: ignore[index]
      verbose=True,
      tools=[SerperDevTool()]
    )

  @agent
  def reporting_analyst(self) -> Agent:
    return Agent(
      config=self.agents_config['reporting_analyst'], # type: ignore[index]
      verbose=True
    )

  @task
  def research_task(self) -> Task:
    return Task(
      config=self.tasks_config['research_task'] # type: ignore[index]
    )

  @task
  def reporting_task(self) -> Task:
    return Task(
      config=self.tasks_config['reporting_task'] # type: ignore[index]
    )

  @crew
  def crew(self) -> Crew:
    return Crew(
      agents=[
        self.researcher(),
        self.reporting_analyst()
      ],
      tasks=[
        self.research_task(),
        self.reporting_task()
      ],
      process=Process.sequential
    )
在 YAML 文件(agents.yamltasks.yaml)中使用的名称应与 Python 代码中的方法名称匹配。

直接代码定义(替代方案)

或者,您也可以直接在代码中定义任务,无需使用 YAML 配置
task.py
from crewai import Task

research_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"
)
直接为任务指定 agent,或者让 CrewAI 的 hierarchical(层级)流程根据角色、可用性等自动决定。

任务输出

理解任务输出对于构建有效的 AI 工作流至关重要。CrewAI 通过 TaskOutput 类提供了一种处理任务结果的结构化方式,该类支持多种输出格式,并可轻松在任务之间传递。 CrewAI 框架中的任务输出被封装在 TaskOutput 类中。该类提供了一种访问任务结果的结构化方式,包括原始输出、JSON 和 Pydantic 模型等多种格式。 默认情况下,TaskOutput 仅包含 raw(原始)输出。只有在原始 Task 对象配置了 output_pydanticoutput_json 时,TaskOutput 才会分别包含 pydanticjson_dict 输出。

任务输出属性

属性参数类型描述
描述description (描述)str任务描述。
摘要summary (摘要)Optional[str]任务摘要,根据描述的前 10 个词自动生成。
原始输出raw (原始)str任务的原始输出。这是输出的默认格式。
Pydantic 模型pydanticOptional[BaseModel]代表任务结构化输出的 Pydantic 模型对象。
JSON 字典json_dictOptional[Dict[str, Any]]代表任务 JSON 输出的字典。
智能体agent (智能体)str执行任务的智能体。
输出格式output_format (输出格式)OutputFormat任务输出的格式,选项包括 RAW、JSON 和 Pydantic。默认为 RAW。
消息messages (消息)list[LLMMessage]最后一次任务执行产生的消息。

任务方法和属性

方法/属性描述
json如果输出格式为 JSON,则返回任务输出的 JSON 字符串表示形式。
to_dict将 JSON 和 Pydantic 输出转换为字典。
str返回任务输出的字符串表示形式,优先级为:Pydantic -> JSON -> 原始。

访问任务输出

任务执行完成后,可以通过 Task 对象的 output 属性访问其输出。TaskOutput 类提供了多种与该输出交互并进行展示的方式。

示例

代码
# Example task
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]
)

# Execute the crew
crew = Crew(
    agents=[research_agent],
    tasks=[task],
    verbose=True
)

result = crew.kickoff()

# Accessing the task output
task_output = task.output

print(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}")

Markdown 输出格式化

markdown 参数支持为任务输出启用自动 Markdown 格式化。设置为 True 时,任务将指示智能体使用正确的 Markdown 语法格式化最终答案。

使用 Markdown 格式化

代码
# Example task with markdown formatting enabled
formatted_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
)
markdown=True 时,智能体将收到额外指令,要求使用以下格式:
  • # 用于标题
  • **text** 用于粗体文本
  • *text* 用于斜体文本
  • -* 用于项目符号列表
  • `code` 用于行内代码
  • ``` 语言名 ``` 用于代码块

带有 Markdown 的 YAML 配置

tasks.yaml
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

Markdown 输出的好处

  • 一致的格式:确保所有输出都遵循正确的 Markdown 约定
  • 更好的可读性:带有标题、列表和强调的结构化内容
  • 文档就绪:输出可直接用于文档系统
  • 跨平台兼容性:Markdown 得到普遍支持
markdown=True 时,Markdown 格式化指令会自动添加到任务提示词中,因此您无需在任务描述中指定格式要求。

任务依赖关系和上下文

任务可以使用 context 属性依赖于其他任务的输出。例如:
代码
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
)

任务护栏 (Guardrails)

任务护栏提供了一种在任务输出传递给下一个任务之前对其进行验证和转换的方法。此功能有助于确保数据质量,并在输出不满足特定标准时向智能体提供反馈。 CrewAI 支持两种类型的护栏:
  1. 基于函数的护栏:具有自定义验证逻辑的 Python 函数,让您可以完全控制验证过程并确保可靠、确定的结果。
  2. 基于 LLM 的护栏:使用智能体的 LLM 根据自然语言标准验证输出的字符串描述。它们非常适合复杂或主观的验证要求。

基于函数的护栏

要为任务添加基于函数的护栏,请通过 guardrail 参数提供验证函数
代码
from typing import Tuple, Union, Dict, Any
from crewai import TaskOutput

def validate_blog_content(result: TaskOutput) -> Tuple[bool, Any]:
    """Validate blog content meets requirements."""
    try:
        # Check word count
        word_count = len(result.raw.split())
        if word_count > 200:
            return (False, "Blog content exceeds 200 words")

        # Additional validation logic here
        return (True, result.raw.strip())
    except Exception as e:
        return (False, "Unexpected error during validation")

blog_task = Task(
    description="Write a blog post about AI",
    expected_output="A blog post under 200 words",
    agent=blog_agent,
    guardrail=validate_blog_content  # Add the guardrail function
)

基于 LLM 的护栏(字符串描述)

无需编写自定义验证函数,您可以使用利用 LLM 验证的字符串描述。当您向 guardrailguardrails 参数提供字符串时,CrewAI 会自动创建一个 LLMGuardrail,它使用智能体的 LLM 根据您的描述来验证输出。 要求
  • 任务必须指定 agent(护栏使用该智能体的 LLM)
  • 提供一个清晰、描述性的字符串,解释验证标准
代码
from crewai import Task

# Single LLM-based guardrail
blog_task = Task(
    description="Write a blog post about AI",
    expected_output="A blog post under 200 words",
    agent=blog_agent,
    guardrail="The blog post must be under 200 words and contain no technical jargon"
)
基于 LLM 的护栏特别适用于:
  • 复杂的验证逻辑:难以通过编程表达的逻辑
  • 主观标准:如语气、风格或质量评估
  • 自然语言要求:比代码更容易描述的要求
LLM 护栏将:
  1. 根据您的描述分析任务输出
  2. 如果输出符合标准,返回 (True, output)
  3. 如果验证失败,返回 (False, feedback) 并提供具体反馈
包含详细验证标准的示例:
代码
research_task = Task(
    description="Research the latest developments in quantum computing",
    expected_output="A comprehensive research report",
    agent=researcher_agent,
    guardrail="""
    The research report must:
    - Be at least 1000 words long
    - Include at least 5 credible sources
    - Cover both technical and practical applications
    - Be written in a professional, academic tone
    - Avoid speculation or unverified claims
    """
)

多个护栏

您可以使用 guardrails 参数为任务应用多个护栏。多个护栏按顺序执行,每个护栏接收上一个护栏的输出。这允许您链接验证和转换步骤。 guardrails 参数接受:
  • 护栏函数或字符串描述列表
  • 单个护栏函数或字符串(与 guardrail 相同)
注意:如果提供了 guardrails,它将优先于 guardrail。设置 guardrails 时,guardrail 参数将被忽略。
代码
from typing import Tuple, Any
from crewai import TaskOutput, Task

def validate_word_count(result: TaskOutput) -> Tuple[bool, Any]:
    """Validate word count is within limits."""
    word_count = len(result.raw.split())
    if word_count < 100:
        return (False, f"Content too short: {word_count} words. Need at least 100 words.")
    if word_count > 500:
        return (False, f"Content too long: {word_count} words. Maximum is 500 words.")
    return (True, result.raw)

def validate_no_profanity(result: TaskOutput) -> Tuple[bool, Any]:
    """Check for inappropriate language."""
    profanity_words = ["badword1", "badword2"]  # Example list
    content_lower = result.raw.lower()
    for word in profanity_words:
        if word in content_lower:
            return (False, f"Inappropriate language detected: {word}")
    return (True, result.raw)

def format_output(result: TaskOutput) -> Tuple[bool, Any]:
    """Format and clean the output."""
    formatted = result.raw.strip()
    # Capitalize first letter
    formatted = formatted[0].upper() + formatted[1:] if formatted else formatted
    return (True, formatted)

# Apply multiple guardrails sequentially
blog_task = Task(
    description="Write a blog post about AI",
    expected_output="A well-formatted blog post between 100-500 words",
    agent=blog_agent,
    guardrails=[
        validate_word_count,      # First: validate length
        validate_no_profanity,    # Second: check content
        format_output             # Third: format the result
    ],
    guardrail_max_retries=3
)
在此示例中,护栏按顺序执行:
  1. validate_word_count 检查字数
  2. validate_no_profanity 检查不当语言(使用步骤 1 的输出)
  3. format_output 格式化最终结果(使用步骤 2 的输出)
如果任何护栏失败,错误会被发送回智能体,任务最多重试 guardrail_max_retries 次。 混合基于函数和基于 LLM 的护栏 您可以在同一个列表中组合使用基于函数和基于字符串的护栏:
代码
from typing import Tuple, Any
from crewai import TaskOutput, Task

def validate_word_count(result: TaskOutput) -> Tuple[bool, Any]:
    """Validate word count is within limits."""
    word_count = len(result.raw.split())
    if word_count < 100:
        return (False, f"Content too short: {word_count} words. Need at least 100 words.")
    if word_count > 500:
        return (False, f"Content too long: {word_count} words. Maximum is 500 words.")
    return (True, result.raw)

# Mix function-based and LLM-based guardrails
blog_task = Task(
    description="Write a blog post about AI",
    expected_output="A well-formatted blog post between 100-500 words",
    agent=blog_agent,
    guardrails=[
        validate_word_count,  # Function-based: precise word count check
        "The content must be engaging and suitable for a general audience",  # LLM-based: subjective quality check
        "The writing style should be clear, concise, and free of technical jargon"  # LLM-based: style validation
    ],
    guardrail_max_retries=3
)
这种方法结合了程序化验证的精确性与基于 LLM 的评估在主观标准上的灵活性。

护栏函数要求

  1. 函数签名:
    • 必须恰好接受一个参数(任务输出)
    • 应该返回一个 (bool, Any) 元组
    • 建议使用类型提示,但非强制
  2. 返回值:
    • 成功时:返回一个 (bool, Any) 元组。例如:(True, validated_result)
    • 失败时:返回一个 (bool, str) 元组。例如:(False, "解释失败的错误消息")

错误处理最佳实践

  1. 结构化错误响应:
代码
from crewai import TaskOutput, LLMGuardrail

def validate_with_context(result: TaskOutput) -> Tuple[bool, Any]:
    try:
        # Main validation logic
        validated_data = perform_validation(result)
        return (True, validated_data)
    except ValidationError as e:
        return (False, f"VALIDATION_ERROR: {str(e)}")
    except Exception as e:
        return (False, str(e))
  1. 错误分类:
    • 使用特定的错误代码
    • 包含相关上下文
    • 提供可操作的反馈
  2. 验证链:
代码
from typing import Any, Dict, List, Tuple, Union
from crewai import TaskOutput

def complex_validation(result: TaskOutput) -> Tuple[bool, Any]:
    """Chain multiple validation steps."""
    # Step 1: Basic validation
    if not result:
        return (False, "Empty result")

    # Step 2: Content validation
    try:
        validated = validate_content(result)
        if not validated:
            return (False, "Invalid content")

        # Step 3: Format validation
        formatted = format_output(validated)
        return (True, formatted)
    except Exception as e:
        return (False, str(e))

处理护栏结果

当护栏返回 (False, error) 时:
  1. 错误被发送回智能体
  2. 智能体尝试修复问题
  3. 过程重复,直到:
    • 护栏返回 (True, result)
    • 达到最大重试次数 (guardrail_max_retries)
带有重试处理的示例
代码
from typing import Optional, Tuple, Union
from crewai import TaskOutput, Task

def validate_json_output(result: TaskOutput) -> Tuple[bool, Any]:
    """Validate and parse JSON output."""
    try:
        # Try to parse as JSON
        data = json.loads(result)
        return (True, data)
    except json.JSONDecodeError as e:
        return (False, "Invalid JSON format")

task = Task(
    description="Generate a JSON report",
    expected_output="A valid JSON object",
    agent=analyst,
    guardrail=validate_json_output,
    guardrail_max_retries=3  # Limit retry attempts
)

从任务中获取结构化的一致输出

同样需要注意的是,团队最后一个任务的输出将成为团队实际的最终输出。

使用 output_pydantic

output_pydantic 属性允许您定义任务输出应遵循的 Pydantic 模型。这确保了输出不仅是结构化的,而且还根据 Pydantic 模型进行了验证。 以下是如何使用 output_pydantic 的示例:
代码
import json

from crewai import Agent, Crew, Process, Task
from pydantic import BaseModel


class Blog(BaseModel):
    title: str
    content: str


blog_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 process
crew = Crew(
    agents=[blog_agent],
    tasks=[task1],
    verbose=True,
    process=Process.sequential,
)

result = crew.kickoff()

# Option 1: Accessing Properties Using Dictionary-Style Indexing
print("Accessing Properties - Option 1")
title = result["title"]
content = result["content"]
print("Title:", title)
print("Content:", content)

# Option 2: Accessing Properties Directly from the Pydantic Model
print("Accessing Properties - Option 2")
title = result.pydantic.title
content = result.pydantic.content
print("Title:", title)
print("Content:", content)

# Option 3: Accessing Properties Using the to_dict() Method
print("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 Object
print("Accessing Properties - Option 5")
print("Blog:", result)

在此示例中:
  • 定义了一个带有 title 和 content 字段的 Pydantic 模型 Blog。
  • 任务 task1 使用 output_pydantic 属性指定其输出应符合 Blog 模型。
  • 执行团队后,您可以按所示的多种方式访问结构化输出。

访问输出的说明

  1. 字典风格索引:您可以直接使用 result[“field_name”] 访问字段。这是因为 CrewOutput 类实现了 getitem 方法。
  2. 直接从 Pydantic 模型:直接从 result.pydantic 对象访问属性。
  3. 使用 to_dict() 方法:将输出转换为字典并访问字段。
  4. 打印整个对象:只需打印 result 对象即可查看结构化输出。

使用 output_json

output_json 属性允许您定义 JSON 格式的预期输出。这确保了任务的输出是一个有效的 JSON 结构,可以轻松解析并在您的应用程序中使用。 以下是如何使用 output_json 的示例:
代码
import json

from crewai import Agent, Crew, Process, Task
from pydantic import BaseModel


# Define the Pydantic model for the blog
class Blog(BaseModel):
    title: str
    content: str


# Define the agent
blog_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 model
task1 = 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 process
crew = Crew(
    agents=[blog_agent],
    tasks=[task1],
    verbose=True,
    process=Process.sequential,
)

# Kickoff the crew to execute the task
result = crew.kickoff()

# Option 1: Accessing Properties Using Dictionary-Style Indexing
print("Accessing Properties - Option 1")
title = result["title"]
content = result["content"]
print("Title:", title)
print("Content:", content)

# Option 2: Printing the Entire Blog Object
print("Accessing Properties - Option 2")
print("Blog:", result)
在此示例中:
  • 定义了一个带有 title 和 content 字段的 Pydantic 模型 Blog,用于指定 JSON 输出的结构。
  • 任务 task1 使用 output_json 属性表明它期望得到符合 Blog 模型的 JSON 输出。
  • 执行团队后,您可以按所示的两种方式访问结构化 JSON 输出。

访问输出的说明

  1. 使用字典风格索引访问属性:您可以直接使用 result[“field_name”] 访问字段。这是因为 CrewOutput 类实现了 getitem 方法,允许您像操作字典一样对待输出。在此选项中,我们从结果中获取 title 和 content。
  2. 打印整个 Blog 对象:通过打印 result,您可以获得 CrewOutput 对象的字符串表示形式。由于实现了 str 方法以返回 JSON 输出,这会将整个输出显示为代表 Blog 对象的格式化字符串。

通过使用 output_pydantic 或 output_json,您可以确保任务产生一致且结构化的格式输出,从而更轻松地在您的应用程序或多个任务中处理和利用数据。

集成工具与任务

利用 CrewAI 工具包LangChain 工具,以增强任务性能和智能体交互。

创建带有工具的任务

代码
import os
os.environ["OPENAI_API_KEY"] = "Your Key"
os.environ["SERPER_API_KEY"] = "Your Key" # serper.dev API key

from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool

research_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 internet
search_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)
这演示了带有特定工具的任务如何覆盖智能体的默认工具集,从而实现定制的任务执行。

引用其他任务

在 CrewAI 中,一个任务的输出会自动传递给下一个任务,但您可以明确定义哪些任务的输出(包括多个)应作为另一个任务的上下文使用。 这在您有一个任务依赖于并非紧随其后的另一个任务的输出时非常有用。这是通过任务的 context 属性完成的:
代码
# ...

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]
)

#...

异步执行

您可以定义一个任务异步执行。这意味着团队不会等待该任务完成就会继续执行下一个任务。这对于耗时较长,或对后续任务执行非关键性的任务非常有用。 然后,您可以在未来的任务中使用 context 属性来定义该任务应等待异步任务的输出完成。
代码
#...

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
)

#...

回调机制

回调函数在任务完成后执行,允许根据任务结果触发操作或通知。
代码
# ...

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
)

#...

访问特定任务输出

团队运行结束后,您可以使用任务对象的 output 属性访问特定任务的输出。
代码
# ...
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 task
print(f"""
    Task completed!
    Task: {task1.output.description}
    Output: {task1.output.raw}
""")

工具覆盖机制

在任务中指定工具允许智能体能力的动态调整,强调了 CrewAI 的灵活性。

错误处理和验证机制

在创建和执行任务时,会有某些验证机制来确保任务属性的健壮性和可靠性。这些包括但不限于:
  • 确保每个任务仅设置一种输出类型,以保持清晰的输出预期。
  • 防止手动分配 id 属性,以维护唯一标识符系统的完整性。
这些验证有助于在 CrewAI 框架内保持任务执行的一致性和可靠性。

保存文件时创建目录

create_directory 参数控制 CrewAI 在将任务输出保存到文件时是否应自动创建目录。此功能对于组织输出并确保文件路径结构正确(特别是在处理复杂的项目层级时)非常有用。

默认行为

默认情况下,create_directory=True,这意味着 CrewAI 会自动创建输出文件路径中缺失的任何目录。
代码
# Default behavior - directories are created automatically
report_task = Task(
    description='Generate a comprehensive market analysis report',
    expected_output='A detailed market analysis with charts and insights',
    agent=analyst_agent,
    output_file='reports/2025/market_analysis.md',  # Creates 'reports/2025/' if it doesn't exist
    markdown=True
)

禁用目录创建

如果您想防止自动创建目录并确保目录已存在,请设置 create_directory=False
代码
# Strict mode - directory must already exist
strict_output_task = Task(
    description='Save critical data that requires existing infrastructure',
    expected_output='Data saved to pre-configured location',
    agent=data_agent,
    output_file='secure/vault/critical_data.json',
    create_directory=False  # Will raise RuntimeError if 'secure/vault/' doesn't exist
)

YAML 配置

您也可以在 YAML 任务定义中配置此行为。
tasks.yaml
analysis_task:
  description: >
    Generate quarterly financial analysis
  expected_output: >
    A comprehensive financial report with quarterly insights
  agent: financial_analyst
  output_file: reports/quarterly/q4_2024_analysis.pdf
  create_directory: true # Automatically create 'reports/quarterly/' directory

audit_task:
  description: >
    Perform compliance audit and save to existing audit directory
  expected_output: >
    A compliance audit report
  agent: auditor
  output_file: audit/compliance_report.md
  create_directory: false # Directory must already exist

用例

自动创建目录 (create_directory=True)
  • 开发和原型环境
  • 带有日期文件夹的动态报告生成
  • 目录结构可能变化的自动化工作流
  • 具有用户特定文件夹的多租户应用
手动管理目录 (create_directory=False)
  • 具有严格文件系统控制的生产环境
  • 必须预先配置目录的安全敏感型应用
  • 具有特定权限要求的系统
  • 要求对目录创建进行审计的合规环境

错误处理

create_directory=False 且目录不存在时,CrewAI 将引发 RuntimeError
代码
try:
    result = crew.kickoff()
except RuntimeError as e:
    # Handle missing directory error
    print(f"Directory creation failed: {e}")
    # Create directory manually or use fallback location
观看下方视频,了解如何在 CrewAI 中使用结构化输出。

结论

任务是 CrewAI 中智能体行动背后的驱动力。通过正确定义任务及其产出,您可以为 AI 智能体设置舞台,使其能够有效地工作,无论是独立工作还是作为协作单元。为任务配备适当的工具、理解执行流程并遵循可靠的验证实践,对于最大限度地发挥 CrewAI 的潜力至关重要,确保智能体为任务做好充分准备,并按预期执行任务。