LangChain & LangGraph · Orientation

The map, for someone who already calls the API by hand

You write your own tool-use loops against the Anthropic and OpenAI APIs. This is what LangChain and LangGraph actually add on top — and the small mental model you need to read a LangGraph and not be surprised.

Two names, one stack. As of their v1.0 releases on 22 October 2025, LangChain and LangGraph are no longer competitors or even really separate tools — they're two altitudes of the same thing.3 Get that relationship straight first; everything else hangs off it.

The one-sentence version

LangChain is the high-level way to build an agent — "the fastest way to build an AI agent," provider-agnostic, batteries included.3 LangGraph is the low-level framework and runtime underneath it, for "highly custom and controllable agents… production-grade, long-running."3

The kicker: in 1.0, LangChain's agents run on the LangGraph runtime. You start high-level and "seamlessly drop down to LangGraph when you need more control."3 It's one ladder, not two products.

Start from what you already do

When you build an agent against the raw API today, you hand-write a loop. It looks like this, in spirit:

# the loop you already write by hand
messages = [user_msg]
while True:
    resp = client.messages.create(model=..., tools=tools, messages=messages)
    if resp.stop_reason != "tool_use":
        break                          # model gave a final answer
    for call in tool_calls(resp):
        result = run_tool(call)            # you dispatch + execute
        messages.append(tool_result(result))
    messages.append(resp)                  # feed it all back, loop again

LangChain's headline abstraction, create_agent, is that loop — standardized. The docs describe it in exactly three steps: send a request to the model with tools and prompt; the model returns either tool calls (execute them, add the results) or a final answer; repeat until done.3 So the first honest answer to "what does it add?" is: it deletes the boilerplate loop you keep rewriting — and standardizes the messy parts around it.

What it adds beyond "less code"

The real value isn't the loop — it's the normalization. LangChain 1.0 introduces standardized content blocks (a .content_blocks property) giving "consistent content types across providers" — reasoning traces, citations, tool calls — so the same code works against Anthropic, OpenAI, and others without you special-casing each provider's response shape.3 If you've ever written if provider == "openai" branches, that's the pain it targets.

So when do you ever touch LangGraph?

The hand-written loop above has a hidden ceiling. It's a straight line: call model → run tools → repeat. The moment you want structure — branch here, loop back there, run two things in parallel, pause for a human, survive a crash and resume — you start hand-rolling a state machine. LangGraph is that state machine, done properly.

The same job at three altitudes
ConcernRaw API (today)LangChainLangGraph
Mental modelA while loop you ownA prebuilt agent loop (create_agent)A graph of nodes & edges — a state machine1
Control flowLinear; you code every branchThe standard agent loop, configuredLoops, branches, parallelism, dynamic routing1
StateA messages list you mutateManaged for youAn explicit, typed State object with reducers1
DurabilityNone — crash loses everythingInherited from LangGraphCheckpointers: persist & resume at any point1
Human-in-the-loopYou build itInherited from LangGraphFirst-class interrupts / pause for review1
You reach for it when…It's a quick scriptA standard agent is enoughYou need control, durability, weird shapes
You, today

Raw API

Maximum control, maximum boilerplate. Every capability above the basic loop is yours to build.

High level

LangChain

Stop rewriting the loop; get provider-agnostic messages. Most agents start (and stay) here.

Low level

LangGraph

The runtime under LangChain. Drop here for branching, persistence, human-in-the-loop, multi-agent.

The LangGraph mental model — enough to read one

Your mission is reading fluency: open someone's StateGraph and narrate what it does. You only need four nouns. The docs put the whole thing in five words: "nodes do the work, edges tell what to do next."1

StateGraph — the graph itself

The primary graph class, parameterized by a State type. You add nodes and edges to it, then call .compile() — which validates the structure and turns on runtime features like checkpointers and breakpoints.1

Your anchor: the whole program. Compiling is "freeze the wiring, hand me a runnable."

State — the shared memory

A schema (a TypedDict, dataclass, or Pydantic model) that flows through the graph. Each key can have a reducer saying how updates apply: default is overwrite; operator.add or add_messages means append/accumulate.1

Your anchor: your messages list — but typed, and the reducer is the rule you'd hand-write for "append vs replace."

Nodes — the work

Plain Python functions. Each receives the current state (plus optional config/runtime), does something, and returns just the slice of state it wants to update.1

Your anchor: one iteration of your loop body — "call the model," or "run the tool" — pulled out into a named function.

Edges — the routing

Normal edges (add_edge) are fixed hops. Conditional edges (add_conditional_edges) call a function to decide where to go next. Execution starts at a virtual START node and ends at END.1

Your anchor: your if stop_reason == "tool_use" branch — promoted to a first-class, drawable arrow.

Under the hood it's message passing in the style of Google's Pregel system: execution runs in discrete super-steps where active nodes run (in parallel if more than one is active), pass messages along edges, and go inactive. When no node is active and no message is in flight, the graph stops.1 You rarely need this detail to read a graph — but it's why parallel branches and loops "just work."

Try this — read it before you scroll

Here's a minimal agent graph. Don't memorize the API — just narrate the flow out loud: what's the state, what do the two nodes do, and where does the loop happen?

from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from typing import Annotated, TypedDict

class State(TypedDict):
    messages: Annotated[list, add_messages]     # reducer = append, not overwrite

def call_model(state):
    return {"messages": [llm.invoke(state["messages"])]}

def route(state):
    last = state["messages"][-1]
    return "tools" if last.tool_calls else END   # the branch

g = StateGraph(State)
g.add_node("model", call_model)
g.add_node("tools", tool_node)
g.add_edge(START, "model")
g.add_conditional_edges("model", route)   # model → tools, or → END
g.add_edge("tools", "model")            # tools loop back to model
agent = g.compile()

The answer: state is a growing message list; model calls the LLM, tools runs any requested tools; route sends control back to the model if there were tool calls, else stops. That tools → model edge is your while True — drawn as a cycle instead of written as a loop.

Don't get burned

This space moved fast and old tutorials lie. Pre-1.0 LangChain pushed LLMChain, initialize_agent, and AgentExecutor — those are legacy. The current idiom is create_agent (high level) and StateGraph (low level). If an example imports AgentExecutor, it predates the world you're learning.3

Check yourself — 3 scenarios

Judgement, not trivia. One per question; reasoning appears instantly.

1. A teammate says "we'll use LangChain or LangGraph, haven't decided." What's the sharpest correction?

Since the 1.0 releases, create_agent is built on the LangGraph runtime. It's one ladder: LangChain on top, LangGraph underneath. The decision is how low you need to go, not which to adopt.

2. You're reading a StateGraph and see messages: Annotated[list, add_messages]. What is add_messages doing?

Each state key has a reducer that says how updates combine. The default overwrites; add_messages (like operator.add) accumulates — which is why the conversation grows instead of being replaced each step.

3. Your hand-written agent works, but the client now needs it to pause for human approval before sending an email and resume after a crash. Which altitude earns its keep?

Persistence (resume after crash) and human-in-the-loop (pause for approval) are exactly the production capabilities LangGraph's runtime provides out of the box — the things that are painful to hand-roll correctly.
Where to go next — you pick

That's the orientation pass. You said you weren't sure where to focus — now you've seen the map, here are the three honest drill-downs. Tell me which itch is strongest and I'll build explainer 0002 around it: