Eight ways agents hand work to each other, each on an everyday task. Watch how it works first, then where it breaks. The right-hand panel shows what each agent gets to see: what an agent sees decides what it can get right.
The patterns from section 1, built in crews/. CrewAI’s model: agents with roles, tasks with expected outputs, a crew that runs them, and Flows for events. You describe the work; CrewAI runs the loop.
CrewAI is an open-source Python framework, not built on LangChain. You say who works (agents) and what needs doing (tasks); CrewAI writes the prompts, runs each agent’s loop and passes results along. This demo uses crewai==1.15.28. Official docs: docs.crewai.com ↗
llm, optional tools. That text becomes its system prompt.Agents docs ↗expected_output, the agent that does it. Can be typed (output_pydantic), checked (guardrail) or async.Tasks docs ↗sequential: each output feeds the next task. hierarchical: a manager agent delegates.Crews docs ↗Processes docs ↗@start, @listen, @router. Calls a crew only where judgment is needed.Flows docs ↗Also built in: tools, memory, knowledge, delegation, checkpoints, and a CLI that scaffolds agents.yaml and tasks.yaml.
Most patterns are one argument: 2 are a Crew setting, 4 are a Task argument, and 2 need a Flow. Click a card to see its code below.
crew.kickoff(){query} in agent and task text is replaced by kickoff(inputs=…).context.max_iter.output_pydantic; then the guardrail. If it fails, the same agent runs again with the reason.TaskOutput, the context for later tasks. The last one is the CrewOutput.The key difference from LangGraph: the loop is inside the framework. You configure it; you don’t draw it. That’s why each step in these crews is a model call: the unit of work is an agent turn.
guardrail= plus guardrail_max_retries: retry with feedback in one argument.output_pydantic checks every answer before the next agent sees it.agents.yaml and tasks.yaml.CREWAI_TELEMETRY_OPT_OUT).| If you need… | Pick | Why |
|---|---|---|
| A working prototype this week, the work maps to roles (research, review, write) | CrewAI | Agents and tasks in English, typed outputs and retries for free |
| Exact control of every branch, loop and join | LangGraph | You draw the graph; nothing runs that isn’t an edge |
| Cheap, fast steps mixed with a few model calls | LangGraph | Nodes can be plain code; only the judgment calls hit the model |
| Long-running runs, crash recovery, a human approving mid-run | LangGraph | Checkpoint every step, interrupt(), resume and rewind |
| A critic that sends work back with feedback | Either | One argument in CrewAI; two edges in LangGraph |
| Event-driven: something in the world starts the run | Either | CrewAI Flow (@start/@router) or your code calling graph.invoke() |
| Non-engineers editing who does what | CrewAI | agents.yaml and tasks.yaml read like a job description |
You don’t have to choose one. A crew can be a single LangGraph node, and a CrewAI Flow can call any Python, including a compiled graph. A common shape: LangGraph (or a Flow) for the skeleton, a crew where a step genuinely needs a team.
The same patterns, for when you need more control than a crew gives you. Every excerpt is the real code in patterns/ and lab/. LangGraph’s model: one state object, nodes that read it and return updates, and edges that decide what runs next. Control flow is yours, explicitly.
LangGraph is an open-source orchestration library from the LangChain team, for Python and JavaScript. You draw your system as a graph; it doesn’t write prompts or define agents for you, and it doesn’t need LangChain. This demo uses langgraph 1.x. Official docs: docs.langchain.com ↗
TypedDict or pydantic model. A reducer like Annotated[list, operator.add] appends; a plain key is overwritten.Graph API docs ↗state → update: a model call, a tool, an API, or plain code. Only the keys it returns change.Graph API docs ↗add_edge (always next), add_conditional_edges (a function picks), Send (N copies in parallel). Cycles are allowed.Graph API docs ↗thread_id: resume after a crash, pause with interrupt(), rewind.Persistence docs ↗Interrupts docs ↗Also built in: subgraphs, streaming, Command (update and jump in one return), a long-term store, and prebuilt agent loops. LangSmith tracing and a hosted platform are optional extras.
Most patterns are an edge you draw: 4 are edges, 1 is what a node passes on, 1 is the state, 1 is the checkpointer, and 1 is your own code calling invoke(). Click a card to see its code below.
graph.invoke()builder.compile(checkpointer=…) checks the graph and returns a runnable. invoke() takes the input and a thread_id.Send fans out.Send(node, payload) for each item. Back to step 2.END finishes. interrupt() pauses and saves; Command(resume=…) continues. recursion_limit stops runaway loops.The idea to keep: you own the loop. Nothing runs that isn’t an edge, and a node is just a function, so the model is called only where you put a call.
Send can shape the graph at run time.interrupt() pauses and saves; the answer can come hours later, from another process.Send vs Command, threads vs store: it’s easy to misread when a node runs.interrupt() the node starts again from its first line, so keep side effects idempotent.| You see… | Because… | Fix |
|---|---|---|
| A node never runs | No edge leads to it | Every node needs an incoming edge. Draw it: graph.get_graph().draw_mermaid() |
InvalidUpdateError at a fan-in | Two parallel nodes wrote the same plain key | Give the key a reducer: Annotated[list, operator.add] |
GraphRecursionError | A cycle with no exit, or a limit set too low | Count turns in state and route to END; set recursion_limit in the config |
| An email sent twice after approval | Resume reruns the node that called interrupt() | Do side effects after the interrupt, in their own node, or make them idempotent |
| The run forgot everything | No checkpointer, or a new thread_id | compile(checkpointer=…) and reuse {"configurable": {"thread_id": …}} |
| A change to state didn’t stick | The node mutated state instead of returning an update | Return a dict with only the keys you changed |
In this project: patterns/ has the four graphs from the live demo; lab/ has the guardrails (owner, budget, approval) with crash, resume and rewind on SqliteSaver.
patterns/) or CrewAI (crews/): the same four patterns.