Introduction to LangGraph
LangGraph is a library for building stateful, multi-step AI workflows as directed graphs. Unlike LangChain chains that run once and exit, LangGraph supports cycles, persistence, and human-in-the-loop — the building blocks of real agentic systems.
Why LangGraph?
| Need | LangGraph solution |
|---|---|
| Agent that loops until it has an answer | Cycles in the graph — not just linear pipelines |
| Multi-step workflows with branching logic | Conditional edges based on state |
| Pause for human approval mid-execution | interrupt_before / interrupt_after |
| Resume a workflow from where it stopped | Checkpointing with MemorySaver or SqliteSaver |
| Multiple agents collaborating | Multi-agent graphs with handoffs |
| Streaming token-by-token output | Built-in stream() with multiple stream modes |
LangChain vs LangGraph
LangChain LCEL
- Linear pipeline
- prompt | llm | parser
- Single pass, no cycles
- Great for simple chains
- No built-in persistence
LangGraph
- Graph of nodes + edges
- Supports cycles & loops
- Stateful across steps
- Checkpointing built-in
- Human-in-the-loop ready
Installation
pip install langgraph
pip install langchain-openai # or langchain-anthropic
pip install langgraph-checkpoint-sqlite # optional: SQLite persistence
Core concepts
| Concept | Description |
|---|---|
| StateGraph | The graph object — you add nodes and edges to it |
| State | A TypedDict shared by all nodes; nodes read & update it |
| Node | A Python function that receives state and returns a state update |
| Edge | A connection between nodes — either fixed or conditional |
| START / END | Special sentinel nodes marking the entry and exit points |
| Checkpointer | Saves state after each step — enables resume and HITL |
Your first graph
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langchain_openai import ChatOpenAI
# 1. Define the shared state
class State(TypedDict):
question: str
answer: str
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# 2. Define nodes (functions that update state)
def ask_llm(state: State) -> dict:
response = llm.invoke(state["question"])
return {"answer": response.content}
def format_answer(state: State) -> dict:
formatted = f"**Answer:** {state['answer']}"
return {"answer": formatted}
# 3. Build the graph
graph = StateGraph(State)
graph.add_node("ask_llm", ask_llm)
graph.add_node("format_answer", format_answer)
# 4. Connect nodes with edges
graph.add_edge(START, "ask_llm")
graph.add_edge("ask_llm", "format_answer")
graph.add_edge("format_answer", END)
# 5. Compile and run
app = graph.compile()
result = app.invoke({"question": "What is LangGraph?", "answer": ""})
print(result["answer"])
Visualising the graph
from IPython.display import Image, display
# Render the graph as a PNG (requires graphviz)
display(Image(app.get_graph().draw_mermaid_png()))
# Or print ASCII representation
app.get_graph().print_ascii()
The execution model
START
- Entry point
- Initial state passed in
Node A
- Reads state
- Returns partial update
Node B
- Reads updated state
- Conditional edge check
END
- Graph exits
- Final state returned
When to use LangGraph vs LCEL: Use LCEL for simple prompt → LLM → parser pipelines. Use LangGraph when you need loops (retry on failure, tool-use cycles), branching decisions, multi-step agent behaviour, persistence between turns, or human approval gates.