Refusal escalation flow
A refusal is information, not an endpoint. Sometimes the refusal is correct and the user needs a clear explanation. Sometimes the refusal is over-cautious and a human reviewer would unblock the request. The escalation flow is what turns a flat no into one of three explicit branches.
from enum import Enum
class RefusalReason(str, Enum):
pii = 'pii'
policy = 'policy'
uncertain = 'uncertain'
async def handle_refusal(reason: RefusalReason, envelope: RequestEnvelope) -> dict:
if reason is RefusalReason.pii:
# Hard refusal: never escalate raw PII to humans
return {'status': 'refused', 'message': 'Cannot process requests with personal data.'}
if reason is RefusalReason.policy:
# Soft refusal: hand to a human review queue
await review_queue.enqueue(envelope)
return {'status': 'pending_review', 'eta_minutes': 30}
if reason is RefusalReason.uncertain:
# Uncertain refusal: try a safer fallback model
return await safer_model.run(envelope)Three reasons, three paths. PII is always a hard refusal because escalating raw PII would defeat the scrub. Policy refusals can be reviewed by a human. Uncertainty calls a smaller, more conservative model as a fallback.
Two rules keep this safe. PII never escalates: forwarding scrubbed-but-still-personal data to a queue defeats the protection. And every escalation produces a structured event with the trace ID, so the audit log shows exactly which refusals went where.
Quiz: Quiz
Loading practice…