Human-in-the-Loop in LangGraph: When to Pause for Human Approval

By Carlos Montiel | Enterprise AI Specialist
Leer en español →
Published: 2026-07-28 | By: Carlos Montiel | Reading time: ~4 minutes

Not every action an agent takes should run unsupervised. LangGraph lets you pause a graph at any node, wait for human approval, and resume exactly where it left off.

Why this isn't optional in sensitive domains

An agent that sends emails to customers, executes transfers, modifies records in an ERP, or generates public announcements shouldn't have full autonomy from day one in production, no matter how well it behaved in testing. The human-in-the-loop pattern isn't a temporary limitation while "the model improves" — it's a permanent governance control for high-impact actions, exactly like a dual-signature approval process in a traditional financial system.

The interrupt() mechanism

LangGraph provides the `interrupt()` function, which pauses graph execution inside a node, persists the state via the configured checkpointer, and returns control to the process that invoked the graph:

from langgraph.types import interrupt, Command def request_approval_node(state: AgentState): decision = interrupt({ "proposed_action": state["action"], "amount": state["amount"], "message": "Approve this transfer?", }) if decision == "approve": return {"approval_status": "approved"} return {"approval_status": "rejected"}

When `interrupt()` runs, the graph stops completely at that point. The `app.invoke()` call that triggered it returns with an interrupt-type object instead of the final result, signaling that human input is needed to continue.

Resuming with Command(resume=...)

Execution resumes with a `Command` object, passing the same original `thread_id` so the checkpointer can recover the exact state where it paused:

config = {"configurable": {"thread_id": "transfer-approval-9931"}} result = app.invoke( {"action": "transfer", "amount": 15000}, config=config, ) # result contains the pending interrupt # ... a human reviews it in an admin panel and approves ... final_result = app.invoke( Command(resume="approve"), config=config, )

Note that the second `invoke()` doesn't repeat the original input: LangGraph rebuilds the state from the checkpoint and continues from the exact point of interruption, without re-running the previous nodes.

interrupt_before and interrupt_after as a declarative alternative

For cases where the pause point is always the same node (for example, always before running a tool that writes to an external system), you can declare it at compile time instead of inside the node's logic:

app = builder.compile( checkpointer=checkpointer, interrupt_before=["execute_transfer"], )

This automatically pauses before `execute_transfer` runs, without needing an explicit call to `interrupt()` inside that function — useful when the control point is structural and doesn't depend on a condition evaluated at runtime.

Editing state before resuming

A frequent case isn't just approve or reject, but the human correcting a parameter before continuing — for example, adjusting the amount of the transfer proposed by the agent. This is solved by updating the state directly via the checkpointer before resuming:

app.update_state( config, {"amount": 12000}, # the human corrects the amount proposed by the agent ) final_result = app.invoke(Command(resume="approve"), config=config)

`update_state()` modifies the persisted checkpoint without running any node, which lets the human approval interface also be an editing interface, not just a binary yes/no button.

Designing the approval panel

In real deployments, the approval flow lives outside the agent's process: a backend that exposes pending interrupts (querying `app.get_state(config)` to list paused threads) and an interface — admin panel, Slack channel, ticket — where a human operator reviews the full context before deciding. The architecture recommendation is to never couple this wait's timeout to the agent's process: the checkpointer persists state indefinitely until someone resumes it, so an approval can take minutes or days without the system losing context or consuming compute resources while it waits.

Carlos Montiel
Enterprise AI Solutions Architect
Specialist in LLMs, Agents, and Orchestration
guatemalia.com/en/#contact · info@guatemalia.com

Need to implement AI at your company?

Carlos Montiel is an enterprise AI solutions architect. He implements LLMs, Agents, RAG, and orchestrators for companies across Guatemala and Latin America. Reach out for a consultation.

Contact Carlos Montiel

info@guatemalia.com