Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›LangChain›LangGraph Introduction

LangGraph

LangGraph Introduction

LangGraph is a library designed to build stateful, multi-actor applications by modeling agentic workflows as cyclic graphs. It matters because it moves beyond rigid, linear chains to allow for complex iterative reasoning and explicit state management. You should reach for it whenever your application requires looping, human-in-the-loop interventions, or long-running tasks that a standard sequential pipeline cannot handle.

The Philosophy of Cyclic Graphs

Standard chains are directed acyclic graphs (DAGs), meaning they have a clear start and end point without the ability to move backward. However, real-world agentic reasoning often requires loops, such as 'reason-act-observe' cycles where an agent tries an action, evaluates the result, and decides whether to continue or pivot. LangGraph treats the application as a graph where nodes represent functions and edges represent the flow of data between these nodes. By enabling cycles, LangGraph allows an agent to revisit a previous state based on incoming information. This is the fundamental shift from static pipelines to dynamic intelligence. You reason about your application not as a sequence of prompts, but as a state machine where each node transforms the state and returns it to a controller. This allows for complex error handling and correction mechanisms that simply do not exist in linear frameworks.

from langgraph.graph import StateGraph
from typing import TypedDict

# Define the state that persists across nodes
class AgentState(TypedDict):
    messages: list[str]

# Define nodes that modify the state
def node_a(state):
    return {"messages": ["Processed in A"]}

# Create the graph
workflow = StateGraph(AgentState)
workflow.add_node("a", node_a)
workflow.set_entry_point("a")
workflow.set_finish_point("a")
app = workflow.compile()

Understanding State Persistence

In LangGraph, the 'State' is the single source of truth passed between nodes. Unlike standard chains where variables might be lost or isolated between steps, the State object is maintained throughout the entire execution of the graph. Because LangGraph uses a typed dictionary (or a Pydantic model) to define this state, every node knows exactly what data structure it is receiving and what it is expected to output. When a node finishes execution, its returned values are merged back into the global state. This makes debugging significantly easier because you can inspect the exact state at any point in the cycle. If you ever need to add a new piece of data—like a temporary scratchpad for the agent's thoughts—you simply update the state definition. This structured approach prevents the common 'missing context' errors that plague complex applications, ensuring that all nodes operate on a consistent and predictable data layer.

from typing import Annotated, TypedDict
import operator

# State with an append-only message list
class State(TypedDict):
    history: Annotated[list[str], operator.add]

def step_node(state: State):
    # New info is added to existing history
    return {"history": ["New insight"]}

# The graph handles merging state automatically
graph = StateGraph(State)
graph.add_node("step", step_node)
graph.set_entry_point("step")
compiled = graph.compile()

Implementing Conditionals and Loops

The power of a graph lies in its edges, which determine where the execution flow moves next. Conditional edges allow you to branch your logic based on the current state. For example, after an agent attempts to call a tool, you might have a node that checks if the tool output was successful or if it contained an error. If there is an error, the conditional edge can route the state back to the 'planning' node to try a different approach. This creates a self-correcting system. Unlike hard-coded if/else chains, LangGraph edges are dynamic functions that evaluate the state in real-time. This allows for sophisticated behaviors like retries, self-critique, and iterative refinement. By modeling your logic as nodes and transitions, you decouple the 'what' (the node's task) from the 'when' (the edge's routing logic), leading to a codebase that is far easier to test and maintain.

def router(state):
    # Return the next node name based on state content
    if "error" in state["history"]: return "fix_node"
    return "end_node"

# Add conditional logic to the flow
workflow.add_conditional_edges("start", router, {"fix_node": "fix", "end_node": "end"})

Human-in-the-Loop Integration

In mission-critical systems, you often cannot leave the agent entirely to its own devices. LangGraph provides a unique mechanism called 'breakpoints' that pause the graph execution after a specific node. When the graph hits a breakpoint, it stops and saves the current state to a database. You can then inspect the state, manually adjust it, or even inject new data before telling the graph to resume from where it left off. This pattern is essential for long-running workflows that require human oversight or approval for high-stakes actions like API calls or file writes. By integrating this into the state machine, you treat human intervention as just another event in the agent's lifecycle. This allows you to build systems that are both automated and controllable, combining the efficiency of autonomous agents with the safety of human verification.

from langgraph.checkpoint.memory import MemorySaver

# Initialize a memory checkpoint to save graph state
memory = MemorySaver()

# Compile with checkpointer to allow pausing
app = workflow.compile(checkpointer=memory)

# Execution pauses at designated nodes
# Resume later by passing the thread_id

Complexity Management via Subgraphs

As your workflows grow, a single large graph becomes difficult to manage. LangGraph solves this through subgraphs, which allow you to encapsulate a complex sequence of nodes into a single node within a larger graph. A subgraph functions like a function call in programming; it takes an input state, performs a complex sub-task using its own internal graph, and then updates the parent state with the result. This hierarchy is crucial for building modular agents where different teams can own different parts of the system. For instance, you could have a 'Research Subgraph' and a 'Coding Subgraph'. The main orchestration graph simply calls them as needed. This approach significantly reduces cognitive load by abstracting away internal implementation details, allowing developers to focus on the high-level orchestration logic while maintaining complete control over specific sub-tasks.

# A subgraph is just a compiled graph used as a node
sub_graph = StateGraph(State)
# ... define nodes and edges for the sub_graph ...

# Add the subgraph to the main graph
main_graph = StateGraph(State)
main_graph.add_node("researcher", sub_graph.compile())

Key points

  • LangGraph models workflows as graphs to enable cyclic execution, which is vital for iterative agent reasoning.
  • State is stored in a structured object that persists across the entire lifespan of the graph.
  • Nodes represent discrete functions, and edges define the conditional transitions between these functions.
  • Conditional edges provide the flexibility to route state back to previous nodes for error correction or refinement.
  • Checkpoints allow for human-in-the-loop interactions by pausing the graph execution at specific points.
  • State merging handles incoming data automatically, ensuring that nodes always operate on the latest version of the context.
  • Subgraphs enable modularity by allowing you to nest small, specialized graphs within a larger orchestration system.
  • LangGraph effectively decouples the task execution logic from the flow control logic, improving overall system maintainability.

Common mistakes

  • Mistake: Treating LangGraph as a replacement for standard LangChain Chains. Why it's wrong: LangGraph is an orchestration framework for cyclic graphs, not a direct substitute for simple sequential chains. Fix: Use LangGraph when your logic requires loops, recursion, or complex state management that simple chains cannot handle.
  • Mistake: Misunderstanding State as a global variable. Why it's wrong: State in LangGraph is explicitly defined via typed dictionaries and updated via reducers. Fix: Use State to define the schema of information passed between nodes and use specific reducer functions to manage updates.
  • Mistake: Blocking the main event loop with synchronous calls inside nodes. Why it's wrong: LangGraph is designed to be asynchronous to handle multi-agent or long-running tasks efficiently. Fix: Always use async-await patterns for I/O bound operations inside your node functions.
  • Mistake: Forgetting to add edges to the graph. Why it's wrong: Without explicit edges, the graph will not know the flow of execution, resulting in an error or a dead-end. Fix: Explicitly use add_edge or add_conditional_edges to define the transitions between nodes.
  • Mistake: Overcomplicating the State object with non-essential metadata. Why it's wrong: A bloated state object increases serialization overhead and complexity. Fix: Keep the State object focused only on the data required for decisions and output generation.

Interview questions

What is LangGraph and why would you use it over a simple LangChain chain?

LangGraph is a library built on top of LangChain specifically designed to build stateful, multi-actor applications with LLMs. While a basic LangChain chain is excellent for simple, linear sequences of tasks, it lacks the ability to handle loops, complex state management, or conditional branching over time. You use LangGraph when your application requires a cyclic graph structure, allowing the model to rethink, iterate on outputs, or wait for human input, which is essential for building robust agents.

Can you explain the role of 'State' in a LangGraph application?

The 'State' in LangGraph is a shared data structure that represents the entire context of your graph execution at any given point in time. It acts as the single source of truth that is passed between nodes. When you define a State schema using a TypedDict, LangGraph automatically handles updates to this state. This is crucial because it ensures that every node in your graph has access to the necessary inputs and the history of actions taken, enabling coordination between different components.

How do nodes and edges function within a LangGraph workflow?

In LangGraph, nodes are essentially Python functions that perform specific units of work, such as calling an LLM or executing a tool. Edges, on the other hand, define the flow between these nodes. Conditional edges allow you to create dynamic paths based on the output of a node—for example, deciding whether to call a tool or finish the task. This structure turns your workflow into a formal state machine, which is significantly more predictable and easier to debug than complex, nested conditional logic inside a single chain.

How does LangGraph facilitate human-in-the-loop interactions?

LangGraph simplifies human-in-the-loop interactions by using 'checkpoints' and 'interrupts.' By configuring a memory saver, you can pause the graph execution at specific nodes, wait for human review or approval, and then resume. The syntax is straightforward: when you compile your graph, you can specify that it should interrupt before certain nodes. The state is saved, allowing the human to inspect and modify it, ensuring the agent stays aligned with user intent before proceeding with potentially impactful actions.

Compare using LangChain's 'AgentExecutor' versus building an agent with LangGraph.

The 'AgentExecutor' is a legacy, high-level abstraction in LangChain that handles loops automatically, which is easy for simple use cases but notoriously difficult to customize. In contrast, LangGraph gives you full control over the agent's internal loop. You define the nodes and edges yourself, which means you can easily customize how the agent handles errors, integrates custom feedback loops, or manages shared state. LangGraph is preferred for production applications because it removes the 'black box' nature of AgentExecutor and provides a clear, maintainable architecture for complex agentic workflows.

How would you implement a recursive 're-thinking' loop in LangGraph?

To implement a re-thinking loop, you define a node that generates an initial response and a subsequent node that evaluates that response for quality or correctness. Using a conditional edge, you check the evaluator's output; if it fails, you route back to the generation node with the updated state containing critique feedback. This is implemented via code similar to: `builder.add_conditional_edges('evaluator', route_to_generator)`. This cyclic approach allows the model to refine its output iteratively, which is impossible in a standard, acyclic LangChain chain.

All LangChain interview questions →

Check yourself

1. What is the primary motivation for using LangGraph over a basic sequential Chain?

  • A.To reduce the token cost of model calls
  • B.To implement cycles and conditional logic in agent workflows
  • C.To automatically generate the code for external API connections
  • D.To replace the need for memory management entirely
Show answer

B. To implement cycles and conditional logic in agent workflows
LangGraph is designed specifically for cycles and iterative control flow. It is not intended to reduce costs or generate code automatically, and it does not remove the need for memory; it actually formalizes it.

2. In LangGraph, what is the role of a 'Reducer' function?

  • A.To compress the prompt sent to the model
  • B.To convert the graph into a standard synchronous chain
  • C.To determine how updates should be merged into the current State
  • D.To delete old messages to save space
Show answer

C. To determine how updates should be merged into the current State
Reducers define the logic for how new values interact with the existing state (e.g., adding to a list vs. overwriting a variable). It is unrelated to compression, synchronization, or simple deletion.

3. When should you use 'add_conditional_edges' instead of 'add_edge'?

  • A.When the next node to execute depends on the result of the current node
  • B.When the execution speed of the graph needs to be faster
  • C.When you are connecting a node to multiple potential destinations simultaneously
  • D.When the graph has more than ten nodes
Show answer

A. When the next node to execute depends on the result of the current node
Conditional edges are used for branching logic based on state values. 'add_edge' is for fixed, linear transitions; speed, node count, and simultaneous connections are not the primary drivers for conditional logic.

4. Why is it important to define a clear State schema in LangGraph?

  • A.It speeds up the model's inference time
  • B.It acts as the single source of truth for all nodes in the workflow
  • C.It prevents the user from using external tools
  • D.It is required by the model to understand the user's intent
Show answer

B. It acts as the single source of truth for all nodes in the workflow
The State schema ensures type safety and consistency across the graph, acting as the 'source of truth.' It does not impact model inference speed, limit tool usage, or translate intent.

5. What happens if a node in a LangGraph workflow fails during execution?

  • A.The graph automatically restarts from the beginning
  • B.The entire graph execution stops unless error handling is defined
  • C.The graph ignores the failure and skips to the final node
  • D.The graph saves the partial output to the database and exits
Show answer

B. The entire graph execution stops unless error handling is defined
LangGraph execution follows the defined structure strictly; unhandled exceptions propagate and stop execution. It does not automatically restart, skip, or save state by default.

Take the full LangChain quiz →

← PreviousReAct AgentNext →Nodes, Edges, and State

LangChain

24 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app