LangGraph Tutorial: Building Stateful and Cyclic AI Agents with Python
- Authors

- Name
- Nino
- Occupation
- Senior Tech Editor
The landscape of Large Language Model (LLM) applications is shifting from simple prompt-response chains to autonomous, stateful agents. While frameworks like LangChain excel at linear workflows, complex real-world scenarios—such as iterative coding, multi-step research, or autonomous email management—require a more robust orchestration layer. This is where LangGraph enters the scene.
In this comprehensive tutorial, we will explore how to use LangGraph to build stateful AI agents. We will also look at how integrating high-performance APIs from n1n.ai can significantly enhance the reliability and speed of these agents. By the end of this guide, you will have a fully functional email-processing agent capable of autonomous decision-making.
What is LangGraph and Why Does It Matter?
LangGraph is an open-source library designed for building stateful, multi-actor applications with LLMs. Built on top of LangChain, it introduces the concept of a State Graph. Unlike a standard Directed Acyclic Graph (DAG), LangGraph allows for cycles, which are essential for agentic behavior where a model needs to repeat a task until a specific condition is met.
Key features include:
- Persistence: Automatically save the state of your agent after every step.
- Cycles: Enable iterative loops for self-correction and reasoning.
- Human-in-the-loop: Pause execution to wait for human approval or input.
- Multi-agent Support: Coordinate multiple specialized agents within a single graph.
To power these complex workflows, you need a stable backend. Using n1n.ai allows you to swap between models like Claude 3.5 Sonnet, OpenAI o3, or DeepSeek-V3 effortlessly, ensuring your agent always has the right 'brain' for the task.
Core Concepts: Nodes, Edges, and State
Before we dive into the code, let's define the three pillars of a LangGraph application:
- State: A shared data structure that represents the current status of the application. Every node reads from and writes to this state.
- Nodes: These are the functions or 'steps' in your workflow. A node can be an LLM call, a tool execution, or a Python function.
- Edges: These define the logic for moving from one node to another. Conditional Edges allow the graph to branch based on the LLM's output.
Setting Up Your Environment
To follow this tutorial, you will need Python 3.9+ and an API key for your preferred LLM. We recommend using n1n.ai to access multiple models through a single, unified interface, which simplifies the development of multi-agent systems.
# Create a virtual environment
python -m venv venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`
# Install dependencies
pip install langgraph langchain-openai pydantic
Set your environment variables:
export OPENAI_API_KEY="your_n1n_api_key_here"
export OPENAI_API_BASE="https://api.n1n.ai/v1" # If using n1n.ai proxy
Building an Email Processing Agent
Our goal is to build an agent that reads an incoming email, categorizes it (e.g., Support, Sales, Spam), and either drafts a response or archives it.
Step 1: Define the State
We start by defining what information our graph needs to track.
from typing import TypedDict, List
class AgentState(TypedDict):
email_content: str
category: str
draft_response: str
steps_taken: List[str]
Step 2: Define the Nodes
Each node is a Python function that takes the State and returns an updated version of it.
from langchain_openai import ChatOpenAI
# Initialize the model via n1n.ai
llm = ChatOpenAI(model="gpt-4o", api_key="your_key", base_url="https://api.n1n.ai/v1")
def categorize_email(state: AgentState):
content = state["email_content"]
prompt = f"Categorize this email: {content}. Categories: Support, Sales, Spam."
response = llm.invoke(prompt)
return {"category": response.content, "steps_taken": ["categorized"]}
def draft_reply(state: AgentState):
content = state["email_content"]
prompt = f"Draft a polite reply to: {content}"
response = llm.invoke(prompt)
return {"draft_response": response.content, "steps_taken": ["drafted"]}
def archive_email(state: AgentState):
return {"steps_taken": ["archived"]}
Step 3: Define the Graph Logic
Now we connect the nodes using a StateGraph.
from langgraph.graph import StateGraph, END
workflow = StateGraph(AgentState)
# Add nodes
workflow.add_node("categorizer", categorize_email)
workflow.add_node("drafter", draft_reply)
workflow.add_node("archiver", archive_email)
# Set entry point
workflow.set_entry_point("categorizer")
# Add conditional edges
def route_email(state: AgentState):
if "Spam" in state["category"]:
return "archive"
return "draft"
workflow.add_conditional_edges(
"categorizer",
route_email,
{
"archive": "archiver",
"draft": "drafter"
}
)
# Finalize edges
workflow.add_edge("drafter", END)
workflow.add_edge("archiver", END)
# Compile the graph
app = workflow.compile()
Why Use LangGraph Over Standard Chains?
In a standard LangChain Chain, the flow is fixed. If the LLM makes a mistake in the categorization step, the chain fails. In LangGraph, you can add a cycle. For example, if the drafter detects that the categorization was wrong, it can route the state back to the categorizer. This self-healing capability is what separates simple bots from true AI agents.
Performance Optimization with n1n.ai
When running stateful agents, latency can accumulate quickly because each node requires an LLM call. Using n1n.ai provides several advantages:
- Low Latency: Optimized routing to the closest model data center.
- Reliability: Automatic failover between providers (e.g., if OpenAI is down, route to Anthropic via the same API).
- Cost Management: Monitor the token usage of your complex graphs in one dashboard.
Advanced: Adding Persistence
LangGraph allows you to add a checkpointer. This means that if your server crashes mid-execution, you can resume the agent's work from the exact node where it stopped.
from langgraph.checkpoint.sqlite import SqliteSaver
memory = SqliteSaver.from_conn_string(":memory:")
app = workflow.compile(checkpointer=memory)
# Running with a thread_id allows the graph to remember history
config = {"configurable": {"thread_id": "user_123"}}
app.invoke({"email_content": "I need help with my bill"}, config)
Conclusion
LangGraph is the definitive tool for developers looking to move beyond basic LLM scripts into the world of production-grade AI agents. By leveraging the power of state graphs, cycles, and persistence, you can build systems that are not only smarter but also more resilient.
To ensure your agents perform at their peak, always use a high-quality API aggregator. Get a free API key at n1n.ai.