Sitemap

🧠 Demystifying LangGraph: A Beginner’s Guide to State, Nodes, and Reducers

3 min readApr 22, 2025

LangGraph is a powerful framework designed to build stateful, composable workflows, particularly suited for applications involving Large Language Models (LLMs). By structuring your application as a graph, LangGraph allows for clear, maintainable, and scalable designs. In this article, we’ll delve into the fundamental components of LangGraph: State, Nodes, and Reducers, and demonstrate how they interact through a simple example.​

🔍 Core Components of LangGraph

1. State: The Memory of Your Graph

In LangGraph, the State represents the shared memory that persists throughout the execution of the graph. It’s typically defined using a TypedDict, dataclass, or Pydantic model, specifying the structure and types of data your graph will handle.​

For instance, if you’re building a chatbot, your state might include a list of messages exchanged during the conversation.​

2. Nodes: Units of Work

Nodes are the building blocks of your graph. Each node is a function that takes the current state as input, performs a specific task, and returns an update to the state. Nodes can represent various operations, such as processing user input, calling an external API, or generating a response using an LLM.

3. Reducers: Managing State Updates

When multiple nodes update the same part of the state, Reducers define how these updates are merged. By default, LangGraph will overwrite the existing value with the new one. However, you can specify custom reducers to combine values in different ways, such as appending to a list or merging dictionaries.​

🛠️ Building a Simple LangGraph Application

Let’s walk through creating a basic LangGraph application that simulates a simple chatbot.

Step 1: Define the State

We’ll define a state that keeps track of the conversation messages.​

from typing import Annotated
from typing_extensions import TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages

# Define the structure of the state
class ChatState(TypedDict):
# 'messages' will store a list of BaseMessage objects
# The 'add_messages' reducer appends new messages to the existing list
messages: Annotated[list[BaseMessage], add_messages]

Here, we’re using the add_messages reducer to append new messages to the existing list, preserving the conversation history.

Step 2: Implement Node Functions

We’ll create a node that simulates generating a response to the user’s message.​

from langchain_core.messages import AIMessage

# Define a node function that generates a response
def generate_response(state: ChatState) -> dict:

# Retrieve the latest user message from the state
user_message = state["messages"][-1].content

# Create a response by echoing the user's message
response = f"Echo: {user_message}"

# Return the new AI message to be appended to the state
return {"messages": [AIMessage(content=response)]}

This function takes the latest user message and returns an AI-generated response.​

Step 3: Build the Graph

Now, we’ll construct the graph by adding our node and defining the execution flow.​

from langgraph.graph import StateGraph, START, END

# Initialize the StateGraph with the defined ChatState
builder = StateGraph(ChatState)

# Add the 'generate_response' node to the graph
builder.add_node("responder", generate_response)

# Set the entry point of the graph to the 'responder' node
builder.set_entry_point("responder")

# Set the finish point of the graph to the 'responder' node
builder.set_finish_point("responder")

# Compile the graph to finalize its structure
chat_graph = builder.compile()

Step 4: Execute the Graph

Finally, we’ll run the graph with an initial user message.​

from langchain_core.messages import HumanMessage

# Define the initial state with a user message
initial_state = {"messages": [HumanMessage(content="Hello, LangGraph!")]}

# Invoke the graph with the initial state
final_state = chat_graph.invoke(initial_state)

# Print out the conversation messages
for msg in final_state["messages"]:
print(f"{msg.type.capitalize()}: {msg.content}")

Output:

Human: Hello, LangGraph!
Ai: Echo: Hello, LangGraph!

đź§© Understanding the Flow

  1. Initial State: We start with a HumanMessage containing the user's input.​
  2. Node Execution: The generate_response node processes the latest message and appends an AIMessage to the state.​
  3. State Update: The add_messages reducer ensures the new message is added to the existing list without overwriting previous messages.​

--

--

Parveen Khurana
Parveen Khurana

Written by Parveen Khurana

Writing on Data Science, Philosophy, Emotional Health | Grateful for the little moments and every reader | Nature lover at heart | Follow for reflective musings

No responses yet