news 2026/9/7 20:09:35

如何写出合法的 CrewAI crewai.flow/v1 声明式 Flow:AGENTS.md 编写规范全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何写出合法的 CrewAI crewai.flow/v1 声明式 Flow:AGENTS.md 编写规范全解析

如何写出合法的 CrewAI crewai.flow/v1 声明式 Flow:AGENTS.md 编写规范全解析

【免费下载链接】crewAIFramework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks.项目地址: https://gitcode.com/GitHub_Trending/cr/crewAI

本篇以 CrewAI CLI 声明式 Flow 项目模板中内置的 AGENTS.md 为核心,逐条解析编写合法crewai.flow/v1YAML/JSON 声明的完整规则:从状态(state)建模、方法(method)编排、三类动作(expression / agent / crew)选型,到 CEL 表达式插值、路由(router/emit)机制与完整字段级 API 参考。读完本文,你既能约束 AI 代理替你自动生成 Flow 声明,也能人工写出结构正确、可被crewai run直接执行的声明式 Flow 定义。

一、这份 AGENTS.md 是什么、从哪里来

AGENTS.md 位于 CLI 的声明式 Flow 项目模板目录 templates/declarative_flow/ 下,它不面向人类用户阅读,而是一份写给 AI 代理的“作者指令”:当用户要求 AI 创建或编辑 CrewAI Flow 时,代理必须依据这份文档输出一份单一的、合法的crewai.flow/v1YAML 或 JSON 文档

从源码看,执行crewai flow create --declarative(入口见 create_flow.py 中的_create_declarative_flow)时,CLI 会把该模板目录整体复制到新项目根目录。其中root_template_files显式包含.gitignoreAGENTS.mdREADME.mdpyproject.toml,也就是说AGENTS.md 会随每个声明式 Flow 项目一起落地到项目根目录,成为该项目后续 AI 协作编辑的常备规范。模板同时生成一个最小可运行的 flow.yaml:

schema: crewai.flow/v1 name: {{flow_name}} description: A declarative CrewAI Flow. state: type: dict default: topic: AI agents methods: start: start: true do: call: expression expr: state.topic

这个起步文件展示了 Flow 的最小骨架:schema标识、namestate、以及带start: true的单个方法。而 模板 README 给出的项目操作方式是:

crewai install # 安装依赖 crewai run # 运行声明式 Flow

并可按需在src/<folder>/crews/(可复用 Crew)、src/<folder>/tools/(自定义 Python 工具)、src/<folder>/knowledge/(共享知识文件)中扩展。AGENTS.md 的价值正在于此:它把“如何写一个能通过校验、正确接线、正确传数的 flow.yaml”沉淀为可复制的规则,覆盖从骨架到路由分支的全部细节。

二、输出契约:只返回一份合法的声明文档

文档开篇即规定了两条硬约束:

  1. 只输出一份合法的crewai.flow/v1Flow 声明,不要附带解释性文字(除非用户明确要求);
  2. 先照示例掌握形状与格式,再用文末 API 参考核对精确字段——示例管“形状”,参考管“字段名、必填项、链接类型与允许的 action/state 形状”。

同时文档声明了自己的定位:“把它当作对你的指令,而不是展示给用户的文字”。这正是 AGENTS.md 类文件的典型用法:它是给 LLM 的系统级写作约束。

三、按固定顺序构建 Flow(Build It In This Order)

AGENTS.md 给出的 7 步构建顺序是整份规范的主干,也是人工编写 Flow 时可直接套用的检查清单:

  1. 先定义state。使用type: json_schema,并把 JSON Schema 内联写入;
  2. 必填输入字段放在state.json_schema.required。不要指望用state.default让字段变必填——默认值与必填性是两回事;
  3. 恰好一个方法带start: true(CLI 模板变体中是单入口规则);
  4. 后续方法通过listen接入上游;
  5. 每个方法有且仅有一个do动作对象,do绝不能是列表
  6. ${...}映射从state和已完成的outputs传递数据
  7. 产出前检查所有listenemitoutputs.some_method引用是否有效。

另有两条全局约定:

  • 可选字段只在确有必要时设置,否则信任 CrewAI 默认值并省略;
  • 方法名必须匹配正则^[A-Za-z_][A-Za-z0-9_]*$,即合法的 Python 标识符形式。

四、每个方法只选一种动作,且选最简单的

文档要求“选择能完成任务的最简单动作”,并给出三类动作的选型边界:

动作适用场景关键写法约束
call: expression简单读取、过滤、计算值、确定性路由expr中写原始 CEL,不要用${...}包裹
call: agent单个 AI 工作者:分类、决策、总结、写作、起草rolegoalbackstoryinput都放在with下;agent 动作没有动作级inputs映射
call: crew多 Agent / 多任务协同Crew 定义放在with下;运行期值用动作级inputs映射传入

这三类动作与仓库中的示例文件 flow_definition_example.yaml 完全对应:其中research_brief方法使用call: crewroute_followupwrite_followup方法使用call: agent,正是“Crew 做协同、Agent 做单点判断/写作”的组合示范。

五、显式接线:start、listen、router 与 emit

这一节规定了 Flow 事件模型的核心规则,是声明式 Flow 与 Python 装饰器写法差异最大、也最容易写错的部分:

  • state是初始共享数据形状。动作结果不会自动合并回state——这是与直觉最容易冲突的一点,跨方法传值必须显式走outputs
  • 方法结果通过outputs.method_name读取,且必须在该方法可以运行之后;
  • listen的目标是方法名,或 router 发出的事件名
  • 方法绝不能监听自己的方法名——包括listen的值恰好是与其方法名相同的路由标签(例如方法create_video上写listen: create_video);
  • 方法名与发出事件名共享同一个命名空间,不要用同一个字符串既当方法名又当listen目标;
  • 当一个方法要在多个命名分支间选择时,用router: true+emit
  • router 动作必须恰好返回一个发出事件名字符串,不能返回 JSON、列表或解释文字;
  • start: true标记唯一入口

对于“用 Agent 当路由”的场景,文档给出了可直接复用的 goal 写法:

Return exactly one bare value: approved, rejected, or needs_review. Do not include explanation.

并且明确:路由如果能用计算得出,优先用call: expression而不是 Agent——确定性路由不该消耗 LLM 调用。

六、CEL 与动态值:${...} 插值的精确语义

CEL(Common Expression Language)是 Flow 中“读取数据、做小决定”的表达式语言;更大的工作或有副作用的操作交给 agent 和 crew。文档对表达式形式的规定可以归纳为一张规则表:

场景正确写法说明
原始 CEL写在expr不要${...}包裹原始 CEL
映射字符串中读 Flow 数据Ticket: ${state.ticket_id}字面量文本留在${...}外,直接插值
输入数据statestate.ticket.subject
已完成方法结果outputs.step_nameoutputs.classify_ticket
值本身就是单个${...}domains: "${state.domains}"结果保留原始类型(数字、布尔、对象、列表)
字符串里还有其他文本最终值为文本非文本值会被序列化为 JSON,null变成空文本

两个标准示例:

# 混排文本与 Flow 数据 query: "News about ${state.topic}"
# 保留列表 / 数字类型 domains: "${state.domains}" limit: "${state.limit}"

Crew 侧还有一套独立的{name}占位符插值(不是 CEL):

  • Crew 文本用{name}占位符引用 crew inputs,例如Research {topic}
  • crew inputs 只有在 agent 或 task 文本中引用了对应{name}占位符时,才真正成为提示词的一部分——传了一个没有任何占位符引用的输入,等于没有“grounding”(事实锚定);若 Crew 确实需要某字段,就把占位符写进 agent 的goal、task 的descriptionexpected_output

关于取值的具体规则还包括:

  • Agent 需要多个字段时,写一个带标签和分隔符的文本值,例如Ticket ID: ${state.ticket_id}; Message: ${state.message}
  • Crew 动作级inputs才是真正的 Crew kickoff 输入,运行期数据用${...}state/outputs取;仅靠inputs不构成 grounding,必须配合占位符;
  • Crew 输出是对象:取文本用${outputs.research_brief.raw};结构化输出用${outputs.research_brief.json_dict.field}${outputs.research_brief.pydantic.field}
  • 不要把整个 Crew 输出塞给 Agent 输入(如${outputs.research_brief}是错误的);
  • Agent 输出也可能是对象:${outputs.classify_ticket.raw}${outputs.classify_ticket.pydantic.category}
  • with.inputs(Crew 定义内)只用于静态默认值;agent 动作的with.input是该 agent 的单一输入值。

七、“Do Not”清单:十一条高频错误红线

AGENTS.md 用一整节列出禁止项,这些基本都对应真实校验失败或行为异常,逐条核对价值很高:

  1. 不要发明 Flow 声明形状之外的顶层键;
  2. 不要使用声明 schema 之外的字段;
  3. 不要在一个方法的do下放多个动作;
  4. 不要让do变成列表;
  5. 不要用 CEL 的+在动作映射里拼接文本——保持文本字面量,动态值各自用${...}插入;
  6. 不要在some_method可以运行之前引用outputs.some_method
  7. 不要把方法的listen设为自己的方法名(含相同的路由标签,如方法create_videolisten: create_video);
  8. 不要用同一个字符串同时作为方法的listen目标与方法名;
  9. 不要在没有router: true的情况下使用emit
  10. 不要指望 crew 动作级inputs单独完成 grounding——没有匹配占位符的输入对提示词而言基本无效;
  11. 不要在精确性重要时让 Agent“自行推断缺失事实”,应要求它把缺失的日期、金额、报价、日志或约束标记为 unknown;
  12. 不要在调用方不会消费流式结果时设置config.stream: true——常规生成的 Flow 与 CLI 冒烟测试都应省略它。

八、完整示例:Crew 研究 + 路由式跟进

文档给出的主示例是一个“Crew 研究评审 + 路由式跟进”的 Flow,展示了 state 建模、crew 动作、router 方法与分支 agent 的完整组合(该示例与仓库中 flow_definition_example.yaml 一致):

schema: crewai.flow/v1 name: ResearchReviewFlow state: type: json_schema json_schema: type: object properties: topic: type: string audience: type: string required: - topic - audience default: topic: AI agent orchestration audience: platform engineering leaders methods: research_brief: start: true do: call: crew with: agents: researcher: role: Research analyst goal: Research {topic} for {audience} backstory: Expert at concise technical research. reviewer: role: Strategy reviewer goal: Decide whether the research needs an executive follow-up backstory: Experienced at reviewing technical briefs for leaders. tasks: - name: research_task description: Research {topic} for {audience}. expected_output: Key findings and tradeoffs. agent: researcher - name: review_task description: Review the research and decide if an executive follow-up is needed. expected_output: 'A brief review ending with `needs_followup: true` or `needs_followup: false`.' agent: reviewer inputs: topic: Default topic audience: Default audience inputs: topic: "${state.topic}" audience: "${state.audience}" route_followup: listen: research_brief router: true emit: - followup - done do: call: agent with: role: Follow-up router goal: 'Return exactly one bare value: followup or done. Do not include explanation.' backstory: Skilled at routing reviewed research briefs. input: "Reviewed research: ${outputs.research_brief.raw}" write_followup: listen: followup do: call: agent with: role: Executive communications specialist goal: Draft a concise executive follow-up from the reviewed research backstory: Writes crisp follow-ups for technical leaders. input: "${outputs.research_brief.raw}"

这个示例几乎把前述全部规则串了一遍,值得逐行对照:

  • statejson_schema内联声明,required明确列出topic/audiencedefault仅提供缺省值(二者不互相替代);
  • research_briefstart: true的唯一入口,call: crew;Crew 定义内inputs静态默认,而动作级inputs"${state.topic}"把运行期值真正注入 kickoff——同时Research {topic} for {audience}中的{name}占位符完成了 grounding;
  • route_followuprouter: true方法,emit声明了followup/done两个合法分支,其 agent 的 goal 严格限定“只返回一个裸值”;它读取的是${outputs.research_brief.raw}(对象输出的文本视图);
  • write_followup监听的是事件名followup而非方法名——这正是“事件与方法共享命名空间、分支方法挂事件名”的标准接法;done分支没有后续方法,流程自然终止。

九、字段级 API 参考

这一节按文档附录顺序整理全部字段,编写声明时可直接对照。

9.1 Flow 顶层定义

字段必填说明
schema可选(默认crewai.flow/v1必须为crewai.flow/v1;手写声明应显式包含
name必填唯一 Flow 名称,用于日志、事件与追踪
description可选(默认null人类可读的摘要
state必填初始状态与执行期更新的状态契约
config可选可序列化的 Flow 级执行配置
methods必填方法名 → 方法定义的映射

9.2 JSON Schema State(state[type=json_schema]

字段必填说明
type可选(默认json_schema固定为json_schema,表示内联 JSON Schema 作为状态契约
json_schema必填用于校验和文档化状态的 JSON Schema;必填字段用其中的required数组声明
default可选(默认null初始化 Flow 状态的默认值;默认值不等于 schema 必填

9.3 Method(methods.<name>

字段必填说明
description可选(默认null方法的人类可读摘要
do必填方法执行时运行的单个动作对象
start可选(默认null标记入口,使用true
listen可选(默认null在某个上游方法或 router 事件之后运行
router可选(默认false方法输出是否作为下一个事件名;router 必须返回单个事件名字符串
emit可选(默认null该方法可能发出的事件声明列表;事件名应唯一且不与方法名冲突

9.4 Action:按call判别的联合类型

允许的三种形状:call: crewcall: agentcall: expression

Crew Action(methods.<name>.do[call=crew]

字段必填说明
call必填判别字段,固定crew
with必填内联 Crew 定义
inputs可选(默认null传给 Crew 的运行期输入;用${...}插入 Flow 值,并在 agent/task 文本中以{name}引用,如{"topic": "${state.topic}"}

Crew Definition(...do[call=crew].with

字段必填说明
agents必填按名称索引的内联 agent 映射
tasks必填有序任务列表
inputs可选静态默认输入,作为{name}占位符参与插值;运行期值优先用动作级inputs

Crew Agent Definition(...with.agents.<name>

字段必填说明
role/goal/backstory必填三者的插值都使用{name}占位符(不是 CEL)
settings可选透传给 loader 的附加设置,如{"llm": "openai/gpt-4o-mini"}
llm可选(默认null模型字符串或内联 LLM 配置对象(如{"max_tokens": 4096, "model": "openai/gpt-4o-mini"}
planning_config可选(默认null计划配置,max_attempts限制任务执行前计划修正次数
allow_delegation可选(默认null允许 agent 之间委派与提问
max_iter可选(默认null单个 agent 执行任务的最大迭代次数
max_rpm可选(默认nullagent 执行时每分钟最大请求数
max_execution_time可选(默认nullagent 执行任务的超时秒数
tools可选(默认null工具引用或序列化定义;字符串引用可用 CrewAI 工具名、custom:<name>module:Class全限定引用
apps可选(默认null平台应用,如gmailslack/send_message
mcps可选(默认nullMCP 服务器引用或配置;支持 HTTPS URL、集成 slug、#tool_name后缀,或内联对象配置

LLM Definition

字段必填说明
model必填模型标识,如openai/gpt-4o-mini
max_tokens可选(默认null输出 token 上限;为 null 时由 provider 默认值生效

Crew Task Definition(...with.tasks[]

字段必填说明
description必填任务指令,支持{name}插值
expected_output必填期望输出描述,支持{name}插值
name可选(默认null任务名
agent可选(默认null承接该任务的 crew agent 名称

Agent Action(methods.<name>.do[call=agent]

字段必填说明
call必填固定agent
with必填单个 Agent 定义;输入放在with.inputagent 动作不支持动作级inputs

Agent Definition(...do[call=agent].with:字段集合与 Crew Agent Definition 相同(role/goal/backstory必填,settingsllmplanning_configallow_delegationmax_itermax_rpmmax_execution_timetoolsappsmcps可选),另加一个必填字段:

字段必填说明
input必填Agent 提示词模板,用${...}插入 Flow 值,如Ticket: ${state.ticket_id}

Expression Action(methods.<name>.do[call=expression]

字段必填说明
call必填固定expression
expr必填针对 state、outputs 与局部上下文求值的 CEL 表达式

9.5 Config(config

字段默认说明
tracingnull覆盖 Flow 追踪;省略时使用执行默认值
streamfalse是否发出流式事件(仅在调用方会消费流时设置)
memorynull传给 Flow 执行的可序列化记忆配置
input_providernull用于提供初始 state 的 provider 键
suppress_flow_eventsfalse为本定义禁用 Flow 事件发出
max_method_calls100单次 kickoff 允许的最大方法执行次数
defer_trace_finalizationfalse延迟 trace 终结,允许调用方稍后完成追踪
checkpointnull检查点配置;true表示使用默认检查点

9.6 跨字段规则(Cross-Field Rules)

  1. 每个方法恰好一个do动作对象、一个call判别值;
  2. listen目标位于“方法名 + router 事件名”的同一命名空间中;
  3. 方法不能监听自己的方法名;
  4. router 方法的结果必须命中一个已声明的emit值;
  5. Crew 动作级inputs即 Crew kickoff 输入,运行期值在那里使用 CEL 包裹字符串;
  6. Crew agent/task 插值使用来自求值后 crew inputs 的{name}占位符;
  7. Agent 的with.input必须是文本——用${outputs.method_name.raw}${outputs.method_name.json_dict.summary}这类文本字段。

十、源码纵深:CLI 模板是参数化 Skill 模板的“精简变体”

把 AGENTS.md 放回仓库语境中看,会发现它并不是孤立文本。在 lib/crewai/src/crewai/flow/templates/flow_definition_skill.md.j2 中存在一份 Jinja2 模板,内容与 AGENTS.md 同源,但通过特性开关参数化——例如include_non_linear_flows(允许多入口与非线性listenlisten支持and/or组合)、include_tool_actioncall: tool打包确定性工作)、include_script_actioncall: script内联可信 Python,明确标注“脚本不做沙箱”)、include_each_actioncall: each逐项重复子管道)、include_hitlhuman_feedback人工检查点)等。从源码结构看,CLI 项目模板中的 AGENTS.md 正是该参数化模板在“仅 expression / agent / crew 三种动作、单入口”配置下实例化出的保守版本——这也是为什么 CLI 模板写死“恰好一个start: true方法”,而参数化版本在非线性 Flow 下会放宽为“至少一个”。

声明的加载与执行侧在 run_declarative_flow.py 中:load_declarative_flow负责把 flow.yaml/JSON 定义加载为 Flow,crewai run会优先检测当前是否为声明式 Flow 项目环境(is_declarative_flow_project_env)并走声明式执行路径,crewai flow plot则可对定义做可视化。声明解析与校验的库侧实现见 flow_definition.py,相关行为有 test_flow_definition.py、test_flow_from_definition.py 等测试覆盖。

十一、实践要点小结

把 AGENTS.md 的规则浓缩成可执行的写作纪律:

  1. state 先行json_schema内联、required显式、default只补缺省;
  2. 单动作原则:每个方法一个do,按“能算则 expression、单点 AI 用 agent、协同用 crew”的梯度选型;
  3. 显式接线outputs.method_name读结果、listen挂上游、router 方法router: true+emit声明分支、分支方法监听事件名;
  4. 两套插值体系不混用:Flow 层用${...}(CEL),Crew 层用{name}占位符,且后者必须被 agent/task 文本实际引用才生效;
  5. 产出前自检:逐个核对listenemitoutputs.*引用与方法名/事件名命名空间冲突;
  6. 省略可选配置streammemory等字段除非确有需要,否则交给默认值。

遵循这套规范写出的crewai.flow/v1声明,既能通过 CLI 项目的声明式校验并被crewai run直接执行,也能作为 AI 协作编辑 Flow 的稳定契约——这正是 AGENTS.md 在 CrewAI 声明式 Flow 工作流中的定位。

【免费下载链接】crewAIFramework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks.项目地址: https://gitcode.com/GitHub_Trending/cr/crewAI

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 20:07:58

基于Schema.org的结构化数据标注实战:企业GEO优化技术实现

Schema.org结构化数据是给AI搜索引擎看的"标准化说明书"——它用JSON-LD格式将网页中的企业名称、服务内容、联系方式、FAQ等信息标记为AI可识别的实体和属性&#xff0c;帮助AI引擎快速理解页面内容并做出推荐。据Princeton大学GEO研究论文&#xff08;arXiv:2311.0…

作者头像 李华
网站建设 2026/9/7 20:07:26

计算机毕业设计之jsp通识教育选课系统

随着信息时代的来临&#xff0c;过去的传统管理方式缺点逐渐暴露&#xff0c;对过去的传统管理方式的缺点进行分析&#xff0c;采取计算机方式构建通识教育选课系统。本文通过课题背景、课题目的及意义相关技术&#xff0c;提出了一种课程信息、学生选课等于一体的系统构建方案…

作者头像 李华
网站建设 2026/9/7 20:06:38

VMware虚拟机无法启动?硬盘空间占用排查与清理扩容实战

说实话&#xff0c;我遇到过好几次这种让人血压飙升的场面&#xff1a;早上打开VMware Workstation&#xff0c;想继续昨晚没调完的测试环境&#xff0c;点了“开启此虚拟机”&#xff0c;结果客户机要么卡在启动界面半天没反应&#xff0c;要么直接弹出一句“客户机操作系统已…

作者头像 李华
网站建设 2026/9/7 20:05:03

大模型能写完一部长篇小说吗?长文一致性是最大难点

让 AI 写一篇短文很容易&#xff0c;让 AI 写完一部长篇小说却很难。问题不在文笔&#xff0c;而在"一致性"——人物、伏笔、时间线、世界观&#xff0c;写到第 50 章还能记得第 5 章埋的线吗&#xff1f;这篇从技术角度拆解 AI 写长篇的真正难点&#xff0c;以及现在…

作者头像 李华