How to set up agent-human collaboration workflows
Agent workflow, human review interface or approval system
What this does
A human-in-the-loop (HITL) workflow forces an AI agent to pause at defined decision points, present a summary of intended actions, and resume only after receiving explicit human approval. This prevents autonomous agents from causing irreversible harm by requiring review for high-impact or destructive actions.
Steps
Create a configuration file checkpoints.toml that enumerates which actions require human review. Each entry specifies a checkpoint_id, a corresponding action_pattern (regex matching the tool call name), and a description_template that summarizes the action. Examples include deploying a model to production as a high-impact action, sending external API requests as a data risk action, and deleting records from a database as a destructive action.
Build a FastAPI service with two routes: POST /pending and POST /approve/{request_id}. The /pending route accepts a JSON payload containing request_id, action_description, agent_context, and timestamp, storing the request in a pending_reviews table with a waiting status. The /approve/{request_id} route updates the request's status to approved or rejected based on the payload field decision. Return HTTP 201 for successful creations and 200 for status updates.
Modify the agent's tool executor to check the action_pattern against the requested tool call before execution. If a match is found, call the /pending endpoint, log the pause, and enter a polling loop that checks the pending_reviews status every 5 seconds. Continue polling until the status changes from waiting. If approved, proceed with the tool call. If rejected, log the rejection, stop the agent loop, and emit a CollaborationError.
Create a simple HTML page served by the FastAPI app that lists all entries from pending_reviews where status is waiting. Each row displays the action description, a human-readable timestamp, and two buttons for Approve and Reject. These buttons submit a POST request to the corresponding approval endpoint. Style the page with basic CSS to differentiate pending items in amber from already-reviewed items in green or red.
Record the local run evidence. Save the exact command, runtime or package version, model name if applicable, and observed output so the result can be reproduced later.
Confirm the local starting state. Print the active binary, package version, model name, or configuration path before changing the workflow.
Run the smallest complete path. Execute the minimum command or script that proves the guide works end to end on the local machine.
Compare against expected output. Check the final line, status code, generated artifact, or model response against the verification section before expanding the setup.
Record the local run evidence. Save the exact command, runtime or package version, model name if applicable, and observed output so the result can be reproduced later.
Verification
Programmatically invoke the tool that triggers a checkpoint: a delete operation matching action_pattern = "delete_*". Confirm a pending review appears in the database and the reviewer page. Click Approve and confirm the agent resumes execution. Reset the test and click Reject, confirming the agent stops and logs a CollaborationError. Expected output: the pending_reviews table contains 1 row with status waiting within 1 second of the trigger; the reviewer HTML page displays the pending action with the correct description; after clicking Approve, polling resolves within 5 seconds and the tool executes; after clicking Reject, the agent loop terminates with a logged error containing "CollaborationError: rejected".
Common failures
- Agent blocks indefinitely on slow review: The polling loop has no timeout, causing the agent to hang if a reviewer does not respond. Add a
timeout_secondsconfiguration defaulting to 30, after which the tool call fails with aTimeoutError. - Race condition on concurrent reviews: Multiple checkpoint triggers create duplicate requests before the insert completes. Use database-level row locking or a unique constraint on
request_id. - Missing context in the reviewer page: The reviewer cannot distinguish between similar actions without additional context. Include the full agent state snapshot in the payload sent to
/pending. - Approval latency exceeding SLA: Reviewers are not notified of pending items immediately. Integrate a push notification (email or webhook) triggered in the
/pendingroute. - Rejection not propagated to parent caller: The agent catches
CollaborationErrorinternally and continues as if nothing happened. Ensure the error propagates upward by re-raising it after logging.
Related guides
- Implement agent planning and task decomposition — human approval steps can be inserted as special pause points in the task decomposition graph.
- Build a research agent that browses the web — research agents benefit from human review before surfacing synthesized findings externally.