07. Human-in-the-Loop

Chapter 7 of 18 · 15 min

LangGraph supports pausing graph execution mid-run for human review via the interrupt_before and interrupt_after configuration on compile(). When an interrupt fires, execution stops, state is checkpointed, and the graph waits for a resumption signal. This is the primary mechanism for building human-in-the-loop agent systems.

from langgraph.graph import StateGraph
from langgraph.checkpoint.memory import MemorySaver

builder = StateGraph(AgentState)
builder.add_node("execute_trade", execute_trade_node)
builder.add_edge(START, "execute_trade")
builder.add_edge("execute_trade", END)

memory = MemorySaver()
graph = builder.compile(checkpointer=memory, interrupt_before=["execute_trade"])

When you call graph.invoke(state, config={"configurable": {"thread_id": "t1"}}), it pauses before execute_trade runs. To resume after human approval:

approved_state = graph.invoke(Command(resume={"approved": True}), config=config)

The Command object with resume= injects data into the state at the resumption point. The interrupted node sees the resumed data as part of the state it receives. This pattern maps onto approval workflows, content moderation, code review before execution, and anything requiring human judgment in an automated pipeline.

The failure mode: without a checkpointer, interrupt() saves no state and the graph cannot resume from the interruption point—you get an error about a missing checkpoint. Always instantiate MemorySaver (or a persistent checkpointer) and pass it to compile() before using interrupts.

Local verification checkpoint

Run the smallest example from this chapter in a local workspace and record the package version, runtime, data path, and observed output. If the result depends on model size, vector count, CPU/GPU backend, or available memory, note that constraint beside the exercise so the lesson remains reproducible.

Local verification checkpoint

Run the smallest example from this chapter in a local workspace and record the package version, runtime, data path, and observed output. If the result depends on model size, vector count, CPU/GPU backend, or available memory, note that constraint beside the exercise so the lesson remains reproducible.

EXERCISE

Build a graph that interrupts before a send_alert node. Invoke the graph with thread_id "hitl-test", confirm it pauses, then resume with {"confirmed": True}. Print the final state to confirm the alert node received the confirmation.