Learnixo
Back to blog
AI Systemsintermediate

Why LangGraph?

Understand what LangGraph adds over LangChain's linear chains, when to reach for it, and how its graph-based control flow enables true agentic systems.

Asma Hafeez KhanMay 15, 20267 min read
LangGraphAI AgentsState MachineLangChainPython
Share:𝕏

Why LangGraph?

LangChain gave developers a toolkit for chaining LLM calls. It works well for pipelines where the sequence of steps is fixed at authoring time: retrieve context, format prompt, call LLM, parse output. But real agent behavior rarely follows a straight line. An agent needs to decide, retry, loop, and branch — and for that, LangChain's sequential chains hit a wall.

LangGraph is the answer. It replaces the linear chain metaphor with a directed graph, where nodes are functions and edges are explicit transitions. You keep everything you like about LangChain (ChatOpenAI, retrievers, tool calling) and add the ability to express cycles, branches, and multi-step stateful logic.


What LangGraph Adds

| Capability | LangChain LCEL | LangGraph | |---|---|---| | Sequential steps | Yes | Yes | | Branching (if/else routing) | Limited | First-class | | Cycles and loops | No | Yes | | Persistent state across steps | No | Yes (state schema) | | Built-in checkpointing | No | Yes | | Human-in-the-loop pausing | No | Yes | | Multi-agent orchestration | No | Yes |

LangGraph is not a replacement for LangChain — it is built on top of it. You still use ChatOpenAI, PromptTemplate, and tool integrations. LangGraph provides the orchestration layer that decides which component runs next and what data it sees.


When to Use LangGraph

Use LangGraph when your agent needs any of the following:

Cycles — The agent must loop: reason, act, observe, reason again. The classic ReAct pattern is a cycle. LCEL has no way to express this.

Conditional routing — Based on the LLM output or retrieved data, execution must take different paths. LangGraph's add_conditional_edges makes this explicit and debuggable.

Multi-step state accumulation — The agent builds up information across many steps (retrieved documents, tool results, intermediate answers) and later steps depend on earlier ones.

Checkpointing and resumability — The agent must be able to pause, persist state, and resume later — either for human review or because it runs for a long time.

Human-in-the-loop — Before taking an irreversible action (sending an email, writing to a database), the agent must pause and wait for human approval.

Multi-agent systems — A supervisor orchestrates specialist agents. Each agent is a subgraph; the supervisor routes between them.


LangChain LCEL vs LangGraph

LCEL (LangChain Expression Language) uses the | pipe operator to chain runnables:

Python
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(model="gpt-4o-mini")

chain = (
    ChatPromptTemplate.from_template("Answer this question: {question}")
    | llm
    | StrOutputParser()
)

result = chain.invoke({"question": "What is the capital of France?"})
print(result)  # Paris

This is perfect for a single-pass pipeline. The moment you need to look at the output and decide whether to retry or route elsewhere, LCEL becomes awkward.

LangGraph expresses the same logic as a graph, but lets you add conditional edges afterward:

Python
from langgraph.graph import StateGraph, START, END
from langchain_openai import ChatOpenAI
from typing import TypedDict

llm = ChatOpenAI(model="gpt-4o-mini")

class State(TypedDict):
    question: str
    answer: str

def answer_node(state: State) -> dict:
    response = llm.invoke(state["question"])
    return {"answer": response.content}

graph = StateGraph(State)
graph.add_node("answer", answer_node)
graph.add_edge(START, "answer")
graph.add_edge("answer", END)

app = graph.compile()
result = app.invoke({"question": "What is the capital of France?"})
print(result["answer"])  # Paris

Now suppose you want to validate the answer and retry if it is too short:

Python
def validate_node(state: State) -> dict:
    # just pass through  routing logic is in the edge function
    return {}

def route_after_validate(state: State) -> str:
    if len(state["answer"]) < 20:
        return "answer"   # retry
    return END

graph = StateGraph(State)
graph.add_node("answer", answer_node)
graph.add_node("validate", validate_node)
graph.add_edge(START, "answer")
graph.add_edge("answer", "validate")
graph.add_conditional_edges("validate", route_after_validate)

app = graph.compile()
result = app.invoke({"question": "Explain quantum entanglement briefly."})

This is impossible to express cleanly in LCEL. In LangGraph it is four lines.


Key Concepts Preview

Before diving into code, here is a quick map of the core concepts:

StateGraph — The main class. You instantiate it with your state schema and register nodes and edges on it.

Python
from langgraph.graph import StateGraph
graph = StateGraph(MyState)

State schema — A TypedDict (or Pydantic model) that defines every piece of data that flows through the graph. Every node receives the full state and returns a partial update.

Python
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages

class AgentState(TypedDict):
    messages: Annotated[list, add_messages]
    query: str
    retrieved_docs: list[str]
    final_answer: str

Node — A plain Python function with the signature (state: MyState) -> dict. It reads from state, does work (call an LLM, query a database, call a tool), and returns only the keys it changed.

Python
def retrieve_node(state: AgentState) -> dict:
    docs = retriever.invoke(state["query"])
    return {"retrieved_docs": [d.page_content for d in docs]}

Edge — A connection from one node to another. Can be unconditional (add_edge) or conditional (add_conditional_edges).

Python
graph.add_edge("retrieve", "generate")   # always go from retrieve to generate
graph.add_conditional_edges("generate", decide_next)  # routing function

START and END — Special sentinel nodes. START is the implicit entry point; END terminates the graph.


Installation

Bash
pip install langgraph langchain-openai langchain-core

For checkpointing with SQLite (production-ready persistence):

Bash
pip install langgraph-checkpoint-sqlite

For the LangGraph development server and Studio UI (optional but recommended for debugging):

Bash
pip install langgraph-cli

Verify installation:

Python
import langgraph
import langchain_openai
print(langgraph.__version__)   # e.g. 0.2.x
print(langchain_openai.__version__)

Set your API key:

Python
import os
os.environ["OPENAI_API_KEY"] = "sk-..."

Or in a .env file:

OPENAI_API_KEY=sk-...

A Minimal End-to-End Example

This is the smallest complete LangGraph program — a single-node graph that calls an LLM and returns the answer:

Python
import os
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langchain_openai import ChatOpenAI

os.environ["OPENAI_API_KEY"] = "sk-..."

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

class State(TypedDict):
    question: str
    answer: str

def llm_node(state: State) -> dict:
    response = llm.invoke(state["question"])
    return {"answer": response.content}

# Build the graph
builder = StateGraph(State)
builder.add_node("llm", llm_node)
builder.add_edge(START, "llm")
builder.add_edge("llm", END)

app = builder.compile()

# Run it
output = app.invoke({"question": "What is LangGraph used for?"})
print(output["answer"])

Even this minimal example demonstrates the core pattern you will use throughout this course:

  1. Define a state schema
  2. Write node functions that read state and return partial updates
  3. Register nodes and edges on a StateGraph
  4. Compile and invoke

Why Not Just Use Python?

A fair question. You could implement branching and loops with plain Python functions. LangGraph adds:

  • Automatic checkpointing — State is saved after every node with zero extra code
  • Built-in streaming — Call app.stream(input) to get updates after each node
  • Human-in-the-loop — Pause and resume with interrupt_before
  • Studio visualization — The LangGraph Studio UI renders your graph interactively
  • Thread management — Multiple concurrent conversations with separate state via thread_id
  • Time travel — Replay from any past checkpoint

These are hard to build from scratch. LangGraph gives them to you out of the box.


Summary

| Use LCEL when | Use LangGraph when | |---|---| | Single-pass pipeline | Cycles or retries needed | | No state accumulation | State builds across many steps | | No human review needed | Human approval required | | Simple chains | Multi-agent orchestration | | Prototyping quickly | Production agent systems |

The rest of this course builds up every concept — state schemas, conditional edges, cycles, checkpointing, human-in-the-loop, subgraphs, and multi-agent supervision — using real LangGraph code you can run today.

Enjoyed this article?

Explore the AI Systems learning path for more.

Found this helpful?

Share:𝕏

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.