By Lordpatil · · 4 min read

LangGraph Core Concepts: A Simple Explainer

A short and concise explanation of the core concepts of LangGraph. It is designed to be easily understandable for anyone new to the framework.

AI agentslanggraphconceptsexplainerai

LangGraph Core Concepts: A Simple Explainer

This document provides a short and concise explanation of the core concepts of LangGraph. It is designed to be easily understandable for anyone new to the framework.

Graph API Concepts

At its heart, LangGraph models complex workflows as graphs. Think of it as a flowchart for your application where you can define logic, loops, and conditional branches.

Graphs

A LangGraph is built from three main components:

  1. State: A shared data structure that holds the current information of your application. It's the "memory" of your graph that gets passed around and updated.
  2. Nodes: Python functions that perform the actual work. A node takes the current State, does something (like calling an LLM, running a tool, or performing a calculation), and returns an update for the state.
  3. Edges: These are the connections between nodes. They define the path of execution, telling the graph which node to run next based on the current State.

In short: Nodes do the work, Edges tell what to do next.

To make a graph runnable, you must compile it. This step checks your graph's structure and prepares it for execution.

# graph_builder is an instance of StateGraph with nodes and edges added
graph = graph_builder.compile()

State

The State defines the data schema for your graph. It's typically a TypedDict. Every node receives the state and can return updates to it.

Schema

The schema is the structure of your state.

from typing_extensions import TypedDict

class MyGraphState(TypedDict):
    question: str
    answer: str
    history: list

Reducers

Reducers are functions that define how state updates are applied. By default, any update from a node overwrites the existing value in the state. You can change this behavior.

For example, to make a list append-only instead of being overwritten, you can use a reducer like operator.add.

from typing import Annotated
from typing_extensions import TypedDict
from operator import add

class MyGraphState(TypedDict):
    # 'question' will be overwritten on each update
    question: str

    # New items for 'history' will be added to the existing list
    history: Annotated[list, add]

MessagesState

Since tracking conversation history is very common, LangGraph provides a pre-built MessagesState which automatically manages a list of messages using an add_messages reducer. This is highly convenient for building chatbots.

from langgraph.graph import MessagesState

# Inherit from MessagesState to get a 'messages' key with an appending reducer
class ChatState(MessagesState):
    user_name: str

Nodes

Nodes are the workhorses of your graph. They are simple Python functions that receive the current state and return a dictionary of updates.

# A simple node that updates the state
def my_first_node(state: MyGraphState):
    # state["question"] would be available here
    update = {"answer": "This is a simple answer."}
    return update

# Add the node to your graph builder
builder.add_node("node_name", my_first_node)

There are two special nodes:

  • START: The entry point of the graph.
  • END: A terminal node that stops the execution of that path.

Edges

Edges connect your nodes and define the control flow.

Normal Edges

A normal edge creates a fixed path from one node to another.

# Always go from 'node_1' to 'node_2'
builder.add_edge("node_1", "node_2")

Conditional Edges

A conditional edge uses a function to decide the next node(s) based on the current state. This allows for branching and loops. The function should return the name of the next node.

def should_i_continue(state: MyGraphState) -> str:
    if len(state["history"]) > 5:
        return "end_process" # Route to the 'end_process' node
    else:
        return "continue_process" # Route to the 'continue_process' node

# Add a conditional edge from 'some_node'
builder.add_conditional_edges("some_node", should_i_continue)

Advanced Control Flow

LangGraph provides special return types for more complex logic.

Send

Used for dynamic fan-out operations, like in a map-reduce pattern. A conditional edge can return a list of Send objects to trigger multiple node calls in parallel, each with its own specific input.

from langgraph.graph import Send

def fan_out_to_process_subjects(state: MyGraphState):
    # For each subject, trigger a 'process_one' node call with a specific subject
    return [Send("process_one", {"subject": s}) for s in state['subjects']]

builder.add_conditional_edges("start_node", fan_out_to_process_subjects)

Command

A Command allows a node to both update the state and decide where to go next, combining the roles of a node and a conditional edge. This is very useful for multi-agent systems where an agent needs to pass control to another.

from typing import Literal
from langgraph.types import Command

def agent_node(state: State) -> Command[Literal["other_agent", "end_node"]]:
    if some_condition:
        # Update state and route to 'other_agent'
        return Command(update={"foo": "bar"}, goto="other_agent")
    else:
        # Just route to the end
        return Command(goto="end_node")

Persistence

LangGraph's persistence layer allows you to save and resume the state of a graph at any point. This is the foundation for powerful features like memory, human-in-the-loop, and time-travel debugging.

Checkpointers

A checkpointer automatically saves a snapshot of the graph's state after every step. To use it, you just pass it during graph compilation.

from langgraph.checkpoint.sqlite import SqliteSaver

memory = SqliteSaver.from_conn_string(":memory:")
graph = builder.compile(checkpointer=memory)

Threads and Checkpoints

  • Thread: A single, continuous execution or conversation, identified by a thread_id. All state changes for a conversation are saved to its thread. To invoke a graph with persistence, you must provide a thread_id.

    config = {"configurable": {"thread_id": "user_123_conversation_1"}}
    graph.invoke({"question": "Hi!"}, config=config)
    
  • Checkpoint: A snapshot of the graph's state at a specific moment in a thread. LangGraph saves a checkpoint at every step, creating a complete history of the execution that you can inspect or revert to.


Key Applications & Capabilities

Multi-agent Systems

You can build complex systems by composing multiple "agents". In LangGraph, an agent is just a graph (or a node). These agents can be orchestrated by a "supervisor" agent, forming a hierarchy. This pattern is excellent for breaking down complex problems into specialized tasks.

Human-in-the-loop

Thanks to persistence, you can pause a graph's execution at any point (e.g., before a critical tool call) and wait for human input. A user can review the state, approve or reject the action, or even modify the state before the graph resumes.

Visualization

LangGraph can generate diagrams of your graph, which is incredibly helpful for debugging and understanding complex flows.

# Get a PNG image of the graph diagram
Image(graph.get_graph().draw_mermaid_png())

Authored by Chirag Patil