The state is a crucial component in LangGraph. Using state, you can transfer information into different nodes of the graph. Due to LangGraph’s flexibility, There are many ways to define State in LangGraph. Let’s check all the other ways.
Define state in LangGraph by inheriting classes
In Python, certain predefined classes, such as TypedDict and Pydantic, allow their properties to be inherited in a state class, enabling seamless integration into LangGraph’s workflow. Let’s check them out!
State with TypedDict
In Python, TypedDict is a feature from the typing module that allows you to define a dictionary with specific keys and their corresponding value types, similar to a schema.
Unlike regular classes, these TypedDict subclasses don’t have methods or behavior but are used purely for type annotations.
You can define State for LangGraph by inheriting TypedDict
while making state for your class. Here is one example:
import random from typing import TypedDict, Literal from IPython.display import Image,display from langgraph.graph import StateGraph,START, END class TypedDictState(TypedDict): name:str mood: Literal['happy','sad']
Here two variables will be passed among nodes: name
and mood
.
For more specific value constraints, you can use things like the Literal
type hint as just like the one used above for mood
.
State with Pydantic
The Pydantic library is highly useful for creating classes in Python, particularly when working with data validation and parsing. It provides a powerful and easy-to-use framework for defining classes with strict type annotations, validating input data, and converting data to appropriate types automatically.
We can leverage Pydantic’s BaseModel functionality for our graph’s state creation. Luckily Langchain also provides their custom BaseModel that is capable with our LangGraph.
Let’s check it out:
from langchain_core.pydantic_v1 import BaseModel, validator,ValidationError class PydanticState(BaseModel): name: str mood: Literal['happy','sad']
Unlike TypedDict, Pydantic can perform validation to check whether data conforms to the specified types and constraints at runtime. This will be very useful when you want to pass only limited set of predefined inputs to the graph.
from pydantic import BaseModel, field_validator, ValidationError class PydanticState(BaseModel): name: str mood: str # "happy" or "sad" @field_validator('mood') @classmethod def validate_mood(cls, value): # Ensure the mood is either "happy" or "sad" if value not in ["happy", "sad"]: raise ValueError("Each mood must be either 'happy' or 'sad'") return value try: state = PydanticState(name="John Doe", mood="mad") except ValidationError as e: print("Validation Error:", e)
State with Dataclass
Dataclass module is ideal for creating lightweight, immutable, or mutable data containers with type hints, default values, and support for comparison and sorting.
Let’s check the example of it:
from dataclasses import dataclass @dataclass class DataclassState: name: str mood: Literal["happy","sad"]
Define state in LangGraph with Reducers
Until now, you’ve seen the state created by inheriting class. This is good choice if your state is being utilised by one node at a time(sequentially). But this will cause error if you want to access your state parallel or want to add items to the list without overwriting the previous one.
This problems can be solved by reducer functions. let’s check them out!
from operator import add from typing import Annotated class State(TypedDict): foo: Annotated[list[int], add]
In above example we have used add
reducer function that will append integer items to the list in a variable called foo
. Now as this will append items to the list(without overwriting them), you can invoke multiple nodes with the same state at a time.
If your use case is different, then you can also define your custom reducer for state creation.
For storing messages and appending messages, the below schema is used in LangGraph.
from typing import Annotated from langchain_core.messages import AnyMessage from langgraph.graph.message import add_messages # Define a custom TypedDict that includes a list of messages with add_messages reducer class CustomMessagesState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] added_key_1: str added_key_2: str # etc
FYI: The above state is a default state schema for the LangGraph, this will append the messages from each state.
Define state with MessagesState
MessagesState
is a predefined class provided by LangGraph to do the same operation of appending messages to the list(as you saw above) without explicitly using reducer.
from langgraph.graph import MessagesState # Use MessagesState, which includes the messages key with add_messages reducer class ExtendedMessagesState(MessagesState): # Add any keys needed beyond messages, which is pre-built added_key_1: str added_key_2: str # etc
Conclusion
As you’ve seen, LangGraph offers various ways to define state, giving you the flexibility to create class schemas tailored to your specific needs. There’s no definitive right or wrong approach—just find what works best for your application. So, go ahead and build amazing apps with LangGraph!
Also Read: Effortlessly Create an Amazing ReAct Agent with LangGraph