Why an agent acting alone is not always the goal
Part 2 described the agent loop as observe, think, act, repeat. Part 3 showed how the act step usually means calling a tool: searching, reading a file, writing to a database, sending a message. Part 8 added guardrails for when things go wrong: retries, timeouts, and stopping conditions so the loop does not spin forever on a problem it cannot solve. All of that machinery assumes the agent keeps going by itself. This part is about the moments where you deliberately interrupt that assumption and bring a person into the loop before, during or after an action.
The reason is simple. An agent that reads a document and summarises it can be wrong without much cost; you reread the summary, you notice the mistake, you move on. An agent that sends a refund, deletes a record, publishes a post under your company's name, or pushes code to production can be wrong in a way that is expensive, embarrassing or impossible to undo. The loop does not know the difference between these two kinds of actions unless you tell it. Human in the loop is the design pattern for telling it.
What human in the loop actually means
Human in the loop, often abbreviated HITL, means a point in the agent's execution where it pauses and waits for a person to look at something before the loop continues, or where a person's input becomes part of what the agent acts on next. It is not the same as a person simply using a chat interface to talk to an agent turn by turn; that is just how most agents are used already. HITL specifically refers to a checkpoint inserted around a particular action, usually one with enough consequence that letting the agent proceed unsupervised is not acceptable.
It helps to separate three positions a person can occupy relative to an automated system, because the phrase "human in the loop" gets used loosely for all three:
- In the loop: the system cannot proceed past a certain point without a person's explicit decision. Nothing happens until someone says yes, no, or here is a correction.
- On the loop: the system runs on its own, but a person is watching in real time or near real time and can intervene, pause or override it if something looks wrong.
- Out of the loop: the system runs fully unsupervised and a person only reviews the outcome afterwards, if at all, usually through logs or occasional audits.
These are not three separate technologies, they are three settings on the same dial. Part 4 talked about the spectrum between a fixed workflow and a free-roaming agent; this is a related but different spectrum, running from heavy supervision to no supervision. You choose a setting per action, not once for the whole system. A coding agent might be on the loop for reading files and running tests, and in the loop for anything that touches the production branch.
Four patterns of human involvement
In practice, human in the loop shows up as one of a small number of recurring patterns. Knowing their names helps when you are reading about a system or deciding which one to build.
Approval gates
The agent decides what it wants to do, presents the proposed action to a person, and waits. The person approves, rejects, or edits the proposed action before it runs. This is the strictest pattern: nothing happens without a yes. A support agent that drafts a refund of 80 dollars and waits for a manager to click approve before the payment actually goes out is using an approval gate.
Review and edit
The agent performs the action, or produces a draft of it, and a person reviews the result afterwards, with the option to correct it before it is finalised or published. The difference from an approval gate is timing: the work is done first, then checked, rather than checked then done. A content agent that writes a draft blog post and puts it in a queue for an editor to read and adjust before it goes live is using review and edit. This pattern suits anything where producing a draft is cheap and reversible, but publishing it is not.
Escalation
The agent itself decides it is not confident enough, or the situation falls outside what it was built to handle, and it hands the problem to a person rather than guessing. This connects directly to the stopping conditions from part 8: instead of retrying endlessly or returning a low-confidence answer, a well-designed agent recognises certain failure signatures and routes them to a human. A customer asks for a refund of 4,000 dollars when the agent's instructions only cover refunds up to 200 dollars; the right behaviour is not to refuse or to guess, it is to escalate.
Monitoring and audit
The agent runs unsupervised, but every action is logged in a way a person can inspect later, and ideally a person is watching a live feed of actions closely enough to catch a problem quickly. This is the lightest form of human in the loop, closer to the "out of the loop" end of the spectrum, but it still counts because the existence of review changes how the system is built: logs need to be complete, actions need to be attributable, and there needs to be a way to reverse or compensate for a bad action after the fact.
Most real systems use more than one of these patterns at once, assigned to different actions by risk level, which is the subject of the next section.
Deciding what needs a human: a simple risk model
The temptation when building your first agent with real tool access is to either gate everything, which makes the agent feel pointless because a person has to approve every step, or to gate nothing, which works fine until the agent does something costly. A better approach is to score each action the agent can take along two dimensions and let the score decide the pattern.
- Reversibility: can the action be undone cheaply and quickly if it turns out to be wrong? Reading a file is fully reversible, it changes nothing. Sending an email to a customer is not reversible at all; once it is sent, it is sent.
- Impact: if the action is wrong, how much does it cost in money, trust, legal exposure or time to fix? Deleting a test record costs nothing. Deleting a customer's account record costs a support ticket, an apology and possibly a data recovery effort.
Put the two together and you get a rough four-way split that is enough to design around without needing a formal framework:
- Low impact, reversible: let the agent act with no gate. Example: searching documentation, reading a spreadsheet, drafting a reply that nobody has seen yet.
- Low impact, hard to reverse: use review and edit, so a person can catch mistakes before they become visible, but the agent is not blocked while it works. Example: posting an internal status update that a teammate glances at later.
- High impact, reversible: let the agent act, but log it clearly and monitor, because the cost of a mistake is to undo it, not to prevent it in advance. Example: updating a draft configuration file that has not been deployed yet.
- High impact, hard to reverse: require an approval gate, and consider escalation if the agent's confidence is low. Example: sending a refund over a set amount, deleting a customer account, publishing content externally, merging code to the main branch, transferring money.
Working through the small business email agent from earlier makes this concrete. Drafting a reply to a customer is low impact and fully reversible, nothing has happened yet, so no gate is needed. Sending that reply once it looks right is harder to reverse but usually low impact if the content is accurate, so review and edit, where a person skims drafts before they go out, is often enough. Refunding 20 dollars for a late delivery is a judgement call many businesses are happy to automate below a threshold, because the cost of occasionally over-refunding a small amount is lower than the cost of a human reviewing every single one. Refunding 4,000 dollars, or deleting a customer's account entirely, sits firmly in the last category: an approval gate, every time, with no exceptions baked into the agent's instructions.
Notice that the threshold itself, 20 dollars versus 4,000 dollars, is a business decision, not a technical one. The job of the system design is to make that threshold easy to express, easy to change, and consistently enforced, not to guess at a universally correct number.
Where the checkpoint sits inside the loop
Part 2 described the loop as observe, think, act. A human checkpoint is inserted between think and act: the agent has decided what it wants to do, and instead of executing that decision immediately, the system checks whether this particular action requires a person's sign-off, and if so, pauses there.
def run_step(agent_decision, policy):
"""agent_decision is a dict like
{"tool": "issue_refund", "args": {"amount": 4000, "order_id": "A123"}}
policy decides whether an action needs human approval.
"""
if policy.requires_approval(agent_decision):
approved, final_args = policy.request_approval(agent_decision)
if not approved:
return {"status": "rejected", "action": agent_decision}
agent_decision["args"] = final_args # a human may edit, not just approve
return execute_tool(agent_decision)
class RefundPolicy:
AUTO_APPROVE_LIMIT = 20
def requires_approval(self, decision):
if decision["tool"] != "issue_refund":
return False
return decision["args"]["amount"] > self.AUTO_APPROVE_LIMIT
def request_approval(self, decision):
print(f"Approval needed: refund {decision['args']['amount']} "
f"for order {decision['args']['order_id']}")
answer = input("Approve? (y / n / edit amount): ").strip()
if answer.lower() == "y":
return True, decision["args"]
if answer.lower() == "n":
return False, decision["args"]
try:
new_amount = float(answer)
decision["args"]["amount"] = new_amount
return True, decision["args"]
except ValueError:
return False, decision["args"]
This is plain Python with no external library, runnable as shown if you supply your own execute_tool function. Read it as a shape, not a finished product. The policy object is deliberately separate from the agent's own reasoning: the agent decides what it wants to do, but a separate, simpler, auditable piece of code decides whether that decision needs sign-off. Keeping the policy outside the model's own judgement matters, because you do not want the same system that might be wrong about whether a refund is justified also being the one that decides whether its own action is risky enough to check. The threshold of 20 dollars is plain code, not a prompt instruction, which means it cannot be talked out of itself by a persuasive customer message, and it can be changed by editing one line rather than rewriting a prompt and hoping the model still respects it under pressure.
The request_approval function above blocks on input(), which is fine for a script you are testing at a terminal but will not work for a real system where the agent might be running as a background service and the approver is a manager checking a queue once an hour. That gap, between a toy example and something that works in production, is what the next section covers.
Async human in the loop: queues, tickets and timeouts
A blocking call like input() assumes a person is sitting there watching the agent run, which rarely matches reality. Most real human in the loop systems separate the agent process from the approval process entirely:
- The agent reaches a gated action, writes a request to a queue or a database table, and stops working on that particular task, moving on to other work if it has any.
- A person sees the pending request later, through a dashboard, a ticketing system, a chat message or an email, and responds whenever they get to it.
- A separate process watches for that response and resumes the agent's task, feeding the human's decision back in as if it were the result of a tool call.
This decoupling is what makes human in the loop practical at any real scale. It also raises a question the blocking version avoids: what happens if nobody responds? A refund request that sits unanswered for three days leaves a customer waiting and a task half-finished. Systems typically handle this with an explicit timeout policy attached to the gate, decided in advance rather than improvised when it happens:
- Fail closed: if no one responds within the time limit, treat it as rejected. This is the safer default for high-impact, hard-to-reverse actions, because an unapproved refund or an unapproved deletion is worse than a delayed one.
- Fail open: if no one responds within the time limit, proceed anyway. This only makes sense for actions where the cost of a wrongful auto-approval is genuinely lower than the cost of the delay, which is rarer than people assume.
- Escalate further: if the first approver does not respond, route the request to a second person or a different channel, rather than silently defaulting either way.
The choice between these is, again, a business decision baked into policy code, not something to leave implicit. A system that fails open by accident, simply because nobody thought about the timeout case, tends to discover the problem the same way it discovers any other untested edge case: when it happens for real, with real consequences.
Escalation as a stopping condition
Part 8 covered stopping conditions: situations where the loop should stop retrying and return control, because it is not making progress, has hit a resource limit, or has produced the same failing result too many times. Escalation to a human is one of the most useful stopping conditions available, and it is worth treating as a first-class exit from the loop rather than an afterthought bolted on when things go wrong.
Consider an agent handling customer refund requests with the 20 dollar auto-approve threshold from earlier. A customer writes in asking for a refund but gives an order number that does not match any record in the system. A poorly designed agent might retry the lookup a few times, assume a typo, guess at the closest matching order, and issue a refund against the wrong customer, all without anyone noticing until the real customer complains that their order is still unrefunded. A better design recognises this as exactly the kind of ambiguity that should stop the loop and escalate: "order number not found after two lookup attempts, forwarding to a human with the original message and the closest three matches found." The person reviewing it can resolve in seconds what the agent would have had to guess at, and guessing is precisely the failure mode escalation exists to prevent.
The signal to escalate on does not have to be sophisticated. Useful triggers include: the agent's own stated confidence is low, a tool call failed more than a small fixed number of times, the request falls outside a documented range (like the refund amount example), or the situation matches a pattern explicitly flagged as always needing review, such as any request that mentions legal action or a safety complaint. None of these require the agent to be unusually self-aware; they require the system around the agent to watch for specific, checkable conditions and route accordingly.
Calibrating trust over time
Teams that put a new agent into production with real tool access almost always start with more human oversight than they expect to need permanently, and that is the right instinct. A new email-drafting agent might have every single draft reviewed for the first few weeks. A new refund agent might have its auto-approve threshold set lower than the business ultimately wants, precisely so that mistakes in the first batch of refunds are caught before the threshold is raised.
What changes over time is not the design pattern, it is the settings. As the agent accumulates a track record, the threshold for auto-approval can rise, the set of actions requiring an approval gate can shrink, and some gates can be downgraded to review and edit or monitoring. This works only if two things are in place from the start: a complete, attributable log of what the agent did and what a human decided about it, and a way to measure the rate of mistakes against the rate of human overrides. Without the log, there is no evidence to justify loosening the gate; without the measurement, loosening it is a guess dressed up as confidence.
It is worth resisting the opposite temptation too, which is to treat a good track record as permission to remove human oversight from an action category rather than adjust its threshold. A refund agent that has correctly handled a thousand refunds under 20 dollars has given you evidence about refunds under 20 dollars, not about refunds of any size, and not about a different kind of action like account deletion. Trust calibration happens per action category, scored by the risk model from earlier, not as a single global dial for the whole agent.
Common mistakes
- Approval fatigue: gating too many low-stakes actions trains the approver to click yes without reading, which means the gate stops functioning as a check and becomes a formality. A gate only works if the person on the other end genuinely has the time and attention to evaluate what they are approving.
- Confusing clarification with approval: if the agent is unsure what the user wants, the fix is to ask the user a clarifying question, not to escalate to a separate approver who was never part of the original conversation and has no extra information to offer.
- No audit trail: an approval gate without a record of what was proposed, who approved it, when, and what was actually executed cannot be reviewed later, cannot support the trust calibration described above, and offers no real accountability if something goes wrong.
- Fail-open by default without deciding to: a timeout that silently lets a high-impact action through because nobody configured the policy is often worse than having no gate at all, because it creates a false sense of safety.
- Gating the wrong layer: putting the check inside the language model's own reasoning, by instructing it in a prompt to "always ask before doing X," is weaker than enforcing the check in code outside the model, because a model can be argued out of a prompt instruction by a sufficiently persuasive input, where a policy function cannot.
- Treating human in the loop purely as legal cover: a gate added only so that someone can say a human was involved, without giving that human enough context, time or authority to actually catch a mistake, provides the appearance of safety without the function of it.
- Not giving the approver enough context: showing a manager the bare line "refund $4,000, order A123" with no link to the original complaint, the order history or why the agent thinks this is justified forces a decision made on too little information, which pushes people back toward rubber-stamping.
Where this shows up in practice
Human in the loop is not a niche technique reserved for exotic systems; it appears wherever an agent's actions have real consequences outside a sandbox.
- Coding agents that can edit files and run commands are routinely allowed to read code and run tests unsupervised, but required to open a pull request for a person to review before any change merges into the main branch.
- Customer support agents draft replies and resolutions, with low-value actions like answering a question auto-sent and higher-value actions like refunds or account changes queued for a person to approve.
- Content and marketing agents draft posts, emails or ad copy, which sit in a review queue before anything goes out under the company's name.
- Data and infrastructure agents that can modify configuration or delete records are typically allowed to act on staging environments freely, but gated on production, especially for destructive operations.
- Agents handling anything regulated, such as financial transactions, medical information or legal documents, are gated not only for good design reasons but often because regulation or company policy requires a documented human decision at specific points.
How much human in the loop is too much
Part 4 drew a distinction between workflows, where the steps and their order are fixed in advance, and agents, where the system itself decides what to do next based on what it observes. It is worth noticing what happens when you gate every single action an agent takes: you end up with something that behaves a lot like a workflow again, except the steps are proposed by a model instead of written by a developer, and a person approves each one before it runs. That can be exactly the right design for a high-stakes task where every action genuinely needs sign-off. But if you find yourself gating everything simply out of general nervousness, it is worth asking whether an agent was the right tool for the job at all, versus a fixed workflow with one well-placed approval step, which is usually simpler to build, test and explain.
The useful question is not "how do I add human oversight to this agent" but "which specific actions in this agent's toolset justify a checkpoint, and which pattern, approval, review, escalation or monitoring, fits each one." Answered action by action using the reversibility and impact model from earlier, the result is usually a system where most of what the agent does runs freely, because most actions are cheap to get wrong, and a small number of actions are gated carefully, because those are the ones that matter.
Summary and what comes next
Human in the loop is the design pattern for inserting a person into an agent's execution at the points where a mistake would be costly or hard to undo. The main patterns are approval gates, which block until a person decides; review and edit, which checks work after it is done but before it is final; escalation, which lets the agent itself hand off situations it should not resolve alone; and monitoring, the lightest form, where a person can see and intervene but nothing waits for them. Deciding which pattern fits which action comes down to two questions: how reversible is this action, and how much does it cost if it is wrong. The checkpoint itself belongs in code around the agent, not in a prompt instruction the model might talk itself out of, and it needs to work asynchronously in any real system, with an explicit, deliberate policy for what happens if nobody responds in time. The goal is not maximum caution everywhere, which produces approval fatigue and an agent that is really just a slow workflow, but a small number of carefully placed checkpoints on the actions that actually warrant them, backed by logs that let you loosen those checkpoints later with evidence instead of guesswork.
The next part moves from design patterns to tooling: how to choose a framework for building agents, what the common frameworks actually provide versus what you can build yourself in plain code, and when skipping a framework entirely is the more sensible choice.
Comments (0)
No comments yet. Be the first to share your thoughts.