关于 design-task
design-task 是用于设计 CrewAI 任务的技能,涵盖清晰的指令、输出、依赖关系和质量检查。它还说明结构化输出、护栏、异步执行及人工审核等配置与执行细节。
主要功能
- 01定义任务说明和预期输出
- 02说明任务上下文与依赖关系
- 03涵盖结构化输出和文件输出
- 04配置异步执行与人工审核
- 05介绍函数和 LLM 护栏
适用场景
- 01为研究任务设定明确标准
- 02向后续任务传递选定结果
- 03在结果传递前进行校验
- 04暂停关键结果以供人工审核
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ crewaiinc/ skills --skill design-task安装后在 Claude Code 中输入/design-task确认已加载。
附带文件references/structured-output.md
详细介绍
CrewAI 任务设计指南
如何编写有效的任务,让 Agent 产出可靠、高质量的结果。
已于 2026-10-01 针对 crewai 1.15.22 和 1.15.23 验证。 已于 2026-10-01 使用真实大模型进行实测。 关于当前准确的 API 格式(导入、参数名称、结构化输出、guardrail 签名),请以 check-crewai-api 技能为准;如果本技能与其内容有出入,请遵循 check-crewai-api。
80/20 法则:将 80% 的精力投入任务设计,20% 的精力投入 Agent 设计。 任务是你最重要的杠杆。设计良好的任务搭配普通 Agent,也胜过设计糟糕的任务搭配优秀 Agent。
1. 有效任务的构成
每个任务都需要两项内容:描述(要做什么以及如何做)和 expected_output(结果应是什么样)。两者缺一不可——仅使用 Task(description=...) 会引发 ValidationError ... expected_output Field required。
描述——指令
好的描述应包含:
- 做什么——核心操作
- 如何做——具体步骤或方法
- 背景——任务为何重要、结果将用于何处
- 约束——范围限制、需要避免的事项
- 输入——可用的数据或上下文
research_task:
description: >
Conduct thorough research about {topic} for the year {current_year}.
Your research should:
1. Identify the top 5 key trends and breakthroughs
2. For each trend, find at least 2 credible sources
3. Note any controversies or competing viewpoints
4. Assess potential industry impact (high/medium/low)
Focus on developments from the last 6 months.
Do NOT include speculation or unverified claims.
The output will feed into a report for {target_audience}.
expected_output: >
A structured research brief with 5 sections, one per trend.
Each section includes: trend name, 2-3 paragraph summary,
source citations, impact assessment (high/medium/low),
and a confidence level for your findings.
agent: researcher
预期输出——成功标准
expected_output 用于告诉 Agent 什么样的结果才算“完成”。请具体说明:
- 格式——项目符号、段落、JSON、表格
- 结构——章节、标题、顺序
- 长度——大致字数或条目数
- 质量指标——是否需要引用、置信度等级、具体字段
| 不佳的预期输出 | 良好的预期输出 |
|---|---|
A research report | 一份结构化简报,包含 5 个部分,每部分包括:趋势名称、2-3 段摘要、来源引用和影响评级 |
An analysis of the data | 一个 Markdown 表格,包含以下列:指标名称、当前值、30 天趋势和建议采取的行动。至少包含 10 项指标。 |
A blog post | 一篇 1000-1500 字的技术博客文章,包含:标题、引言、3-4 个带代码示例的主体章节,以及包含后续步骤的结论 |
2. 单一目标原则
一个任务 = 一个目标。 切勿将多个操作合并到一个任务中。
# DON'T - a "god task" with four objectives
research_and_write_task:
description: >
Research {topic}, analyze the findings, write a blog post,
and proofread it for grammar errors.
expected_output: >
A polished blog post about {topic}.
# DO - focused tasks, one objective each
research_task:
description: >
Research {topic} and identify the top 5 key developments.
expected_output: >
A research brief with 5 sections covering key trends.
agent: researcher
writing_task:
description: >
Using the research findings, write a technical blog post about {topic}.
expected_output: >
A 1000-1500 word blog post with introduction, main sections, and conclusion.
agent: writer
# ...and an editing_task with agent: editor
每个任务都有一个明确目标。顺序流程会自动传递上下文。
3. 任务配置参考
必需参数
Task(description="...", expected_output="...", agent=researcher) # agent: required for sequential, optional for hierarchical
不含 Agent 的顺序型 Crew 会在 Crew(...) 处失败:Sequential process error: Agent is missing in the task ...。
使用 context 设置任务依赖关系
analysis_task = Task(description="Analyze the research findings...", expected_output="...",
agent=analyst, context=[research_task]) # receives only research_task's output
顺序型和层级型 Crew 遵循相同规则:
- 不设置
context——任务会接收之前运行的所有任务的原始输出。 context=[a, b]——任务只会接收这些任务的输出。context=[]——任务不会接收任何先前输出。
context 条目必须是 Crew 中较早的任务;如果指向较晚的任务,会在 Crew(...) 处失败(“context dependency on a future task”)。
结构化输出
如果下游代码需要解析结果,请使用 output_pydantic 或 output_json:
from pydantic import BaseModel
class ResearchReport(BaseModel):
trends: list[str]
confidence: float
sources: list[str]
research_task = Task(description="...", agent=researcher,
expected_output="A structured report with trends, confidence score, and sources.",
output_pydantic=ResearchReport) # agent's output is parsed into this model
重要: expected_output 始终是一个字符串描述,绝不能是类名。Pydantic 模型应放在 output_pydantic 中,而 expected_output 文本则告诉 Agent 应包含哪些字段。output_pydantic 和 output_json 只能设置其中一个(同时设置会引发 Only one output type can be set)。
访问结构化输出:
result = crew.kickoff(inputs={...})
last_task_output = result.pydantic # Pydantic model from the LAST task (None if it has no output_pydantic)
all_outputs = result.tasks_output # List of all TaskOutput objects
first_task = all_outputs[0].pydantic # Pydantic from a specific task
assert first_task is not None, "structured output was dropped"
在 Python 中设置 output_pydantic,不要在 tasks.yaml 中设置(见第 5 节)。不要使用 Task(response_format=...)(会被静默忽略)或 Task(response_model=...)(.pydantic 仍为 None)。更多信息:structured-output.md。
文件输出
Task(..., output_file="output/report.md") 会保存输出;create_directory(默认为 True)会创建缺失的目录。写入内容取决于输出类型:普通任务写入原始文本;但如果设置了 output_pydantic 或 output_json,则会写入模型的 JSON(即使文件名以 .md 结尾)。如果你想从结构化任务生成人类可读的文件,请添加一个不使用模型的独立格式化任务,并为其指定 output_file。
异步执行
pros = Task(..., agent=analyst, async_execution=True)
cons = Task(..., agent=critic, async_execution=True) # a DIFFERENT agent
verdict = Task(..., agent=analyst, context=[pros, cons])
crew = Crew(agents=[analyst, critic], tasks=[pros, cons, verdict])
异步任务启动后不会等待;连续的异步任务会并发运行。下一个同步任务会等待所有待处理的异步任务完成后才启动,并且(未设置 context 时)会看到它们的所有输出;设置 context=[...] 可选择要使用哪些输出。
以下规则均会强制执行:
- 每个并发运行的异步任务都必须使用自己的 Agent。 两个异步任务使用同一个 Agent 时,会在启动时失败,并报错
RuntimeError: Executor is already running. Cannot invoke the same executor instance concurrently. - 一个 crew 最多只能以一个异步任务结束(
The crew must end with at most one asynchronous task)——请以一个汇总结果的同步任务收尾。 - 异步任务不能在自己的
context中列出同一并发运行中的异步任务;ConditionalTask也不能设为异步。
人工审核
Task(..., human_input=True) 会在最终确定前暂停,以供人工审核。Agent 生成答案后,终端会显示 “Human Feedback Required” 面板,并从 stdin 读取一行输入。输入反馈后,Agent 会修改答案并再次询问;输入空行(按 Enter)即可接受答案。适用于需要人工批准的关键输出。
此功能需要交互式 stdin。在 CI、服务器或任何 stdin 已关闭的运行环境中,input() 会引发 EOFError,并且会在 Agent 重试后才发生,因此你还要为额外的大模型调用付费。若要通过脚本驱动,请通过管道传入答案:printf 'Make it shorter.\n\n' | python run.py(一轮反馈,然后接受答案)。对于无法依赖终端的审批步骤,请参阅 build-flow 技能中的 Flow @human_feedback。
不要使用 human_input=True 或 Flow @human_feedback 来模拟常规的后续聊天。 在对话式 Flow 中,下一条用户消息应通过另一次 flow.handle_turn(message, session_id=...) 调用来处理。人工审核用于在特定任务/步骤输出传递到下游之前,对其进行批准或修正。
Markdown 格式
Task(..., markdown=True) 会向任务提示词追加一条指令,要求最终答案必须使用 Markdown(标题、粗体/斜体、项目符号列表、代码跨度和围栏代码块)。
回调
def log_completion(output: TaskOutput) -> None: # from crewai import TaskOutput
print(f"Task completed: {output.description[:50]}...")
Task(..., callback=log_completion) # called with the TaskOutput after the task and its guardrails finish
4. 任务护栏——质量控制
护栏会在任务输出传递到下一步之前对其进行验证。如果验证失败,错误会反馈给 Agent,任务会重试,最多重试 guardrail_max_retries 次(默认为 3)。之后任务会引发 Task failed guardrail validation after N retries. Last error: ...。
基于函数的护栏
from typing import Any
from crewai import Task, TaskOutput
def validate_word_count(output: TaskOutput) -> tuple[bool, Any]:
"""Ensure output is between 500-2000 words."""
word_count = len(output.raw.split())
if word_count < 500:
return (False, f"Output too short ({word_count} words). Expand to at least 500 words.")
if word_count > 2000:
return (False, f"Output too long ({word_count} words). Condense to under 2000 words.")
return (True, output.raw)
Task(..., guardrail=validate_word_count, guardrail_max_retries=3) # max retries (default: 3)
返回格式: (bool, Any)——第一个元素表示通过/失败,第二个元素是在成功时返回的结果(一个会成为任务原始输出的字符串——通常是 output.raw;绝不能为 None),或在失败时返回的错误消息。应返回字符串,而不是 TaskOutput 本身:当任务设置了 output_pydantic 且其 Agent 使用了工具时,护栏内部的 output.pydantic 仍为 None;(True, output) 会使其保持为 None,因此 result.pydantic 最终也会是 None;而 (True, output.raw) 则允许 crewai 对其进行转换(已在 1.15.22 和 1.15.23 上验证)。将返回类型标注为 tuple[bool, Any],或不进行标注:在 Task(...) 中使用 -> bool 会引发 If return type is annotated, it must be Tuple[bool, Any]。请使用 guardrail_max_retries,不要使用已弃用的 max_retries。
基于 LLM 的护栏
Task(..., agent=writer, guardrail="Verify the output contains at least 3 source citations and no speculative claims.")
字符串护栏会通过一次额外的大模型调用进行检查,该调用使用任务 Agent 的大模型。适合主观质量检查。任务必须设置 agent,否则 Task(...) 会引发 Agent is required to use non-programmatic guardrails。
串联多个护栏
def validate_no_pii(output: TaskOutput) -> tuple[bool, Any]:
if "@" in output.raw:
return (False, "Remove email addresses.")
return (True, output.raw)
Task(..., guardrails=[
validate_word_count, # Function: check length
validate_no_pii, # Function: check for PII
"Ensure the tone is professional and appropriate for a business audience.", # LLM check
])
护栏按顺序执行。每个护栏都会接收上一个护栏的输出(字符串结果会替换下一个护栏的 output.raw)。可以混合使用基于函数的(确定性)检查和基于 LLM 的(主观)检查。如果同时设置了 guardrails=[...] 和 guardrail=,则只会使用列表。
5. YAML 配置(推荐)
tasks.yaml
research_task: # full description/expected_output as in section 1
description: >
Conduct thorough research about {topic} for {current_year}.
expected_output: >
A structured research brief with 5 sections.
agent: researcher
analysis_task:
description: >
Analyze the research findings and recommend actions for {target_audience}.
expected_output: >
A prioritized list of 5 recommendations with rationale and expected impact.
agent: analyst
context:
- research_task
report_task:
description: >
Compile a final report combining research and analysis for {target_audience}.
expected_output: >
A polished markdown report with executive summary, findings and recommendations.
agent: writer
output_file: output/report.md
在 crew.py 中连接配置
from pydantic import BaseModel
from crewai import Agent, Crew, Task
from crewai.project import CrewBase, agent, crew, task
class Recommendations(BaseModel):
items: list[str]
@CrewBase
class ResearchCrew:
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
# @agent methods researcher, analyst, writer omitted
@task
def research_task(self) -> Task:
return Task(config=self.tasks_config["research_task"])
@task
def analysis_task(self) -> Task:
# context and agent come from YAML; the model class must be set here in Python
return Task(config=self.tasks_config["analysis_task"], output_pydantic=Recommendations)
@task
def report_task(self) -> Task:
return Task(config=self.tasks_config["report_task"]) # output_file comes from YAML
@crew
def crew(self) -> Crew:
return Crew(agents=self.agents, tasks=self.tasks)
方法名称必须与 YAML 键完全相同。 YAML 中的 context: 条目会通过调用对应名称的 @task 方法解析,agent: 则通过调用对应名称的 @agent 方法解析,因此名称不匹配会导致 crew 构建失败。description、expected_output、agent、context、output_file、human_input、async_execution 和 markdown 可在 YAML 中使用;output_pydantic、output_json、函数护栏和 tools 应放在 Python 方法中。
6. 任务依赖和上下文流
任务按列表顺序运行。不带 context 的任务会接收所有更早任务的原始输出。
research_task → analysis_task → report_task
↓ ↓ ↓
(none) output 1 output 1 + 2
无需为此设置 context=——这是隐式的。使用它可以缩小或调整依赖关系:
# Diamond dependency pattern
task_a = Task(...) # Entry point
task_b = Task(..., context=[task_a]) # Depends on A
task_c = Task(..., context=[task_a]) # Also depends on A
task_d = Task(..., context=[task_b, task_c]) # Depends on both B and C
条件任务
from pydantic import BaseModel
from crewai import Task, TaskOutput
from crewai.tasks.conditional_task import ConditionalTask # not crewai.task
class Items(BaseModel):
items: list[str]
gather = Task(description="List data sources for {topic}...", expected_output="A list of sources.",
agent=researcher, output_pydantic=Items) # the condition below reads .pydantic
def needs_more_data(output: TaskOutput) -> bool:
return len(output.pydantic.items) < 10
extra_research = ConditionalTask(description="Fetch additional data sources...", expected_output="...",
agent=researcher,
condition=needs_more_data) # runs only if the previous output has < 10 items
条件会接收紧邻它之前的任务的 TaskOutput。被跳过的条件任务仍会出现在 result.tasks_output 中,且 raw == ""。ConditionalTask 不能是第一个任务,不能异步运行,且 crew 不能只包含条件任务。
7. 任务工具
任务可以拥有自己的工具,这些工具会替代 Agent 在该特定任务中的默认工具:
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
Task(description="Search for and scrape the top 5 articles about {topic}...", expected_output="...",
agent=researcher, tools=[SerperDevTool(), ScrapeWebsiteTool()]) # task-specific tools
如果在任务上设置了 tools,Agent 在该任务中将仅使用这些工具——工具列表不会合并。若要使用 Agent 的工具,请不要设置该项。
当任务需要 Agent 通常没有的工具、需要限制 Agent 在某个任务中的工具,或同一个 Agent 在不同任务中需要不同工具集时,请使用任务级工具。
8. 变量插值
在 YAML 中使用 {variable} 占位符来创建可复用任务:
research_task:
description: >
Research {topic} trends for {current_year}, targeting {target_audience}.
expected_output: >
A report on {topic} suitable for {target_audience}.
变量会在启动时替换:crew.kickoff(inputs={"topic": "AI Agents", "current_year": "2026", "target_audience": "developers"})。
常见错误:
inputs中缺少变量 → kickoff 会引发ValueError: Missing required template variable ... 'audience' not found in inputs dictionary- 使用
{{ }}Jinja2 语法 → crewAI 使用单层花括号{ };{{topic}}会渲染为{AI Agents} inputs中有未使用的变量 → 会被静默忽略(不会报错)
9. 常见任务设计错误
| 错误 | 影响 | 修复方法 |
|---|---|---|
| 描述含糊(“研究这个主题”) | Agent 生成的内容浅显且缺乏重点 | 添加具体步骤、限制条件和上下文 |
| 预期输出含糊(“一份报告”) | Agent 自行猜测格式和结构 | 指定格式、章节、篇幅和质量标准 |
| 在一个任务中包含多个目标 | Agent 无法把其中任何一个做好 | 将任务拆分为目标明确、用途单一的任务 |
| 将每轮聊天都建模为一个 Crew 任务 | 任务是批处理/工作流单元,而不是对话会话循环 | 使用对话式 Flow,并针对每条用户消息调用 handle_turn() |
| 下游任务看到过多或错误的先前输出 | 默认会传递所有先前输出 | 使用 context=[prior_task](或 context=[])进行选择 |
expected_output 引用了 Pydantic 类 | Agent 看到的是类名字符串,而非字段名称 | 将 expected_output 保留为人类可读的字符串;使用 output_pydantic 指定模型 |
在 tasks.yaml 中设置 output_pydantic | 出现 KeyError,或模型被丢弃且 .pydantic 为 None | 在 @task 方法中设置 output_pydantic=Model |
| 同一 Agent 上有两个异步任务 | RuntimeError: Executor is already running | 每个并发运行的异步任务使用一个 Agent |
在 CI 或服务端设置 human_input=True | 重试浪费后出现 EOFError | 将答案传入 stdin,或使用 Flow @human_feedback |
| 数据任务缺少工具 | Agent 会编造数据,而不是获取数据 | 为任务或 Agent 添加工具 |
| 关键输出没有护栏 | 错误输出未经检查便传递到下游 | 添加函数或 LLM 护栏 |
结构化任务的护栏返回 (True, output) | 虽然运行通过,但 result.pydantic 为 None | 返回 (True, output.raw);断言 .pydantic 不为 None |
| 预期输出或护栏过于严格 | Agent 不断重试,直到出现 Task failed guardrail validation | 设定具体但可实现的要求;调低 guardrail_max_retries,以便更快失败 |
| 描述重复背景故事 | 浪费 token,并使 Agent 困惑 | 描述 = 要做什么;背景故事 = 你是谁 |
10. 任务设计检查清单
运行任务前,请确认:
- 描述包含要做什么、如何做、上下文和限制条件
- 预期输出指定格式、结构和质量标准
- 目标单一——每个任务有一个明确目标
- 已分配 Agent(顺序执行的 crews 和字符串护栏均为必需)
- 当默认设置(所有先前输出)不合适时,通过
context设置依赖项 - 为需要外部数据的任务提供工具
- 在 Python 中设置结构化输出,并断言
.pydantic非 None - 为关键输出设置护栏,并返回
(bool, value) - 异步任务各自使用独立的 Agent,之后跟随一个同步任务
- YAML 中的变量与
inputs字典的键相匹配 - 预期输出可实现——在增加复杂度前,先用简单运行进行测试
参考资料
如需深入了解特定主题,请参阅:
- 结构化输出 -
output_pydantic、output_json、response_model和response_format在 LLM、Agent、Task 和 Crew 各级别的用法
相关技能:
- check-crewai-api - crewai 1.15.x 中当前的导入路径、参数名称、结构化输出和护栏形式
- getting-started — 项目脚手架、选择合适的抽象、Flow 架构
- design-agent — Agent 的角色-目标-背景故事框架、参数调优、工具分配、记忆与知识配置
- build-flow - Flow 状态、路由器和
@human_feedback - test-crewai-project - 使用存根 LLM 离线测试护栏和任务连接
- connect-tools-and-mcp - 附加到任务的工具,以及现有的
crewai_tools名称 - ask-docs - 查询 CrewAI 实时文档,获取这些技能未涵盖的问题