Decide by reversibility, not by importance
The useful axis for deciding what needs a human is not how important an action is. It is how hard it is to undo.
- Reversible in one click: draft an email, add a tag, create an unpublished record. Let the model do it. Requiring approval here trains people to click Approve without reading, which destroys the value of every gate you have.
- Reversible with effort: publish a post, update a customer record, cancel a booking. Let it act, log it clearly, and provide a visible undo.
- Not reversible: send money, send a message to a customer, delete data, change permissions, sign anything. Human approval, every time, with the specifics on screen.
A useful sharpening: anything a stranger sees, anything that moves money, and anything you cannot get back. Those three cover almost every case.
What a good approval screen shows
Approval fatigue is the failure mode of this whole area. A dialog that says The assistant wants to run send_email. Approve? teaches people to click yes.
Show the thing itself:
- The exact action, rendered: the full email with recipient, subject and body; the amount and the account; the rows that will be deleted, with a count
- Why, in one line: the user request or the rule that led here
- What changes and what does not: “this refunds ₹2,400 to the original card; it does not cancel the subscription”
- Approve, edit, reject: with edit as a real option. Most rejections are of a nearly right action, and forcing the person to reject and start again wastes the work.
One approval per action. Batch approval of twelve heterogeneous actions is a single click that nobody reads.
The gate belongs in the tool, not the prompt
This is the mistake worth naming explicitly. “Always ask the user before sending an email” in a system prompt is a preference, not a control. It will hold most of the time and fail exactly when something unusual is happening, which is when you needed it.
The gate goes in code, at the point of effect:
def send_email(to, subject, body):
if not approvals.granted(action_id(to, subject, body)):
raise NeedsApproval(to=to, subject=subject, body=body)
return mail.send(to, subject, body)The model cannot talk its way past that, because the model is not involved. NeedsApproval comes back through the loop as a recoverable result, the run pauses, and the pending action is stored for a person. This is the same principle as authorising against the session rather than the arguments: anything that must always happen is code, and anything in the prompt is a suggestion.
Pausing a run properly
An agent waiting for approval may wait for hours, so the run cannot live in a request handler.
Persist the whole state: messages so far, pending tool call, run id, who may approve, an expiry. When approval arrives, resume from that state rather than starting again. Two rules that save you: expire pending approvals (a refund approved from a two-week-old context is approving something nobody remembers), and re-validate at execution time (the order may have been cancelled while the request sat in a queue).
Handing to a person, and handing back
Escalation is a normal outcome, not a failure. It should be triggered by rules you write, not by the model’s judgement about its own competence:
- The user asked twice for a human
- Sentiment or complaint language crossed a threshold
- The topic is on your list: legal, medical, safety, a named regulator
- Confidence checks failed, or retrieval returned nothing
- The loop hit a budget
When it fires, hand over properly. A person picking up a conversation needs a two-line summary of what was asked, what was tried and what failed, not a 40-turn transcript to read while a customer waits. Carry the context, keep the ticket id, and do not make the customer repeat themselves. Most people’s anger at automated support comes from that one thing.
And give the human a way back. A conversation that escalated may return to the assistant once the specific issue is resolved. A one-way door means every escalation permanently consumes a person.
Count the gate
Instrument it like anything else: how often approval is requested, how often it is granted unchanged, how often edited, how often rejected.
A 99 per cent approval rate means the gate is theatre and the reviewer is rubber-stamping: either automate the action or narrow the gate to the cases that are actually contested. A 40 per cent rejection rate means the model should not be proposing these at all. The useful range is in between, and knowing where you sit is the difference between oversight and its appearance.
Every lesson here is open. Your progress is recorded once you pass the Python, from Zero, for AI exam.
Check your understanding
An assistant’s system prompt says it must always ask before issuing a refund. Refunds are occasionally issued without a prompt appearing. What is the structural fix?
Pick the one you would defend. Your answer stays private.
Stuck on something?Ask Sayali, your AI tutor