Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions samples-v2/openai_agents/ORDER_RETURNS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Order Return Processing System

An order return processing system built with Azure Functions and OpenAI Agents, demonstrating advanced orchestration patterns and multi-agent workflows.

## Overview

This system automatically processes customer return requests using AI agents to validate return reasons, process refunds, and route edge cases to human review. It showcases real-world business logic implementation with Azure Durable Functions.

## Quick Start

### Submit a Return Request
```bash
curl -X POST http://localhost:7071/api/order_return_processor \
-H "Content-Type: application/json" \
-d '{
"order_id": "ORD-12345",
"customer_id": "CUST-67890",
"product_category": "Electronics",
"purchase_date": "2024-10-01",
"return_reason": "Product arrived damaged in shipping"
}'
```

### Check Processing Status
```bash
# Use the statusQueryGetUri from the submission response
curl http://localhost:7071/runtime/webhooks/durabletask/instances/{instance_id}
```

## API Reference

### Endpoints

| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/order_return_processor` | Submit a new return request |
| `GET` | `/runtime/webhooks/durabletask/instances/{instance_id}` | Check processing status |


### Request Schema

```json
{
"order_id": "string (required)",
"customer_id": "string (required)",
"product_category": "string (required)",
"purchase_date": "string (required)",
"return_reason": "string (required)"
}
```

## Business Logic

### Validation Rules

**✅ Auto-Approved Returns**
- Defective or broken products
- Wrong item shipped
- Damaged during shipping
- Product not as described
- Quality issues
- Size/fit problems

**❌ Requires Human Review**
- Changed mind without valid cause
- Found item cheaper elsewhere
- Buyer's remorse
- Financial reasons
- Vague complaints

## Example Responses

### Successful Auto-Approval
```json
{
"status": "approved_and_processed",
"validation": {
"agent_response": "Return approved - product defect identified",
"validation_result": { "is_valid": true }
},
"refund": {
"refund_details": {
"success": true,
"refund_amount": 93.00,
"transaction_id": "REF-ABC123",
"processing_time": "3-5 business days"
}
},
"message": "Return approved and refund processed successfully"
}
```

### Human Review Required
```json
{
"status": "pending_human_review",
"validation": {
"agent_response": "Return requires manual review - unclear reason",
"validation_result": { "is_valid": false }
},
"human_review": {
"review_ticket_id": "REV-XYZ789",
"estimated_review_time": "24-48 hours",
"message": "Your return request has been escalated for human review"
}
}
```

## Architecture

The system uses a multi-agent orchestration pattern:

1. **Order Return Processor** (Main Orchestrator) - Coordinates the entire workflow
2. **Validation Agent** - Analyzes return reasons against business rules
3. **Refund Agent** - Processes approved refunds automatically
4. **Human Review Activity** - Creates support tickets for manual cases

## File Structure

```
basic/
├── order_return_validation.py # Validation agent
└── refund_processing.py # Refund processing agent

order_return_orchestrators.py # Main orchestration logic
test_order_return.py # Testing examples and utilities
```

## Testing

```bash
# Start the function app
func start

# Test valid return (should auto-approve)
curl -X POST http://localhost:7071/api/order_return_processor \
-H "Content-Type: application/json" \
-d '{"order_id":"TEST-001","customer_id":"CUST-001","product_category":"Electronics","purchase_date":"2024-10-01","return_reason":"arrived damaged"}'

# Test invalid return (should require human review)
curl -X POST http://localhost:7071/api/order_return_processor \
-H "Content-Type: application/json" \
-d '{"order_id":"TEST-002","customer_id":"CUST-002","product_category":"Clothing","purchase_date":"2024-09-15","return_reason":"changed my mind"}'

# Check status using the response from above requests
# Look for "statusQueryGetUri" in the response and use that URL
curl {statusQueryGetUri_from_response}
```
138 changes: 138 additions & 0 deletions samples-v2/openai_agents/basic/order_return_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from __future__ import annotations

from pydantic import BaseModel
from typing import Literal

from agents import Agent, Runner, function_tool


class ReturnValidationResult(BaseModel):
is_valid: bool
reason: str
confidence_score: float # 0.0 to 1.0
order_id: str


class OrderReturnRequest(BaseModel):
order_id: str
return_reason: str
purchase_date: str
product_category: str
customer_id: str


@function_tool
def validate_return_reason(return_request: OrderReturnRequest) -> ReturnValidationResult:
"""
Validate if an order return reason is legitimate based on company policy.
Valid reasons include: defective product, wrong item received, damaged in shipping,
not as described, quality issues, size/fit issues (for clothing).
Invalid reasons include: changed mind after 30 days, buyer's remorse,
found cheaper elsewhere, impulse purchase regret.
"""

# Simulate policy validation logic
valid_reasons = [
"defective", "damaged", "wrong item", "not as described",
"quality issues", "size issue", "fit issue", "broken",
"missing parts", "expired"
]

invalid_reasons = [
"changed mind", "buyer's remorse", "found cheaper",
"impulse purchase", "don't need", "financial reasons"
]

reason_lower = return_request.return_reason.lower()

# Check for valid reasons
is_valid = any(valid_reason in reason_lower for valid_reason in valid_reasons)

# Check for invalid reasons
if any(invalid_reason in reason_lower for invalid_reason in invalid_reasons):
is_valid = False

# Calculate confidence based on keyword matching
confidence = 0.8 if is_valid else 0.7

validation_reason = (
"Return reason matches company policy for valid returns" if is_valid
else "Return reason does not meet company return policy criteria"
)

return ReturnValidationResult(
is_valid=is_valid,
reason=validation_reason,
confidence_score=confidence,
order_id=return_request.order_id
)


def main(return_request_data: dict):
"""Main function to run the order return validation agent"""

agent = Agent(
name="Order Return Validation Specialist",
instructions="""
You are an expert order return validation specialist. Your job is to:
1. Analyze customer return requests carefully
2. Determine if the return reason is valid according to company policy
3. Provide clear reasoning for your decision
4. Be fair but firm in applying policy guidelines

Valid return reasons typically include:
- Defective or broken products
- Wrong item shipped
- Damaged during shipping
- Product not as described
- Quality issues
- Size/fit problems (for applicable items)

Invalid return reasons typically include:
- Changed mind without valid cause
- Found item cheaper elsewhere
- Buyer's remorse
- Financial hardship
- General dissatisfaction without specific issue

Always use the validate_return_reason tool to check the policy compliance.
Based on the tool result, clearly state if the return is VALID or INVALID.
End your response with either "Return is VALID" or "Return is INVALID".
""",
tools=[validate_return_reason],
)

# Convert dict to OrderReturnRequest
return_request = OrderReturnRequest(**return_request_data)

user_message = f"""
Please validate this return request:

Order ID: {return_request.order_id}
Customer ID: {return_request.customer_id}
Product Category: {return_request.product_category}
Purchase Date: {return_request.purchase_date}
Return Reason: {return_request.return_reason}

Is this a valid return request according to our company policy?
"""

result = Runner.run_sync(agent, user_message)
# Parse the agent's response to extract validation decision
agent_response = result.final_output
is_valid = "valid" in str(agent_response).lower() and "invalid" not in str(agent_response).lower()

# Create a structured validation result
validation_result = {
"is_valid": is_valid,
"reason": "Parsed from agent response",
"confidence_score": 0.8 if is_valid else 0.7,
"order_id": return_request_data.get("order_id")
}

return {
"agent_response": agent_response,
"validation_result": validation_result
}
Loading