CrewAI多智能体框架的实操教程-构建流程-3

1、简介

构建您的第一个流程

了解如何创建结构化的、事件驱动的工作流程,并对执行进行精确控制。

利用 Flows 控制 AI 工作流程

CrewAI Flows 代表了 AI 编排的全新境界,将 AI 代理团队的协作能力与程序化编程的精准性和灵活性相结合。团队擅长代理协作,而流程则让您能够精细地控制 AI 系统各个组件的交互方式和时间。
我将逐步讲解如何创建一个功能强大的 CrewAI Flow,它可以生成涵盖任何主题的全面学习指南。本教程将演示 Flows 如何通过结合常规代码、直接 LLM 调用和基于团队的处理,为您的 AI 工作流提供结构化、事件驱动的控制。

是什么让 Flows 如此强大

流程使您能够:
  1. 结合不同的 AI 交互模式:使用团队完成复杂的协作任务,直接调用 LLM 进行更简单的操作,并使用常规代码进行程序逻辑
  2. 构建事件驱动系统:定义组件如何响应特定事件和数据变化
  3. 跨组件维护状态:在应用程序的不同部分之间共享和转换数据
  4. 与外部系统集成:将您的 AI 工作流程与数据库、API 和用户界面无缝连接
  5. 创建复杂的执行路径:设计条件分支、并行处理和动态工作流

2、创建 CrewAI Flow 项目

首先,让我们使用 CLI 创建一个新的 CrewAI Flow 项目。此命令将设置一个脚手架项目,其中包含流程所需的所有目录和模板文件。
crewai create flow guide_creator_flow
cd guide_creator_flow
这将生成一个具有流程所需的基本结构的项目。

3、项目结构

此结构可以清晰地区分流程的不同组件:
  • main.py文件中的主要流程逻辑
  • crews目录中的专业团队
  • tools目录中的自定义工具

4、添加团队

我们的流程需要专门的团队来处理内容创作过程。让我们使用 CrewAI CLI 添加一个内容创作团队:
crewai flow add-crew content-crew
此命令会自动为您的团队创建必要的目录和模板文件。内容编写团队将负责编写和审核指南的各个部分,并按照我们主应用程序安排的整体流程进行工作。

5、配置代理

# src/guide_creator_flow/crews/content_crew/config/agents.yaml

content_writer:
  role: >
    教育内容撰稿人  # 代理人的角色名称,用于标识其职责
  goal: >
    创作引人入胜且信息丰富的内容,能够全面解释分配的主题,
    并为读者提供有价值的见解  # 此代理的目标或任务方向
  backstory: >
    你是一位才华横溢的教育内容撰稿人,擅长创作清晰、生动的内容。
    你能够将复杂概念以通俗易懂的语言解释出来,并善于组织信息,
    以帮助读者逐步建立理解。  # 背景故事,帮助模型扮演该代理角色时具备相应的“身份”与写作风格


content_reviewer:
  role: >
    教育内容审稿人与编辑  # 代理人的角色名称
  goal: >
    确保内容准确、全面、结构良好,并在多个部分之间保持一致性  # 审稿人的目标任务
  backstory: >
    你是一位严谨的编辑,拥有多年教育内容审校经验。
    你擅长发现内容中的细节问题,提升内容的清晰度与连贯性。
    你在保持原作者风格的同时,确保各个部分之间的质量和风格统一。  # 背景故事,指导模型如何理解并执行编辑任务
这些代理定义确立了特定角色和视角,这将决定我们的AI代理如何进行内容创作。请注意,每个代理都有其独特的目的和专长。

6、配置任务

更新任务配置文件来定义具体的写作和审阅任务:
# src/guide_creator_flow/crews/content_crew/config/tasks.yaml

write_section_task:
  description: >
    撰写一个关于主题“{section_title}”的全面章节内容

    章节描述:{section_description}
    目标读者:{audience_level} 水平的学习者

    请确保你的内容符合以下要求:
    1. 以简短的引言开始,介绍章节主题
    2. 清晰地解释所有关键概念,并提供示例
    3. 如适用,请包含实际应用或练习
    4. 以关键要点的总结结尾
    5. 字数控制在大约 500–800 字之间

    使用 Markdown 格式进行排版,包括合适的标题、列表和强调标记。

    以下是前面已写的章节:
    {previous_sections}

    请确保你的内容与先前章节保持一致,并在已有概念基础上进一步延伸。
  expected_output: >
    一篇结构清晰、内容全面的章节,使用 Markdown 格式,能够充分解释所选主题,并适合目标读者水平。
  agent: content_writer  # 指派给 content_writer 代理人来执行此任务

review_section_task:
  description: >
    请审阅并改进以下关于“{section_title}”的章节内容:

    {draft_content}

    目标读者:{audience_level} 水平的学习者

    以下是前面已写的章节:
    {previous_sections}

    请确保你的审阅工作包括:
    1. 修正所有语法或拼写错误
    2. 提高内容的清晰度与可读性
    3. 确保内容全面且准确
    4. 检查与之前章节内容的一致性
    5. 优化整体结构与逻辑流畅性
    6. 补充缺失的关键信息(如有)

    请以 Markdown 格式提供改进后的章节内容。
  expected_output: >
    一篇改进后的高质量章节内容,保持原始结构不变,
    但增强了清晰度、准确性和一致性。
  agent: content_reviewer  # 指派给 content_reviewer 代理人来执行此任务
  context:
    - write_section_task  # 指定此任务与 write_section_task 有上下文关联,用于提供审阅时的背景信息

这些任务定义向我们的代理提供了详细的指示,确保他们创作的内容符合我们的质量标准。请注意,context审核任务中的参数如何创建一个工作流,让审核人员可以访问作者的成果。

7、配置船员

配置船员实施文件以定义我们的代理和任务如何协同工作:
# 导入 CrewAI 所需的核心模块
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai.agents.agent_builder.base_agent import BaseAgent
from typing import List

# 使用装饰器 @CrewBase 定义一个 Crew 项目类,表示一个内容创作小组
@CrewBase
class ContentCrew():
    """内容创作小组"""

    # 定义代理人列表,类型为 BaseAgent 的列表
    agents: List[BaseAgent]
    # 定义任务列表,类型为 Task 的列表
    tasks: List[Task]

    # 定义内容撰稿代理人
    @agent
    def content_writer(self) -> Agent:
        return Agent(
            config=self.agents_config['content_writer'],  # 从配置中读取 content_writer 的配置
            verbose=True  # 启用详细日志输出
        )

    # 定义内容审稿代理人
    @agent
    def content_reviewer(self) -> Agent:
        return Agent(
            config=self.agents_config['content_reviewer'],  # 从配置中读取 content_reviewer 的配置
            verbose=True  # 启用详细日志输出
        )

    # 定义“撰写章节”任务
    @task
    def write_section_task(self) -> Task:
        return Task(
            config=self.tasks_config['write_section_task']  # 从任务配置中获取 write_section_task 的内容
        )

    # 定义“审阅章节”任务,并设置上下文为写作任务的输出
    @task
    def review_section_task(self) -> Task:
        return Task(
            config=self.tasks_config['review_section_task'],  # 从任务配置中获取 review_section_task 的内容
            context=[self.write_section_task()]  # 设置写作任务的输出为该任务的上下文
        )

    # 定义最终的团队编排方法,将代理人和任务组装为一个 Crew 实例
    @crew
    def crew(self) -> Crew:
        """创建内容创作团队"""
        return Crew(
            agents=self.agents,           # 使用定义好的代理人列表
            tasks=self.tasks,             # 使用定义好的任务列表
            process=Process.sequential,   # 按顺序执行任务(可选值还有 parallel 等)
            verbose=True                  # 启用详细运行日志
        )
这个团队定义确立了我们的代理与任务之间的关系,并建立了一个连续的流程:内容撰写者创建草稿,然后审阅者对其进行改进。虽然这个团队可以独立运作,但在我们的流程中,它将作为更大系统的一部分进行协调。

8、创建流程

创建流程来协调整个指南的创建过程。在这里,我们将把常规 Python 代码、直接 LLM 调用以及我们的内容创作团队整合成一个紧密结合的系统。
我们的流程将:
  • 获取主题和受众级别的用户输入
  • 直接致电法学硕士 (LLM) 以创建结构化的指南大纲
  • 使用内容编写团队按顺序处理每个部分
  • 将所有内容合并成最终的综合文档
让我们在main.py文件中创建流程:
# 导入标准库模块
import json
import os
from dotenv import load_dotenv

from typing import List, Dict

# 导入 pydantic,用于定义结构化数据模型
from pydantic import BaseModel, Field

# 导入 CrewAI 相关核心类
from crewai import LLM
from crewai.flow.flow import Flow, listen, start

# 导入自定义的内容创作团队定义
from guide_creator_flow.crews.content_crew.content_crew import ContentCrew

load_dotenv()

# -------------------------------
# 定义结构化数据模型
# -------------------------------

class Section(BaseModel):
    """指南的每个章节结构"""
    title: str = Field(description="章节标题")
    description: str = Field(description="章节需要涵盖的简要描述")

class GuideOutline(BaseModel):
    """整本指南的大纲结构"""
    title: str = Field(description="指南标题")
    introduction: str = Field(description="对主题的简介")
    target_audience: str = Field(description="目标读者描述")
    sections: List[Section] = Field(description="指南中各章节的列表")
    conclusion: str = Field(description="指南的结语或总结")

# -------------------------------
# 定义流程的状态结构(状态持久化用)
# -------------------------------

class GuideCreatorState(BaseModel):
    """指南创作过程中的状态记录"""
    topic: str = ""  # 指南主题
    audience_level: str = ""  # 目标受众水平(beginner/intermediate/advanced)
    guide_outline: GuideOutline = None  # 整体大纲
    sections_content: Dict[str, str] = {}  # 各章节的内容(按标题保存)

# -------------------------------
# 定义主流程类 GuideCreatorFlow
# -------------------------------

class GuideCreatorFlow(Flow[GuideCreatorState]):
    """用于创建综合指南的流程"""

    @start()
    def get_user_input(self):
        """步骤1:获取用户输入的主题和目标受众"""
        print("\n=== 创建你的综合指南 ===\n")

        # 获取用户输入的主题
        # self.state.topic = input("你想创建哪方面的指南?请输入主题:")
        self.state.topic="公路车选购指南"

        # 获取受众水平并校验合法性
        while True:
            # audience = input("目标读者是?(beginner/intermediate/advanced):").lower()
            audience="advanced"
            if audience in ["beginner", "intermediate", "advanced"]:
                self.state.audience_level = audience
                break
            print("请输入 'beginner'、'intermediate' 或 'advanced' 作为受众水平")

        print(f"\n即将为 {self.state.audience_level} 水平的读者创建关于「{self.state.topic}」的指南...\n")
        return self.state

    @listen(get_user_input)
    def create_guide_outline(self, state):
        """步骤2:调用大模型生成指南大纲"""
        print("正在生成指南大纲...")

        # 初始化 LLM,设定返回格式为 GuideOutline 模型
        llm = LLM(model="openai/gpt-4o",api_key=os.environ.get("OPENAI_API_KEY"), response_format=GuideOutline)

        # 构造提示词,告诉 LLM 创建结构化 JSON 大纲
        messages = [
            {"role": "system", "content": "你是一个用于输出 JSON 的助手。"},
            {"role": "user", "content": f"""
            请为 "{state.topic}" 创建一个适合 {state.audience_level} 水平学习者的综合指南大纲。

            大纲应包括:
            1. 一个吸引人的指南标题
            2. 对主题的简要介绍
            3. 4-6 个主要章节,每章需有标题和简要说明
            4. 一个结语或总结
            """}
        ]

        # 调用大模型
        response = llm.call(messages=messages)

        # 解析返回的 JSON 数据为字典,再转换为 GuideOutline 对象
        outline_dict = json.loads(response)
        self.state.guide_outline = GuideOutline(**outline_dict)

        # 确保输出目录存在
        os.makedirs("output", exist_ok=True)

        # 将大纲保存为 JSON 文件
        with open("output/guide_outline.json", "w") as f:
            json.dump(outline_dict, f, indent=2)

        print(f"指南大纲创建完成,共包含 {len(self.state.guide_outline.sections)} 个章节")
        return self.state.guide_outline

    @listen(create_guide_outline)
    def write_and_compile_guide(self, outline):
        """步骤3:撰写所有章节并整合为完整指南"""
        print("开始撰写章节并整合为完整指南...")
        completed_sections = []  # 记录已完成的章节标题

        # 按章节顺序逐一处理,确保上下文连贯
        for section in outline.sections:
            print(f"正在处理章节:{section.title}")

            # 构建上下文:前面章节的内容(便于保持一致性)
            previous_sections_text = ""
            if completed_sections:
                previous_sections_text = "# 已完成章节内容\n\n"
                for title in completed_sections:
                    previous_sections_text += f"## {title}\n\n"
                    previous_sections_text += self.state.sections_content.get(title, "") + "\n\n"
            else:
                previous_sections_text = "当前为第一章节,尚无前文。"

            # 使用内容团队完成该章节的撰写与审阅
            result = ContentCrew().crew().kickoff(inputs={
                "section_title": section.title,
                "section_description": section.description,
                "audience_level": self.state.audience_level,
                "previous_sections": previous_sections_text,
                "draft_content": ""  # 初始为空,由 content_writer 生成,reviewer 审阅
            })

            # 存储该章节内容
            self.state.sections_content[section.title] = result.raw
            completed_sections.append(section.title)
            print(f"章节已完成:{section.title}")

        # 组装最终完整指南内容(Markdown格式)
        guide_content = f"# {outline.title}\n\n"
        guide_content += f"## Introduction\n\n{outline.introduction}\n\n"

        # 添加每一个章节内容
        for section in outline.sections:
            section_content = self.state.sections_content.get(section.title, "")
            guide_content += f"\n\n{section_content}\n\n"

        # 添加结语
        guide_content += f"## Conclusion\n\n{outline.conclusion}\n\n"

        # 保存最终指南到文件
        with open("output/complete_guide.md", "w") as f:
            f.write(guide_content)

        print("\n完整指南已生成,保存在 output/complete_guide.md")
        return "指南创建成功"

# -------------------------------
# 启动函数
# -------------------------------

def kickoff():
    """执行整个指南创建流程"""
    GuideCreatorFlow().kickoff()
    print("\n=== 流程完成 ===")
    print("你的综合指南已保存在 output 目录中。")
    print("可打开 output/complete_guide.md 查看结果。")

def plot():
    """可视化流程结构图"""
    flow = GuideCreatorFlow()
    flow.plot("guide_creator_flow")
    print("流程结构图已保存为 guide_creator_flow.html")

# 如果作为主程序运行,则执行
if __name__ == "__main__":
    kickoff()
    # from crewai import LLM
    #
    # llm = LLM(model="gpt-4o")
    # response = llm.call("你好?")
    # print(response)

让我们分析一下这个流程中发生的事情:
  • 我们为结构化数据定义了 Pydantic 模型,以确保类型安全和清晰的数据表示。
  • 我们创建一个状态类来维护流程中不同步骤的数据。
  • 我们实现了三个主要的流程步骤:
    • 使用 @start() 装饰器获取用户输入
    • 通过直接 LLM 调用创建指南大纲
    • 与内容团队一起处理各个部分
  • 我们使用 @listen() 装饰器在步骤之间建立事件驱动的关系。
这就是流程的强大之处——将不同类型的处理(用户交互、直接 LLM 调用、基于团队的任务)组合成一个连贯的事件驱动系统。

9、设置环境变量

使用您的 API 密钥在项目根目录下创建一个 .env 文件。有关配置提供程序的详细信息,请参阅 前面博文。
OPENAI_API_KEY=your_openai_api_key
# or
GEMINI_API_KEY=your_gemini_api_key
# or
ANTHROPIC_API_KEY=your_anthropic_api_key

10、安装依赖项

初始化安装所需的依赖项:
crewai install

11、运行流程

现在是时候看看您的流程的实际效果了!使用 CrewAI CLI 运行它:
crewai flow kickoff
运行此命令后,您将看到流程开始运行:
  • 它会提示您输入主题和受众级别
  • 它会为您的指南创建一个结构化的大纲
  • 它会处理每个部分,内容撰写者和审核者会在每个部分进行协作
  • 最后,它会将所有内容汇编成一份综合指南
这展示了流程在协调涉及多个 AI 和非 AI 组件的复杂流程方面的强大功能。
输出完成

12、可视化您的流程

流程的强大功能之一是能够可视化其结构:
crewai flow plot
这将创建一个 HTML 文件,显示流程的结构,包括不同步骤之间的关系以及它们之间流动的数据。这种可视化对于理解和调试复杂流程非常有帮助。
打开输出的html页面,查看流程

13、查看输出

流程完成后,您会在输出目录中找到两个文件:
  • guide_outline.json:包含指南的结构化大纲
  • complete_guide.md:包含所有章节的综合指南
花点时间查看这些文件,并欣赏您所构建的成果,一个结合用户输入、直接 AI 交互和协作代理工作,从而生成复杂且高质量输出的系统。
guide_outline.json预览
complete_guide.md 最终文档预览

14、本教程特点

本指南创建流程展示了 CrewAI 的几个强大功能:
  1. 用户交互:流程直接从用户收集输入
  2. 直接 LLM 调用:使用 LLM 类进行高效、单一用途的 AI 交互
  3. 使用 Pydantic 的结构化数据:使用 Pydantic 模型来确保类型安全
  4. 带上下文的顺序处理:按顺序写入部分,并提供前面的部分作为上下文
  5. 多代理团队:利用专门的代理(作者和审阅者)进行内容创作
  6. 状态管理:维护流程不同步骤的状态
  7. 事件驱动架构:使用@listen装饰器来响应事件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值