Skip to main content
The Human-in-the-Loop (HITL) middleware lets you add human oversight to agent tool calls. When a model proposes an action that might require review—for example, writing to a file or executing SQL—the middleware can pause execution and wait for a decision. It does this by checking each tool call against a configurable policy. If intervention is needed, the middleware issues an interrupt that halts execution. The graph state is saved using LangGraph’s persistence layer, so execution can pause safely and resume later. A human decision then determines what happens next: the action can be approved as-is (approve), modified before running (edit), rejected with feedback (reject), or responded to directly (respond) for “ask user” style tools.

Interrupt decision types

The middleware defines four built-in ways a human can respond to an interrupt: The available decision types for each tool depend on the policy you configure in interrupt_on. When multiple tool calls are paused at the same time, each action requires a separate decision. Decisions must be provided in the same order as the actions appear in the interrupt request. Use reject when the human is denying the requested action. Use respond only when the human is acting as the tool, such as answering an ask_user prompt. Do not use respond to deny side-effecting tools, because its message is treated as a successful tool result.
When editing tool arguments, make changes conservatively. Significant modifications to the original arguments may cause the model to re-evaluate its approach and potentially execute the tool multiple times or take unexpected actions.

Configuring interrupts

To use HITL, add the middleware to the agent’s middleware list when creating the agent. You configure it with a mapping of tool actions to the decision types that are allowed for each action. The middleware will interrupt execution when a tool call matches an action in the mapping.
You must configure a checkpointer to persist the graph state across interrupts.In production, use a persistent checkpointer like AsyncPostgresSaver or MongoDBSaver. For testing or prototyping, use InMemorySaver.When invoking the agent, pass a config that includes the thread ID to associate execution with a conversation thread. See the LangGraph interrupts documentation for details.
interruptOn
object
required
Mapping of tool names to approval configs
Tool approval config options:
allowAccept
boolean
default:"false"
Whether approval is allowed
allowEdit
boolean
default:"false"
Whether editing is allowed
allowRespond
boolean
default:"false"
Whether responding/rejection is allowed

Conditional interrupts

By default, every tool call listed in interrupt_on pauses for review. To pause only some calls, add a when predicate to a tool’s InterruptOnConfig. The predicate receives a ToolCallRequest and returns True to interrupt or False to auto-approve, so you can gate on the tool’s arguments. Conditional interrupts are currently available in Python only.

Responding to interrupts

When you invoke the agent, it runs until it either completes or an interrupt is raised. An interrupt is triggered when a tool call matches the policy you configured in interrupt_on. With version="v2", the result is a GraphOutput with an interrupts attribute containing the actions that require review. You can then present those actions to a reviewer and resume execution once decisions are provided.

Decision types

Use approve to approve the tool call as-is and execute it without changes.

Multiple decisions

When multiple actions are under review, provide a decision for each action in the same order as they appear in the interrupt:

Streaming with human-in-the-loop

You can stream real-time updates while the agent runs and handles interrupts using stream_events(). Use stream.messages to stream LLM tokens and stream.values to check agent state snapshots for interrupts.
See the Streaming guide for more details on stream modes.

Execution lifecycle

The middleware defines an after_model hook that runs after the model generates a response but before any tool calls are executed:
  1. The agent invokes the model to generate a response.
  2. The middleware inspects the response for tool calls.
  3. If any calls require human input, the middleware builds a HITLRequest with action_requests and review_configs and calls interrupt.
  4. The agent waits for human decisions.
  5. Based on the HITLResponse decisions, the middleware executes approved or edited calls, synthesizes ToolMessage’s for rejected calls, returns human replies directly as ToolMessage’s for respond decisions, and resumes execution.

Custom HITL logic

For more specialized workflows, you can build custom HITL logic directly using the interrupt primitive and middleware abstraction. Review the execution lifecycle above to understand how to integrate interrupts into the agent’s operation.