Berlin Tech Meetup: The Future of Relational Foundation Models, Systems, and Real-World Applications

Register now:
PyG/Use Case11 min read

Ticket Routing: GNN on Agent-Skill-History Graphs

Poor ticket routing increases resolution time by 40% and costs enterprises $22B annually in wasted agent time. Here is how to build a GNN that matches tickets to agents using expertise graphs learned from resolution history.

PyTorch Geometric

TL;DR

  • 1Ticket routing is a bipartite matching problem on an agent-skill-ticket graph. GNNs learn agent expertise from resolution history and match it to ticket requirements automatically.
  • 2HeteroConv aggregates agent resolution patterns, ticket content signals, and customer context for nuanced ticket-agent matching beyond keyword rules.
  • 3On RelBench benchmarks, GNNs achieve 75.83 AUROC vs 62.44 for flat-table LightGBM. Learned expertise profiles drive the improvement over rule-based routing.
  • 4Pre-computed agent embeddings enable sub-50ms routing. New tickets are embedded from content and customer context, then matched to available agents.
  • 5KumoRFM routes tickets with one PQL query (76.71 AUROC zero-shot), learning expertise patterns from your support data automatically.

The business problem

Enterprise support teams handle millions of tickets annually. Poor routing, sending a billing question to a technical specialist, or a complex integration issue to a junior agent, increases average resolution time by 40% and costs enterprises $22 billion annually in wasted agent time and escalations. Good routing gets the right ticket to the right agent on the first try.

Why flat ML fails

  • Keyword matching is brittle: “Payment failed” could be a billing issue, a technical integration bug, or a fraud case. Keywords alone cannot disambiguate.
  • No expertise modeling: Agent skills are not just tags. An agent who resolved 200 complex API integration tickets has deep expertise that a tag-based system cannot quantify.
  • No customer context: A ticket from a customer with 10 previous billing issues is likely billing-related, regardless of keyword content. Flat models miss this history.
  • No load balancing: The best agent for a ticket may be overloaded. Graph-aware routing considers agent capacity alongside match quality.

The relational schema

schema.txt
Node types:
  Agent    (id, team, seniority, current_load)
  Ticket   (id, content_emb, priority, channel, created_at)
  Skill    (id, category, complexity_level)
  Customer (id, plan, tenure, ltv, support_history_count)

Edge types:
  Agent    --[has_skill]-->   Skill    (proficiency, tickets_resolved)
  Agent    --[resolved]-->    Ticket   (resolution_time, csat)
  Ticket   --[requires]-->    Skill    (importance)
  Ticket   --[filed_by]-->    Customer
  Customer --[has_history]--> Ticket   (outcome, satisfaction)

Agent-skill edges capture demonstrated expertise. Ticket-skill edges capture requirements. The GNN matches expertise to requirements while considering customer context.

PyG architecture: HeteroConv for ticket-agent matching

routing_model.py
import torch
import torch.nn.functional as F
from torch_geometric.nn import SAGEConv, HeteroConv, Linear

class TicketRoutingGNN(torch.nn.Module):
    def __init__(self, hidden_dim=128):
        super().__init__()
        self.agent_lin = Linear(-1, hidden_dim)
        self.ticket_lin = Linear(-1, hidden_dim)
        self.skill_lin = Linear(-1, hidden_dim)
        self.customer_lin = Linear(-1, hidden_dim)

        self.conv1 = HeteroConv({
            ('agent', 'has_skill', 'skill'): SAGEConv(
                hidden_dim, hidden_dim),
            ('agent', 'resolved', 'ticket'): SAGEConv(
                hidden_dim, hidden_dim),
            ('ticket', 'requires', 'skill'): SAGEConv(
                hidden_dim, hidden_dim),
            ('ticket', 'filed_by', 'customer'): SAGEConv(
                hidden_dim, hidden_dim),
        }, aggr='sum')

        self.conv2 = HeteroConv({
            ('agent', 'has_skill', 'skill'): SAGEConv(
                hidden_dim, hidden_dim),
            ('ticket', 'requires', 'skill'): SAGEConv(
                hidden_dim, hidden_dim),
            ('ticket', 'filed_by', 'customer'): SAGEConv(
                hidden_dim, hidden_dim),
        }, aggr='sum')

    def encode(self, x_dict, edge_index_dict):
        x_dict['agent'] = self.agent_lin(x_dict['agent'])
        x_dict['ticket'] = self.ticket_lin(x_dict['ticket'])
        x_dict['skill'] = self.skill_lin(x_dict['skill'])
        x_dict['customer'] = self.customer_lin(
            x_dict['customer'])

        x_dict = {k: F.relu(v) for k, v in
                  self.conv1(x_dict, edge_index_dict).items()}
        x_dict = self.conv2(x_dict, edge_index_dict)
        return x_dict

    def match_score(self, agent_emb, ticket_emb):
        return (agent_emb * ticket_emb).sum(dim=-1)

Agent embeddings encode demonstrated expertise from resolution history. Ticket embeddings encode requirements and customer context. Dot product scores the match quality.

Expected performance

  • Round-robin routing: ~35 AUROC (random baseline)
  • LightGBM (keyword features): 62.44 AUROC
  • GNN (expertise graph): 75.83 AUROC
  • KumoRFM (zero-shot): 76.71 AUROC

Or use KumoRFM in one line

KumoRFM PQL
PREDICT best_agent FOR ticket
USING agent, ticket, skill, customer, resolution_history

One PQL query. KumoRFM learns agent expertise from resolution history and matches tickets to optimal agents.

Frequently asked questions

Why use GNNs for ticket routing instead of rule-based systems?

Rule-based routing uses keyword matching and queue assignment. GNNs see the full context: agent expertise (from resolved ticket history), ticket complexity (from similar past tickets), customer context (from account history), and current agent load. This enables nuanced matching that rules cannot achieve.

What graph structure represents ticket routing?

Agents, tickets, skills, and customers form a heterogeneous graph. Edges connect agents to skills they have demonstrated (from resolution history), tickets to required skills (from content analysis), customers to their ticket history, and agents to previously resolved similar tickets.

How does the graph capture agent expertise?

Agent expertise is inferred from resolution history: an agent who has resolved 50 billing tickets with high CSAT scores has strong billing expertise. The GNN aggregates this from the agent's resolved-ticket subgraph, producing a nuanced expertise profile that goes beyond keyword-based skill tags.

Can GNN routing handle real-time ticket assignment?

Yes. Pre-compute agent embeddings (updated hourly) and skill embeddings. When a new ticket arrives, compute the ticket embedding from its content and customer context, then find the best-matching available agent via embedding similarity. Inference takes under 50ms.

How does KumoRFM handle ticket routing?

KumoRFM takes your support database (agents, tickets, resolutions, customers, skills) and predicts optimal agent assignment with one PQL query. It learns agent expertise patterns and ticket-skill matching from resolution history automatically.

Learn more about graph ML

PyTorch Geometric is the open-source foundation for graph neural networks. Explore more layers, concepts, and production patterns.