Building a Hotel Front Desk Agent: Check-In, Concierge, and Guest Services
Build an AI front desk agent for hotels that handles guest check-in, room assignment, amenity information, local recommendations, and complaint resolution with graceful escalation.
What a Hotel Front Desk Agent Does
A hotel front desk handles a remarkable breadth of tasks: checking guests in and out, answering questions about amenities, recommending restaurants, resolving complaints, coordinating with housekeeping, and processing special requests. An AI front desk agent replicates these capabilities across phone, chat, and kiosk channels — available 24/7 without shift changes.
The key architectural challenge is routing guest intents to the right sub-capability while maintaining a warm, hospitality-appropriate tone throughout every interaction.
Modeling Hotel State
The agent needs access to room inventory, guest records, and hotel amenity data.
from dataclasses import dataclass, field
from datetime import date, datetime
from enum import Enum
from typing import Optional
class RoomStatus(Enum):
AVAILABLE = "available"
OCCUPIED = "occupied"
CLEANING = "cleaning"
MAINTENANCE = "maintenance"
class RoomType(Enum):
STANDARD = "standard"
DELUXE = "deluxe"
SUITE = "suite"
PENTHOUSE = "penthouse"
@dataclass
class Room:
number: str
room_type: RoomType
floor: int
status: RoomStatus
rate_per_night: float
features: list[str] = field(default_factory=list)
@dataclass
class GuestReservation:
confirmation_id: str
guest_name: str
email: str
phone: str
check_in: date
check_out: date
room_type: RoomType
assigned_room: Optional[str] = None
checked_in: bool = False
special_requests: list[str] = field(default_factory=list)
@dataclass
class Hotel:
name: str
rooms: list[Room] = field(default_factory=list)
reservations: list[GuestReservation] = field(default_factory=list)
amenities: dict[str, str] = field(default_factory=dict)
def find_reservation(self, confirmation_id: str) -> GuestReservation | None:
return next(
(r for r in self.reservations if r.confirmation_id == confirmation_id),
None,
)
def available_rooms(self, room_type: RoomType) -> list[Room]:
return [
r for r in self.rooms
if r.room_type == room_type and r.status == RoomStatus.AVAILABLE
]
def assign_room(self, reservation: GuestReservation) -> Room | None:
candidates = self.available_rooms(reservation.room_type)
if not candidates:
return None
# Prefer higher floors for loyalty members, lower for accessibility
selected = candidates[0]
selected.status = RoomStatus.OCCUPIED
reservation.assigned_room = selected.number
reservation.checked_in = True
return selected
Building the Front Desk Agent Tools
from agents import Agent, function_tool
hotel = Hotel(
name="The Grand Horizon",
rooms=[
Room("201", RoomType.STANDARD, 2, RoomStatus.AVAILABLE, 159.0, ["city view"]),
Room("305", RoomType.DELUXE, 3, RoomStatus.AVAILABLE, 229.0, ["balcony", "ocean view"]),
Room("501", RoomType.SUITE, 5, RoomStatus.AVAILABLE, 399.0, ["living room", "ocean view"]),
],
amenities={
"pool": "Rooftop pool open 7 AM to 10 PM, towels provided poolside",
"gym": "24-hour fitness center on the 2nd floor, key card access",
"restaurant": "Horizon Bistro on the ground floor, breakfast 6:30-10:30 AM",
"spa": "Ocean Spa on the 4th floor, reservations recommended",
"wifi": "Complimentary WiFi, network: GrandHorizon-Guest, no password needed",
"parking": "Valet parking $35/night, self-park garage $20/night",
},
)
@function_tool
def check_in_guest(confirmation_id: str) -> str:
reservation = hotel.find_reservation(confirmation_id)
if not reservation:
return f"No reservation found with confirmation ID {confirmation_id}."
if reservation.checked_in:
return f"{reservation.guest_name} is already checked in to room {reservation.assigned_room}."
room = hotel.assign_room(reservation)
if not room:
return f"No {reservation.room_type.value} rooms currently available. Offering upgrade options."
return (
f"Welcome, {reservation.guest_name}! You are checked into room {room.number} "
f"on floor {room.floor} ({', '.join(room.features)}). "
f"Check-out is {reservation.check_out.isoformat()}."
)
@function_tool
def get_amenity_info(amenity_name: str) -> str:
amenity_lower = amenity_name.lower()
for key, info in hotel.amenities.items():
if amenity_lower in key.lower():
return info
available = ", ".join(hotel.amenities.keys())
return f"Amenity '{amenity_name}' not found. Available amenities: {available}"
@function_tool
def log_guest_complaint(
confirmation_id: str, category: str, description: str, urgency: str
) -> str:
reservation = hotel.find_reservation(confirmation_id)
guest_name = reservation.guest_name if reservation else "Unknown Guest"
ticket_id = f"CMP-{datetime.now().strftime('%H%M%S')}"
if urgency == "high":
return (
f"Ticket {ticket_id} created for {guest_name}: {category}. "
f"Escalating to duty manager immediately. "
f"A manager will contact you within 5 minutes."
)
return (
f"Ticket {ticket_id} created for {guest_name}: {category}. "
f"Our team will address this within 30 minutes."
)
@function_tool
def get_local_recommendations(category: str) -> str:
recommendations = {
"restaurants": [
"Sotto Mare - Italian seafood, 5 min walk",
"Sakura House - Japanese, 10 min walk",
"The Rooftop Kitchen - American, hotel rooftop",
],
"attractions": [
"City Art Museum - 15 min by taxi",
"Harbor Walk - 5 min walk from lobby",
"Botanical Gardens - 20 min by taxi",
],
"shopping": [
"Harbor Mall - 10 min walk",
"Old Town Market - 15 min by taxi",
],
}
cat_lower = category.lower()
for key, recs in recommendations.items():
if cat_lower in key:
return "\n".join(f"- {r}" for r in recs)
return f"No recommendations for '{category}'. Try: restaurants, attractions, shopping."
front_desk_agent = Agent(
name="Front Desk Agent",
instructions="""You are the front desk agent at The Grand Horizon hotel.
Greet guests warmly. Help with check-in, amenity questions, local
recommendations, and complaint resolution. For complaints, always
apologize sincerely and log a ticket. For urgent issues like safety
or plumbing, escalate immediately.""",
tools=[check_in_guest, get_amenity_info, log_guest_complaint, get_local_recommendations],
)
Handling Escalation Gracefully
Not every situation can be resolved by AI. The agent must know when to hand off to a human manager.
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
ESCALATION_TRIGGERS = [
"legal", "lawyer", "police", "medical emergency",
"discrimination", "assault", "injury", "refund over $500",
]
def should_escalate(message: str) -> bool:
message_lower = message.lower()
return any(trigger in message_lower for trigger in ESCALATION_TRIGGERS)
When the agent detects an escalation trigger, it immediately connects the guest to a human staff member rather than attempting a resolution that requires human judgment.
FAQ
How does the agent handle room upgrade requests?
When a guest requests an upgrade, the agent checks availability for the next tier up, calculates the price difference, and presents the option. If the guest is a loyalty member or if the upgrade is complimentary (due to a complaint resolution), the agent applies it directly. Paid upgrades require confirmation of the additional charge before proceeding.
What if multiple guests arrive simultaneously for check-in?
The AI agent handles concurrent conversations natively since each session is independent. Unlike a single human host, the agent can process fifty check-ins simultaneously. Each conversation maintains its own state, so there is no cross-talk or confusion between guests.
How does the agent verify guest identity during check-in?
The agent confirms identity by matching the confirmation ID with the guest's name and the last four digits of the credit card on file. For additional security, it can send a one-time verification code to the email or phone number associated with the reservation.
#HotelAI #FrontDeskAutomation #GuestServices #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.