Recursive Delegation in Swarm, CrewAI, and LangGraph

How OpenAI Swarm, CrewAI, and LangGraph implement recursive delegation. Each framework handles context passing, result aggregation, and agent spawning differently.

From Pattern to Implementation

The Recursive Delegation pattern describes the concept: agents spawn child agents with scoped contexts, creating a tree of delegated work. The concept is simple; the implementation choices are where teams get stuck.

OpenAI Swarm, CrewAI, and LangGraph all support recursive delegation, but they make fundamentally different decisions about context isolation, and that decision shapes everything downstream.

OpenAI Swarm

Swarm is OpenAI’s experimental framework for multi-agent orchestration. Agent handoffs are its core abstraction, which makes recursive delegation easy to set up and hard to scale.

The core model: agents are defined with instructions, functions, and handoff targets. When Agent A hands off to Agent B, the full conversation history comes along. This makes result aggregation trivial; everything is in the shared history. It also means context grows with every handoff unless you explicitly trim it.

Swarm does not enforce context isolation. Each agent sees the full conversation history unless you filter it yourself. This gives you control, but requires discipline to implement Isolate properly.

from swarm import Swarm, Agent

leaf_agent = Agent(
    name="LeafWorker",
    instructions="Process the assigned subtask with your focused context."
)

def spawn_child(context_subset):
    return leaf_agent

parent_agent = Agent(
    name="Parent",
    instructions="""You are a delegator. When given a large task:
1. Break it into subtasks
2. For each subtask, call spawn_child with the relevant context subset
3. Synthesize the results""",
    functions=[spawn_child]
)

CrewAI

CrewAI makes the opposite bet from Swarm: isolation by default. Agents have roles, goals, and backstories. Tasks define expected outputs. Crews orchestrate the whole thing into a process that can be sequential, hierarchical, or custom.

When a worker agent receives a task, it gets only the task description, relevant tools, and whatever context the manager explicitly passes. No shared history leaking between agents. This is the right default for most multi-agent systems, because context bleed between agents is one of the fastest ways to degrade quality.

The manager agent receives task outputs and synthesizes them. It never sees the full context each worker operated in, only the results.

from crewai import Agent, Task, Crew, Process

worker = Agent(
    role="Specialist",
    goal="Process your assigned subtask with focused attention",
    backstory="You are an expert in your specific domain."
)

manager = Agent(
    role="Manager",
    goal="Break down complex tasks and delegate to specialists",
    backstory="You coordinate work across a team of specialists.",
    allow_delegation=True
)

task = Task(
    description="Analyze this codebase for security issues",
    expected_output="A security audit report",
    agent=manager
)

crew = Crew(
    agents=[manager, worker],
    tasks=[task],
    process=Process.hierarchical,
    manager_agent=manager
)

result = crew.kickoff()

The abstraction is higher-level than Swarm. You trade flexibility for structured process management and built-in isolation. For most teams, that’s a good trade.

LangGraph

LangGraph sits between Swarm and CrewAI on the abstraction spectrum. You model your agent system as a graph: state flows between nodes, edges define transitions (including conditional routing), and subgraphs enable recursive patterns.

The key differentiator: you define an explicit state schema. Every node receives typed state and returns typed updates. This gives you precise control over what context each agent sees, at the cost of more boilerplate than either Swarm or CrewAI.

from langgraph.graph import StateGraph, END
from typing import TypedDict, List, Annotated
import operator

class AgentState(TypedDict):
    task: str
    context: str
    results: Annotated[List[str], operator.add]
    depth: int

def parent_node(state: AgentState):
    if state["depth"] >= 2:
        return {"results": [f"Completed: {state['task']}"]}
    # break_into_subtasks and extract_relevant_context are your decomposition logic
    subtasks = break_into_subtasks(state["task"])
    return {
        "task": subtasks[0],
        "context": extract_relevant_context(state["context"], subtasks[0]),
        "depth": state["depth"] + 1
    }

def child_node(state: AgentState):
    # process_subtask: your LLM call or tool invocation goes here
    result = llm.run(state["task"], context=state["context"])
    return {"results": [result]}

def aggregate_node(state: AgentState):
    final_result = synthesize(state["results"])
    return {"results": [final_result]}

workflow = StateGraph(AgentState)
workflow.add_node("parent", parent_node)
workflow.add_node("child", child_node)
workflow.add_node("aggregate", aggregate_node)
workflow.set_entry_point("parent")
workflow.add_conditional_edges(
    "parent",
    lambda s: "delegate" if s["depth"] < 2 else "complete",
    {"delegate": "child", "complete": "aggregate"}
)
workflow.add_edge("child", "aggregate")
workflow.add_edge("aggregate", END)
app = workflow.compile()

More code to write, but when your workflow has branching logic or needs to maintain custom state across steps, the explicitness pays for itself in debuggability.

Comparison

FrameworkAbstraction LevelContext ControlDelegation StyleBest For
SwarmLowManual via historyHandoff-basedSimple delegation, rapid prototyping
CrewAIHighAutomatic per-taskHierarchical processStructured workflows, role-based teams
LangGraphMediumExplicit stateGraph-basedComplex routing, custom state management

The Context Management Decision

This is the decision that matters most, and it’s the one these frameworks make differently.

Swarm shares everything by default. Context grows with every handoff, which is simple to reason about when you have 2-3 agents but becomes a liability beyond that. CrewAI takes the opposite approach: isolation by default, where each agent sees only what you explicitly provide. Safer, but you need to think carefully about what context the manager passes to workers, because under-sharing is as bad as over-sharing. LangGraph forces the question by requiring an explicit state schema; nothing flows between nodes unless you put it there. More work upfront, but the most predictable behavior at runtime.

Recommendations

Start with CrewAI unless you have a specific reason not to. Isolation by default is the right starting point for most multi-agent systems, and the role-based abstraction maps naturally to how people think about dividing work.

Swarm is useful for prototypes where you want to validate the delegation structure before committing to a framework, but don’t ship it without adding context filtering. Shared history is a footgun for anything beyond 3-4 agents because context bloats faster than you’d expect.

If CrewAI’s abstractions don’t fit your workflow, reach for LangGraph. Complex conditional routing, cycles, or custom state shapes that don’t map to a role/task model are where the explicit graph earns its boilerplate. The extra code is worth it when you need to debug exactly what context each agent received and why.