0Pricing
AI Agents · Leçon

Routage des tickets et logique d’escalade

Classer l’intention, orienter vers des agents spécialisés et définir les déclencheurs d’escalade.

Routage des tickets et logique d’escalade est une leçon AI Agents gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Agents, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Agents comprend 4 leçons au total.

Le problème du routage

Un agent du service client reçoit chaque jour des milliers de messages variés : litiges de facturation, réinitialisations de mot de passe, défauts de produit, retards de livraison et demandes de fonctionnalités. Envoyer chaque message au même gestionnaire produit des réponses lentes et de faible qualité.

Le routage des demandes classe chaque message et l'envoie à l'équipe la mieux à même de le résoudre.

Classification des intentions avec un LLM

La couche de routage appelle un LLM avec une invite de classification. Le modèle renvoie une réponse structurée contenant une étiquette intent et un score de confidence.

import openai, json

client = openai.OpenAI(api_key='YOUR_OPENAI_KEY')

INTENTS = ['billing', 'technical_support', 'returns_refunds',
           'account_access', 'shipping', 'general_inquiry']

def classify_intent(message: str) -> dict:
    prompt = (
        f'Classify this customer message into exactly one intent.\n'
        f'Intents: {INTENTS}\n'
        f'Message: "{message}"\n'
        f'Respond with JSON: {{"intent": "...", "confidence": 0.0-1.0}}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content)

Routage vers des files d'attente spécialisées

Une fois l'intention connue, acheminez la demande vers la file d'attente spécialisée appropriée. Chaque file possède ses propres modèles de réponse, SLA et règles d'escalade.

ROUTING_MAP = {
    'billing':           'queue_billing',
    'technical_support': 'queue_tech',
    'returns_refunds':   'queue_returns',
    'account_access':    'queue_tech',
    'shipping':          'queue_fulfillment',
    'general_inquiry':   'queue_general'
}

def route_ticket(ticket: dict) -> str:
    result = classify_intent(ticket['message'])
    intent = result['intent']
    confidence = result['confidence']
    queue = ROUTING_MAP.get(intent, 'queue_general')
    ticket['intent'] = intent
    ticket['confidence'] = confidence
    ticket['queue'] = queue
    return queue

Seuil de confiance pour l'escalade

Si le classifieur est incertain (confiance inférieure à 0,7), le routage automatique peut être incorrect. Les demandes à faible confiance doivent être transmises à un humain pour un triage manuel plutôt que d'être automatiquement orientées vers un spécialiste.

CONFIDENCE_THRESHOLD = 0.70

def route_with_escalation(ticket: dict) -> dict:
    result = classify_intent(ticket['message'])
    intent = result['intent']
    confidence = result['confidence']

    if confidence < CONFIDENCE_THRESHOLD:
        return {
            'ticket_id': ticket['id'],
            'action': 'escalate_to_human',
            'reason': f'Low confidence: {confidence:.2f}',
            'suggested_intent': intent
        }

    queue = ROUTING_MAP.get(intent, 'queue_general')
    return {
        'ticket_id': ticket['id'],
        'action': 'route_to_queue',
        'queue': queue,
        'intent': intent,
        'confidence': confidence
    }

Escalade des priorités basée sur le SLA

Même les demandes automatiquement orientées peuvent dépasser leur SLA si elles ne sont pas résolues à temps. Une tâche en arrière-plan compare l'ancienneté des demandes aux objectifs SLA et transmet les demandes en retard à une file d'attente de supervision.

from datetime import datetime, timezone

SLA_HOURS = {
    'queue_billing':      4,
    'queue_tech':         8,
    'queue_returns':      24,
    'queue_fulfillment':  12,
    'queue_general':      48
}

def check_sla_breach(ticket: dict) -> bool:
    created = datetime.fromisoformat(ticket['created_at'])
    age_hours = (datetime.now(timezone.utc) - created).total_seconds() / 3600
    sla = SLA_HOURS.get(ticket['queue'], 24)
    if age_hours > sla and ticket['status'] == 'open':
        ticket['queue'] = 'queue_supervisor_escalation'
        ticket['escalation_reason'] = f'SLA breach: {age_hours:.1f}h > {sla}h'
        return True
    return False

if __name__ == '__main__':
    from datetime import datetime, timedelta, timezone
    old_ticket = {
        'created_at': (datetime.now(timezone.utc) - timedelta(hours=10)).isoformat(),
        'queue': 'queue_billing',
        'status': 'open',
    }
    breached = check_sla_breach(old_ticket)
    print(f'SLA breached: {breached}')
    if breached:
        print('Escalation reason:', old_ticket['escalation_reason'])

Routage multi-étiquettes pour les demandes complexes

Certains messages concernent plusieurs domaines : « Ma commande est arrivée cassée et j'ai été facturé deux fois. » Un classifieur multi-étiquettes renvoie plusieurs intentions ; la demande est dupliquée dans les deux files d'attente et les agents coordonnent sa résolution.

def classify_multi_intent(message: str) -> list[dict]:
    prompt = (
        f'A customer message may have multiple intents.\n'
        f'Intents: {INTENTS}\n'
        f'Message: "{message}"\n'
        f'Return JSON array: [{{"intent": "...", "confidence": 0.0}}]\n'
        f'Include only intents with confidence > 0.5'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    data = json.loads(resp.choices[0].message.content)
    return data.get('intents', [])

# Route to multiple queues
def route_multi(ticket: dict) -> list[str]:
    intents = classify_multi_intent(ticket['message'])
    return [ROUTING_MAP.get(i['intent'], 'queue_general') for i in intents]

Extraction des métadonnées d'une demande

Avant le routage, extrayez les métadonnées du message pour aider les spécialistes : numéros de commande, noms de produits et identifiants de compte. Cela accélère la résolution en éliminant la première série de questions de clarification.

def extract_metadata(message: str) -> dict:
    prompt = (
        f'Extract structured metadata from this customer message.\n'
        f'Return JSON: {{"order_id": null, "product": null, "account_email": null}}\n'
        f'Use null for fields not mentioned.\n'
        f'Message: "{message}"'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content)

meta = extract_metadata('My order #A12345 for the blue headphones never arrived.')
print(meta)  # {'order_id': 'A12345', 'product': 'blue headphones', 'account_email': None}

Augmentation de la priorité basée sur le sentiment

Les clients mécontents sont plus susceptibles de partir. Détectez le sentiment négatif et augmentez la priorité de la demande afin que les clients insatisfaits obtiennent une réponse plus rapidement, même si leur délai SLA n'est pas encore expiré.

def detect_sentiment(message: str) -> str:
    prompt = f'Classify sentiment as positive/neutral/negative.\nMessage: "{message}"\nReturn JSON: {{"sentiment": "..."}}'
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content)['sentiment']

def set_priority(ticket: dict) -> str:
    sentiment = detect_sentiment(ticket['message'])
    if sentiment == 'negative':
        ticket['priority'] = 'high'
    elif sentiment == 'positive':
        ticket['priority'] = 'low'
    else:
        ticket['priority'] = 'normal'
    return ticket['priority']

Définition de la chaîne d'escalade

Définissez une chaîne d'escalade claire afin que chaque file d'attente dispose d'une solution de repli. Lorsque la file du premier niveau ne parvient pas à résoudre la demande dans le délai SLA, celle-ci passe au niveau 2, puis au niveau 3 (spécialiste senior), et enfin au superviseur.

ESCALATION_CHAIN = {
    'queue_tech':              'queue_tech_tier2',
    'queue_tech_tier2':        'queue_tech_senior',
    'queue_tech_senior':       'queue_supervisor_escalation',
    'queue_billing':           'queue_billing_senior',
    'queue_billing_senior':    'queue_supervisor_escalation',
    'queue_returns':           'queue_supervisor_escalation',
    'queue_fulfillment':       'queue_supervisor_escalation',
    'queue_general':           'queue_supervisor_escalation',
    'queue_supervisor_escalation': None  # terminal — human manager
}

def escalate(ticket: dict) -> str | None:
    next_queue = ESCALATION_CHAIN.get(ticket['queue'])
    if next_queue:
        ticket['queue'] = next_queue
    return next_queue

if __name__ == '__main__':
    ticket = {'queue': 'queue_tech'}
    for _ in range(3):
        nxt = escalate(ticket)
        print(f"Escalated to: {ticket['queue']}")
        if nxt is None:
            break

Chaîne complète de traitement du routage

Combinez la classification, l'extraction des métadonnées, l'analyse du sentiment et la vérification du SLA dans une seule chaîne de traitement exécutée pour chaque demande entrante.

def process_ticket(raw_ticket: dict) -> dict:
    ticket = dict(raw_ticket)

    # Step 1: Classify and route
    routing = route_with_escalation(ticket)
    ticket.update(routing)

    # Step 2: Extract metadata
    ticket['metadata'] = extract_metadata(ticket['message'])

    # Step 3: Set priority from sentiment
    ticket['priority'] = set_priority(ticket)

    # Step 4: Check if already breaching SLA
    if ticket.get('created_at'):
        check_sla_breach(ticket)

    return ticket

result = process_ticket({
    'id': 'T001',
    'message': 'I was charged twice for my subscription last month!',
    'created_at': '2026-05-28T10:00:00+00:00',
    'status': 'open'
})
print(result)

Surveillance de la précision du routage

Suivez la précision du routage en soumettant un pourcentage des demandes automatiquement orientées à un contrôle humain. Lorsqu'un spécialiste réaffecte une demande à une autre file d'attente, il s'agit d'une erreur de routage. Réinjectez ces erreurs pour améliorer l'invite ou affiner un classifieur.

import random

def log_routing_decision(ticket: dict, final_queue: str):
    was_correct = ticket.get('queue') == final_queue
    if not was_correct:
        print(f'[ROUTING_ERROR] ticket={ticket["id"]} '
              f'predicted={ticket["queue"]} actual={final_queue} '
              f'confidence={ticket.get("confidence", 0):.2f}')

# Specialist reassigns ticket: log the discrepancy
def specialist_reassign(ticket: dict, new_queue: str):
    log_routing_decision(ticket, new_queue)
    ticket['queue'] = new_queue
    return ticket

if __name__ == '__main__':
    ticket = {'id': 'T-1001', 'queue': 'queue_billing', 'confidence': 0.62}
    specialist_reassign(ticket, 'queue_tech')

Quel seuil de confiance doit déclencher une escalade humaine plutôt qu'un routage automatique ?

Le choix du bon seuil de confiance permet d'équilibrer le taux d'automatisation et la précision du routage. Un seuil trop élevé entraîne trop d'escalades ; un seuil trop bas conduit à de mauvais routages.

Récapitulatif du routage des demandes

Un routage efficace des demandes combine la classification des intentions par un LLM avec un seuil de confiance pour l'escalade humaine, l'extraction des métadonnées pour accélérer la résolution, la priorité basée sur le sentiment pour les clients à risque et une chaîne d'escalade SLA afin qu'aucune demande ne soit oubliée.

Questions Fréquemment Posées

La leçon « Routage des tickets et logique d’escalade » est-elle gratuite ?

Oui — le texte complet de « Routage des tickets et logique d’escalade » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Agents, passe à CoddyKit PRO. Le cours AI Agents comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Routage des tickets et logique d’escalade » ?

Classer l’intention, orienter vers des agents spécialisés et définir les déclencheurs d’escalade. Tu pratiques AI Agents avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer AI Agents ?

Aucune expérience préalable n'est requise. AI Agents sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Routage des tickets et logique d’escalade » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon AI Agents ?

Oui. Chaque leçon AI Agents inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Routage des tickets et logique d’escalade
  2. Intégration CRM : Salesforce et HubSpot
  3. Protocoles de transfert vers un humain
  4. Gestion du contexte et de l’historique client
← Retour à AI Agents