← All posts
AI2026.10.05 02:13

How to Design Human-in-the-Loop for AI Agents

If an agent's action cannot be undone, a human must approve it. Inline, confidence-based, and multi-level approval gates built with LangGraph interrupts and checkpoints.

Table of Contents

  1. Overview
  2. Core Concepts and Mechanics of Human-in-the-Loop
  3. Approval Stage Design Patterns
  4. Implementing Human-in-the-Loop with LangGraph
  5. Performance and Trade-off Analysis
  6. Considerations for Production Deployment
  7. Closing Thoughts

Overview

The Problem

As AI agents move into real projects in earnest, the question of how much automation to allow has become one of the central design challenges. An agent that sends emails automatically, modifies a database, or approves payments through an external API is clearly efficient — but a single wrong call can produce results that are hard to undo. Human-in-the-Loop (HitL) is the design principle that bridges this gap. It structurally embeds a human confirmation or approval step inside the automation pipeline, right before the agent takes a critical action. This post starts with the conceptual motivation for HitL and then walks through the patterns and operational practices for implementing it in a real agent pipeline.

The Limits of the Old Approach

Early LLM usage was simple. Because the structure was a single request-response cycle — user sends input, model replies — a model mistake amounted to one wrong answer. Agent architectures changed that. An agent autonomously chains multiple steps and manipulates real systems (filesystems, databases, external services) at each step. A bad judgment by the agent then propagates in a cascade. Instead of "draft an email" it becomes "send an email." Instead of "generate a query" it becomes "execute DELETE." Fully automated pipelines offer the benefit of speed, but they carry the structural vulnerability of no verification.

AI Agent Reasoning Loop A flowchart where a user request is passed to agent reasoning, which calls a tool, receives the result, and iterates through a reasoning loop before returning a final response. Re-reason on done INPUT User Request AGENT Agent Reasoning LLM · reasoning TOOL Tool Call DB · API · File RESULT Return Result OUTPUT Final Response Reasoning Loop Main Flow (focal) General Flow Process Step Key Step

The tool-call step in an automation pipeline is the point that creates side effects that are hard to undo.


Core Concepts and Mechanics of Human-in-the-Loop

The Automation Spectrum and Where HitL Sits

It helps to think of agent automation level as a spectrum. One end is fully manual — a human makes every decision. The other end is full automation — the agent owns every judgment and every action. HitL does not sit somewhere in the middle. It is a design philosophy that selectively inserts intervention points only at specific nodes, based on risk and irreversibility. Generating an email draft can be automated freely; the actual send warrants a human review. Read queries can run automatically; UPDATE and DELETE queries require approval. HitL is not about giving up on automation — it is about deliberately scoping where automation applies.

Automation level Description When it fits Watch out for
Fully manual Human decides every step High-risk, high-cost decisions Slow, does not scale
HitL (approval gate) Human intervenes only at critical steps When you need automation plus a safety net Must design for approval delays
Supervised automation Runs automatically, human reviews after Fast execution, post-hoc review is acceptable Correction cost after execution
Full automation Agent decides and executes everything Low-risk, high-repetition tasks Risk of error propagation

How It Works: Persisting and Resuming State

The technical core of HitL is a mechanism that persists the agent's execution state and resumes from exactly the point of interruption when an external event — a human approval — arrives. Describing it as "the agent pauses and the human replies" makes it sound simple, but the actual implementation involves several layers of problems. The agent's context (memory, previous tool execution results, conversation history) must not be lost while waiting for approval. Multiple agent instances must be able to wait for different approvals at the same time. And after approval, the right instance must resume in the right state. Modern agent frameworks provide a checkpointing mechanism for exactly this purpose.

Human-in-the-Loop Agent Execution Flow When an agent detects a critical action during node execution, it saves a checkpoint and waits for human approval. On approval it resumes execution; on rejection it aborts or runs an alternative. No Yes Approve Reject Agent Start STEP Node Execute Critical Action? SAVE Save State checkpoint WAIT Awaiting Approval Approval Result RESUME Restore State Resume ABORT Abort Run Alternative NEXT Next Node Done LEGEND Normal Flow Approval Path Resume Waiting Abort/Error

Saving state at a checkpoint and resuming from that exact point when the approval signal arrives is the core of HitL implementation.

Classifying Intervention Triggers

Putting an approval gate on every agent action eliminates the benefits of automation. In real projects, deciding which actions should trigger an intervention is one of the most important design decisions you will make. Three criteria cover most cases. First, irreversibility — actions that are difficult or impossible to undo after execution (data deletion, email delivery, payment processing) always get an approval gate. Second, threshold-based — a gate is inserted dynamically when the monetary amount or scope of impact exceeds a certain level. Third, confidence-based — when the agent itself has low confidence in its own judgment, it delegates to a human. Combining these three criteria lets you make most gate-placement decisions systematically.

Approval gates are not a sign of distrust in the agent. They exist because some actions require a human to share responsibility, even when the agent is correct.


Approval Stage Design Patterns

Pattern 1: Inline Approval Gate

The simplest pattern. An interrupt node is inserted immediately before a specific node in the agent graph, and execution pauses until a human response arrives. In LangGraph this is declared with the interrupt_before or interrupt_after parameter. The advantage is that the implementation is simple and the flow is easy to follow. Because the nodes at which execution stops are declared statically at graph-definition time, approval points are easy to identify during code review or audits. The downside is limited flexibility. It is not a good fit when gates need to be inserted or skipped dynamically based on conditions.

Human-in-the-Loop Approval Gate Flow Shows the flow where an AI agent selects a tool, passes through an approval gate (interrupt), then either executes the tool and processes the result on approval, or returns a message on rejection. Approve Reject INPUT Tool Select tool call GATE Approval Gate interrupt ACTION Tool Execute tool.run() OUTPUT Process Result REJECTED Return Msg user feedback Normal path Approved Rejected (interrupt) Decision gate Rejected state

An inline gate is a fixed branch point in the graph; the flow itself splits based on the approval decision.

Pattern 2: Dynamic Gate (Confidence-Based)

In this pattern the agent decides at runtime whether to request approval. For example: if the number of records to be deleted is under 100, execute automatically; if it is 100 or more, request approval. Or: delegate to a human when the agent's own confidence score falls below a threshold. This pattern effectively reduces unnecessary approval requests and lowers the human's approval fatigue. Requiring approval for every action in practice causes the responsible person to become desensitized to approval requests — the same phenomenon well-known in security as alert fatigue. Dynamic gates prevent this while still guaranteeing intervention when the risk is high.

Human-in-the-Loop Decision Flow A Human-in-the-Loop flow where the agent reasoning result branches to an approval request if the impact scope threshold is exceeded, or proceeds to auto-execution if not. No Yes Approve Reject AGENT Agent Reasoning Impact Scope Over Threshold? HUMAN Approval Request AUTO Auto Execute ALT Alt Execute RESULT Result LEGEND Key Step Exec Step Result Store Alt Path

Deciding dynamically whether to insert a gate based on a threshold keeps the right balance between approval frequency and risk level.

Pattern 3: Multi-Level Approval

In regulated industries — finance, healthcare, law — a single approval is sometimes not enough. The larger the amount and the wider the impact, the higher the authority required. The multi-level approval pattern arranges multiple approval gates in series or in parallel. Serial arrangement means each stage must be approved in order before proceeding. Parallel arrangement means multiple reviewers evaluate simultaneously, and the request passes when a majority or all agree. The key design question in this pattern is whether to isolate each approver from the previous approver's opinion. For audit purposes it is fine to make all opinions visible, but when independent judgment matters, each approver should receive only the original content.

Approval structure Pass condition Example use case Delay risk
Single approval 1 approver agrees General operational approvals Low
Serial multi-stage All stages pass in order Regulatory compliance, audit trails High
Parallel majority Majority agrees Committee decisions Medium
Parallel unanimous Everyone agrees High-risk, irreversible actions Very high

Implementing Human-in-the-Loop with LangGraph

Basic Setup

LangGraph is a framework in the LangChain ecosystem for implementing state-machine-based agent graphs. Since version 0.1 it has officially supported the Checkpointer and interrupt features, making it one of the most practical tools for HitL implementations. MemorySaver is an in-memory checkpointer for development and testing; in production use SqliteSaver or PostgresSaver. The checkpointer's job is to serialize and save the graph state before and after each node execution, so that when an agent stops at an interrupt the state is persisted.

python
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import interrupt, Command
from typing import TypedDict, Annotated
import operator

# Graph state definition: manage message history and approval context together
class AgentState(TypedDict):
    messages: Annotated[list, operator.add]
    pending_action: dict           # information about the action awaiting approval
    action_approved: bool          # approval result

def should_interrupt(state: AgentState) -> bool:
    """Determine whether this is a critical action."""
    action = state.get("pending_action", {})
    # delete, update, and send actions always require approval
    return action.get("type") in {"delete", "update", "send"}

def approval_node(state: AgentState) -> AgentState:
    """Approval gate node: waits until a human response arrives."""
    action = state["pending_action"]
    # interrupt() saves the current state and halts execution.
    # When resumed, the human's response is passed as the return value of interrupt().
    response = interrupt({
        "question": f"Do you approve the following action?",
        "action": action,
    })
    # response is delivered as Command(resume={"approved": True/False})
    return {"action_approved": response.get("approved", False)}

# Compile the graph with a checkpointer
checkpointer = MemorySaver()
graph = (
    StateGraph(AgentState)
    .add_node("approval_gate", approval_node)
    # ... add remaining nodes
    .compile(checkpointer=checkpointer, interrupt_before=["tool_execution"])
)

interrupt() immediately halts the current node's execution and saves state to the checkpointer. Passing a Command(resume=...) object from outside resumes execution from exactly the point of interruption.


Full Implementation: The Entire Approval Flow

Here is the complete flow: send an approval request, receive a response, and resume execution. In real-world usage, approval notifications are sent via a Slack webhook, email, or an internal dashboard. When a reviewer clicks the approval button, that event is delivered to the backend together with the agent's thread_id.

python
import asyncio

# First run of the agent: interrupt fires just before the critical action
config = {"configurable": {"thread_id": "workflow-001"}}

initial_state = {
    "messages": [{"role": "user", "content": "Delete the withdrawn accounts from the customer table"}],
    "pending_action": {},
    "action_approved": False,
}

# Step 1: invoke the graph → automatically stops at the interrupt point
result = graph.invoke(initial_state, config)
# result["__interrupt__"] = [{"value": {"question": "...", "action": {...}}}]

interrupted_info = result.get("__interrupt__", [])
if interrupted_info:
    approval_request = interrupted_info[0]["value"]
    # Send Slack notification (use webhooks in a real implementation)
    print(f"Approval request: {approval_request['question']}")
    print(f"Action details: {approval_request['action']}")

# Step 2: resume after the reviewer approves
# Pass the resume signal and the approval result together via Command(resume=...)
from langgraph.types import Command

resume_result = graph.invoke(
    Command(resume={"approved": True}),
    config  # use the same thread_id to restore state
)
# resume_result contains the final completed state
print(f"Execution complete: {resume_result['messages'][-1]['content']}")

The key point is that both the initial invoke call and the resume call use the same config containing the same thread_id. The checkpointer uses this ID as a key to save and retrieve state.


Testing and Validation

HitL testing must cover two scenarios without exception. First, verify that the correct action executes when approval is granted. Second, verify that the agent moves safely to an alternative path when the request is rejected or times out. Timeout handling is especially important: a separate expiry policy is needed to prevent the agent from waiting indefinitely when the approver is unavailable or unresponsive.

Human-in-the-Loop interrupt handling flow Flow diagram where an AI agent executes invoke, determines whether an interrupt occurs, and branches into resume, abort, or expire based on notification, timeout, and approval. Yes No Yes No Yes No invoke interrupt raised? NOTIFY Notify OK Complete Before timeout response? Approved ? OK Resume EXPIRE Expire ABORT Abort LEGEND Start Decision (interrupt/response/approval) OK·Resume Abort·Expire

Explicitly validating all three paths — timeout, rejection, and approval — in tests is what prevents unexpected behavior in production.


Performance and Trade-off Analysis

The Reality of Latency

Introducing HitL increases the total pipeline latency by however long it takes for a human to respond. This is an intentional design choice, not a bug, but it does affect overall system throughput. Using async processing means that while one workflow waits for approval, others can proceed, minimizing overall throughput loss. From measurements on real projects, approval wait times during business hours averaged anywhere from a few minutes to tens of minutes. Managing this as an SLA requires an escalation policy: if the primary approver does not respond within N minutes, the request is automatically forwarded to a secondary approver.

Processing mode Average latency (approval included) Throughput Suitable workload
Synchronous, serial Same as human response time Low Single flow where order matters
Async, parallel Based on the longest path High Multiple independent workflows
Batch approval N requests handled at once Medium Many similar, repetitive actions

Comparison with Alternative Approaches

The approach most often compared to HitL is post-hoc review: the agent executes first, then a human reviews the logs and rolls back if something is wrong. This approach is superior in throughput, but it cannot be applied to irreversible actions such as sending email or processing payments. HitL, on the other hand, guarantees review before execution and is therefore better suited for regulatory compliance and audit requirements. Another alternative is an automatic rollback mechanism: wrap all agent actions in transactions and auto-recover on failure. This works well for database operations, but is hard to apply when there are no transaction semantics — for example, sending email or calling external APIs.

Human-in-the-Loop Gate Decision Flow Based on Irreversibility A decision flow starting from whether an action is irreversible, evaluating rollback feasibility and audit sufficiency in order, resulting in one of: HitL pre-approval, auto-execute with rollback standby, or post-execution review. Yes No Yes No Yes No Start Irreversible action? GATE HitL Gate Pre-approval Rollback possible? AUTO Auto Execute + Rollback Standby Audit sufficient? AUDIT Post-Review Log-based LEGEND Decision HitL Gate Auto Process Post-Review Force HitL

The right order is: first assess irreversibility and rollback feasibility, then choose the appropriate intervention strategy.

When to Choose HitL

Not every agent needs HitL. There are three main situations where it is the right choice. First, regulated environments: in finance, healthcare, and law, a human review record for certain actions is a legal requirement. Second, early deployment: when an agent's reliability has not been sufficiently validated, approval gates create a feedback loop for catching mistakes and improving the agent. Third, high cost of mistakes: when the cost of an error — bulk data deletion, mass email sending, large transactions — far exceeds the benefit of automation, HitL is the rational choice.


Considerations for Production Deployment

Common Mistakes and Pitfalls

The most frequent problem when first introducing HitL is state loss. Using interrupt without a checkpointer configured means all state waiting for approval disappears when the process restarts. In production, always use a persistent storage backend (PostgreSQL, Redis) for the checkpointer. The second pitfall is duplicate execution. When a resume signal is delivered more than once due to a network issue, you need idempotency guarantees to prevent the same action from executing twice. Include a unique execution ID in the thread_id and add logic that detects attempts to resume an already-completed execution. The third problem is insufficient approval context. If the approval request message does not give the reviewer enough information to make a judgment, the review degenerates into a rubber-stamp process where the reviewer always approves or always rejects.

Resume Signal Processing Flow Shows how a Human-in-the-Loop AI agent, upon receiving a resume signal, checks for duplicate execution ID and state validity in sequence, then branches into resume execution, ignore/log, or error notification. Yes No Yes No Resume Signal TRIGGER Exec ID Duplicate? State Valid? LOG Ignore·Log Resume Execution ERROR Error Notify Start Decision OK Error Ignore

Duplicate-resume prevention and state validity checks are the minimum conditions for guaranteeing idempotency in production.

Monitoring and Debugging

The metrics to monitor in an agent pipeline that includes HitL differ from those for a typical service. Beyond response time and throughput, you need to track the number of instances waiting for approval, average approval wait time, approval rate vs. rejection rate, and timeout frequency. A sudden drop in approval rate can be a signal that the agent has started producing actions that deviate from what reviewers expect. Frequent timeouts call for a review of the escalation policy. Integrating an agent tracing tool such as LangSmith lets you visually inspect the full execution path, interruption points, and resume history for each thread_id, which substantially reduces debugging time.

Metric Normal range Warning signal Response
Instances waiting for approval Stable Sharp increase Check for processing bottleneck or notification errors
Average approval wait time Within SLA Exceeds SLA Reconfigure escalation policy
Approval rate 80%+ Below 50% Review agent action quality
Timeout frequency Under 5% per month Over 20% per month Check approver notification channel

Scaling and Migration

You need to design upfront for how to scale the HitL system as the number of agents and workflow complexity grows. A structure where a single person handles all approvals becomes a bottleneck, so establish a routing policy that distributes approval responsibilities based on workflow type or scope of impact. For action types where data has proven the agent reliable enough, apply a progressive automation strategy that gradually removes HitL gates. To do this, include a feedback loop in the design from the start that records both the approval decision and the actual outcome. Being able to review after the fact whether a rejected action was genuinely wrong or an over-rejection is what enables an objective assessment of the agent's reliability.

HitL Trust-Based Automation Loop The AI agent executes actions and logs results, accumulates approvals and logs to evaluate trust, removes the HitL gate if trust is sufficient, or fine-tunes and re-executes if not. Yes No After retrain ACTION Execute Action + Log Result LOG Approval Status + Result Log STORE Accumulate Data Trust Sufficient? RESULT Remove HitL Gate FINETUNE Fine-tune Agent LEGEND Key Step Automated Improvement Accumulated Data Feedback Loop

The more approval history data accumulates, the stronger the evidence base for deciding which action types the agent can be trusted with.


Closing Thoughts

Key Takeaways

This post examined how to structurally embed Human-in-the-Loop into AI agent automation pipelines. The technical core of HitL is state checkpointing and an external-event-driven resume mechanism. LangGraph's interrupt combined with a checkpointer is the practical way to achieve this. Approval patterns fall into three types — inline gate, dynamic gate, and multi-level approval — and you choose the right one based on the action's irreversibility and scope of impact. In production, the key management concerns are preventing state loss, blocking duplicate executions, defining an escalation policy, and monitoring approval quality.

Decision Criteria

The first question to ask when considering HitL is: "Can we undo it if the agent makes a mistake?" If the answer is no, and if the cost of that mistake significantly outweighs the benefit of automation, then HitL is not optional — it is required. Conversely, putting approval gates on low-risk repetitive tasks where the agent's reliability is already well-established undermines the very benefits of automation. Good HitL design comes from the balance of intervening as little as possible while making intervention certain whenever it is truly needed. That balance point should be continuously adjusted as the agent matures and operational data accumulates.