LangGraph: editorial guidance
For API reference (signatures, imports, exhaustive method lists), use the mcpdoc MCP tools: fetch_docs("https://docs.langchain.com/oss/python/langgraph/..."). This skill is the opinions layer; the docs are the facts layer.
When to drop down to raw StateGraph
Most agents do NOT need this. Use create_agent(...) + middleware first (see the langchain-agents-middleware skill). Drop down to StateGraph only when:
- Multiple LLM calls in a single graph with custom routing between them.
- Branches that run in parallel and merge.
- Non-message state (custom dataclasses, dicts, dataframes flowing through nodes).
- Multi-graph workflows where one graph calls another as a subgraph.
If your problem fits "one model, some tools, in a loop" — even if the loop is complex — create_agent is the right tool. Don't reach for StateGraph out of habit.
Things the docs won't warn you about
- A node returning
{}is a no-op; returnNoneto signal "no state change" cleanly. add_conditional_edgesmappings must includeENDif any branch terminates — leaving it out is a silent bug, not an error.compile()is not idempotent acrossbind_tools— rebind tools, then re-compile.langgraph devreloads on file change; if it stops reloading, the graph likely failed to import — check the terminal for the exception.- A graph with
interrupt()calls but no checkpointer will throw at invoke time, not at compile time. Always pairinterrupt()withcompile(checkpointer=...).
Production essentials (rules of thumb)
- Always pass a
thread_idinconfig={"configurable": {"thread_id": ...}}for any agent with persistent state. A missingthread_idsilently starts a fresh thread. InMemorySaveris for dev only. Production =PostgresSaver(multi-instance safe) orSqliteSaver(single-node, low-volume). State dies with the process forInMemorySaver.- Resume an interrupted thread by passing
Noneas input with the samethread_id. The runtime picks up where the interrupt fired. - Custom state schemas need reducers.
Annotated[list, add_messages]appends; without the reducer, each node replaces the field instead of accumulating. - For node-level retries on raw
StateGraph, useRetryPolicy. Forcreate_agentagents, preferToolRetryMiddleware/ModelRetryMiddleware— same effect, cleaner composition.
Doc URLs to fetch with mcpdoc
https://docs.langchain.com/oss/python/langgraph/graph-api.md—StateGraph, nodes, edgeshttps://docs.langchain.com/oss/python/langgraph/durable-execution.md— checkpointers +thread_idhttps://docs.langchain.com/oss/python/langgraph/streaming.md—stream_modemodeshttps://docs.langchain.com/oss/python/langgraph/persistence.md— Postgres / Sqlite checkpointershttps://docs.langchain.com/oss/python/langgraph/subgraphs.md— multi-graph composition
When the user is mid-task and you need a method signature or import path, fetch from these URLs. Don't guess.