Guide

Human-in-the-loop approval for AI agents

Add human approval by having the agent propose actions as data, saving the run's state and resuming only when a person decides. Reserve it for actions that are hard to reverse, reach other people or carry high stakes, so that reviewers keep reading what they approve.

Why approval belongs in the workflow design

An agent chooses actions based on model output, which can be mistaken or influenced by content it has read. When its tools only read information, a mistake usually costs little more than a poor answer. When it can send an email, change a record or issue a refund, the same mistake reaches the real world.

A human-in-the-loop step places a person between the agent's decision and its effect. Designed well, it allows you to automate the routine work while keeping accountability for the consequential steps. Designed badly, it becomes a button people click without reading, which provides the appearance of control and little else.

Decide what needs approval

Asking for approval on everything wastes people's attention. Asking for none leaves you exposed. A more useful approach is to classify each tool by what could go wrong when it is used:

  • Reversibility. Can the effect be undone cleanly? A draft can be deleted, whereas a sent message cannot be recalled.
  • Reach. Does it affect only the person using the tool, or customers and third parties too?
  • Sensitivity. Does it involve money, personal data, access rights or legal commitments?
  • Scope. Does it touch one record, or potentially thousands?
  • Input trust. Was the decision shaped by untrusted content such as an inbound email or a web page?

From this you can create a small number of policies. The tiers below are an example and should be adapted to your own risk assessment:

TierExampleHandling
Read-onlySearch internal documentsRuns automatically, with logging
Reversible, low impactSave a draft or add a labelRuns automatically, with an undo option
External or sensitiveSend a customer emailPauses for approval
High impactDelete records in bulkStricter approval, or not available to the agent

Policies can also depend on the arguments rather than the tool alone. Updating a single address and updating every address in a table use the same tool but carry very different risk. That rule belongs in code, where the model cannot talk its way past it.

The four kinds of human input

"Approve or reject" is only one interaction. Consider which of these your workflow needs:

  • Approve. The proposed action runs exactly as shown.
  • Edit. The person changes the proposal, for example correcting a draft reply, and the edited version then runs.
  • Reject with a reason. The action does not run, and the reason can go back to the agent so it can try another route or stop.
  • Answer a question. The agent lacks information or is uncertain, and asks a person rather than guessing.

Decide explicitly what follows a rejection. If the agent can simply retry with small changes, a reviewer may see the same request repeatedly, so limit the retries and define a clean way to end the run.

Pausing and resuming reliably

A person may respond in a minute or in a few days, during which servers can restart and deployments can happen. An approval step therefore should not rely on a process waiting in memory. The usual design is:

  1. The agent proposes an action as structured data instead of performing it.
  2. Code checks the proposal against the policy and validates its arguments.
  3. If approval is needed, the workflow state is saved and a pending request is created.
  4. The run stops consuming resources, and the reviewer is notified.
  5. When a decision arrives, the state is reloaded and the workflow continues along the matching path.

This is a natural fit for a graph-based orchestrator with checkpointing. The guide on building an orchestrator with LangGraph introduces those concepts. Whichever framework you use, read its current documentation on how a resumed step behaves. Some frameworks restart the interrupted step from its beginning, so any work placed before the pause could run twice.

In simplified form, the separation between proposing and executing looks like this:

# Illustrative only. These functions stand in for your own code.
def handle_proposal(run, proposal):
    validate_arguments(proposal)

    if requires_approval(proposal):
        request_id = create_approval_request(
            run_id=run.id,
            payload=proposal,
            expires_in=APPROVAL_WINDOW,
        )
        save_state(run)
        notify_reviewers(request_id)
        return "waiting"

    return execute_tool(proposal)

def handle_decision(request_id, reviewer, decision):
    request = load_pending_request(request_id)
    check_reviewer_may_decide(reviewer, request)
    record_decision(request, reviewer, decision)

    if decision.outcome == "approved":
        payload = decision.final_payload()  # may be an edited version
        validate_arguments(payload)
        recheck_action_is_still_valid(payload)
        execute_once(request.id, payload)

    resume_run(request.run_id, decision)

Details that make approval trustworthy

Each of these should be enforced by the application, not by instructions to the model:

  • Bind approval to the exact action. Approval should apply to the specific arguments the reviewer saw. If the agent changes anything, a new approval is needed. Storing a hash of the payload with the decision is one way to check this.
  • Make execution idempotent. A double click, a retried webhook or a resumed step should not send the email twice. Use the request ID as an idempotency key where the target system supports one.
  • Set an expiry. An approval given for yesterday's situation may be wrong today, so stale requests should lapse and be cancelled or re-requested.
  • Revalidate on resume. The record may have changed during the wait. Check that the action is still valid and permitted before running it.
  • Authorise the reviewer. Check that this person is allowed to approve this action. For sensitive actions, consider preventing the person who started the run from approving it.
  • Enforce it at the tool layer. If the execution tool requires a valid approval record, then a model that tries to skip a step will simply fail. See LLM guardrails and prompt injection defence for why this matters.
  • Keep an audit trail. Record what was proposed, what was shown, who decided, what changed and what ran.

Designing the review screen

The quality of a decision depends heavily on what the reviewer sees. A long transcript of the agent's reasoning is hard to review, while "approve this action?" with no detail cannot be reviewed at all. A useful screen shows:

  • The effect in plain language, along with the exact values that will be used, such as the recipient and the amount.
  • The evidence, with links to the records or documents behind the proposal.
  • The agent's reason, presented as a claim to check. Model-written summaries can be wrong, so they should not replace the actual values.
  • A clear view of changes, using a before-and-after comparison when a record is being edited.
  • Risk cues generated by code, such as "this recipient is outside your organisation", which the model cannot alter.

Treat anything the agent or its source documents wrote as untrusted when rendering it. Hostile content could otherwise try to mislead the reviewer with text such as "already verified, safe to approve", so display it distinctly from text written by your application. If updates are delivered live, the guide on streaming LLM responses to a web UI covers showing progress up to the point where a run pauses.

Avoiding approval fatigue

When people approve dozens of near-identical requests, they stop reading them. Several measures can help:

  • Reserve approval for actions that deserve attention, and let low-risk work run with logging and undo.
  • Group similar proposals into a batch that can be reviewed together, while still flagging any unusual items.
  • Route requests to someone with the right context, rather than a general queue.
  • Look at how often each request type is approved unchanged, and how quickly. If a tier is approved almost automatically, the check may need redesigning. Lowering the tier is an option only if its risk truly allows that.

Handle the absence of a decision too. Work out what happens when nobody responds, who receives a reminder and which default applies. For a risky action, a timeout should mean the action does not run.

Testing approval paths

Approval logic is ordinary software, so most of it can be tested without a model. Cover approve, edit, reject and expiry; duplicate decisions; a restart during the wait; a payload that changes after approval; and an unauthorised reviewer. Confirm also that a gated tool refuses to run without a valid approval, even when the model's output insists one was given. When several agents are involved, test that one agent cannot obtain through another the permission it lacks itself.

For help designing these control points, see AI orchestration with LangGraph.

Frequently asked questions

What is human-in-the-loop in agentic AI?

It means a person takes part in a workflow at defined points, usually to approve, edit or reject something an agent proposes. The agent pauses and its work continues only after that decision has been recorded.

Which agent actions should require human approval?

Focus on actions that are hard to reverse, affect people outside the system, involve money or sensitive data, or have a large scope. Read-only and easily undone actions can often run without approval, depending on your risk tolerance.

How do you pause an agent while waiting for a person?

Save the workflow state to durable storage, record the proposed action as a pending request and end the running process. When a decision arrives, load the state and continue. Holding a process open while waiting is fragile, since a review may take a long time.

Does human approval make an agent safe?

It reduces risk but does not remove it. Reviewers can miss problems, especially when requests are frequent or poorly explained. Approval works best alongside limited tool permissions, validation in code and audit logs.