Human in the loop LangGraph example: what recoverable execution requires

Human in the loop LangGraph example: what recoverable execution requires

Key takeaways

  • Interrupt before a consequential tool call runs, and give the reviewer explicit authority.
  • Persist graph state so approval can arrive after a refresh or restart.
  • Make external actions idempotent so a retry does not repeat the effect.

A human in the loop LangGraph example is easy to demonstrate: pause, ask for approval, then resume. Recoverable execution asks more of the harness. The interrupt needs a policy, the reviewer needs defined choices, and the checkpoint must survive the way the system actually runs. Decisions need an audit trail. Waiting needs a bound. Resumption needs durable storage. External actions need protection against duplicate effects.

We use those concerns as seven checks: policy, reviewer authority, checkpoint durability, auditability, timeout behavior, restart persistence, and duplicate-side-effect protection. A workflow that passes them has more than an approval screen. It has a control boundary that remains legible when execution stops and starts again.

LangGraph earns its structure when the workflow needs durable control

Choose LangGraph when the work needs stateful orchestration, not because an agent framework is the default shape for every tool call. LangGraph is a low-level orchestration framework for stateful agents. Its structure fits workflows where graph state, durable checkpoints, and human approval are part of execution.

That fit is narrow enough to be useful. A plain software development kit or a simple ReAct loop is a better match for simple tool use or question answering that does not need durable checkpoints, graph state, or human approval. Adding a graph does not create a recovery requirement. The workload, authority boundary, and failure mode create it.

Three questions expose the fit. Does the workflow need to retain graph state while a person considers an action? Does execution need a durable checkpoint for a later return? Does the action require human approval before it runs? Simple tool use and question answering can stay with a plain software development kit or a simple ReAct loop when the answer to those requirements is no. Stateful approval work gives the graph structure something specific to carry.

Start with the execution path. If the model can answer and finish without carrying state across a pause, a smaller agent loop may be enough. If a proposed action must wait for a person, retain its state, and continue later, the graph has a concrete job. The choice rests on workflow-complexity fit, not on a universal ranking between frameworks.

This distinction also keeps approval logic out of vague prompt instructions. Routes, pauses, and audit trails can become explicit behavior in the system. That makes the control boundary something an engineer can inspect. Once that boundary is explicit, the first design question is precise: which proposed actions are allowed to cross it without review?

Which actions should interrupt?

Interrupt policy belongs at the tool-call boundary. Human-in-the-loop middleware can check each proposed call against a configurable policy, so review is tied to the action the system is about to take. Sending an email, deleting a record, executing a financial transaction, and other irreversible operations require review and approval before execution.

Delete, email, and write actions cross a review gate with defined reviewer choices, while read and list actions bypass interruption.

Reviewer authority should be just as explicit as the interrupt. Approval permits the pending action. Rejection blocks it. Editing permits a reviewer to change a proposed call only where the policy allows that choice. An approval gate is incomplete when the interface shows buttons that the execution policy has not actually granted.

That authority is also the practical boundary in AI delegation. Capability tells us what the agent can propose. Policy determines what it may execute without human direction.

The following example policy separates consequential actions, actions with narrower reviewer authority, and read-only operations:

ActionInterrupt policyAllowed decisionsExecution boundary
delete_fileInterrupt enabledApprove, edit, rejectReview before the tool call runs
send_emailInterrupt enabledApprove, edit, rejectReview before the tool call runs
write_fileInterrupt enabledApprove, reject; editing disabledReview before the tool call runs
read_fileInterrupt disabledNo review decisionNo human interruption
lsInterrupt disabledNo review decisionNo human interruption

How a human in the loop LangGraph example pauses execution

Human-in-the-loop middleware adds oversight to agent tool calls. When the model proposes an action covered by the review policy, the middleware can pause execution and wait for a decision. When intervention is needed, it issues an interrupt that halts execution.

A policy sends reviewed tool calls through an interrupt and persisted checkpoint for later resumption, while no-review calls proceed.

The execution path has four distinct mechanisms:

  1. Tool-call oversight evaluates the proposed call.
  2. The configured policy determines whether review is required.
  3. An interrupt halts execution for the pending decision.
  4. LangGraph persistence saves graph state so execution can resume later.

Together, these mechanisms let the harness pause safely and resume later. The interrupt is the stop signal. Persisted graph state is what gives the stopped work somewhere to return to. Treating those as one feature hides the most important recovery question: what survives while the reviewer is absent?

The pending action also needs to remain pending. The action has been proposed, but the human decision arrives before it runs. That ordering is the point of the boundary. The system can present the action for approval without treating a model proposal as permission to execute it.

For the broader wiring of interrupts and resumption, see our LangGraph human-in-the-loop guide. The recoverability test begins after the pause works: close or refresh the interface, move the decision to another component, restart the process, and then determine whether the same execution can continue safely.

Durable pause means returning to the stopped execution point

A useful pause can outlive the screen that displayed it. The human-in-the-loop pattern presents the pending action and resumes only after explicit approval. In LangGraph, interrupts and checkpoints make that pause durable.

Consider the ordinary page-refresh boundary. A reviewer can refresh the page or answer from a different component. The agent can then resume from the point where execution stopped instead of replaying the whole run. The interface that collects the answer and the process that holds execution do not have to be the same component.

That behavior turns a pause into recoverable control. The reviewer is responding to a stored execution state, not to a temporary browser event. The system can combine policy review with checkpoint recovery, preserving the pending decision while execution is suspended.

This gives the checkpoint a concrete test. Trigger an interrupt, let the interface state disappear, and submit the decision through the component that now owns review. Recovery succeeds when the graph returns to the stopped point with the pending action and reviewer decision intact. Replaying the whole run is a different behavior, and it can revisit work that already happened.

The same test should separate the review message from the saved execution. The reviewer needs the pending action in a component where a decision can be made. The graph needs the checkpoint from which execution will continue. A page refresh exercises the interface boundary. A response from another component exercises the handoff. Returning to the stopped point exercises checkpoint recovery. Each observation identifies a different part of the pause that must remain available.

The checkpoint does not settle every recovery problem. It preserves graph execution across the pause. The storage behind that checkpoint still determines whether the state remains available when the process itself restarts. That is why a working frontend handoff and restart-safe persistence need separate tests.

Frontend handoff and restart-safe storage solve different parts of the flow

A frontend can collect a decision without proving that the checkpoint survives a process restart. A minimal LangGraph and FastAPI example can pause an agent, wait for frontend input, and resume execution through embedded mode and a React interface. That demonstrates the handoff between execution and review.

Storage answers the durability question. An in-memory checkpointer suits local development. When production pause and resume must survive process restarts, use a durable checkpointer such as SQLite or Postgres. This is an implementation boundary, not a cosmetic deployment choice: the state needed for resumption has to remain available after the process that created it is gone.

Test the two paths independently. First, confirm that the interface can receive the pending action and return the reviewer decision. Then restart the process while an action is waiting and confirm that durable storage still holds the checkpoint needed for resumption. A successful React interaction establishes the handoff. Restart-safe storage establishes persistence across process failure.

Local development and production call for different persistence choices. In-memory checkpointing is suitable for local development. When a production pause must survive a process restart, use a durable checkpointer such as SQLite or Postgres. The saved graph state then remains available for later resumption after the process restarts.

Once both paths work, the control surface still needs to explain who decided what and how long the workflow has been waiting.

Audit and waiting behavior belong in the control surface

Record each approve, reject, and edit decision with a timestamp and the identity of the user who made it. The audit record can be compact, but its fields should be unambiguous:

  • Decision: approve, reject, or edit
  • Timestamp: the time the decision was made
  • Reviewer: the identity of the user who made the decision

This record makes the human action part of the execution trajectory. The system is not merely resuming after an unnamed signal. It is resuming after a specific person made a specific decision at a recorded time. Explicit implementation patterns can make routes, pauses, and audit trails visible product behavior instead of hiding them inside prompt logic.

Waiting also needs a visible state. Long-running agents should not block indefinitely on human review, and the interface can show how long an agent has been waiting. No single timeout duration follows from that requirement. The duration and what happens when it expires remain workload decisions, but indefinite waiting should not be the accidental default.

Treat waiting as an operational state that can be inspected. The reviewer sees that a decision is pending. The operator sees its waiting duration. The audit trail records the eventual decision. Those controls make a stalled approval distinguishable from active execution without asking anyone to infer state from a silent interface.

Approval is not the last control in the execution path. Checkpoint recovery preserves graph state across a pause. Retries without idempotency can create duplicate side effects in distributed systems. External actions therefore need their own retry control.

How do retries avoid duplicate side effects?

Make each external action idempotent. Idempotency means that repeated attempts of the same logical operation produce the same external outcome as one attempt. Without it, retries in a distributed system can create duplicate side effects.

The key phrase is "same logical operation." A retry needs a stable identity that connects it to the original attempt. Stable keys, atomic gates, conditional writes, and safe retry policies help prevent duplicate workflow runs. The graph checkpoint can tell the workflow where to continue. The idempotency control prevents continuation from applying the same external effect again.

When the data model has no natural field for an idempotency key, use an operations table with a uniqueness constraint. The table records the key for the logical operation. A repeated attempt encounters the same unique key instead of creating a second operation record. That pattern gives the retry path a concrete gate.

This is the part a pause-and-resume demo usually leaves exposed. Restart safety extends beyond recovering the checkpoint. The external effect also has to withstand a repeated attempt. An approved email, deletion, or transaction remains consequential when execution resumes, so duplicate-effect protection belongs beside the interrupt policy in the harness design.

Apply the seven checks to one proposed tool call at your next approval boundary. Write down its interrupt policy, reviewer choices, checkpoint store, audit fields, waiting behavior, restart test, and idempotency gate. If the interrupt or resume path is still unclear, work through our deeper LangGraph human-in-the-loop guide with that tool call in hand.

More from Lab Notes.