Building a Food Delivery Support Agent: Order Tracking and Issue Resolution
Build an AI support agent for food delivery platforms that tracks orders in real time, provides accurate ETAs, categorizes issues, and processes refunds through structured workflows.
The Delivery Support Challenge
Food delivery platforms handle thousands of support inquiries per hour: "Where is my order?", "I received the wrong item," "My food arrived cold," "The driver cannot find my address." Each inquiry category requires a different resolution workflow, and customers expect instant responses during an experience that is already time-sensitive.
An AI support agent resolves the majority of these inquiries automatically while knowing exactly when to escalate to a human agent — and handing off with full context when it does.
Order State Model
The foundation of a delivery support agent is a comprehensive order state model that the agent can query in real time.
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from enum import Enum
from typing import Optional
class OrderStatus(Enum):
PLACED = "placed"
CONFIRMED = "confirmed"
PREPARING = "preparing"
READY_FOR_PICKUP = "ready_for_pickup"
DRIVER_ASSIGNED = "driver_assigned"
PICKED_UP = "picked_up"
EN_ROUTE = "en_route"
ARRIVING = "arriving"
DELIVERED = "delivered"
CANCELLED = "cancelled"
class IssueCategory(Enum):
MISSING_ITEM = "missing_item"
WRONG_ITEM = "wrong_item"
COLD_FOOD = "cold_food"
LATE_DELIVERY = "late_delivery"
DRIVER_ISSUE = "driver_issue"
QUALITY_ISSUE = "quality_issue"
NEVER_DELIVERED = "never_delivered"
SPILLED = "spilled"
@dataclass
class DeliveryOrder:
order_id: str
customer_name: str
customer_phone: str
restaurant_name: str
items: list[dict]
status: OrderStatus
placed_at: datetime
estimated_delivery: datetime
driver_name: Optional[str] = None
driver_phone: Optional[str] = None
driver_location: Optional[dict] = None
actual_delivery: Optional[datetime] = None
total: float = 0.0
delivery_fee: float = 0.0
@property
def is_late(self) -> bool:
now = datetime.now()
return now > self.estimated_delivery and self.status != OrderStatus.DELIVERED
@property
def minutes_until_delivery(self) -> int:
delta = self.estimated_delivery - datetime.now()
return max(0, int(delta.total_seconds() / 60))
@dataclass
class SupportTicket:
ticket_id: str
order_id: str
category: IssueCategory
description: str
resolution: str = ""
refund_amount: float = 0.0
created_at: datetime = field(default_factory=datetime.now)
resolved: bool = False
Building the Support Agent Tools
from agents import Agent, function_tool
# Simulated order database
orders_db: dict[str, DeliveryOrder] = {}
tickets_db: list[SupportTicket] = []
@function_tool
def track_order(order_id: str) -> str:
order = orders_db.get(order_id)
if not order:
return f"Order {order_id} not found. Please verify the order ID."
status_messages = {
OrderStatus.PLACED: "Your order has been placed and is awaiting restaurant confirmation.",
OrderStatus.CONFIRMED: "The restaurant has confirmed your order.",
OrderStatus.PREPARING: "Your food is being prepared.",
OrderStatus.READY_FOR_PICKUP: "Your order is ready and waiting for a driver.",
OrderStatus.DRIVER_ASSIGNED: f"Driver {order.driver_name} has been assigned.",
OrderStatus.PICKED_UP: f"Driver {order.driver_name} has picked up your order.",
OrderStatus.EN_ROUTE: f"Your order is on the way. ETA: {order.minutes_until_delivery} minutes.",
OrderStatus.ARRIVING: "Your driver is arriving now!",
OrderStatus.DELIVERED: f"Your order was delivered at {order.actual_delivery}.",
}
message = status_messages.get(order.status, f"Status: {order.status.value}")
if order.is_late:
message += " We apologize for the delay."
return message
@function_tool
def get_driver_location(order_id: str) -> str:
order = orders_db.get(order_id)
if not order or not order.driver_location:
return "Driver location is not available at this time."
loc = order.driver_location
return (
f"Driver {order.driver_name} is at {loc.get('street', 'unknown location')}, "
f"approximately {loc.get('distance_km', '?')} km away. "
f"ETA: {order.minutes_until_delivery} minutes."
)
@function_tool
def report_issue(order_id: str, category: str, description: str) -> str:
order = orders_db.get(order_id)
if not order:
return f"Order {order_id} not found."
try:
issue_cat = IssueCategory(category)
except ValueError:
valid = ", ".join(c.value for c in IssueCategory)
return f"Invalid category. Valid options: {valid}"
# Determine refund eligibility and amount
refund_rules = {
IssueCategory.MISSING_ITEM: ("partial", 0.0),
IssueCategory.WRONG_ITEM: ("full_item", 0.0),
IssueCategory.COLD_FOOD: ("partial", 0.30),
IssueCategory.LATE_DELIVERY: ("delivery_fee", order.delivery_fee),
IssueCategory.NEVER_DELIVERED: ("full", order.total),
IssueCategory.SPILLED: ("full", order.total),
IssueCategory.QUALITY_ISSUE: ("partial", 0.25),
IssueCategory.DRIVER_ISSUE: ("escalate", 0.0),
}
rule_type, amount = refund_rules.get(issue_cat, ("escalate", 0.0))
ticket = SupportTicket(
ticket_id=f"TKT-{len(tickets_db)+1:04d}",
order_id=order_id,
category=issue_cat,
description=description,
)
if rule_type == "full":
ticket.refund_amount = order.total
ticket.resolution = f"Full refund of ${order.total:.2f} issued."
ticket.resolved = True
elif rule_type == "delivery_fee":
ticket.refund_amount = order.delivery_fee
ticket.resolution = f"Delivery fee refund of ${order.delivery_fee:.2f} issued."
ticket.resolved = True
elif rule_type == "partial":
refund = round(order.total * amount, 2) if amount < 1 else amount
ticket.refund_amount = refund
ticket.resolution = f"Partial credit of ${refund:.2f} issued."
ticket.resolved = True
else:
ticket.resolution = "Escalated to senior support team."
ticket.resolved = False
tickets_db.append(ticket)
return f"Ticket {ticket.ticket_id} created. {ticket.resolution}"
@function_tool
def request_redelivery(order_id: str) -> str:
order = orders_db.get(order_id)
if not order:
return f"Order {order_id} not found."
if order.status != OrderStatus.DELIVERED:
return "Redelivery is only available for delivered orders with issues."
return (
f"Redelivery requested for order {order_id}. "
f"A new driver will pick up a fresh order from {order.restaurant_name}. "
f"Estimated delivery: 35-45 minutes."
)
delivery_support_agent = Agent(
name="Delivery Support Agent",
instructions="""You are a customer support agent for a food delivery platform.
Help customers track orders, report issues, and resolve problems quickly.
Always check the order status first before addressing concerns. Be empathetic
about delays and food quality issues. Offer refunds or redelivery when
appropriate based on the issue type.""",
tools=[track_order, get_driver_location, report_issue, request_redelivery],
)
FAQ
How does the agent determine whether to offer a refund or redelivery?
The agent uses a rules engine that maps issue categories to resolution actions. Missing items and quality issues trigger partial refunds. Never-delivered and spilled orders qualify for full refunds. For wrong items, the agent offers both a refund for the incorrect item and optional redelivery of the correct one. The customer can choose their preferred resolution.
What prevents customers from abusing the refund system?
The agent integrates with a customer risk score calculated from historical claims. Customers with a high frequency of refund requests are flagged, and the agent escalates their tickets to a human reviewer instead of auto-approving refunds. The escalation is transparent — the agent tells the customer their issue is being reviewed by a specialist.
How does the agent handle real-time ETA updates when a driver is stuck in traffic?
The order tracking system receives GPS updates from the driver's app every 30 seconds. The agent's track_order tool reads the latest estimated delivery time, which the routing engine recalculates dynamically based on current traffic conditions. If the ETA changes significantly, the system can proactively notify the customer without waiting for them to ask.
#FoodDelivery #CustomerSupportAI #OrderTracking #AgenticAI #Python #LearnAI #AIEngineering
CallSphere Team
Expert insights on AI voice agents and customer communication automation.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.