Crews inside flows: choosing the design

CrewAI · Practical · 12 min

Picking the right structure early saves rewrites when an app moves from prototype to production.

Inside a flow step you can call a crew like any other code:

@listen(plan)
def write(self):
    result = WritingCrew().crew().kickoff(inputs={"topic": self.state.topic})
    self.state.draft = result.raw

crewai create flow NAME scaffolds a flow project: main.py holds the flow, and crews/ contains one folder per crew. crewai run detects that the project is a flow and runs it. A JSON-first crew can be loaded inside a step with load_crew(path).

When to use what (following CrewAI's own guidance):

  • Low complexity, low precision (brainstorming, simple drafts): one simple crew.
  • Low complexity, high precision (extraction, classification): a flow with direct LLM or single-agent calls and structured outputs.
  • High complexity, low precision (research reports, content pipelines): a crew with several specialised agents.
  • High complexity, high precision (regulated or mission-critical work): a flow that orchestrates crews with validation steps between them.

Crews are quicker to prototype. Flows are easier to test, debug and maintain because the control flow is ordinary code. Start with the simplest design that works and add structure as requirements become clear.

A common production shape: a flow validates input, calls a research crew, checks the result with code or a guardrail, routes to a human when needed, and saves the outcome. Each crew stays small and focused.

Example

from pydantic import BaseModel
from crewai import Agent, Crew, Task
from crewai.flow import Flow, listen, start

def writing_crew() -> Crew:
    writer = Agent(role="Blog writer", goal="Write clear posts", backstory="Writes for engineers.")
    post = Task(description="Write a 150-word post about {topic}.", expected_output="Markdown.", agent=writer)
    return Crew(agents=[writer], tasks=[post])

class PostState(BaseModel):
    topic: str = ""
    draft: str = ""

class PostFlow(Flow[PostState]):
    @start()
    def validate(self):
        if not self.state.topic.strip():
            raise ValueError("topic is required")
    @listen(validate)
    def write(self):
        self.state.draft = writing_crew().kickoff(inputs={"topic": self.state.topic}).raw
    @listen(write)
    def publish(self): return f"{len(self.state.draft.split())} words ready"

print(PostFlow().kickoff(inputs={"topic": "Python virtual environments"}))

Remember

  • Flow steps call crew.kickoff(...) and store results in state
  • crewai create flow NAME scaffolds main.py plus crews/
  • Crews for open-ended work; flows for control, validation and precision

Watch out for

  • Building one huge crew with many agents for a process that is mostly fixed steps; a flow with small crews is cheaper and easier to debug.

Check yourself

  1. Per CrewAI's guidance, which design fits a high-complexity, high-precision process such as regulated document review?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.crewai.com/en/guides/concepts/evaluating-use-cases