Ethical Guidelines and Human Oversight › The Role of Human Oversight
AI Agent HandbookAll chapters Ethical Guidelines and Human Oversight › The Role of Human OversightOne section · Sections in this chapter6 / 12 ↓
Even with strong ethical guidelines, your agent will encounter situations where human judgment is needed. This is where human oversight comes in.
Human oversight means having a person review, approve, or audit the agent's decisions, especially for high-stakes situations. The level of oversight should match the risk.
Levels of Human Oversight
Different situations call for different levels of human involvement:
Level 1: Human in the Loop (HITL)
The agent proposes actions but a human must approve before they're executed. This is appropriate for high-stakes decisions.
## Using Claude Sonnet 4.5 with human-in-the-loop workflow
import os
from anthropic import Anthropic
client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
class HITLAgent:
def __init__(self):
self.pending_actions = []
def propose_action(self, action_type, details, reasoning):
"""Agent proposes an action for human review"""
action_id = len(self.pending_actions)
self.pending_actions.append(
{
"id": action_id,
"type": action_type,
"details": details,
"reasoning": reasoning,
"status": "pending",
}
)
return f"""PROPOSED ACTION #{action_id}
Type: {action_type}
Details: {details}
Reasoning: {reasoning}
This action requires your approval.
- Approve: agent.approve({action_id})
- Reject: agent.reject({action_id})
- Request changes: agent.modify({action_id}, new_details)"""
def approve(self, action_id):
"""Human approves the action"""
if action_id >= len(self.pending_actions):
return "Invalid action ID"
action = self.pending_actions[action_id]
if action["status"] != "pending":
return f"Action already {action['status']}"
# Execute the action
action["status"] = "approved"
return f"Action #{action_id} approved and executed: {action['details']}"
def reject(self, action_id, reason=None):
"""Human rejects the action"""
if action_id >= len(self.pending_actions):
return "Invalid action ID"
action = self.pending_actions[action_id]
action["status"] = "rejected"
action["rejection_reason"] = reason
return f"Action #{action_id} rejected. {reason if reason else ''}"
def get_audit_log(self):
"""Get a log of all proposed actions and their outcomes"""
return self.pending_actions
## Example usage
agent = HITLAgent()
## Agent proposes sending an important email
proposal = agent.propose_action(
action_type="send_email",
details="Send email to board@company.com with Q4 financial results",
reasoning="User requested quarterly report distribution. This is high-stakes "
"communication with company leadership, so requesting approval.",
)
print(proposal)
## Human reviews and approves
result = agent.approve(0)
print(result)Level 2: Human on the Loop (HOTL)
The agent acts autonomously but a human monitors its actions and can intervene if needed. This is appropriate for medium-risk situations.
## Using Claude Sonnet 4.5 with human-on-the-loop monitoring
class HOTLAgent:
def __init__(self, review_threshold=0.7):
self.action_log = []
self.review_threshold = review_threshold
def execute_action(self, action_type, details, confidence):
"""Execute action with optional human review based on confidence"""
action_id = len(self.action_log)
# Log the action
self.action_log.append(
{
"id": action_id,
"type": action_type,
"details": details,
"confidence": confidence,
"flagged_for_review": confidence < self.review_threshold,
}
)
if confidence < self.review_threshold:
return f"""ACTION EXECUTED (Flagged for review)
ID: {action_id}
Type: {action_type}
Details: {details}
Confidence: {confidence:.2f}
This action was executed but flagged for review due to low confidence.
Review with: agent.review_action({action_id})"""
else:
return f"Action executed: {details}"
def review_action(self, action_id):
"""Human reviews a flagged action"""
if action_id >= len(self.action_log):
return "Invalid action ID"
action = self.action_log[action_id]
return f"""REVIEW ACTION #{action_id}
Type: {action["type"]}
Details: {action["details"]}
Confidence: {action["confidence"]:.2f}
If this action was inappropriate:
- Undo: agent.undo_action({action_id})
- Adjust settings: agent.adjust_threshold()"""
def get_flagged_actions(self):
"""Get all actions flagged for review"""
return [a for a in self.action_log if a["flagged_for_review"]]
## Example usage
agent = HOTLAgent(review_threshold=0.7)
## High confidence action (executes without review)
result = agent.execute_action(
"send_routine_email", "Send weekly status update to team", confidence=0.95
)
print(result)
## Low confidence action (executes but flagged)
result = agent.execute_action(
"schedule_meeting", "Schedule meeting with new contact", confidence=0.6
)
print(result)
## Human reviews flagged actions periodically
flagged = agent.get_flagged_actions()
print(f"\n{len(flagged)} actions flagged for review")Action executed: Send weekly status update to team ACTION EXECUTED (Flagged for review) ID: 1 Type: schedule_meeting Details: Schedule meeting with new contact Confidence: 0.60 This action was executed but flagged for review due to low confidence. Review with: agent.review_action(1) 1 actions flagged for review
Level 3: Human Out of the Loop (HOOTL)
The agent acts fully autonomously, but all actions are logged for later audit. This is appropriate for low-risk, routine tasks.
## Using Claude Sonnet 4.5 with audit logging
class HOOTLAgent:
def __init__(self):
self.audit_log = []
def execute_action(self, action_type, details):
"""Execute action autonomously with audit logging"""
import datetime
action_id = len(self.audit_log)
timestamp = datetime.datetime.now().isoformat()
# Log the action
self.audit_log.append(
{
"id": action_id,
"timestamp": timestamp,
"type": action_type,
"details": details,
}
)
# Execute without human involvement
return f"Action executed: {details}"
def get_audit_log(self, action_type=None, start_date=None):
"""Retrieve audit log for review"""
log = self.audit_log
if action_type:
log = [a for a in log if a["type"] == action_type]
if start_date:
log = [a for a in log if a["timestamp"] >= start_date]
return log
def generate_audit_report(self):
"""Generate a summary report of agent actions"""
from collections import Counter
action_counts = Counter(a["type"] for a in self.audit_log)
report = "AUDIT REPORT\n"
report += f"Total actions: {len(self.audit_log)}\n\n"
report += "Actions by type:\n"
for action_type, count in action_counts.most_common():
report += f" {action_type}: {count}\n"
return report
## Example usage
agent = HOOTLAgent()
## Agent acts autonomously
agent.execute_action("send_routine_email", "Daily standup reminder")
agent.execute_action("update_calendar", "Added team lunch event")
agent.execute_action("send_routine_email", "Weekly newsletter")
## Human reviews audit log periodically
print(agent.generate_audit_report())AUDIT REPORT Total actions: 3 Actions by type: send_routine_email: 2 update_calendar: 1
Choosing the Right Level of Oversight
How do you decide which level of oversight to use? Consider these factors:
Stakes: How much harm could result from a mistake?
- High stakes (financial transactions, legal documents) → Human in the loop
- Medium stakes (important emails, scheduling) → Human on the loop
- Low stakes (routine reminders, simple queries) → Human out of the loop
Reversibility: Can the action be easily undone?
- Irreversible (sending emails, deleting data) → Higher oversight
- Reversible (creating drafts, setting reminders) → Lower oversight
Frequency: How often does this action occur?
- Rare, unusual actions → Higher oversight
- Routine, frequent actions → Lower oversight
User preference: How much control does the user want?
- Some users prefer more autonomy, others want more control
- Make oversight levels configurable
Here's a framework for categorizing actions:
## Using Claude Sonnet 4.5 with risk-based oversight
from enum import Enum
class OversightLevel(Enum):
HITL = "human_in_loop" # Requires approval
HOTL = "human_on_loop" # Monitored, can intervene
HOOTL = "human_out_of_loop" # Audited after the fact
class ActionClassifier:
def __init__(self):
# Define oversight requirements for different action types
self.oversight_rules = {
"send_email": {
"external": OversightLevel.HITL, # Emails to external contacts
"internal": OversightLevel.HOTL, # Emails to team
"automated": OversightLevel.HOOTL, # Routine notifications
},
"modify_data": {
"delete": OversightLevel.HITL, # Deletions require approval
"update": OversightLevel.HOTL, # Updates are monitored
"create": OversightLevel.HOOTL, # Creating new items is low-risk
},
"schedule": {
"cancel": OversightLevel.HITL, # Canceling requires approval
"create": OversightLevel.HOTL, # Creating is monitored
"remind": OversightLevel.HOOTL, # Reminders are low-risk
},
}
def get_oversight_level(self, action_type, subtype):
"""Determine required oversight level for an action"""
if action_type in self.oversight_rules:
rules = self.oversight_rules[action_type]
return rules.get(subtype, OversightLevel.HOTL) # Default to HOTL
return OversightLevel.HOTL # Default for unknown actions
## Example usage
classifier = ActionClassifier()
## Check oversight requirements
print(classifier.get_oversight_level("send_email", "external")) # HITL
print(classifier.get_oversight_level("schedule", "remind")) # HOOTL
print(classifier.get_oversight_level("modify_data", "delete")) # HITLOversightLevel.HITL OversightLevel.HOOTL OversightLevel.HITL