Course Building Agentic AI Systems Chapter 13 Difficulty advanced Estimated Time 600 min

Chapter 13: CrewAI & OpenAI Agents SDK

CrewAI & OpenAI Agents SDK in Building Agentic AI Systems.

59% complete

Learning Objectives

By the end of this chapter, you will be able to:

  • Explain the agentic AI concept behind CrewAI & OpenAI Agents SDK.
  • Apply CrewAI & OpenAI Agents SDK to design reliable, production-grade agent systems.
  • Recognize operational trade-offs in tool use, orchestration, safety, and cost.

Chapter 13: CrewAI & OpenAI Agents SDK

Role-based crews, event-driven flows, and the triage agent pattern

Two Complementary Frameworks

LangGraph (Chapter 12) gives maximum control via explicit graph definitions. CrewAI and the OpenAI Agents SDK prioritize speed of development and ergonomics. They are not competitors — each serves a different point on the control vs. simplicity spectrum.

CrewAI

  • Role-based agents ("Researcher", "Writer", "Editor")
  • ~46K GitHub stars, 450M monthly workflows
  • Fastest time-to-working-demo
  • Sequential and parallel crew execution
  • Built-in event-driven Flows

OpenAI Agents SDK

  • Agents + Runners + Handoffs + Guardrails
  • 97% successful run rate in benchmarks
  • Native MCP support
  • Best for OpenAI ecosystem users
  • ~10 minutes to hello-world

CrewAI

CrewAI models a multi-agent system as a "crew" of agents with distinct roles, each assigned tasks. The crew executes tasks in a configured order (sequential or parallel), with agents optionally delegating to one another.

python — CrewAI content production crew
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool

search_tool = SerperDevTool()

# ── Define Agents with Roles ─────────────────────────────────────────────────

researcher = Agent(
    role="Senior Research Analyst",
    goal="Find comprehensive, accurate information on the given topic",
    backstory=(
        "You are an expert researcher with 10 years of experience synthesizing "
        "complex information from multiple sources. You always cite your sources."
    ),
    tools=[search_tool],
    llm="gpt-4o",
    verbose=True,
)

writer = Agent(
    role="Content Strategist",
    goal="Write clear, engaging content based on research findings",
    backstory=(
        "You transform complex research into accessible, compelling narratives. "
        "You write for a technical audience and always back claims with evidence."
    ),
    llm="gpt-4o",
)

# ── Define Tasks ─────────────────────────────────────────────────────────────

research_task = Task(
    description="Research the current state of {topic}. Find key developments in 2025-2026.",
    expected_output="A structured research report with key findings, sources, and data points.",
    agent=researcher,
)

writing_task = Task(
    description="Write a 500-word article about {topic} based on the research report.",
    expected_output="A complete article with title, intro, 3 body sections, and conclusion.",
    agent=writer,
    context=[research_task],   # this task depends on research_task's output
)

# ── Assemble Crew ─────────────────────────────────────────────────────────────

crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    process=Process.sequential,   # or Process.hierarchical for supervisor pattern
    verbose=True,
)

result = crew.kickoff(inputs={"topic": "AI agent frameworks in 2026"})

CrewAI Flows — Event-Driven Orchestration

Flows extend CrewAI beyond sequential crews to event-driven pipelines. A Flow method decorated with @start or @listen runs when a specific event fires or when another method completes.

python — CrewAI Flow example
from crewai.flow.flow import Flow, start, listen, router

class ContentFlow(Flow):

    @start()
    def classify_request(self):
        return "technical" if "code" in self.state.get("topic", "") else "general"

    @router(classify_request)
    def route_by_type(self, result: str) -> str:
        return "technical_crew" if result == "technical" else "general_crew"

    @listen("technical_crew")
    def run_technical_crew(self):
        # run technical writing crew
        return technical_crew.kickoff(inputs=self.state)

    @listen("general_crew")
    def run_general_crew(self):
        return general_crew.kickoff(inputs=self.state)

flow = ContentFlow()
result = flow.kickoff(inputs={"topic": "Python async patterns"})

OpenAI Agents SDK

The OpenAI Agents SDK (successor to the experimental Swarm project) provides a minimal, production-ready agent framework centered around Agents, Runners, Handoffs, and Guardrails.

python — triage agent with handoffs
from agents import Agent, Runner, handoff, input_guardrail, GuardrailFunctionOutput
from pydantic import BaseModel

# ── Specialist agents ────────────────────────────────────────────────────────

billing_agent = Agent(
    name="Billing Agent",
    instructions=(
        "You handle billing questions: invoices, charges, refunds, and payment methods. "
        "Be concise and factual. If you cannot resolve the issue, say so."
    ),
)

technical_agent = Agent(
    name="Technical Support Agent",
    instructions=(
        "You handle technical issues: bugs, configuration, API errors, and performance. "
        "Ask for logs or error messages before diagnosing."
    ),
)

# ── Input guardrail — blocks off-topic requests ──────────────────────────────

class TopicCheck(BaseModel):
    is_support_related: bool
    reasoning: str

@input_guardrail
async def support_topic_guardrail(ctx, agent, input_text) -> GuardrailFunctionOutput:
    result = await Runner.run(
        Agent(
            name="Topic Classifier",
            instructions="Determine if this message is customer support related.",
            output_type=TopicCheck,
        ),
        input=input_text,
    )
    check = result.final_output
    return GuardrailFunctionOutput(
        output_info=check,
        tripwire_triggered=not check.is_support_related,
    )

# ── Triage agent — routes to specialists ─────────────────────────────────────

triage_agent = Agent(
    name="Triage Agent",
    instructions=(
        "Classify the customer request and route it to the appropriate specialist. "
        "Use billing_handoff for billing questions, technical_handoff for technical issues."
    ),
    handoffs=[
        handoff(billing_agent, tool_name_override="billing_handoff"),
        handoff(technical_agent, tool_name_override="technical_handoff"),
    ],
    input_guardrails=[support_topic_guardrail],
)

# ── Run ───────────────────────────────────────────────────────────────────────

import asyncio

async def main():
    result = await Runner.run(
        triage_agent,
        input="I was charged twice for my subscription last month. Please help.",
    )
    print(result.final_output)

asyncio.run(main())

Framework Comparison

CriterionLangGraphCrewAIOpenAI SDK
Control granularityMaximum (graph-level)Medium (role/task)Medium (agent/handoff)
Time to first working agentHours–daysMinutes–hoursMinutes
Checkpointing / fault toleranceBuilt-inLimitedVia sessions
Human-in-the-loopFirst-classPluginLimited
MCP supportVia toolsVia toolsNative
Model agnosticismFull (LangChain)FullOpenAI-first, LiteLLM for others
Production reliability (benchmarks)95%91%97%
Best use caseComplex stateful workflowsRole-based parallel crewsSimple chains, OpenAI users

Which to choose?

CrewAI if you need a working prototype quickly and your task maps naturally to distinct roles. OpenAI Agents SDK if you are already in the OpenAI ecosystem and need the triage/handoff pattern. LangGraph if you need fine-grained control, checkpointing, or complex conditional flows in production.

Chapter 13 Quiz

1. In CrewAI, what does setting context=[research_task] on a writing task do?

2. In the OpenAI Agents SDK, what triggers a "handoff"?

3. Which framework is best suited for a complex stateful workflow with checkpointing and human-in-the-loop approval steps?