This example demonstrates how to use AsyncHumanLayer with FastAPI to create an API with human-in-the-loop approval flows.
The example shows how to:
- Use AsyncHumanLayer with FastAPI endpoints
- Handle human approvals for API operations
- Process both approved and denied responses
- Structure async API endpoints with human-in-the-loop flows
-
Create a virtual environment and activate it:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Copy
.env.exampleto.envand fill in your API keys:cp .env.example .env # Add your keys to .env: # HUMANLAYER_API_KEY=your_key_here # OPENAI_API_KEY=your_key_here
The main application (app.py) shows how to:
-
Initialize AsyncHumanLayer:
from humanlayer import AsyncHumanLayer hl = AsyncHumanLayer(verbose=True)
-
Create functions requiring approval:
@hl.require_approval() async def multiply(a: int, b: int) -> int: return a * b
-
Handle approvals in endpoints:
@app.post("/math/multiply") async def math_multiply(a: int, b: int) -> Dict[str, str | int]: result = await multiply(a, b) if isinstance(result, str): # Handle denial message return {"status": "denied", "message": result} return {"status": "success", "result": result} or, with fetch_approval @app.post("/math/multiply") async def math_multiply(a: int, b: int) -> Dict[str, str | int]: approval_result = await hl.fetch_approval( FunctionCallSpec( fn="multiply", kwargs={"a": a, "b": b}, ) ) if not approval_result.approved: return {"status": "denied", "message": result} result = await multiply(a, b) return {"status": "success", "result": result}
Start the server:
python app.py
# Or
uvicorn app:app --reloadUsing curl:
# Test multiplication
curl -X POST "http://localhost:8000/math/multiply?a=5&b=3"
# Test division
curl -X POST "http://localhost:8000/math/divide?a=10&b=2"Or you can ask a question to the human in an asyncio/fastapi compatible way:
curl -X POST "http://localhost:8000/ask-question?question=what+is+the+weather+in+tokyo"Successful operation:
{
"status": "success",
"result": 15
}Denied operation:
{
"status": "denied",
"message": "User denied multiply with message: Not allowed"
}- Async operations with human approval
- Error handling for denials and failures
- Type hints and proper response handling
- Health check endpoint with approval flow
- CORS middleware for API access
- Swagger UI at
/docs
- Operations requiring approval can be handled in two ways:
- Using the
@hl.require_approval()decorator - Using
hl.fetch_approval()to explicitly check approval before execution
- Using the
- When using
fetch_approval(), checkapproval_result.approvedto handle approvals/denials - The health check demonstrates a complete approval flow
- Responses should handle both successful operations and denials