Skip to content
Forward Deployed

Forward Deployed
Lessons and contents
Learn

LangGraph Runtime: Persistence, HITL & Streaming: overview

Source
From the RAG & Agents Engineering course
By
Sourav Banerjee
Last updated
8 Nov 2026

Report an issue

T4.3 builds a graph that runs from start to end in one call. Real workflows stop and start again: a person approves a step hours later, a payment provider times out, a deploy restarts the worker, a user wants to see progress while the graph runs. The T4.4 notebooks build on four ideas: the checkpointer, interrupt(), subgraphs and streaming modes, plus the retry policies, loop bounds and state rules that make a resumed run safe.

The running example is the refund desk of Larkspur Cloud, the fictional host whose handbook T5.1 to T5.3 index. A refund request enters a graph modelled on the refund agent in LangGraph State Management: triage, assess risk, refund at once when the risk is low, and wait for the billing team's approval when it is high. Two threads carry the pages and the lab, refund-17 (low risk) and refund-99 (high risk).

In short

  • A checkpointer saves the whole state after every step under a thread_id. The four-node low-risk refund saves 6 checkpoints, steps -1 to 4. Any process with the same saver and thread id can read them, resume from them or fork them.
  • interrupt() pauses a node, saves the run and returns the payload to the caller under __interrupt__. Command(resume=value) continues it, and the node runs again from its first line, so code above the interrupt() call runs twice.
  • A subgraph is a compiled graph used as a node. With shared keys you add it directly; with different keys a wrapper node maps parent state in and out. Keys the parent does not declare are dropped on the way out.
  • Streaming modes decide what the caller sees while a run is in flight. For the same four-node run, values yields 5 chunks, updates 4, checkpoints 6, tasks 8 and debug 14. messages yields LLM tokens from every model call inside every node.
  • Every resumed or retried node can repeat a side effect. In the lab, a refund whose provider response is lost reaches the customer twice unless the call carries an idempotency key.

Mental model

A refund that pauses for approval The high-risk refund refund-99 runs triage, assess and notify, then human_gate calls interrupt() and the first call returns. A second call resumes it with the answer approve; human_gate runs again from its first line, then execute and done. The checkpointer saves 8 checkpoints, steps -1 to 6. Requestrefund-99 triage assessrisk? low high notify human_gateinterrupt() resume execute done notice sent once call 1 returns __interrupt__ refund applied Checkpointer, thread refund-99: step, then next node -1start 0triage 1assess 2notify 3gate 4execute 5done 6end
  1. Call 1 sends the request on thread refund-99. Two checkpoints are saved before any node runs: step -1, the input, and step 0.
  2. triage appends a line to events, and checkpoint step 1 records it.
  3. assess reads risk=high and routes to notify. Step 2.
  4. notify sends the approval request to the billing team. Step 3 names human_gate as the next node.
  5. human_gate calls interrupt(). Call 1 returns with __interrupt__, and the thread waits with no worker attached.
  6. Call 2 resumes the thread with the billing team’s answer, approve. human_gate runs again from its first line, and this time interrupt() returns that answer. Step 4.
  7. execute calls the payment provider and the refund is applied. Step 5.
  8. done finishes the run: 8 checkpoints in all, steps -1 to 6.

The checkpointer writes after every step. At the gate, the first invoke returns while refund-99 waits at human_gate, and nothing runs until somebody calls Command(resume="approve") on the same thread, minutes or days later, from any worker that can reach the saver. Everything this module adds is about what happens between those two calls and after them: which code runs again, what the caller sees, and what the outside world receives twice.

Interactive lab

What runs twice on resume: open the file in a browser. Pick the high-risk refund with no fault and guards off: the billing team gets 2 approval notices for one request, because the notice sits above interrupt(). Then choose Response lost, RetryPolicy: the retry that saves the run also refunds the customer twice. Turn the guards on and both counts drop to 1, with the same number of client calls.

How it connects

  • Before: T4.3 builds the graphs this module pauses and resumes: state, reducers, nodes, conditional edges. T4.1 and T4.2 supply the chat models and tools inside the nodes.
  • Next: T5.1 starts the RAG pipeline these graphs will orchestrate. T7.2's HumanInTheLoopMiddleware and T8.3's approval gate are built on interrupt(). T9.2's grade-and-retry loops need the bounds from lesson 5 of T4.4, T10.1 keeps conversations in checkpointer threads, and T11.1 to T11.3 compose agents as subgraphs.

Key Takeaways

  • Compile with a checkpointer and pass a thread_id whenever a run may pause, crash or continue later; use a durable, shared saver in production.
  • Treat every node as code that can run more than once. Keep side effects after interrupt() or in their own node, and give every external write an idempotency key.
  • Pick the stream mode for the screen: updates for progress, messages filtered by node for typing, values when the client renders whole state.
  • Bound every loop twice: a counter that a node increments and the router reads, and an explicit recursion_limit as the backstop.

Rate your confidence and keep notes on the module page.