LangGraph: Build Durable, Stateful AI Agents in Python
Tech Tips 6 min read advanced

LangGraph: Build Durable, Stateful AI Agents in Python

A practical guide to LangGraph, the durable agent framework that hit 1.0 in October 2025 and the 1.2 line by mid-2026. It covers the three core primitives (state, nodes, edges), conditional edges for branching and loops, and checkpointer-based persistence for crash recovery and memory. It also explains the deprecation of create_react_agent in favor of LangChain's create_agent, and the rule of thumb for choosing between the high-level agent builder and low-level StateGraph.

Marcus Rivera
Marcus Rivera
Jul 26, 2026

Most "AI agent" demos are a single while loop wrapped around a chat completion. They work in a notebook and fall apart in production the moment a server restarts, a user walks away mid-task, or a step needs a human to click "approve." LangGraph is the framework built for the part that comes after the demo: durable, stateful, long-running agents that survive a crash and pick up exactly where they left off.

LangGraph and its higher-level sibling LangChain both hit their first stable 1.0 release on October 22, 2025, with a public commitment to no breaking changes until 2.0. As of July 2026 the library is on the 1.2 line, it is downloaded around 90 million times a month, and it runs in production at Uber, LinkedIn, Klarna, JP Morgan, and Blackrock. This is a practical guide to what LangGraph actually gives you and when to reach for it.

Install and requirements

LangGraph needs Python 3.10 or newer — 3.9 support was dropped when it hit EOL in October 2025. Install it with pip:

pip install -U langgraph

Or, if you use uv (the approach the LangChain team recommends in their own docs):

uv pip install --upgrade langgraph

That is the entire dependency for the low-level graph API. If you also want the fast high-level agent builder covered at the end of this article, add langchain as well.

The mental model: state, nodes, edges

LangGraph asks you to describe your agent as a graph rather than a script. There are exactly three concepts to learn.

State is the single object that flows through your agent — what it remembers. You define its shape with a TypedDict. Nodes are plain Python functions that receive the current state and return an update to it. Edges connect nodes and decide what runs next. That is the whole model, and everything else is built on top of it.

Here is a minimal graph with one node:

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    topic: str
    draft: str

def write_draft(state: State) -> dict:
    # Your model call would go here.
    return {"draft": f"An article about {state['topic']}"}

builder = StateGraph(State)
builder.add_node("write_draft", write_draft)
builder.add_edge(START, "write_draft")
builder.add_edge("write_draft", END)

graph = builder.compile()
result = graph.invoke({"topic": "state machines"})
print(result["draft"])

START and END are the two built-in sentinel nodes marking where execution enters and leaves the graph. Note what the node returns: a partial update, not the whole state. LangGraph merges each node's return value into the running state for you, which is what keeps larger graphs readable.

Branching with conditional edges

A straight line of nodes is just a pipeline. Agents become interesting when they decide what to do next. That is a conditional edge — you attach a router function that inspects the state and returns the name of the next node.

def route(state: State) -> str:
    if len(state["draft"]) < 20:
        return "expand"
    return "publish"

builder.add_conditional_edges("write_draft", route, {
    "expand": "expand_node",
    "publish": "publish_node",
})

Because the routing logic is an ordinary function, you can drive it with a model's output, a tool result, a confidence score, or a hard-coded rule. Loops fall out of the same mechanism: point an edge back at an earlier node and the graph will cycle until the router sends it to END. This mix of deterministic and model-driven control is exactly what LangGraph is built for, and it is why the framework sits a level below a one-line agent builder.

The feature that earns its keep: durable state

Everything above you could hand-roll. Persistence is the reason to adopt LangGraph. When you compile a graph with a checkpointer, LangGraph saves the full state after every node executes. If the process dies, the graph resumes from the last checkpoint instead of starting over — and the same mechanism gives you multi-turn memory and human-in-the-loop pauses essentially for free.

from langgraph.checkpoint.memory import InMemorySaver

checkpointer = InMemorySaver()
graph = builder.compile(checkpointer=checkpointer)

config = {"configurable": {"thread_id": "user-42"}}
graph.invoke({"topic": "checkpoints"}, config)

The thread_id is what ties a series of calls together into one conversation. Call the graph again with the same thread_id and it continues where it stopped; use a different one and you get a clean session. InMemorySaver is fine for development; for production, swap it for a database-backed checkpointer (LangGraph ships Postgres and SQLite savers) and your agent state survives restarts and deploys. Multi-day approval workflows, background jobs that span sessions, and pause-for-human-review flows are all the same feature under the hood.

When you don't need this much control

Here is the honest part most tutorials skip: if your agent is just "call a model, let it use tools, repeat," you should not be writing graphs by hand. LangChain 1.0 introduced create_agent for exactly that default loop, and it runs on the LangGraph runtime underneath, so you keep the durable state without the boilerplate.

from langchain.agents import create_agent

agent = create_agent(
    model="openai:gpt-5",
    tools=[get_weather],
    system_prompt="Help the user by checking the weather in their city.",
)

result = agent.invoke({"messages": [{"role": "user", "content": "Weather in SF?"}]})

One important migration note: the old create_react_agent from langgraph.prebuilt is now deprecated, and its functionality moved into langchain.agents as create_agent. If you are following a tutorial written before late 2025, that is the single change most likely to bite you. create_agent also brings middleware — built-in hooks for human-in-the-loop approval, automatic summarization when context fills up, and PII redaction — that let you customize the loop without dropping down to raw graphs.

The rule of thumb from the LangChain team is clean: reach for create_agent when your workflow fits the model→tools→response loop, and drop down to LangGraph's StateGraph when you need branching, cycles, a mix of deterministic and agentic steps, or tight control over cost and latency. Because agents built with create_agent are themselves graphs, you can nest one inside a larger LangGraph workflow and migrate gradually.

The Bottom Line

LangGraph is not the fastest way to get an agent talking — that is create_agent, and you should start there. LangGraph is the fastest way to get an agent you can trust in production: one whose state persists, whose execution resumes after a crash, and whose control flow you can see and shape instead of hoping a prompt holds it together. Learn the three primitives — state, nodes, edges — install the 1.2 line on Python 3.10+, and add a checkpointer the moment your agent does anything a user would be annoyed to lose. That single decision is the line between a demo and a system.

More in Tech Tips

LiteLLM: One Unified API for Every LLM Provider in 2026
Tech Tips

LiteLLM: One Unified API for Every LLM Provider in 2026

LiteLLM is an open-source gateway that gives developers a single OpenAI-format interface to call 100+ LLM providers. This tutorial covers installing the SDK and Proxy Server, switching providers by changing a model string, unified exception handling, streaming, and adding cost tracking, observability, virtual keys, and budgets.

By Marcus Rivera · 7 min · Jul 17, 2026

Langfuse: LLM Observability That Debugs Your AI Agents
Tech Tips

Langfuse: LLM Observability That Debugs Your AI Agents

Langfuse is an open-source, MIT-licensed LLM observability platform acquired by ClickHouse in January 2026. It provides hierarchical tracing, prompt management, evaluations, and datasets. Its OpenTelemetry-based Python SDK v3 uses the @observe decorator and integrates with LangChain, the OpenAI SDK, Anthropic, and LiteLLM.

By Marcus Rivera · 6 min · Jul 16, 2026

Unsloth: Fine-Tune LLMs 2x Faster on a Single GPU
Tech Tips

Unsloth: Fine-Tune LLMs 2x Faster on a Single GPU

Unsloth is an open-source library that fine-tunes open LLMs (Llama, Qwen, Mistral, Gemma, gpt-oss) roughly 2x faster and with up to 70% less VRAM than a stock Hugging Face setup, without sacrificing accuracy. It achieves this with custom OpenAI Triton kernels and a manual backpropagation engine, and fuses LoRA with 4-bit quantization. It runs on any NVIDIA GPU with CUDA Capability 7.0+, including the free Colab T4. Install with 'pip install unsloth' and use FastLanguageModel.from_pretrained plus get_peft_model to attach LoRA adapters before training with trl's SFTTrainer.

By Marcus Rivera · 6 min · Jul 10, 2026