Home / Notebooks / AI / Agents
AI / Agents
intermediate

LangGraph Essentials

A practical introduction to LangGraph for building stateful, multi-step AI agent workflows

July 13, 2026
Updated regularly

LangGraph Essentials

> LangGraph is a framework for building AI applications as explicit, stateful graphs instead of linear prompt chains. This notebook covers what problem it solves, its core building blocks, and a compact example of wiring up an agent that can loop, branch, and pause.

What is LangGraph?

LangGraph is a low-level orchestration library (built by the LangChain team) for building applications where an LLM's control flow needs to be more than "prompt in, answer out." Instead of chaining steps in a straight line, you model the application as a graph: nodes are units of work, edges define how control moves between them, and a shared state object flows through the whole run.

This matters because real agents rarely execute in a straight line. They call a tool, look at the result, decide whether to try again, ask a human for approval, or hand off to a different specialist. That kind of control flow is naturally cyclic — something a simple chain can't express, but a graph can.

Core characteristics:

  • Stateful by design — a typed state object is threaded through every node
  • Cyclic graphs — agents can loop back (retry, re-plan) instead of being limited to a single forward pass
  • Built-in persistence — checkpointers can save state so a run can pause and resume later
  • Human-in-the-loop — a graph can pause before a node and wait for approval
  • Streaming — intermediate steps and tokens can be streamed as the graph executes
  • Why Not Just a Simple Chain?

    A chain (prompt → LLM → parse → done) is fine for single-shot tasks. It breaks down once you need:

  • Conditional branching — "if the model calls a tool, go run it; otherwise, finish"
  • Loops — "keep retrying the tool call, up to 3 times, until it succeeds"
  • Shared, evolving state — multiple steps reading and writing the same context (messages, retrieved documents, scratch notes)
  • Resumability — a workflow that spans minutes, hours, or requires a human to click "approve" before continuing
  • LangGraph exists specifically for this class of problem — it's the layer above "just call the LLM API," used once an application's control flow becomes a graph rather than a line.

    Core Concepts

  • State — a typed schema (e.g. a TypedDict or Pydantic model) that represents everything the graph carries between steps: conversation history, tool results, counters, flags.
  • Nodes — plain functions that receive the current state and return a partial update to it. A node might call an LLM, call a tool, or run deterministic logic.
  • Edges — connections between nodes. Normal edges always go from A to B. Conditional edges run a routing function against the state to decide which node comes next.
  • Checkpointer — a persistence backend (in-memory, SQLite, Postgres, etc.) that snapshots state after each step, enabling pause/resume and multi-turn memory across sessions.
  • Common Use Cases

  • Tool-using agents that need to retry, re-plan, or chain multiple tool calls before answering
  • Approval workflows — e.g. draft an email, pause for a human to approve, then send
  • Long-running assistants that must resume a conversation or task across sessions
  • Multi-agent systems where control explicitly hands off between a router, specialists, and a synthesizer
  • Practical Example: A Tool-Calling Agent Loop

    This sketch shows the shape of a minimal agent graph: an LLM node that may request a tool, a tool-execution node, and a conditional edge that loops back until the model is done calling tools.

    from typing import TypedDict, Annotated
    from langgraph.graph import StateGraph, END
    from langgraph.graph.message import add_messages
    from langchain_core.messages import AnyMessage
    
    class AgentState(TypedDict):
        messages: Annotated[list[AnyMessage], add_messages]
    
    def call_model(state: AgentState) -> dict:
        response = llm_with_tools.invoke(state["messages"])
        return {"messages": [response]}
    
    def call_tools(state: AgentState) -> dict:
        last_message = state["messages"][-1]
        results = [run_tool(call) for call in last_message.tool_calls]
        return {"messages": results}
    
    def should_continue(state: AgentState) -> str:
        last_message = state["messages"][-1]
        return "tools" if last_message.tool_calls else END
    
    graph = StateGraph(AgentState)
    graph.add_node("agent", call_model)
    graph.add_node("tools", call_tools)
    graph.set_entry_point("agent")
    graph.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
    graph.add_edge("tools", "agent")  # loop back after tool execution
    
    app = graph.compile(checkpointer=my_checkpointer)
    
    result = app.invoke(
        {"messages": [("user", "What's the weather in Jakarta, then convert it to Fahrenheit?")]},
        config={"configurable": {"thread_id": "user-123"}},
    )
    

    The thread_id in the config is what makes this resumable — the checkpointer keys state by thread, so calling invoke again with the same thread_id continues the same conversation from where it left off.

    Best Practices

  • Keep node functions small and single-purpose — one node, one job
  • Define a typed state schema up front rather than passing loose dictionaries around
  • Use a real checkpointer (not the default in-memory one) for anything that needs to survive a restart
  • Add explicit conditional edges for error paths instead of letting exceptions propagate silently
  • Stream intermediate steps to the user for long-running graphs — it makes latency feel intentional
  • When to Reach for LangGraph (and When Not To)

    Good fit:

  • Multi-step agents with tool use, retries, or branching logic
  • Workflows that need to pause for human input
  • Anything that must resume across sessions or process restarts
  • Overkill for:

  • Single-shot completions (classification, summarization, extraction)
  • Simple RAG lookups with no branching (a linear chain is simpler and easier to reason about)
  • Key Takeaways

  • LangGraph models agent control flow as a graph, not a chain — which is what cycles, branching, and pausing actually require
  • State is explicit and typed, flowing through every node in the graph
  • Checkpointers turn a single run into a resumable, multi-turn process
  • Reach for it once your control flow stops being a straight line — not before
  • Resources

  • LangGraph docs: https://langchain-ai.github.io/langgraph/
  • LangGraph GitHub: https://github.com/langchain-ai/langgraph
  • Topics

    LangGraphAgent OrchestrationState MachinesLangChainWorkflow Automation

    Found This Helpful?

    If you have questions or suggestions for improving these notes, I'd love to hear from you.