The Brief, and Whether It Needs AI at All
Week 1's questions answered on a real problem
Fourteen weeks of methods, applied once, to a problem that has not appeared before. A helpdesk receives tickets in free text. Each needs routing to a team and marking urgent or not, and at the moment a person reads every one.
Before any code: is this even an AI problem
Week 1's questions, answered honestly, because this is the step most often skipped.
- What decision changes? Which queue a ticket lands in and how quickly somebody looks at it. Both are acted on, so the output has a use.
- Could a person write the rules? Partly. Routing looks like keyword matching. Urgency does not, because it is expressed differently every time.
- What does a wrong answer cost? A misrouted ticket is a delay. A missed urgent ticket is a real problem. The two errors are not equal, which decides the metric.
- Do the labels exist? Yes, because the helpdesk already records which team resolved each ticket. Urgency has to be labelled, which is a cost.
- Will it still look like this? New systems arrive, so the vocabulary will drift. It will need monitoring and retraining.
import random
random.seed(5)
rng = np.random.RandomState(5)
# An IT helpdesk. Tickets are routed to a team and marked urgent or not.
# Urgency lives in a phrase, not a word, so week 4's lesson applies.
TEAM_WORDS = {
'network': ['vpn', 'wifi', 'router', 'firewall', 'connection'],
'accounts': ['password', 'login', 'permissions', 'mailbox', 'licence'],
'hardware': ['laptop', 'monitor', 'keyboard', 'docking station',
'printer'],
}
URGENT = ['cannot work at all', 'whole team is blocked',
'client demo in an hour', 'production is down']
CALM = ['when you get a chance', 'no rush at all',
'sometime this week is fine', 'low priority']
FRAME = ['the {thing} is not working, {tail}',
'having trouble with the {thing}, {tail}',
'my {thing} keeps failing, {tail}',
'can someone look at the {thing}, {tail}']
texts, teams, urgent = [], [], []
for _ in range(500):
for team, words in TEAM_WORDS.items():
for is_urgent in (True, False):
tail = random.choice(URGENT if is_urgent else CALM)
texts.append(random.choice(FRAME).format(
thing=random.choice(words), tail=tail))
teams.append(team)
urgent.append(int(is_urgent))
from sklearn.model_selection import train_test_split
(train_x, test_x, train_t, test_t,
train_u, test_u) = train_test_split(texts, teams, urgent,
test_size=0.3, random_state=0,
stratify=teams)
print('%d tickets, %d for training' % (len(texts), len(train_x)))
print()
for t, team, u in list(zip(texts, teams, urgent))[:5]:
print('%-9s %-7s %s' % (team, 'urgent' if u else 'normal', t))
print()
import collections
print('teams: %s' % dict(collections.Counter(teams)))
print('urgent share: %.2f' % (sum(urgent) / len(urgent)))
network urgent my connection keeps failing, client demo in an hour
network normal can someone look at the wifi, when you get a chance
accounts urgent having trouble with the password, cannot work at all
accounts normal can someone look at the login, sometime this week is fine
hardware urgent the printer is not working, production is down
teams: {'network': 1000, 'accounts': 1000, 'hardware': 1000}
urgent share: 0.50