CrewAI Patterns

Executive Summary

CrewAI is a Python framework for building multi-agent systems using a declarative, role-based model where developers define agents by persona (role, goal, backstory), assign them tasks, and compose them into crews that execute workflows collaboratively. It prioritizes ease of configuration over fine-grained control, making it appropriate for task-based workflows where agent roles map naturally to human team structures. This chapter covers CrewAI's architecture, configuration patterns, process types, and the architectural decision of when to choose CrewAI over LangGraph. AI architects evaluating multi-agent frameworks and engineers implementing task-based agent teams should read this chapter.

ℹ Note

Note: CrewAI's API evolves rapidly. Verify current syntax and features in the official CrewAI documentation. The architectural patterns in this chapter are stable; specific API signatures may change between versions.

Learning Objectives

  • Describe CrewAI's four core concepts (Agents, Tasks, Tools, Crews) and how they compose
  • Configure a sequential and a hierarchical crew for an enterprise workflow
  • Choose between sequential and hierarchical process types based on task dependency structure
  • Identify the architectural trade-offs between CrewAI and LangGraph
  • Design crew configurations that follow enterprise tool authorization principles

Business Problem

Building multi-agent systems with raw SDK code or LangGraph requires explicit graph topology design, state schema definition, and routing logic implementation. For many enterprise use cases — particularly those mapping to human team workflows — the overhead of graph design is not matched by the control it provides.

A clinical documentation review team has natural role structures: a Retrieval Specialist who finds relevant documents, a Clinical Analyst who evaluates clinical criteria, and a Documentation Writer who drafts the output. These roles map directly to CrewAI's agent model. The framework's declarative nature reduces agent system implementation to configuration rather than graph programming.

Why This Technology Exists

CrewAI (released 2024) emerged from the observation that many multi-agent use cases followed a team-task pattern: a group of specialized agents, each with a defined role, collaborating on a set of tasks to achieve a goal. This pattern is so common — research teams, analysis teams, content production teams — that it warranted a framework abstraction.

The design philosophy differs fundamentally from LangGraph: LangGraph is graph-first (you design the graph, the framework executes it); CrewAI is role-first (you define roles and tasks, the framework orchestrates them). This makes CrewAI faster to configure for role-based workflows but less expressive for workflows requiring complex conditional routing, cycles, or fine-grained state management.

Conceptual Explanation

CrewAI's model has four concepts:

Agent: An LLM-powered entity with a defined role, goal, and backstory. The role and goal form the agent's system prompt; the backstory provides context that shapes its reasoning style. Agents are assigned tools they can use.

Task: A unit of work with a description of what to do, the expected output format, and the agent responsible for it. Tasks are the nodes of the workflow.

Tool: A callable function exposed to agents. CrewAI tools follow the same design principles as tools in any agent system: descriptive names, clear schemas, idempotent write operations.

Crew: The composition of agents and tasks, plus a process type that determines how they execute.

Core Architecture

text
Crew
├── Process: Sequential | Hierarchical
├── Agents
│   ├── Agent(role, goal, backstory, tools, llm)
│   └── Agent(...)
└── Tasks
    ├── Task(description, expected_output, agent)
    └── Task(description, expected_output, agent, context=[prior_task])

Process Types

Sequential: Tasks execute in order, each task's output automatically available to subsequent tasks as context. Simple, predictable, and appropriate when tasks have linear dependencies.

Hierarchical: A manager agent (auto-created or specified) receives the overall goal, decomposes it into subtasks, delegates them to worker agents, and synthesizes results. More flexible; the manager can reassign tasks based on interim results.

Architecture Diagram

Components

Agent Configuration

python
from crewai import Agent
import anthropic

# Verify current CrewAI integration patterns at crewai.com/docs
clinical_analyst = Agent(
    role="Clinical Criteria Analyst",
    goal=(
        "Evaluate whether a patient's clinical profile meets the criteria "
        "for a requested medical procedure based on current clinical guidelines."
    ),
    backstory=(
        "You are a clinical informatics specialist with deep expertise in "
        "evidence-based medicine and payer clinical criteria. You are precise, "
        "evidence-driven, and always cite the specific guideline section "
        "supporting your evaluation. You do not make diagnoses or treatment "
        "recommendations — you evaluate criteria only."
    ),
    tools=[guideline_search_tool, patient_data_tool],
    llm="claude-opus-4-8",  # Verify current model ID at docs.anthropic.com
    verbose=True,
    allow_delegation=False,  # This worker does not delegate further
)

Task Configuration

python
from crewai import Task

clinical_eval_task = Task(
    description=(
        "Evaluate whether patient {patient_id} meets clinical criteria for "
        "procedure {procedure_code}. "
        "1. Review the patient summary provided in context. "
        "2. Search for the relevant clinical guidelines for this procedure. "
        "3. Evaluate each criterion. "
        "4. Produce a structured evaluation with: criteria_met (bool), "
        "   rationale (string), supporting_guidelines (list of citations)."
    ),
    expected_output=(
        "A JSON object with: criteria_met (boolean), rationale (string explaining "
        "the evaluation), supporting_guidelines (list of citation strings). "
        "Example: {\"criteria_met\": true, \"rationale\": \"...\", "
        "\"supporting_guidelines\": [\"ADA Standards 2025, Section 9\"]}"
    ),
    agent=clinical_analyst,
    context=[patient_retrieval_task],  # receives patient_retrieval_task output
)

Crew Assembly and Execution

python
from crewai import Crew, Process

prior_auth_crew = Crew(
    agents=[retrieval_agent, clinical_analyst, documentation_agent],
    tasks=[patient_retrieval_task, clinical_eval_task, documentation_task],
    process=Process.sequential,
    verbose=True,
)

result = prior_auth_crew.kickoff(inputs={
    "patient_id": "P-12345",
    "procedure_code": "95810",
})

Implementation Patterns

Pattern 1: Sequential Prior Authorization Crew

python
"""
CrewAI sequential prior authorization workflow.
Educational Example — Illustrative multi-agent configuration.
Not intended for clinical decision making.

Prerequisites: pip install crewai anthropic
"""
from __future__ import annotations

try:
    from crewai import Agent, Task, Crew, Process
    from crewai.tools import BaseTool
    CREWAI_AVAILABLE = True
except ImportError:
    CREWAI_AVAILABLE = False
    print("CrewAI not installed. Run: pip install crewai")

from pydantic import BaseModel, Field
import json


# ── Tool definitions ─────────────────────────────────────────────────────────

class PatientDataInput(BaseModel):
    patient_id: str = Field(description="Patient identifier")

class GuidelineSearchInput(BaseModel):
    query: str = Field(description="Natural language search query for clinical guidelines")
    procedure_code: str = Field(default="", description="Optional CPT/HCPCS code to filter results")


if CREWAI_AVAILABLE:
    class GetPatientSummaryTool(BaseTool):
        name: str = "get_patient_summary"
        description: str = (
            "Retrieve a patient's clinical summary including active diagnoses, "
            "current medications, and relevant lab values. Use when you need "
            "patient-specific clinical context. Returns structured patient data."
        )
        args_schema: type[BaseModel] = PatientDataInput

        def _run(self, patient_id: str) -> str:
            # Stub: production calls FHIR R4 API
            data = {
                "patient_id": patient_id,
                "diagnoses": ["Obstructive Sleep Apnea (suspected)", "Obesity"],
                "bmi": 36.1,
                "epworth_score": 14,
                "ahi_screening": 22.3,
                "current_medications": ["Lisinopril 10mg", "Metformin 500mg"],
            }
            return json.dumps(data)

    class SearchGuidelinesTool(BaseTool):
        name: str = "search_clinical_guidelines"
        description: str = (
            "Search the institutional clinical guidelines library for evidence-based "
            "criteria and recommendations. Use when evaluating medical necessity or "
            "clinical appropriateness. Returns up to 3 relevant guideline passages."
        )
        args_schema: type[BaseModel] = GuidelineSearchInput

        def _run(self, query: str, procedure_code: str = "") -> str:
            # Stub: production queries vector store
            return json.dumps({
                "results": [
                    {
                        "title": "AASM Sleep Study Guidelines 2023",
                        "content": "Polysomnography (CPT 95810) is indicated for patients with "
                                  "suspected OSA with Epworth Sleepiness Scale ≥ 10 and AHI ≥ 15 "
                                  "on home sleep test, or BMI ≥ 35 with symptoms.",
                        "relevance": 0.91
                    }
                ]
            })

    # ── Agents ───────────────────────────────────────────────────────────────

    retrieval_agent = Agent(
        role="Clinical Data Retrieval Specialist",
        goal="Accurately retrieve complete patient clinical data required for prior authorization evaluation.",
        backstory=(
            "You are a clinical data specialist who retrieves structured patient information "
            "from the EHR system. You retrieve exactly the data requested, verify completeness, "
            "and present it in a structured format for downstream clinical evaluation."
        ),
        tools=[GetPatientSummaryTool()],
        verbose=True,
        allow_delegation=False,
    )

    clinical_analyst_agent = Agent(
        role="Clinical Criteria Analyst",
        goal="Evaluate clinical necessity using evidence-based guidelines. Produce clear, cited evaluations.",
        backstory=(
            "You are a clinical informatics expert specializing in medical necessity evaluation. "
            "You evaluate patient data against current evidence-based criteria, always citing "
            "specific guideline sections. You are objective and evidence-driven. "
            "You do not make diagnoses — you evaluate documented criteria only."
        ),
        tools=[SearchGuidelinesTool()],
        verbose=True,
        allow_delegation=False,
    )

    documentation_agent = Agent(
        role="Prior Authorization Documentation Specialist",
        goal="Draft clear, complete prior authorization letters based on clinical evaluation results.",
        backstory=(
            "You are a medical documentation specialist who translates clinical evaluations "
            "into well-structured prior authorization determination letters. "
            "Your letters are precise, professionally written, and clearly communicate "
            "the clinical rationale. All letters are clearly marked as drafts requiring physician review."
        ),
        tools=[],  # Documentation agent uses no tools — works from context only
        verbose=True,
        allow_delegation=False,
    )

    # ── Tasks ─────────────────────────────────────────────────────────────────

    retrieval_task = Task(
        description=(
            "Retrieve the clinical summary for patient {patient_id}. "
            "Use the get_patient_summary tool with the provided patient ID. "
            "Verify that the summary includes: diagnoses, BMI, relevant screening scores, "
            "and current medications. Present the complete summary."
        ),
        expected_output=(
            "A complete patient clinical summary including: active diagnoses, BMI, "
            "relevant screening test scores, and current medications. "
            "Format as a structured list."
        ),
        agent=retrieval_agent,
    )

    evaluation_task = Task(
        description=(
            "Evaluate whether the patient meets clinical criteria for procedure {procedure_code}. "
            "1. Review the patient summary from the previous task. "
            "2. Search for relevant clinical guidelines using the procedure code. "
            "3. Evaluate each criterion in the guidelines against the patient's data. "
            "4. Produce a structured determination: criteria_met (yes/no), specific criteria "
            "   met and not met, and the guideline citations supporting each point."
        ),
        expected_output=(
            "A clinical evaluation report containing: "
            "overall determination (MEETS CRITERIA / DOES NOT MEET CRITERIA), "
            "specific criterion-by-criterion analysis, "
            "and supporting guideline citations for each point."
        ),
        agent=clinical_analyst_agent,
        context=[retrieval_task],
    )

    documentation_task = Task(
        description=(
            "Draft a prior authorization determination letter based on the clinical evaluation. "
            "The letter must include: patient identifier, procedure requested, "
            "determination (approval/denial), clinical rationale with guideline citations, "
            "and a clear statement that this is a DRAFT requiring physician review. "
            "Label the letter: 'Educational Example — Not for clinical use.'"
        ),
        expected_output=(
            "A professionally formatted prior authorization determination letter draft. "
            "Must be clearly marked as DRAFT PENDING PHYSICIAN REVIEW. "
            "Must include clinical rationale with specific guideline citations."
        ),
        agent=documentation_agent,
        context=[retrieval_task, evaluation_task],
    )

    # ── Crew ─────────────────────────────────────────────────────────────────

    prior_auth_crew = Crew(
        agents=[retrieval_agent, clinical_analyst_agent, documentation_agent],
        tasks=[retrieval_task, evaluation_task, documentation_task],
        process=Process.sequential,
        verbose=True,
    )


def run_prior_auth_crew(patient_id: str, procedure_code: str) -> str:
    """Run the prior authorization crew for a given patient and procedure."""
    if not CREWAI_AVAILABLE:
        return "CrewAI not available. Install with: pip install crewai"

    result = prior_auth_crew.kickoff(inputs={
        "patient_id": patient_id,
        "procedure_code": procedure_code,
    })
    return str(result)


if __name__ == "__main__":
    print("=== CrewAI Prior Authorization Crew ===")
    print("Educational Example — Not for clinical use\n")

    output = run_prior_auth_crew("P-DEMO-001", "95810")
    print("\n=== Final Output ===")
    print(output)

Pattern 2: Hierarchical Process with Manager Agent

python
# Hierarchical process — manager agent decomposes and delegates
hierarchical_crew = Crew(
    agents=[retrieval_agent, clinical_analyst_agent, documentation_agent],
    tasks=[retrieval_task, evaluation_task, documentation_task],
    process=Process.hierarchical,
    manager_llm="claude-opus-4-8",  # Manager uses frontier model; workers can use smaller models
    verbose=True,
)
# In hierarchical mode, the manager can re-delegate tasks and adapt the workflow
# based on interim results — suitable for complex, adaptive workflows.

Enterprise Considerations

Model assignment by agent role. CrewAI supports per-agent LLM configuration. Assign frontier models (Opus-class) to agents requiring complex reasoning (Clinical Analyst, Manager in hierarchical mode). Assign smaller, faster models (Haiku-class) to agents performing focused tasks (Retrieval Specialist, Documentation Writer). This can reduce per-crew cost by 30–60% without meaningful quality degradation.

Task output validation. CrewAI tasks specify an expected_output but do not enforce it — the agent produces text that may or may not match the expected format. For machine-parseable outputs (JSON clinical evaluations), add output validation in the calling code and implement retry logic when the output does not parse correctly.

Parallelism. Sequential process executes tasks in order. If the retrieval and guideline search tasks are independent, they could run in parallel, reducing total latency. CrewAI supports parallel task execution via async_execution=True on tasks; evaluate whether your task dependencies allow this.

Memory. CrewAI provides agent-level memory options: short-term (conversation within a task), long-term (PostgreSQL/ChromaDB across runs), and entity memory (specific entity tracking). For HMS workflows, enable short-term memory per crew run and long-term memory for patient-specific context.

Security Considerations

Backstory as trust boundary. The agent backstory is part of the system prompt. It should explicitly constrain scope: "You evaluate criteria only — you do not recommend treatments or make diagnoses." Without explicit scope constraints in the backstory, agents may exceed their intended role if prompted by task descriptions that push boundaries.

Tool authorization. Apply the same tool authorization principles from Chapter 2: each agent's tool list should contain only tools appropriate for its role. A documentation agent with access to a submit<em>to</em>payer tool is a misconfiguration.

Healthcare Example

⊕ Healthcare Example

Educational Example — Illustrative Workflow. Not intended for clinical decision making.

A Reference Healthcare Organization's clinical documentation review crew uses three agents:

Agent Role Model Tier Tools Allow Delegation
Clinical Data Retrieval Specialist Haiku (focused, fast) get<em>patient</em>summary, get<em>lab</em>results No
Clinical Criteria Analyst Opus (complex reasoning) search<em>guidelines, evaluate</em>criteria No
Documentation Specialist Sonnet (quality writing) None (context only) No

No agent has delegation enabled — the crew process (sequential) handles all routing. External submission tools are not in any agent's tool registry — submission is handled by a separate HITL workflow after crew completion.

Common Mistakes

No expected<em>output specification. Without specifying the expected output format, agents produce inconsistent output structures that break downstream tasks. Always specify the exact format in expected</em>output.

allow_delegation=True without oversight. When agents can delegate, they can create recursive delegation chains that are hard to trace and control. Disable delegation for worker agents in sequential processes; use hierarchical process instead when delegation is needed.

Manager agent using same model as workers. In hierarchical mode, the manager performs complex planning and coordination — it benefits from a frontier model. Workers perform focused tasks — they can often use smaller models effectively.

No memory for multi-session workflows. A crew with no memory configuration starts fresh on every run. For patient-specific workflows that span multiple interactions, configure long-term memory to persist relevant context.

Best Practices

  • Use sequential process for linear task workflows with clear dependencies; use hierarchical for adaptive workflows
  • Assign frontier models to agents requiring complex reasoning; use smaller models for focused tasks
  • Specify expected_output in detail for every task, especially those producing machine-parseable data
  • Disable allow_delegation for worker agents in sequential crews; it adds unpredictability
  • Apply the principle of least privilege to agent tool lists — only tools needed for the role
  • Test agent output format consistency across multiple runs before deploying to production

Alternatives

Framework Best For When to Prefer LangGraph Instead
CrewAI (Sequential) Linear role-based workflows; team emulation When you need complex conditional routing
CrewAI (Hierarchical) Adaptive task delegation; unknown task structure When you need typed state and checkpointing
LangGraph Production workflows requiring persistence, HITL, typed state When role-based config is sufficient
Custom orchestrator Maximum control; unusual topology When you want to reduce dependencies
AutoGen Conversational multi-agent patterns When agents need to debate/negotiate

Trade-offs

Dimension CrewAI Advantage CrewAI Cost
Configuration speed Declarative; fast to set up Less control than LangGraph
Role clarity Role/goal/backstory maps to human teams State management is implicit
Checkpointing Memory options available Less mature than LangGraph checkpointing
Conditional routing Hierarchical process provides some flexibility Not as expressive as LangGraph graph edges
Output validation expected_output guides agents Does not enforce format — validation is manual

Interview Questions

Q1: When would you choose CrewAI over LangGraph for an enterprise agentic workflow?

Category: Architecture Difficulty: Senior Role: AI Architect

Answer Framework:

The choice comes down to what the workflow's primary complexity is: role/task decomposition or graph/state complexity.

Choose CrewAI when: the workflow maps naturally to a team of specialized humans (researcher, analyst, writer); the task sequence is either linear or can be delegated by a manager agent; you need a working prototype quickly and the operational requirements (checkpointing, typed state, complex HITL) are not yet defined.

Choose LangGraph when: the workflow requires typed, persistent state that is shared across multiple nodes; HITL is required at specific points and resumption must be reliable; the workflow has complex conditional routing (different paths based on data, not just sequential delegation); you need fault-tolerant, resumable workflows in production with a PostgreSQL-backed checkpointer.

In practice, many teams prototype with CrewAI and migrate to LangGraph when they hit the operational requirements wall. A hybrid is also possible: use LangGraph as the outer state machine with CrewAI crews as sub-workflows at specific nodes.

Key Takeaways

  • CrewAI models agents as roles (role, goal, backstory) and workflows as task sequences — appropriate for team-emulation patterns
  • Sequential process executes tasks in order with automatic context passing; hierarchical process uses a manager agent for dynamic delegation
  • Assign frontier models to planning/reasoning agents; use smaller models for focused task agents
  • Always specify expected_output in detail; validate output format in calling code
  • CrewAI is faster to configure than LangGraph; LangGraph provides more control for complex state, routing, and HITL requirements
  • Tool authorization principles apply identically in CrewAI: each agent gets only tools appropriate to its role

Glossary

Term Definition
Agent (CrewAI) An LLM-powered entity defined by role, goal, backstory, and assigned tools
Task (CrewAI) A unit of work with description, expected output, and an assigned agent
Crew The composition of agents and tasks with a defined execution process
Sequential process Tasks execute in order; each task's output is automatically available as context to subsequent tasks
Hierarchical process A manager agent decomposes the goal, delegates tasks, and synthesizes results
allow_delegation Agent configuration flag; when True, the agent can reassign tasks to other agents

Further Reading

In This Repository:

External References:

  • CrewAI official documentation — authoritative source; verify current API before implementation
  • CrewAI GitHub repository — source code and example implementations

Previous: LangGraph Deep Dive | Next: Human-in-the-Loop