理解决策框架

使用 CrewAI 构建 AI 应用时,最重要的决策之一是为特定用例选择合适的方法。您应该使用 Crew?还是 Flow?或者是两者的结合?本指南将帮助您评估需求并做出明智的架构决策。

这一决策的核心在于理解应用中**复杂性**与**精确性**之间的关系

CrewAI 应用的复杂性 vs 精确性矩阵

该矩阵有助于可视化不同的方法如何与不同的复杂性和精确性要求相匹配。让我们探讨每个象限的含义以及它如何指导您的架构选择。

复杂性-精确性矩阵解释

什么是复杂性?

在 CrewAI 应用的语境下,**复杂性**指

  • 所需的不同步骤或操作的数量
  • 需要执行的任务的多样性
  • 不同组件之间的相互依赖性
  • 对条件逻辑和分支的需求
  • 整体工作流的复杂程度

什么是精确性?

在此语境下,**精确性**指

  • 最终输出所需的准确性
  • 对结构化、可预测结果的需求
  • 可复现性的重要性
  • 对每个步骤所需控制的级别
  • 输出变异的容忍度

四个象限

1. 低复杂性,低精确性

特征

  • 简单、直接的任务
  • 对输出变异有一定的容忍度
  • 步骤数量有限
  • 创意或探索性应用

推荐方法: 使用少量 Agent 的简单 Crew

用例示例

  • 基本内容生成
  • 头脑风暴
  • 简单摘要任务
  • 创意写作辅助

2. 低复杂性,高精确性

特征

  • 需要精确、结构化输出的简单工作流
  • 需要可复现的结果
  • 步骤有限但精度要求高
  • 通常涉及数据处理或转换

推荐方法: 直接调用 LLM 的 Flow 或具有结构化输出的简单 Crew

用例示例

  • 数据提取与转换
  • 表单填写和验证
  • 结构化内容生成 (JSON, XML)
  • 简单分类任务

3. 高复杂性,低精确性

特征

  • 多步骤、多阶段的过程
  • 创意或探索性输出
  • 组件之间复杂的交互
  • 对最终结果变异的容忍度

推荐方法: 使用多个专业 Agent 的复杂 Crew

用例示例

  • 研究与分析
  • 内容创作流程
  • 探索性数据分析
  • 创意性问题解决

4. 高复杂性,高精确性

特征

  • 需要结构化输出的复杂工作流
  • 多个相互依赖的步骤,且有严格的精度要求
  • 需要复杂的处理和精确的结果
  • 通常是关键任务应用

推荐方法: 编排多个 Crew 并包含验证步骤的 Flow

用例示例

  • 企业决策支持系统
  • 复杂数据处理流程
  • 多阶段文档处理
  • 受监管行业的应用

在 Crew 和 Flow 之间选择

何时选择 Crew

在以下情况下 Crew 是理想选择:

  1. 您需要协作智能 - 多个具有不同专业知识的 Agent 需要协同工作
  2. 问题需要涌现式思考 - 解决方案受益于不同的视角和方法
  3. 任务主要是创意或分析性的 - 工作涉及研究、内容创作或分析
  4. 您看重适应性而非严格结构 - 工作流可以受益于 Agent 的自主性
  5. 输出格式可以有一定的灵活性 - 输出结构的一些变异是可以接受的
# Example: Research Crew for market analysis
from crewai import Agent, Crew, Process, Task

# Create specialized agents
researcher = Agent(
    role="Market Research Specialist",
    goal="Find comprehensive market data on emerging technologies",
    backstory="You are an expert at discovering market trends and gathering data."
)

analyst = Agent(
    role="Market Analyst",
    goal="Analyze market data and identify key opportunities",
    backstory="You excel at interpreting market data and spotting valuable insights."
)

# Define their tasks
research_task = Task(
    description="Research the current market landscape for AI-powered healthcare solutions",
    expected_output="Comprehensive market data including key players, market size, and growth trends",
    agent=researcher
)

analysis_task = Task(
    description="Analyze the market data and identify the top 3 investment opportunities",
    expected_output="Analysis report with 3 recommended investment opportunities and rationale",
    agent=analyst,
    context=[research_task]
)

# Create the crew
market_analysis_crew = Crew(
    agents=[researcher, analyst],
    tasks=[research_task, analysis_task],
    process=Process.sequential,
    verbose=True
)

# Run the crew
result = market_analysis_crew.kickoff()

何时选择 Flow

在以下情况下 Flow 是理想选择:

  1. 您需要对执行进行精确控制 - 工作流需要精确的序列和状态管理
  2. 应用具有复杂的状态要求 - 您需要在多个步骤中维护和转换状态
  3. 您需要结构化、可预测的输出 - 应用需要一致、格式化的结果
  4. 工作流涉及条件逻辑 - 需要根据中间结果采取不同的路径
  5. 您需要将 AI 与程序代码结合 - 解决方案需要 AI 能力和传统编程
# Example: Customer Support Flow with structured processing
from crewai.flow.flow import Flow, listen, router, start
from pydantic import BaseModel
from typing import List, Dict

# Define structured state
class SupportTicketState(BaseModel):
    ticket_id: str = ""
    customer_name: str = ""
    issue_description: str = ""
    category: str = ""
    priority: str = "medium"
    resolution: str = ""
    satisfaction_score: int = 0

class CustomerSupportFlow(Flow[SupportTicketState]):
    @start()
    def receive_ticket(self):
        # In a real app, this might come from an API
        self.state.ticket_id = "TKT-12345"
        self.state.customer_name = "Alex Johnson"
        self.state.issue_description = "Unable to access premium features after payment"
        return "Ticket received"

    @listen(receive_ticket)
    def categorize_ticket(self, _):
        # Use a direct LLM call for categorization
        from crewai import LLM
        llm = LLM(model="openai/gpt-4o-mini")

        prompt = f"""
        Categorize the following customer support issue into one of these categories:
        - Billing
        - Account Access
        - Technical Issue
        - Feature Request
        - Other

        Issue: {self.state.issue_description}

        Return only the category name.
        """

        self.state.category = llm.call(prompt).strip()
        return self.state.category

    @router(categorize_ticket)
    def route_by_category(self, category):
        # Route to different handlers based on category
        return category.lower().replace(" ", "_")

    @listen("billing")
    def handle_billing_issue(self):
        # Handle billing-specific logic
        self.state.priority = "high"
        # More billing-specific processing...
        return "Billing issue handled"

    @listen("account_access")
    def handle_access_issue(self):
        # Handle access-specific logic
        self.state.priority = "high"
        # More access-specific processing...
        return "Access issue handled"

    # Additional category handlers...

    @listen("billing", "account_access", "technical_issue", "feature_request", "other")
    def resolve_ticket(self, resolution_info):
        # Final resolution step
        self.state.resolution = f"Issue resolved: {resolution_info}"
        return self.state.resolution

# Run the flow
support_flow = CustomerSupportFlow()
result = support_flow.kickoff()

何时结合 Crew 和 Flow

最复杂的应用通常受益于 Crew 和 Flow 的结合

  1. 复杂的多阶段过程 - 使用 Flow 编排整体过程,使用 Crew 处理复杂的子任务
  2. 需要创意和结构的应用 - 使用 Crew 处理创意任务,使用 Flow 处理结构化过程
  3. 企业级 AI 应用 - 使用 Flow 管理状态和过程流,同时利用 Crew 进行专业工作
# Example: Content Production Pipeline combining Crews and Flows
from crewai.flow.flow import Flow, listen, start
from crewai import Agent, Crew, Process, Task
from pydantic import BaseModel
from typing import List, Dict

class ContentState(BaseModel):
    topic: str = ""
    target_audience: str = ""
    content_type: str = ""
    outline: Dict = {}
    draft_content: str = ""
    final_content: str = ""
    seo_score: int = 0

class ContentProductionFlow(Flow[ContentState]):
    @start()
    def initialize_project(self):
        # Set initial parameters
        self.state.topic = "Sustainable Investing"
        self.state.target_audience = "Millennial Investors"
        self.state.content_type = "Blog Post"
        return "Project initialized"

    @listen(initialize_project)
    def create_outline(self, _):
        # Use a research crew to create an outline
        researcher = Agent(
            role="Content Researcher",
            goal=f"Research {self.state.topic} for {self.state.target_audience}",
            backstory="You are an expert researcher with deep knowledge of content creation."
        )

        outliner = Agent(
            role="Content Strategist",
            goal=f"Create an engaging outline for a {self.state.content_type}",
            backstory="You excel at structuring content for maximum engagement."
        )

        research_task = Task(
            description=f"Research {self.state.topic} focusing on what would interest {self.state.target_audience}",
            expected_output="Comprehensive research notes with key points and statistics",
            agent=researcher
        )

        outline_task = Task(
            description=f"Create an outline for a {self.state.content_type} about {self.state.topic}",
            expected_output="Detailed content outline with sections and key points",
            agent=outliner,
            context=[research_task]
        )

        outline_crew = Crew(
            agents=[researcher, outliner],
            tasks=[research_task, outline_task],
            process=Process.sequential,
            verbose=True
        )

        # Run the crew and store the result
        result = outline_crew.kickoff()

        # Parse the outline (in a real app, you might use a more robust parsing approach)
        import json
        try:
            self.state.outline = json.loads(result.raw)
        except:
            # Fallback if not valid JSON
            self.state.outline = {"sections": result.raw}

        return "Outline created"

    @listen(create_outline)
    def write_content(self, _):
        # Use a writing crew to create the content
        writer = Agent(
            role="Content Writer",
            goal=f"Write engaging content for {self.state.target_audience}",
            backstory="You are a skilled writer who creates compelling content."
        )

        editor = Agent(
            role="Content Editor",
            goal="Ensure content is polished, accurate, and engaging",
            backstory="You have a keen eye for detail and a talent for improving content."
        )

        writing_task = Task(
            description=f"Write a {self.state.content_type} about {self.state.topic} following this outline: {self.state.outline}",
            expected_output="Complete draft content in markdown format",
            agent=writer
        )

        editing_task = Task(
            description="Edit and improve the draft content for clarity, engagement, and accuracy",
            expected_output="Polished final content in markdown format",
            agent=editor,
            context=[writing_task]
        )

        writing_crew = Crew(
            agents=[writer, editor],
            tasks=[writing_task, editing_task],
            process=Process.sequential,
            verbose=True
        )

        # Run the crew and store the result
        result = writing_crew.kickoff()
        self.state.final_content = result.raw

        return "Content created"

    @listen(write_content)
    def optimize_for_seo(self, _):
        # Use a direct LLM call for SEO optimization
        from crewai import LLM
        llm = LLM(model="openai/gpt-4o-mini")

        prompt = f"""
        Analyze this content for SEO effectiveness for the keyword "{self.state.topic}".
        Rate it on a scale of 1-100 and provide 3 specific recommendations for improvement.

        Content: {self.state.final_content[:1000]}... (truncated for brevity)

        Format your response as JSON with the following structure:
        {{
            "score": 85,
            "recommendations": [
                "Recommendation 1",
                "Recommendation 2",
                "Recommendation 3"
            ]
        }}
        """

        seo_analysis = llm.call(prompt)

        # Parse the SEO analysis
        import json
        try:
            analysis = json.loads(seo_analysis)
            self.state.seo_score = analysis.get("score", 0)
            return analysis
        except:
            self.state.seo_score = 50
            return {"score": 50, "recommendations": ["Unable to parse SEO analysis"]}

# Run the flow
content_flow = ContentProductionFlow()
result = content_flow.kickoff()

实际评估框架

要确定特定用例的正确方法,请遵循此分步评估框架:

步骤 1:评估复杂性

通过考虑以下因素,在 1-10 的范围内评估应用的复杂性:

  1. 步骤数量:需要多少个不同的操作?

    • 1-3 步:低复杂性 (1-3)
    • 4-7 步:中等复杂性 (4-7)
    • 8+ 步:高复杂性 (8-10)
  2. 相互依赖性:不同部分之间的相互关联程度如何?

    • 依赖性少:低复杂性 (1-3)
    • 一些依赖性:中等复杂性 (4-7)
    • 许多复杂依赖性:高复杂性 (8-10)
  3. 条件逻辑:需要多少分支和决策?

    • 线性过程:低复杂性 (1-3)
    • 一些分支:中等复杂性 (4-7)
    • 复杂的决策树:高复杂性 (8-10)
  4. 领域知识:所需知识的专业程度如何?

    • 通用知识:低复杂性 (1-3)
    • 一些专业知识:中等复杂性 (4-7)
    • 多个领域的深厚专业知识:高复杂性 (8-10)

计算平均分以确定整体复杂性。

步骤 2:评估精确性要求

通过考虑以下因素,在 1-10 的范围内评估您的精确性要求:

  1. 输出结构:输出必须有多结构化?

    • 自由格式文本:低精确性 (1-3)
    • 半结构化:中等精确性 (4-7)
    • 严格格式化 (JSON, XML):高精确性 (8-10)
  2. 准确性需求:事实准确性有多重要?

    • 创意内容:低精确性 (1-3)
    • 信息内容:中等精确性 (4-7)
    • 关键信息:高精确性 (8-10)
  3. 可复现性:跨次运行的结果必须有多一致?

    • 允许变异:低精确性 (1-3)
    • 需要一定的一致性:中等精确性 (4-7)
    • 需要精确复现:高精确性 (8-10)
  4. 错误容忍度:错误的潜在影响是什么?

    • 影响低:低精确性 (1-3)
    • 影响中等:中等精确性 (4-7)
    • 影响高:高精确性 (8-10)

计算平均分以确定整体精确性要求。

步骤 3:映射到矩阵

将您的复杂性和精确性得分绘制到矩阵中:

  • 低复杂性 (1-4),低精确性 (1-4):简单 Crew
  • 低复杂性 (1-4),高精确性 (5-10):直接调用 LLM 的 Flow
  • 高复杂性 (5-10),低精确性 (1-4):复杂 Crew
  • 高复杂性 (5-10),高精确性 (5-10):编排 Crew 的 Flow

步骤 4:考虑附加因素

除了复杂性和精确性,还需考虑:

  1. 开发时间:Crew 通常原型开发更快
  2. 维护需求:Flow 提供更好的长期可维护性
  3. 团队专业知识:考虑您的团队对不同方法的熟悉程度
  4. 可伸缩性要求:对于复杂应用,Flow 通常具有更好的伸缩性
  5. 集成需求:考虑解决方案如何与现有系统集成

结论

选择 Crew 和 Flow(或结合使用)是一个关键的架构决策,它会影响 CrewAI 应用的有效性、可维护性和可伸缩性。通过评估您的用例在复杂性和精确性维度的需求,您可以做出符合特定要求的明智决策。

请记住,最佳方法通常会随着应用的成熟而演变。从满足您需求的最简单解决方案开始,并准备好随着经验积累和需求更清晰而完善您的架构。

您现在拥有了一个评估 CrewAI 用例并根据复杂性和精确性要求选择正确方法的框架。这将帮助您构建更有效、可维护和可伸缩的 AI 应用。

后续步骤