Skip to content

Top 5 Methods to Create a State in LangGraph

  • 4 min read
  • by
Top 5 Methods to Create a State in LangGraph

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

Leave a Reply

Your email address will not be published. Required fields are marked *