Tutorials Logic, IN info@tutorialslogic.com

LangGraph Human in the Loop: Interrupts, Review Queues, and Approval Workflows

LangGraph Human in the Loop

Human review is one of LangGraph’s strongest production features because it acknowledges a simple truth: some actions should not be fully automated, even when an LLM can draft them convincingly.

The framework’s interrupt model lets a graph pause at the exact moment external input is required, persist its state, and resume later with a reviewer decision or edit. That is much more powerful than bolting a manual checkpoint onto an otherwise opaque agent loop.

This page is about turning human involvement into a first-class workflow step rather than an operational afterthought.

What Interrupts Are and Why They Matter

Official docs describe interrupts as dynamic pause points that can occur anywhere inside node logic. When an interrupt fires, LangGraph saves the graph state and waits until you resume execution with a value.

That makes interrupts ideal for approvals, clarifications, manual edits, exception handling, and workflows where accountability matters.

  • Interrupt payloads must be JSON-serializable.
  • A checkpointer is required because the graph must save its place.
  • The resumed value becomes the return value of `interrupt()` inside the node.

Approval Design Beyond Yes or No

Many teams stop at approve or reject, but real review flows often need edit, defer, escalate, or request-more-context outcomes. Model those explicitly in state and routing so the graph reflects actual operations.

A strong review step shows the human enough evidence to make a decision quickly: the proposed action, the supporting context, the tool outputs, and the risk rationale.

  • Approve for direct continuation
  • Reject for alternate workflow or failure state
  • Edit for reviewer-modified content
  • Escalate for higher-risk manual handling

Node Restart Semantics Change How You Write Review Code

A subtle but important rule from the docs: when a node resumes after an interrupt, execution restarts from the beginning of that node. Code before the interrupt runs again.

That means side effects before an interrupt must be idempotent, and interrupt calls should not be hidden inside broad `try/except` blocks that catch the control-flow exception.

  • Do not perform irreversible side effects before interrupt unless they are idempotent.
  • Do not wrap interrupts in bare exception handlers.
  • Keep pre-interrupt code safe to re-run.

Manual Review Architecture

There are two common styles. One uses a dedicated review node with an interrupt payload. The other routes to a queue state and lets an external UI or worker resume the graph later. Both are valid; the choice depends on how your operational tooling is organized.

In either case, the graph should preserve the review reason, reviewer input, and the post-review route clearly in state.

  • Use a review node when the pause belongs directly in node logic.
  • Use queue-style orchestration when external review systems already exist.
  • Persist reviewer identity and notes when accountability matters.

Execution Flow for a Risky Action

A safe flow might be: draft response, score risk, interrupt for human review if the risk is high, then either publish, revise, or escalate based on reviewer input. This keeps the model helpful without giving it unsupervised power.

The important design move is to put review before the irreversible action, not after it as a logging step.

  • Start state: proposed action and evidence
  • Risk scoring node adds risk metadata
  • High-risk route pauses with interrupt
  • Reviewer resumes with decision payload
  • Graph routes to publish, revise, or escalate

Interrupts Are Durable Approval Boundaries

A human-in-the-loop graph should treat review as a durable boundary. The graph reaches an interrupt with a clear review payload, persists state, waits for external input, and resumes with the reviewer decision. This is different from asking a question inside a transient model call.

The review payload should include the proposed action, target system, evidence, risk, editable draft content when relevant, and available decisions. A reviewer should be able to approve, edit, reject, or escalate without reconstructing the whole trace manually.

Resume data should be validated just like user input. If the reviewer edits a draft, the graph should check format, policy, and required fields before continuing. Human input is trusted for intent but still needs application validation.

Interrupts also need timeout and cancellation behavior. A run waiting forever is operational debt. Define what happens after a day, a week, or a policy-specific deadline.

  • Create clear review payloads before interrupting.
  • Persist pending approval state durably.
  • Validate resume data before continuing.
  • Support approve, edit, reject, cancel, and escalate paths.
  • Define timeout behavior for abandoned reviews.

Review Queue Operations

In production, human review becomes a queue. That queue needs assignment, priority, filtering, audit history, and permissions. A compliance reviewer should not see every customer draft. A support lead should see the cases assigned to their team. Review UI is part of the agent system.

Review queues should show context compactly. Include the user request, current state summary, proposed action, evidence, and model confidence. Avoid forcing reviewers to read raw conversation logs unless they need to investigate.

After review, store the decision with reviewer identity, timestamp, before-and-after content, and reason where possible. These records are useful for audits, evaluation, and improving future policy.

Measure review outcomes. High edit rates may mean the model needs better instructions or evidence. High rejection rates may mean the approval policy is catching risk or the agent is proposing poor actions. Both are valuable signals.

  • Treat review as an operational queue.
  • Permission review items by team, tenant, and role.
  • Record decisions and edits for audit.
  • Measure approval, edit, rejection, and escalation rates.
  • Use reviewer feedback to improve evaluations.

Approval Workflow Review

Review each interrupt as if you are the human approver. Does the payload explain the proposed action, target, evidence, risk, and alternatives? Can the reviewer edit or reject safely? Is the resume path clear?

Then inspect operational behavior. Who owns pending reviews? What happens if the reviewer is unavailable? Can another authorized reviewer take over? Does the run expire or escalate after a deadline?

Finally, compare approval decisions to future evaluation data. Reviewer edits and rejections are high-quality feedback. They show where prompts, retrieval, policy, or tool design need improvement.

A mature approval workflow also explains what happens after rejection, so the graph does not leave users wondering whether the task stopped, changed direction, or needs more input.

  • Make review payloads human-readable.
  • Define ownership and timeout behavior.
  • Audit approval, edit, rejection, and escalation.
  • Feed reviewer corrections into evaluations.

Beginner Example: Ask for Approval

This is the smallest interrupt pattern: pause, wait, resume, then update state.

Beginner Example: Ask for Approval
from typing_extensions import TypedDict
from langgraph.types import interrupt

class ApprovalState(TypedDict):
    approved: bool

def approval_node(state: ApprovalState) -> dict:
    approved = interrupt("Do you approve this action?")
    return {"approved": bool(approved)}
  • The interrupt payload can be a simple string for basic approvals.
  • The resumed value is used like ordinary data inside the node.
  • This requires checkpoint persistence when compiled.

Intermediate Example: Review and Edit Content

A reviewer can return structured edits rather than a binary yes/no decision.

Intermediate Example: Review and Edit Content
from typing_extensions import TypedDict
from langgraph.types import interrupt

class ReviewState(TypedDict):
    draft: str
    final: str
    reviewer_notes: str

def review_node(state: ReviewState) -> dict:
    response = interrupt({
        "instruction": "Review this draft",
        "draft": state["draft"],
    })
    return {
        "final": response.get("edited_text", state["draft"]),
        "reviewer_notes": response.get("notes", ""),
    }
  • Structured payloads are more useful than plain strings for real review UIs.
  • The node can preserve both edited output and reviewer notes.
  • This makes human review part of the system record.

Advanced Example: Route by Reviewer Decision

After resumption, the graph can branch cleanly based on the decision type.

Advanced Example: Route by Reviewer Decision
from typing_extensions import TypedDict, Literal

class DecisionState(TypedDict):
    decision: str

def route_after_review(state: DecisionState) -> Literal["publish", "revise", "escalate"]:
    mapping = {
        "approve": "publish",
        "edit": "revise",
        "escalate": "escalate",
    }
    return mapping.get(state["decision"], "revise")
  • Review outcomes should be explicit values in state.
  • A graph with multi-outcome review is much easier to audit later.
  • This is the right pattern for regulated or customer-facing actions.
Key Takeaways
  • Use interrupts when execution genuinely must pause for external input.
  • Keep interrupt payloads simple and serializable.
  • Assume code before an interrupt may run again on resume.
  • Model review outcomes beyond binary approval when the business process needs it.
Common Mistakes to Avoid
Sending the risky action first and asking for review later.
Hiding interrupts inside exception handlers that swallow the control flow.
Treating reviewers as out-of-band operators instead of capturing their decisions in state.

Practice Tasks

  • Add an interrupt gate before a hypothetical refund action.
  • Design a structured payload for an email-review UI.
  • Create a route table for approve, edit, reject, and escalate outcomes.

Frequently Asked Questions

Yes. The runtime needs a checkpointer so it can save graph state while waiting for external input.

Yes. A resume payload can include edited text or structured changes, not just a boolean approval.

Putting non-idempotent side effects before the interrupt and forgetting that the node restarts on resume.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.