Implementing AI-Powered Ticket Routing in Mobile Applications
Classification answers "what is this?" Routing answers "who gets this?" Different problem. A ticket labeled "technical issue"—but which specific agent or queue? Experienced staff, specialized agents, available agent in right timezone. Without AI, it's manual rules in Zendesk that break at scale.
Routing architecture in mobile context
Mobile app is the ticket entry point. Routing happens server-side; client just submits with metadata. But what metadata the client collects determines routing quality.
Minimum metadata for good routing:
-
user_id+ previous ticket history (from cache) -
platform(iOS/Android),app_version,os_version -
last_screen— screen user was on before submitting -
session_events— last 20 actions from analytics (Firebase AnalyticslogEvent) - Category from classifier (if already implemented)
-
device_locale— device language
On iOS, collect:
struct TicketContext: Encodable {
let userId: String
let platform = "ios"
let appVersion: String = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
let osVersion: String = UIDevice.current.systemVersion
let lastScreen: String
let sessionEvents: [String]
let locale: String = Locale.current.identifier
let previousTicketsCount: Int
}
Server-side routing logic
Server receives ticket with context and runs through routing engine. Two approaches:
Rules + ML hybrid
First filter—hard rules. If app_version < "3.0" and category billing, route to legacy billing queue; they know that version. These rules live in codebase, not in model—business changes them, not data scientists.
Second filter—ML ranking across free agents. Use simple multi-armed bandit or gradient boosting (LightGBM) on features: ticket topic, language, agent rating on similar tickets, current workload.
LLM-based routing
For low volume without a data scientist, OpenAI function calling handles routing as zero-shot classifier:
# Backend (Python)
routing_response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "system",
"content": f"Available queues: {json.dumps(queue_descriptions)}. Route the ticket."
}, {
"role": "user",
"content": ticket_text
}],
tools=[route_ticket_tool],
tool_choice={"type": "function", "function": {"name": "route_ticket"}}
)
One gpt-4o-mini call costs ~$0.0001. At 1000 tickets/day that's $3/month. Good starting point.
Display routing status in app
After submit, users want to know what's happening. Implement WebSocket or SSE for real-time status updates.
// Android—update status via StateFlow
class TicketStatusViewModel : ViewModel() {
private val _status = MutableStateFlow<TicketStatus>(TicketStatus.Sent)
val status = _status.asStateFlow()
fun observeTicket(ticketId: String) {
webSocketManager.observe(ticketId)
.onEach { event ->
when (event) {
is TicketEvent.Routed -> _status.value = TicketStatus.Routed(event.agentName, event.estimatedTime)
is TicketEvent.AgentAssigned -> _status.value = TicketStatus.InProgress(event.agentName)
is TicketEvent.Resolved -> _status.value = TicketStatus.Resolved
}
}
.launchIn(viewModelScope)
}
}
iOS equivalent via Combine + URLSessionWebSocketTask.
Reassignment and escalation
Routers make mistakes. Allow agents to reassign and feed that back to the system—training signal for the model. Mobile client should show reassignment without reload.
Common mistake: store assigned_agent_id only server-side without pushing update to mobile via push notification. User sees "ticket submitted" and doesn't know agent already changed.
Process
Audit current routing rules → describe queues and criteria → implement context collection on client → integrate with server routing engine → real-time status in UI → log reassignments for model improvement.
Timeline estimates
Basic rule-based routing with client context—1 week. Hybrid with ML ranking—3–5 weeks. Real-time WebSocket status—3–5 days separate.







