Module 4: State Machines for Agents with LangGraph

1. Introduction: Agents as graphs

Overview

You finished Phase 1. In three modules you built the complete foundation of an agent: you understood what it is (M1), you gave it tools (M2), and you learned to orchestrate them with professional patterns (M3). But there's a problem all three modules share: your agent is still fundamentally linear. It receives input, reasons, acts once or several times, responds. It's a flow that goes from A to B, maybe with internal loops managed by create_react_agent, but with no real control over how execution flows. In the real world, that's not enough. An agent that researches needs to retry if a source fails. An agent that analyzes data needs to take different paths depending on the type of result. An agent that generates reports needs to know when to stop iterating and deliver. Cycles, branching, stop conditions — that's what turns a linear agent into a controlled agent. And that's exactly what this module teaches.

Welcome to Phase 2. This module marks a fundamental shift in the guide. You no longer build independent mini-projects — from here on, you build a single evolving project that grows module by module until it becomes a production-ready multi-agent system. And the central tool for that control is LangGraph's StateGraph: modeling your agent as a state graph where nodes are steps (planning, research, analysis, synthesis) and edges are transitions controlled by explicit conditions. This is not "using StateGraph as a general-purpose tool" — the LangChain & LangGraph guide (#9) already covered that. It's using StateGraph specifically for agents: how to model the perceive-reason-act loop as a cyclic graph, how to design typed state for agent context, and how to use conditional routing as the agent's decision points.

The transition that defines this module is precise: you go from "an agent that acts" to "an agent whose behavior is controlled by a state machine." Every design decision you make here — what fields the state has, how the nodes connect, where you put the conditions — directly affects the next 6 modules. A clean design allows modular extension. A coupled design forces rewrites. This is not a coding module — it's an architecture module.


Where are we in the guide?

Context

This guide has 10 modules organized into 3 phases:

Phase 1: Agent Foundations (Modules 1-3)          ✓ COMPLETED
├── Module 01: Anatomy of an AI Agent             ✓ COMPLETED
├── Module 02: Tool Use Fundamentals              ✓ COMPLETED
└── Module 03: Function Calling Patterns          ✓ COMPLETED

Phase 2: Agent Architecture (Modules 4-7)         ← YOU ARE HERE
├── Module 04: State Machines for Agents          ← THIS MODULE
├── Module 05: Multi-Step Reasoning and Planning
├── Module 06: Memory Systems for Agents
└── Module 07: MCP and Advanced Tool Integration

Phase 3: Multi-Agent & Production (Modules 8-10)
├── Module 08: Multi-Agent Orchestration
├── Module 09: Testing and Evaluation of Agents
└── Module 10: Agents in Production and Alternatives

Phase 2 starts here. The three modules you completed gave you the individual blocks — what an agent is, how to create tools, how to orchestrate them with patterns. Now you need the architecture that ties them together. Phase 2 (modules 4-7) gives you exactly that: flow control (M4), deep reasoning (M5), persistent memory (M6), and standardized tool integration (M7).

Where are you coming from?

Phase 1 left you with three layers of capability:

  • Module 1 — What an agent is: Perceive-reason-act cognitive architecture, agent taxonomy (reactive, deliberative, hybrid), decision framework (agent vs chain vs workflow), manual implementation of the ReAct loop
  • Module 2 — How you give it tools: @tool with Pydantic schemas, bind_tools with tool_choice, manual tool execution loop, real external APIs, robust error handling, InjectedToolArg
  • Module 3 — How you orchestrate those tools: Parallel function calling, forced tool calls and routing, structured extraction, streaming, tool composition, retry patterns and circuit breakers

Those three layers are solid foundations. But something critical is missing: control over the execution flow. Your agent can reason, can use tools, can orchestrate them with sophisticated patterns — but who decides the order? Who decides when to retry? Who decides when to take one path over another? Right now, the model decides everything. And that's a problem when you need guarantees.

Where are you headed?

The Phase 2 progression is deliberate — each module adds a layer of sophistication to the agent:

  1. Module 4 — How you control the flow → State machines: cycles, branching, stop conditions ← HERE
  2. Module 5 — How it reasons deeply → Planning, reflection, self-correction, task decomposition
  3. Module 6 — How it remembers → Short-term, long-term, checkpointing, durable execution
  4. Module 7 — How it connects to the world → MCP servers, clients, dynamic tools, ecosystem

The transition from M3 to M4 is direct: "You have powerful tools and you know how to orchestrate them → now control how the agent decides when to use them, in what order, and under what conditions." M3 taught you what to do with each tool call (parallel, retry, streaming). M4 teaches you when and why each tool call happens — the decision flow that connects them.

After M4, Module 5 takes your state machine and makes it smarter: "Your agent follows a controlled flow → now make it plan before acting and reflect on its own work." M4 controls how execution flows; M5 controls what the agent decides to do inside that flow.


Phase 1 → Phase 2: from linear agents to controlled agents

The limit of what you built in Phase 1

The agent you have at the end of M3 is capable. It can reason, use multiple tools in parallel, handle errors with retries and circuit breakers, extract structured data, and compose tool pipelines. But it runs everything inside an essentially linear flow:

User input → Model reasoning → Tool call(s) → Tool result(s) → Model response

Yes, create_react_agent adds a loop: if the model decides to call another tool, it acts again. But that loop is a black box controlled entirely by the model. You don't decide:

  • How many times it can iterate before you stop execution
  • Which path to take if a tool's result indicates something specific
  • When to retry an entire step vs move on to the next one
  • Which nodes run in what order, with what dependencies

In a demo, that works. In production, you need control. You need to be able to say: "If the result's confidence is below 0.7, research again. If you've already iterated 5 times, stop and deliver what you have. If the query type is simple, skip the analysis step."

The three pillars of a controlled agent

What turns a linear agent into a controlled agent are three capabilities:

1. Cycles (controlled loops)

A linear agent runs once and responds. A controlled agent can return to earlier steps under specific conditions:

reason → act → observe → [result good enough?]
                              ├── YES → synthesize → END
                              └── NO  → reason (another iteration)

The cycle isn't infinite — it has stop conditions: maximum iterations, quality threshold, remaining token budget. Without those controls, an agent with tool access can iterate indefinitely, burning tokens and money.

2. Branching (conditional paths)

A linear agent follows the same path for everything. A controlled agent takes different paths depending on context:

analyze_result →
    ├── type == "factual"    → verify_with_search
    ├── type == "analytical" → deep_analysis
    └── type == "creative"   → synthesize_directly

This isn't the model choosing freely — it's deterministic logic based on the agent's state. The model produces the result; your code decides what to do with it.

3. Stop conditions (knowing when to stop)

An agent without stop conditions is a bug waiting to trigger. Stop conditions include:

  • iteration_count >= max_iterations — no more than N rounds
  • task_complete == True — the goal was met
  • budget_remaining <= 0 — there are no tokens/money left to spend
  • quality_score >= threshold — the result is good enough
  • Absolute timeout — no matter what happens, stop after T seconds

These conditions are your code, not the model's decisions. You define what "enough" means, not the LLM.

Why StateGraph is the answer

LangGraph's StateGraph models exactly this: nodes as agent steps, edges as transitions, and conditional edges as decision points. But you're not going to learn StateGraph from scratch — you already did that in guide #9. What you learn here is how to apply StateGraph specifically to the agent domain:

What guide #9 taughtWhat this module teaches
What a node, an edge, a StateGraph isHow to model perceive-reason-act as nodes of a graph
How to define state with TypedDictHow to design agent state: messages, plan, iteration_count, tool_results, quality_score, budget
How to compile and run a graphHow to build cyclic agent loops with explicit stop conditions
How to use conditional edgesHow to use conditional edges as the agent's decision points: route by result type, confidence, task status
Basic Functional APIWhen Functional API (@entrypoint, @task) is more natural than StateGraph for certain agent patterns
Subgraphs as a conceptSubgraphs as reusable agent modules (research module, analysis module)

The difference is context, not API. The APIs are the same. What changes is what you use them for and how you design with them in the specific domain of intelligent agents.


The evolving project: AI Research Agent

One project, 7 modules

From this point on, you stop doing independent mini-projects. Starting with Module 4, you build a single project that evolves in every module until it becomes a production-ready multi-agent system in Module 10.

That project is the AI Research Agent: a system that receives a research question and produces a structured research report. It's not a chatbot that googles and summarizes — it's an agent with planning, research, analysis, and synthesis as stages controlled by a state machine, able to retry, make decisions based on context, and know when it has enough information to deliver.

The module-by-module evolution

Module 4 (THIS ONE):  Research Agent with a custom state machine
                      → 4 nodes: planning, research, analysis, synthesis
                      → Conditional routing between nodes
                      → Iteration limits and stop conditions
                      → Extensible typed state
     ↓
Module 5:             + Deep planning and reflection
                      → The planning node gets smart
                      → The agent reflects on intermediate results
                      → Self-correction when quality is low
     ↓
Module 6:             + Persistent memory
                      → Results saved cross-session
                      → Checkpointing for durable execution
                      → The agent remembers previous research
     ↓
Module 7:             + MCP servers
                      → Tools reimplemented as MCP servers
                      → Dynamic tool loading
                      → The agent connects to standardized sources
     ↓
Module 8:             + Multi-agent
                      → Researcher, analyst, writer, supervisor
                      → Each sub-agent with its own specialty
                      → Coordination and handoffs between agents
     ↓
Module 9:             + Testing and evaluation suite
                      → Unit tests for each node
                      → Trajectory evaluation
                      → Golden datasets for regression testing
     ↓
Module 10:            + Production deployment
                      → FastAPI serving
                      → Scaling, monitoring, cost control
                      → The Research Agent in real production

What does the Research Agent do in M4?

The version you build in this module is the base version — functional but deliberately simple. It has four nodes:

  1. Planning: Receives the user's question, decides what it needs to research, generates a search plan
  2. Research: Runs web searches based on the plan, gathers information from multiple sources
  3. Analysis: Analyzes and filters the results — what's relevant, what's redundant, what contradicts
  4. Synthesis: Produces the final research report by combining the analyzed findings

The nodes are connected by controlled edges:

START → planning → research → analysis → [enough?]
                                              ├── YES → synthesis → END
                                              └── NO  → planning (re-plan)

The conditional edge after analysis is the agent's first intelligent decision: "Is the information gathered enough to answer the question?" If it isn't, it goes back to planning with the context of what it already found. If it is, it moves on to synthesis.

Why the base version matters

You might ask: "Why not build the complete Research Agent all at once?" Because the quality of the base determines the quality of everything that comes after. If the state design is coupled, adding memory in M6 requires a rewrite. If the nodes don't have clear interfaces, turning them into sub-agents in M8 is painful. If the stop conditions are ad-hoc, testing in M9 is a nightmare.

This module is architecture. The decisions you make here — what fields the state has, how the nodes talk to each other, where the decision points are — carry forward 6 modules. Design with extensibility in mind. Don't build for today — build for M10.


Prerequisites

From the complete Phase 1 (Modules 1-3)

You need these concepts to be solid:

  • Perceive-reason-act cognitive architecture (M1): You understand the agent's fundamental loop and can articulate its components — perception, reasoning, action, memory
  • Agent taxonomy (M1): You can classify agents and decide what type you need for each problem
  • Decision framework (M1): You know when an agent is the right solution vs a chain or a workflow
  • @tool with Pydantic schemas (M2): You can create tools with descriptions, constraints, nested models, error handling
  • Tool execution loop (M2): You understand the full cycle user → model → tool_call → execute → ToolMessage → model
  • Function calling patterns (M3): You've mastered parallel calls, routing, structured extraction, retry patterns

If any of these points doesn't feel solid, go back to the corresponding module. Phase 2 assumes Phase 1 is well-trodden ground.

From guide #9 (LangChain & LangGraph)

From the framework you need fluency in:

  • StateGraph: You know how to create a graph, add nodes with add_node, connect them with add_edge, compile with compile()
  • TypedDict for state: You know how to define the graph's state with TypedDict
  • Conditional edges: You know how to use add_conditional_edges to route based on state
  • Execution and debugging: You can invoke a compiled graph and follow the execution flow
  • LangGraph concepts: START, END, nodes, edges, state — the terminology is familiar to you

This is critical: this module does NOT re-teach StateGraph. It doesn't explain what a node is or how add_edge works. You already know that. Here you learn to apply that knowledge to the specific domain of agents — agent loops, agent state, agent routing. If you need to review guide #9, do it before continuing.

Tools for this module

  • Python 3.11+
  • langchain v1.2+ and langchain-openai
  • langgraph v1.0+
  • OpenAI API key (GPT-4.1 or GPT-4.1-mini)
  • tavily-python for web search (the Research Agent uses it)
  • python-dotenv for handling environment variables
pip install langchain langchain-openai langgraph tavily-python python-dotenv

If you completed the Phase 1 setup, you already have everything installed. There are no new dependencies.


Module 4 objectives

By the end of this module you'll be able to:

  • Model an agent as a StateGraph: Design functional nodes (planning, research, analysis, synthesis) connected by edges as state transitions — not as "pipeline steps" but as a state machine that controls the agent's behavior
  • Design typed state for agent context: Create a TypedDict with Annotated that includes: messages, current_plan, iteration_count, tool_results, quality_score, budget_remaining, metadata — an extensible state that supports the features of future modules (planning M5, memory M6, multi-agent M8)
  • Implement agent loops as cyclic graphs: Build the reason→act→observe→reason cycle with explicit stop conditions (max_iterations, task_complete, exhausted budget) — not infinite loops controlled by the model, but bounded loops controlled by your code
  • Use conditional edges as decision points: Route execution based on tool result type, model confidence, task status, or remaining budget — deterministic logic that complements the model's decisions
  • Implement with the Functional API: Use @entrypoint and @task to implement the same agent patterns and compare when each approach (StateGraph vs Functional API) is more natural for agents
  • Encapsulate capabilities as subgraphs: Create reusable subgraphs (research module, analysis module) with clear interfaces that allow modular composition — the foundation for multi-agent in M8
  • Build the base Research Agent: Implement the first version of the evolving project — a StateGraph with 4 nodes, conditional routing, iteration limits, and an extensible typed state that will grow all the way to M10

Module map

#CapsuleWhat you'll learn
02StateGraph Patterns for AgentsHow to model an agent as a StateGraph: nodes as agent steps (not as generic functions), edges as state transitions. AgentState as a design concept. The difference between a generic graph and an agent graph
03Typed State DesignDesigning the agent's TypedDict: messages, current_plan, iteration_count, tool_results, quality_score, budget_remaining, metadata. Reducers with Annotated. Extensible state for future modules
04Agent Loops as Cyclic GraphsThe central concept: modeling perceive-reason-act as a cycle in the graph. Stop conditions: max_iterations, task_complete, exhausted budget. Debugging cycles with visualization
05Conditional Routing for AgentsConditional edges as decision points: routing by result type, confidence, task status. The difference between deterministic routing (your code) and model routing (tool choice)
06Functional API for Agents@entrypoint and @task for agent patterns: natural while loops for agent loops, if/else for routing, try/except for error handling. When the Functional API beats StateGraph for agents
07Subgraphs as Agent ModulesEncapsulating agent capabilities as reusable subgraphs. Clear interfaces between subgraphs. The foundation for multi-agent (M8): each subgraph can become a sub-agent
08Project: Research Agent with a State MachineFull implementation of the base Research Agent: 4 nodes, conditional routing, iteration limits, typed state, visualization with draw_mermaid_png. The evolving project begins

Learning flow

The module follows a progression that goes from design concepts to a full implementation of the Research Agent.

You start with StateGraph patterns for agents (capsule 02): it's not a re-teaching of StateGraph — it's how to think of your agent as a graph. What it means for a node to be "planning" vs "research", why the transitions between nodes are design decisions, and how the graph's structure reflects the agent's behavior. Here you set up the mental framework for everything that follows.

Then typed state design (capsule 03): the agent's state is not just messages: list[BaseMessage]. A real agent needs fields for its plan, iteration counters, tool results, quality scores, remaining budget, and metadata. Designing this TypedDict is one of the most important decisions of the module — a well-designed state allows clean extension in M5-M10; a badly designed one forces rewrites.

Capsule 04 (agent loops as cyclic graphs) is the central concept of the module. An agent is not a linear chain A→B→C. It's a loop: reason→act→observe→reason. Modeling that loop as a cycle in the graph, with stop conditions that prevent infinite iteration, is what turns a static flow into a dynamic agent. Here you also meet visualization with draw_mermaid_png — not as a nice-to-have, but as a debugging and communication tool.

With conditional routing for agents (capsule 05), you learn to create the agent's decision points. It's not the model choosing freely — it's your code evaluating the state and making deterministic decisions: "If the result is factual, verify it. If it's analytical, dig deeper. If you've already iterated 5 times, stop." Conditional edges are where your logic and the model's intelligence complement each other.

Capsule 06 (Functional API for agents) presents an alternative: @entrypoint and @task let you write agent patterns that feel more natural in Python — while loops for cycles, if/else for routing, try/except for errors. It's not "better or worse" than StateGraph — it's a different tool with different trade-offs, and knowing when to use each one is a skill this module develops.

Capsule 07 (subgraphs as agent modules) gives you modularity. Instead of a monolithic graph, you encapsulate capabilities in reusable subgraphs with clear interfaces. A "research" subgraph you can reuse. An "analysis" subgraph you can extend. This is the direct foundation for multi-agent in M8: every subgraph is a candidate to become a specialized sub-agent.

Finally, the project (capsule 08) integrates everything into the base Research Agent. It's not a new exercise — it's the culmination of the 6 previous capsules applied to a real system that you'll extend over 6 more modules.


Connection with the evolving project

M4 builds the base. M5-M10 extend it.

The design you implement in this module is the foundation for everything that comes. Each later module adds a layer to the Research Agent without rewriting the base:

ModuleWhat it adds to the Research AgentWhat it uses from M4
M5: Planning & ReflectionThe planning node gets smart: it decomposes tasks, creates multi-step plans, reflects on resultsThe graph's planning node, the state's current_plan field
M6: MemoryResults saved cross-session, checkpointing, the agent remembers previous researchThe extensible state (it adds memory fields), the edges that connect nodes
M7: MCPTools reimplemented as MCP servers, dynamic tool loading, standardized sourcesThe research and analysis nodes that use tools, the routing that selects tools
M8: Multi-AgentEach node becomes a specialized sub-agent: researcher, analyst, writer, supervisorThe M4 subgraphs, the interfaces between nodes, the shared state
M9: TestingUnit tests for each node, trajectory evaluation, golden datasetsThe nodes as testable functions, the state as a fixture, the graph as the test subject
M10: ProductionFastAPI serving, scaling, monitoring, cost controlThe compiled graph as a service, the state's budget_remaining, the stop conditions

The question you should ask yourself at every decision

While you design your state, your nodes, your edges, keep asking yourself one question:

"Does this let me add planning (M5), memory (M6), MCP (M7), multi-agent (M8) without a rewrite?"

If the answer is no, redesign. A state field that's a list[str] instead of an extensible model will cost you time in M6. A monolithic node that does research + analysis in a single function will cost you pain in M8. Hardcoded routing with no flexibility will cost you refactoring in M7.

Designing with extensibility in mind is not over-engineering. It's the difference between a solid foundation and one that cracks under the weight of future features.


What this module does NOT cover

  • LangGraph fundamentals — There's no re-teaching of what a node is, how add_edge works, or how to compile a graph. You covered that in guide #9. If you need a refresher, go back there before continuing here
  • Planning, reflection, or self-correction — How the agent decides what to research, how it decomposes complex tasks, how it evaluates its own work. That's all of Module 5. Here you control how execution flows; there you control what the agent decides to do
  • Memory or persistence — Short-term memory, long-term memory, checkpointing, MemorySaver, PostgresSaver. That's Module 6. Here the state lives inside a single run; there it persists across sessions
  • MCP (Model Context Protocol) — How to expose tools as MCP servers, dynamic tool discovery, the MCP ecosystem. That's Module 7. Here the tools connect directly; there they connect through a standardized protocol
  • Multi-agent orchestration — Supervisor patterns, handoffs, specialized sub-agents, shared vs isolated state. That's Module 8. Here you build a single agent with multiple nodes; there, multiple agents that coordinate
  • Formal testing — Unit tests, integration tests, trajectory evaluation, golden datasets. That's Module 9. Here you validate that the graph works; there you test it with formal frameworks
  • Creating individual tools — You already covered that in M2. Here you use tools as ready-made blocks inside the graph's nodes

The boundary is clear: M4 = how the agent's execution flows. M5 = what it decides to do. M6+ = with what additional capabilities it does it.


Design decisions that affect 6 modules

This module has a unique trait in the guide: the decisions you make here are not local. They don't just affect this module — they affect the 6 that follow. These are the key decisions and why they matter:

1. State design

The decision: What fields does your AgentState have? What types does it use? What reducers?

Why it matters down the line:

  • M5 needs fields for current_plan, reflection_notes, subtasks
  • M6 needs serializable fields for persistence and memory_context fields
  • M8 needs a state that multiple agents can read and write without conflicts

The risk: If you design a minimal state (messages and nothing else), every future module requires refactoring the state. If you design an extensible state from M4, future modules only add fields.

2. Interfaces between nodes

The decision: How do the nodes communicate? Through shared state? At what granularity?

Why it matters down the line:

  • M7 needs the nodes that use tools to be able to switch from a direct tool to an MCP server without modifying other nodes
  • M8 needs the nodes to be able to become independent sub-agents with their own inputs/outputs
  • M9 needs the nodes to be testable in isolation

The risk: If the nodes reach into arbitrary state fields, you can't test them in isolation or turn them into sub-agents. If they have clear interfaces (what they read, what they write), the transition to M8 and M9 is natural.

3. Stop conditions

The decision: How and where do you define the stop conditions? Are they hardcoded or configurable?

Why it matters down the line:

  • M6 needs checkpoints to be able to resume interrupted runs — the stop conditions must be serializable state, not ad-hoc logic
  • M9 needs to be able to test stop conditions with controlled values
  • M10 needs to be able to adjust limits at runtime (per user tier, per system load)

The risk: If the stop conditions are a hardcoded if count > 5: break, you can't tune them in production without redeploying. If they're part of the state or the configuration, they're flexible.

4. Node granularity

The decision: How many nodes? How big? One node per concept, or monolithic nodes?

Why it matters down the line:

  • M5 needs the planning node to be an independent extension point
  • M7 needs the research node to be extensible with new sources
  • M8 needs each node to be able to be a sub-agent with its own logic

The risk: A node that does "planning + research" in a single function can't be split in M8 without a rewrite. Nodes with clear responsibilities become sub-agents naturally.

The right mindset

You're not building an agent for M4. You're building the first version of an agent that will evolve all the way to M10. Every design decision has long-term consequences. You don't need to anticipate every future feature — but you do need to leave room for them.

The practical rule: if a design decision makes your code cleaner and more extensible, take it. If extensibility requires extra complexity with no immediate benefit, document the constraint and decide later.


The central concept: an agent is a cyclic graph

Before getting into the technical capsules, there's a concept you need to internalize because it permeates the whole module.

A pipeline is an acyclic graph — a DAG (Directed Acyclic Graph). It goes from A to B to C without turning back:

Input → Process A → Process B → Process C → Output

An agent is a cyclic graph. It has the ability to return to earlier steps, to iterate, to reconsider:

                    ┌────────────────────────────────┐
                    │                                │
                    ▼                                │
Input → Planning → Research → Analysis → [Ready?] ──┘ NO
                                              │
                                             YES
                                              │
                                              ▼
                                          Synthesis → Output

That arrow going back from "Ready?" to "Planning" is what turns a pipeline into an agent. It's a controlled loop — not infinite, but bounded by stop conditions.

Why does this matter? Because the way you model your agent determines what it can do:

  • Without cycles: The agent researches once, analyzes once, synthesizes once. If the first search wasn't enough, it can't try again.
  • With controlled cycles: The agent researches, analyzes, decides it needs more information, researches again with new terms, analyzes again, and when the information is enough, synthesizes. Like a human researcher.

StateGraph gives you the ability to model exactly this: nodes as steps, edges as transitions, conditional edges as decisions, and cycles as the ability to go back. That's an agent as a state graph.

Visualization as a design tool

LangGraph includes draw_mermaid_png(), which generates an image of the graph. This isn't decorative — it's a design and debugging tool:

  • Design: Before implementing, draw your graph. Do the nodes make sense? Are the transitions logical? Do the conditions cover every case?
  • Debugging: When the agent doesn't behave the way you expect, visualize the graph and trace the execution. Which node ran? Which edge did it take? Why did the condition evaluate that way?
  • Communication: When you explain your agent to a colleague, the visual graph says more than 200 lines of code.

Throughout the module, every capsule includes a visualization of the graph. Get used to always visualizing. It's the first debugging tool when an agent doesn't do what you expect.


Evidence of success

By the end of this module, you'll know you succeeded if:

  • ✅ You can design an agent as a StateGraph with functional nodes and explain why each node exists and how it connects to the others
  • ✅ Your AgentState has at least 6 typed fields (messages, plan, iteration_count, tool_results, quality_score, metadata) with appropriate reducers — and you can explain why each field is necessary for the Research Agent
  • ✅ Your graph has at least one controlled cycle with explicit stop conditions — and you can explain what happens if you remove them (infinite iteration, exhausted budget, broken UX)
  • ✅ You can implement conditional routing that takes different paths based on the state — not on the model's decision, but on deterministic logic of your own
  • ✅ You can implement the same agent pattern with StateGraph and with the Functional API, and argue when each approach is more appropriate
  • ✅ You've encapsulated at least one agent capability as a reusable subgraph with a clear interface
  • ✅ Your Research Agent works end-to-end: it receives a question → planning → research → analysis → conditional check → synthesis or re-planning → output
  • ✅ You can visualize your graph with draw_mermaid_png and explain the flow to someone who has never seen your code

Quick self-assessment test

Ask yourself these questions after completing the module:

  1. "If I need to add a memory_context field to the state for M6, can I do it without modifying the existing nodes?" → If yes, your state design is extensible
  2. "If the research node needs to switch from Tavily to an MCP server in M7, do I have to modify other nodes?" → If no, your interfaces between nodes are clear
  3. "If I want the Research Agent to do a maximum of 3 iterations in testing but 10 in production, can I change that without modifying code?" → If yes, your stop conditions are configurable
  4. "Can I explain my graph to a colleague using only the draw_mermaid_png visualization, without showing code?" → If yes, your design is communicable

If you answered yes to all four → you're ready for Module 5 (Multi-Step Reasoning and Planning). If you answered no to any of them → redesign before moving on. M4's decisions carry all the way to M10.


How to use this module

If you're coming straight from Phase 1

You're in the ideal progression. You have the foundations of tool use and function calling. Now you learn to control the execution flow. Read the capsules in order — the progression goes from design concepts (02-03) to execution patterns (04-06) to modular composition (07) to full implementation (08).

If you already used StateGraph in guide #9

The APIs are familiar to you. Focus on what's new:

  • Capsule 03 (Typed state design) — agent state design is fundamentally different from the state of a generic pipeline
  • Capsule 04 (Cyclic agent loops) — how to model the perceive-reason-act loop as a cycle with stop conditions
  • Capsule 08 (Project) — validates that you can design and build the complete Research Agent

If you have experience with agents in production

Go to capsule 03 (state design) to validate your approach, then jump to the project (08). If you can build the Research Agent with extensible state, conditional routing, iteration limits, and modular subgraphs in an hour, you've mastered the module. If any of those pieces gives you trouble, the corresponding capsule gives you the framework.

Estimated time

  • Reading and practice: ~60-75 minutes (capsules 02-07)
  • Project: ~45-60 minutes (capsule 08)
  • Total: ~1.7-2.3 hours

Summary

  • Phase 2 starts here: You go from independent mini-projects to an evolving project (AI Research Agent) that grows through M10
  • From linear to controlled: The agents of Phase 1 were linear. The agents of Phase 2 have cycles, branching, and stop conditions — real control over the execution flow
  • StateGraph for agents, not general: LangGraph is not re-taught. What's taught is how to apply StateGraph to the specific domain of agents: agent loops, agent state, agent routing
  • State design as an architectural decision: The agent's TypedDict is not a technical detail — it's a design decision that affects 6 modules. Design for extensibility
  • The base Research Agent: 4 nodes (planning, research, analysis, synthesis), conditional routing, iteration limits, extensible typed state. Simple but designed to grow
  • Visualization as a tool: draw_mermaid_png isn't decorative — it's debugging, design, and communication. Use it always
  • Extensibility-first: Every design decision must answer: "Does this let me add planning (M5), memory (M6), MCP (M7), multi-agent (M8) without a rewrite?"

Resources

  1. LangGraph Documentation — Official framework documentation. Reference for StateGraph, conditional edges, Functional API
  2. LangGraph Concepts: Low Level — Low-level concepts: nodes, edges, state, reducers, conditional routing
  3. LangGraph How-To: Subgraphs — Practical guide to composition with subgraphs
  4. LangGraph Visualization — How to use draw_mermaid_png to visualize and debug graphs
  5. Building Effective Agents — Anthropic — Anthropic's perspective on designing agents with state machines and flow control
  6. ReAct: Synergizing Reasoning and Acting (Paper) — The ReAct loop as a cyclic graph: the theoretical basis for this module's approach