Human in the loop
Human in the loop (HITL) adds a pause or checkpoint to the agent’s decision making. For a risky action, the agent proposes and a person decides. It is the answer to financial and data-integrity riskProbabilistic risksThe model is probabilistic, so its failures are too: three threats, four things at stake.Opens in a new tab that no guardrailLLM guardrailsChecks around the model, so a bad input or a bad output is caught by something that does not rely on the model behaving.Opens in a new tab on the text can give.
Which actions pause
Not all of them. The orchestrator holds hard-coded rules: for example, a refund above 1000 needs a human, anything below goes straight through. The rule is code, so the model cannot argue its way around it. OWASP names the same control: require a person to approve high-impact actions, and the MCP specification says there should always be a human able to deny a tool call.
In LangGraph
interrupt() stops the run and surfaces a value. The graph’s state is saved by a checkpointer, and Command(resume=...) continues it with the human’s answer as the return value of interrupt().
from typing import TypedDict from langgraph.checkpoint.memory import InMemorySaverfrom langgraph.graph import END, START, StateGraphfrom langgraph.types import Command, interrupt class State(TypedDict): amount: float status: str def refund(state: State) -> dict: if state["amount"] > 1000: approved = interrupt({"action": "refund", "amount": state["amount"]}) if not approved: return {"status": "rejected"} return {"status": "refunded"} graph = ( StateGraph(State) .add_node("refund", refund) .add_edge(START, "refund") .add_edge("refund", END) .compile(checkpointer=InMemorySaver())) config = {"configurable": {"thread_id": "refund-1"}}paused = graph.invoke({"amount": 2500, "status": "new"}, config) # stops at interrupt() graph.invoke(Command(resume=True), config) # the human said yesThe paused run needs a checkpointer and a thread_id to find it again. LangChain also ships HumanInTheLoopMiddleware, where each tool is set to allow approve, edit, reject or respond.
The catch
Latency. A person is slow, and the run waits. It is the best of both worlds only for the few actions that are worth the wait.
The node restarts. On resume, LangGraph re-runs the node from the top, not from the interrupt() line. Any side effect placed before it should be safe to repeat, or it can run twice.
Sources
- Interrupts, LangGraph Docs · accessed October 5, 2026
- Human-in-the-loop, LangChain Docs · accessed October 5, 2026
- LLM06:2025 Excessive Agency, OWASP GenAI Security Project · accessed October 5, 2026
- Tools, Model Context Protocol specification (2025-06-18) · accessed October 5, 2026