machine learning +
Build a Python AI Chatbot with Memory Using LangChain
What Is LangGraph? How It Works and When to Use It
Discover what is LangGraph, how it compares to LangChain, and when graph-based orchestration is the right choice for building reliable AI agents.
LangGraph is a Python library that lets you build AI agent workflows as graphs — with nodes, edges, and shared state. Unlike LangChain’s straight-line chains, LangGraph supports loops, branches, and runtime decisions, which is what real agents need.
Let me paint a scene you’ve likely lived through. You wired up a chatbot using LangChain. It fetches docs, talks to an LLM, and hands back answers. Smooth sailing.
Then your manager drops this on you: “Can it double-check its own replies? If the reply looks off, have it retry with a different tool.” Suddenly that clean pipeline needs to go backwards, pick a new path, and make choices on the fly. That’s not what LangChain was made for.
This is exactly the problem LangGraph was built to solve. In this post, I’ll explain what LangGraph is, show you how it’s different from LangChain, and help you figure out when you should (and shouldn’t) reach for it.
What Is LangGraph?
At its core, LangGraph is a Python library that lets you design AI agent workflows as graphs — where each step can loop, branch, or make choices at runtime. It comes from the same team that built LangChain, but it solves a very different puzzle.
Think of it this way. LangChain hands you the parts — model wrappers, prompt templates, retrievers, tool hooks. LangGraph shows you how to connect those parts into flows that can circle back, take detours, and adapt as they run.
The setup is simple. You describe your workflow as a directed graph with three pieces:
- A node is a Python function that does one job — talk to an LLM, verify a result, call a tool.
- An edge is the link between two nodes. It tells the graph where to go next.
- A state dict travels along the graph. Every node can read it and write to it.
python
# Not runnable -- conceptual overview
# A LangGraph workflow follows this pattern:
# 1. Define state (what data flows through the graph)
# 2. Create nodes (functions that process state)
# 3. Connect nodes with edges (define the flow)
# 4. Compile and run
# graph = StateGraph(State)
# graph.add_node("retrieve", retrieve_docs)
# graph.add_node("generate", generate_answer)
# graph.add_node("check", check_quality)
# graph.add_edge("retrieve", "generate")
# graph.add_conditional_edges("check", decide_next)
# app = graph.compile()
That snippet shows the full mental model in a nutshell. We won’t dive into every API method today — future posts in this series cover that. Right now, the goal is to nail down why this design exists.
Key Insight: Real agents don’t move in a straight line — they loop, retry, branch, and decide on the fly. A graph captures that behavior in a way a linear chain never could.
Why Aren’t Chains Enough?
LangChain follows a straight-line model. One step feeds the next, which feeds the one after that. That’s a chain, and it handles basic tasks just fine.
Here’s what a normal LangChain pipeline looks like:
python
User Question → Retrieve Docs → Build Prompt → Call LLM → Return Answer
Each step fires once and only once, moving forward. No U-turns. No forks. In graph terms, this is a DAG — a directed acyclic graph. “Acyclic” simply means “no going back.”
But the agents you actually want to build don’t work that way. They need to loop. Here are some real examples:
- Self-review: After writing an answer, the agent grades its own work. Bad grade? It takes a different path and tries again.
- Tool selection: The agent chooses one of five tools, runs it, then decides if the output was useful — and maybe picks a new tool.
- Human approval: The workflow stops mid-run so a person can sign off, then resumes or rolls back.
- Write-run-fix loops: A coding agent drafts code, executes it, reads the traceback, patches the bug, and repeats until every test is green.
A chain can’t express any of these. They all require cycles — the ability to jump back to a prior step based on what just happened.
Warning: “Chain” doesn’t mean “simple.” You can build very sophisticated pipelines with LangChain’s LCEL. But every one of them flows in a single direction. None can circle back based on what the LLM just said. That ceiling is exactly what LangGraph lifts.
How Does LangGraph Differ from LangChain?
Nearly everyone asks this first. The short answer: they’re partners, not rivals.
| Aspect | LangChain | LangGraph |
|---|---|---|
| Core metaphor | Chain (sequence) | Graph (nodes + edges) |
| Execution flow | Forward-only (DAG) | Cycles allowed (loops, retries) |
| State management | Implicit (passed through chain) | Explicit (shared state object) |
| Best for | RAG, chatbots, simple tool use | Agents with decisions, loops, reasoning |
| Complexity | Lower learning curve | Higher, but more control |
| Relationship | Foundation library | Built on top of LangChain |
Here’s the bottom line: LangGraph is not a swap for LangChain. It’s a layer that sits above it. All the model wrappers, prompts, and tools you already know? You keep using them. LangGraph just adds the wiring that controls how they connect.
A good analogy: LangChain is a box of Lego bricks. LangGraph is the instruction sheet that tells you which brick to pick up next — and lets you change your mind halfway through.
Tip: Begin with LangChain. Bring in LangGraph only when you hit its limits. If all you do is fetch docs, fill a prompt, and respond — LangChain is plenty. The moment you catch yourself wishing for loops, forks, or persistent state — that’s your cue to switch.
Thought experiment: Could you build a basic RAG pipeline (retrieve → prompt → respond) in LangGraph? Sure. But you’d be adding moving parts for zero payoff. LangGraph only earns its keep when your flow needs cycles or dynamic routing.
Why Use Graph-Based Orchestration?
Fair question: why bother with graphs? Can’t you just use if-else blocks and while loops in plain Python?
Honestly, yes — and for small scripts, you should. But as your agent grows, graphs give you three big wins that raw Python doesn’t:
1. Full visibility into what ran. You can draw the graph, trace every node that fired, and pinpoint the exact spot where things went sideways. Try doing that with six levels of nested if-else.
2. Save, pause, and resume. LangGraph checkpoints the full state at every node. Your agent can freeze mid-run, wait hours for a human to weigh in, and pick right back up — even on a totally different machine.
3. Built-in streaming. Because each node is a separate unit, LangGraph can push results out one node at a time. Your user sees progress as it happens, not just a final answer.
Let me make this concrete. Imagine a research agent that pulls search results, checks source quality, and writes a summary:
python
┌──────────┐
│ START │
└────┬─────┘
│
┌────▼─────┐
│ Search │
└────┬─────┘
│
┌────▼─────┐
┌────│ Evaluate │────┐
│ └──────────┘ │
enough not enough
sources sources
│ │
┌────▼─────┐ ┌────▼─────┐
│ Summarize│ │ Refine │
└────┬─────┘ │ Query │──→ (back to Search)
│ └──────────┘
┌────▼─────┐
│ END │
└──────────┘
Notice the loop: Evaluate → Refine Query → Search → Evaluate again. That back-and-forth is impossible in a chain. In a graph, it’s just another edge.
Note: We’re staying at the concept level today. The next post walks you through installing LangGraph and coding your first graph from zero. For now, I want you to nail down the *why* before we touch the *how*.
What Are the Core Abstractions: StateGraph, Nodes, and Edges?
Every LangGraph workflow is made of three building blocks. I’ll explain each one below — learning them now will make the hands-on posts that follow much easier to digest.
StateGraph is the outer shell. When you create one, you define what data the workflow should carry along. That data lives in a Python TypedDict or a Pydantic model, and every node in the graph can read or write to it.
python
# Not runnable -- illustrative only
from typing import TypedDict
class AgentState(TypedDict):
question: str
documents: list
answer: str
retry_count: int
This state dict is the one source of truth for the whole run. All nodes share the same copy. When a node finishes and sends back fresh values, LangGraph folds them into the existing state.
Nodes are plain Python functions. Each one receives the current state, does some work, and hands back only the fields it changed. That work could be an LLM call, a database query, or a simple flag check.
python
# Not runnable -- illustrative only
def retrieve_documents(state):
docs = search_vector_store(state["question"])
return {"documents": docs}
def generate_answer(state):
answer = call_llm(state["question"], state["documents"])
return {"answer": answer}
Notice the pattern: each function only sends back the keys it updated. No need to copy the entire state — just the delta.
Edges are the arrows that connect one node to another. LangGraph has three flavors:
- Normal edges: A fixed path from node A to node B. Always taken.
- Conditional edges: A small router function that checks the state and returns the name of the next node. This is where branching and looping happen.
- START and END: Built-in markers that tell the graph where to begin and where to stop.
Let me show you how these pieces snap together. First, a basic forward-only graph:
python
# Not runnable -- illustrative only
from langgraph.graph import StateGraph, START, END
graph = StateGraph(AgentState)
graph.add_node("retrieve", retrieve_documents)
graph.add_node("generate", generate_answer)
graph.add_edge(START, "retrieve")
graph.add_edge("retrieve", "generate")
graph.add_edge("generate", END)
So far, this looks just like a chain. The magic kicks in when you introduce a conditional edge:
python
# Not runnable -- illustrative only
def should_retry(state):
if state["answer"] == "" and state["retry_count"] < 3:
return "retrieve" # Loop back
return END # Done
graph.add_conditional_edges("generate", should_retry)
With that single call, a boring pipeline becomes a self-correcting agent. The router function peeks at the state and decides the next move.
Key Insight: Conditional edges are the feature that sets LangGraph apart. You write a tiny function, it inspects the state, and it picks the next node at runtime. That one idea unlocks loops, retries, and branching — everything a real agent needs.
What Are the Best Use Cases for Graph-Based Agents?
Now that you know the building blocks, let me show you where they pay off. These are the five patterns I run into most in production work.
1. Self-correcting RAG. Fetch documents, draft an answer, then grade whether the evidence actually supports the answer. If not, refine the search query and loop. The cycle repeats until quality is good enough — or retries hit a cap.
2. Team-of-agents setups. One supervisor node splits a big task across specialists — a researcher, a coder, a reviewer. Each specialist lives in its own subgraph. The supervisor dispatches jobs and collects the finished pieces.
3. Code-write-test loops. Draft Python code, execute it inside a sandbox, read the stack trace, fix the bug, run again. Keep cycling until every test goes green. This is the engine behind most coding-assistant products.
4. Pause-and-resume with humans. The agent prepares a draft and then freezes. A person reviews it hours later, clicks approve, and the graph restarts from the exact checkpoint — no state lost.
5. Adaptive tool picking. The agent looks at the question, selects the best tool, runs it, and then asks itself: “Was that output actually helpful?” If not, it swaps tools and tries again.
Every one of these patterns relies on at least one loop or fork in the road. That’s why graphs succeed where straight-line chains hit a wall.
When Should You NOT Use LangGraph?
I’ll be upfront — LangGraph is not the answer to every problem. Reaching for it too soon is the number one trap I see newcomers fall into. Here are the cases where you should leave it on the shelf.
Plain Q&A bots. If the whole flow is “user talks, model answers” — you don’t need a graph. A bare API call or a LangChain chain is faster and far simpler.
Straight-line RAG. Grab docs, stuff them into a prompt, get a reply. No branches, no loops. LangChain does this with less code and less overhead.
Quick prototypes. When you’re still figuring out if an idea has legs, write the simplest Python you can. The moment you notice yourself hand-coding retry counters and state dicts — that’s the sign to upgrade.
Lean deployments. LangGraph depends on LangChain, which brings in many packages. If all you need is a single LLM call, the OpenAI or Anthropic SDK on its own may be enough.
Warning: “Newer” doesn’t mean “better for your project.” Some developers adopt LangGraph as an automatic upgrade. It isn’t. It’s a tool for workflows that branch, loop, and carry state. Applying it to a simple pipeline just makes your code harder to read for no benefit.
What Mistakes Should You Avoid When Starting?
Mistake 1: Skipping LangChain basics
LangGraph sits on top of LangChain. If prompt templates, chat models, and tool calling are still fuzzy for you, the graph layer will feel twice as hard. Learn the foundation first — the nodes you write inside the graph are pure LangChain.
Mistake 2: Splitting every step into its own node
When two operations always fire one after the other with no fork between them, put them in a single function. Two separate nodes just add wiring overhead and clutter the graph visual.
Mistake 3: Leaving loops unbounded
A conditional edge that circles back will run forever unless you tell it to stop. Always include a counter like retry_count or max_iterations in your state.
python
# Not runnable -- illustrative only
# BAD: infinite loop risk
def should_retry(state):
if not state["answer"]:
return "retrieve"
return END
# GOOD: bounded loop
def should_retry(state):
if not state["answer"] and state["retry_count"] < 3:
return "retrieve"
return END
One extra key in the state, one extra condition in the router — that’s all it takes to keep your agent from spinning forever.
Quick Check: Test Your Understanding
Cover the article and try to answer from memory:
- What type of execution does LangChain handle? What does LangGraph add on top?
- What are the three core pieces of every LangGraph workflow?
- Name two situations where LangChain is the better choice.
Exercise 1: Identify the Graph Pattern
python
{
"type": "exercise",
"id": "identify-graph-pattern",
"title": "Exercise 1: Identify the Graph Pattern",
"difficulty": "beginner",
"exerciseType": "write",
"instructions": "You're given a description of an AI agent workflow. Your job is to identify whether it needs LangGraph or if LangChain is sufficient. For each scenario, print 'langgraph' or 'langchain'.\n\nScenario 1: A chatbot that translates user text to French.\nScenario 2: An agent that writes SQL, runs it, checks for errors, and retries up to 3 times.\nScenario 3: A document summarizer that takes a PDF and returns a summary.",
"starterCode": "# For each scenario, decide: does it need LangGraph or is LangChain enough?\n# Print 'langgraph' or 'langchain' for each scenario.\n\n# Scenario 1: Translate text to French\nscenario_1 = ___ # fill in\n\n# Scenario 2: Write SQL, run, check errors, retry up to 3 times\nscenario_2 = ___ # fill in\n\n# Scenario 3: Summarize a PDF document\nscenario_3 = ___ # fill in\n\nprint(scenario_1)\nprint(scenario_2)\nprint(scenario_3)",
"testCases": [
{"id": "tc1", "input": "", "expectedOutput": "langchain\nlanggraph\nlangchain", "description": "Correct tool choice for all three scenarios"},
{"id": "tc2", "input": "print(scenario_2)", "expectedOutput": "langgraph", "hidden": true, "description": "Scenario 2 needs LangGraph because of the retry loop"}
],
"hints": [
"Ask yourself: does the workflow need to loop back to a previous step? If yes, that's LangGraph territory.",
"Scenario 1 is input → output (no loop). Scenario 2 has a retry loop (write → run → check → retry). Scenario 3 is input → output (no loop)."
],
"solution": "scenario_1 = 'langchain'\nscenario_2 = 'langgraph'\nscenario_3 = 'langchain'\n\nprint(scenario_1)\nprint(scenario_2)\nprint(scenario_3)",
"solutionExplanation": "Scenarios 1 and 3 are linear: input goes in, output comes out, no loops or branches needed. LangChain handles these perfectly. Scenario 2 requires a loop -- the agent must check for SQL errors and retry -- which is exactly what LangGraph's conditional edges enable.",
"xpReward": 10
}
Exercise 2: Design a Graph Workflow
python
{
"type": "exercise",
"id": "design-graph-workflow",
"title": "Exercise 2: Design a Graph Workflow",
"difficulty": "beginner",
"exerciseType": "write",
"instructions": "Design the state for a customer support agent that:\n1. Classifies the question (billing, technical, general)\n2. Routes to the right specialist\n3. Generates a response\n4. Checks quality -- if the response doesn't address the question, retries (max 2 times)\n\nDefine the state as a dictionary with the required keys and print the key names sorted alphabetically.",
"starterCode": "# Define the state dictionary for a customer support agent graph.\n# Think about what data needs to flow between nodes.\n# Include fields for: the question, category, response, quality check result,\n# and something to prevent infinite loops.\n\nstate_keys = [\n ___, # fill in the required state keys\n]\n\nstate_keys.sort()\nfor key in state_keys:\n print(key)",
"testCases": [
{"id": "tc1", "input": "", "expectedOutput": "category\nquestion\nresponse\nretry_count\nresolved", "description": "All five required state keys printed alphabetically"},
{"id": "tc2", "input": "print(len(state_keys))", "expectedOutput": "5", "hidden": true, "description": "Exactly 5 state keys"}
],
"hints": [
"You need to track: what the user asked, what category it falls into, what answer was generated, whether it passed quality check, and how many retries have happened.",
"The five keys are: 'question', 'category', 'response', 'resolved', 'retry_count'. The retry_count prevents infinite loops in the quality-check-to-retry cycle."
],
"solution": "state_keys = [\n 'question',\n 'category',\n 'response',\n 'retry_count',\n 'resolved',\n]\n\nstate_keys.sort()\nfor key in state_keys:\n print(key)",
"solutionExplanation": "Each key maps to a node's responsibility: 'question' is the input, 'category' is set by the classify node, 'response' by the generate node, 'resolved' by the quality-check node, and 'retry_count' tracks loop iterations to prevent infinite retries.",
"xpReward": 15
}
Summary
Here’s the core takeaway: real AI agents don’t march in a straight line. They circle back, take detours, retry, and pick paths on the fly. LangChain hands you the individual pieces. LangGraph gives you the framework to arrange those pieces into workflows that match how agents actually behave.
You only need three concepts: StateGraph carries the data, Nodes do the work, and Edges — particularly conditional ones — steer the flow.
My advice: don’t reach for LangGraph by default. If your pipeline goes from A to B to C with no forks, LangChain is simpler. But the moment your agent needs to loop, branch, or remember where it left off — LangGraph is the tool for the job.
Up next, we install LangGraph and build our very first working graph from scratch.
Frequently Asked Questions
Is LangGraph a replacement for LangChain?
Not at all. LangGraph is built on top of LangChain — it needs it. You keep using all the models, tools, and retrievers you already know. LangGraph just adds the control layer that lets your flows loop and branch.
python
# LangGraph uses LangChain under the hood
# pip install langgraph # This installs langchain-core automatically
How does LangGraph compare to AutoGen or CrewAI?
They solve different problems. AutoGen and CrewAI are geared toward agents that talk to each other in a conversation-style loop. LangGraph works at a lower level — you draw the exact graph, which means you control every step of the execution. The trade-off: you write more setup code, but you get far more say in what happens and when.
Does LangGraph work with models besides OpenAI?
Absolutely. The graph layer has no opinion about which LLM sits behind it. If LangChain can talk to the model, LangGraph can too — that covers OpenAI, Anthropic, Google, and local models served through Ollama or vLLM.
Can LangGraph handle long-running workflows that span hours or days?
Yes — this is actually one of its strongest selling points. The checkpointing system captures the full state after every node. A workflow can stop dead (while it waits for someone to approve, for instance), then restart days later on a completely different server. Nothing is lost.
References
- LangGraph Official Documentation — Graph API Overview. Link
- LangChain Blog — “LangGraph” (launch announcement). Link
- LangGraph GitHub Repository. Link
- LangChain Official Documentation. Link
- IBM — “What is LangGraph?” Link
- DataCamp — “LangGraph Tutorial: What Is LangGraph and How to Use It?” Link
- Harrison Chase — “Cognitive Architecture for Language Agents.” Link
Free Course
Master Core Python — Your First Step into AI/ML
Build a strong Python foundation with hands-on exercises designed for aspiring Data Scientists and AI/ML Engineers.
Start Free Course →Trusted by 50,000+ learners
Related Course
Master Gen AI — Hands-On
Join 5,000+ students at edu.machinelearningplus.com
Explore Course
Up Next in Learning Path
LangGraph Installation & Setup: Build Your First Graph
