llm_ticket3/agents/deepseek/agent_ticket_analyser.py
2025-04-14 14:10:19 +02:00

196 lines
8.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import json
import time
import logging
from typing import Dict, Any, Optional
# Importer BaseAgent depuis le répertoire utils
from agents.utils.base_agent import BaseAgent
# Configuration du logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger("AgentTicketAnalyser_DeepSeek")
class AgentTicketAnalyser(BaseAgent):
"""
Agent spécialisé pour analyser un ticket et en extraire les informations clés.
Version optimisée pour DeepSeek.
"""
def __init__(self, llm: Any):
"""
Initialise l'agent d'analyse de ticket avec un modèle LLM.
Args:
llm: Instance du modèle de langage à utiliser
"""
super().__init__(llm)
self.temperature = 0.1 # Température très basse pour une analyse factuelle
self.top_p = 0.9
self.max_tokens = 4000
# System prompt spécifique pour l'analyse de tickets avec DeepSeek
self.system_prompt = """Tu es un expert en analyse de tickets pour le support informatique de BRG-Lab pour la société CBAO.
Tu interviens avant l'analyse des captures d'écran pour contextualiser le ticket, identifier les questions posées, et structurer les échanges de manière claire.
Ta mission principale :
1. Identifier le client et le contexte du ticket (demande "name" et "description")
- Récupère le nom de l'auteur si présent
- Indique si un `user_id` est disponible
- Conserve uniquement les informations d'identification utiles (pas d'adresse ou signature de mail inutile)
2. Mettre en perspective le `name` du ticket
- Il peut contenir une ou plusieurs questions implicites
- Reformule ces questions de façon explicite
3. Analyser la `description`
- Elle fournit souvent le vrai point d'entrée technique
- Repère les formulations interrogatives ou les demandes spécifiques
- Identifie si cette partie complète ou précise les questions du nom
4. Structurer le fil de discussion
- Conserve uniquement les échanges pertinents
-Conserve les questions soulevés par "name" ou "description"
- CONSERVE ABSOLUMENT les références documentation, FAQ, liens utiles et manuels
- Identifie clairement chaque intervenant (client / support)
- Classe les informations par ordre chronologique avec date et rôle
5. Préparer la transmission à l'agent suivant
- Préserve tous les éléments utiles à l'analyse d'image : modules cités, options évoquées, comportements décrits
- Mentionne si des images sont attachées au ticket
Structure ta réponse :
1. Résumé du contexte
- Client (nom, email si disponible)
- Sujet du ticket reformulé en une ou plusieurs questions
- Description technique synthétique
2. Informations techniques détectées
- Logiciels/modules mentionnés
- Paramètres évoqués
- Fonctionnalités impactées
- Conditions spécifiques (multi-laboratoire, utilisateur non valide, etc.)
3. Fil de discussion (filtrée, nettoyée, classée)
- Intervenant (Client/Support)
- Date et contenu de chaque échange
- Résumés techniques
- INCLURE TOUS les liens documentaires (manuel, FAQ, documentation technique)
4. Éléments liés à l'analyse visuelle
- Nombre d'images attachées
- Références aux interfaces ou options à visualiser
- Points à vérifier dans les captures (listes incomplètes, cases à cocher, utilisateurs grisés, etc.)
IMPORTANT :
- Ne propose aucune solution ni interprétation
- Ne génère pas de tableau
- Reste strictement factuel en te basant uniquement sur les informations fournies
- Ne reformule pas les messages, conserve les formulations exactes sauf nettoyage de forme"""
def executer(self, ticket_data: Dict[str, Any]) -> str:
"""
Analyse un ticket à partir des données fournies.
Args:
ticket_data: Dictionnaire contenant les données du ticket
- 'ticket_summary': Résumé du ticket
- 'messages': Liste des messages du ticket
Returns:
str: Analyse structurée du ticket
"""
start_time = time.time()
try:
# Extraire le résumé du ticket
ticket_summary = ticket_data.get('ticket_summary', {})
ticket_code = ticket_summary.get('code', 'INCONNU')
ticket_sujet = ticket_summary.get('sujet', 'Sans sujet')
# Log des informations de base du ticket
logger.info(f"Analyse du ticket {ticket_code}: {ticket_sujet}")
print(f" Analyse du ticket {ticket_code}: {ticket_sujet[:80]}{'...' if len(ticket_sujet) > 80 else ''}")
# Construire le contexte à partir des messages
messages = ticket_data.get('messages', [])
# Construire un prompt pour analyser le ticket
ticket_prompt = self._construire_prompt_ticket(ticket_summary, messages)
# Analyser le ticket avec le LLM
analyse = self.llm.generate(
system_prompt=self.system_prompt,
prompt=ticket_prompt,
temperature=self.temperature,
top_p=self.top_p,
max_tokens=self.max_tokens
)
# Calcul du temps de génération
generation_time = time.time() - start_time
# Log de l'analyse complétée
logger.info(f"Analyse complétée en {generation_time:.2f} secondes")
print(f" Analyse complétée en {generation_time:.2f} secondes")
return analyse
except Exception as e:
logger.error(f"Erreur lors de l'analyse du ticket: {str(e)}")
return f"ERREUR: Impossible d'analyser le ticket: {str(e)}"
def _construire_prompt_ticket(self, ticket_summary: Dict[str, Any], messages: list) -> str:
"""
Construit un prompt détaillé à partir des données du ticket.
Args:
ticket_summary: Résumé du ticket
messages: Liste des messages du ticket
Returns:
str: Prompt détaillé pour l'analyse
"""
# Construire l'en-tête avec les informations du ticket
prompt = f"# TICKET: {ticket_summary.get('code', 'INCONNU')}\n"
prompt += f"Sujet: {ticket_summary.get('sujet', 'Sans sujet')}\n"
prompt += f"Statut: {ticket_summary.get('statut', 'Inconnu')}\n"
prompt += f"Priorité: {ticket_summary.get('priorité', 'Non définie')}\n"
prompt += f"Date de création: {ticket_summary.get('date_création', 'Inconnue')}\n\n"
# Ajouter la section des messages
prompt += "## MESSAGES DU TICKET\n\n"
for i, message in enumerate(messages, 1):
# Extraire les informations du message
date = message.get('date', 'Date inconnue')
auteur = message.get('auteur', 'Auteur inconnu')
role = message.get('role', 'Rôle inconnu')
contenu = message.get('contenu', '')
# Ajouter l'en-tête du message
prompt += f"### Message {i} - {date}\n"
prompt += f"De: {auteur} ({role})\n\n"
# Ajouter le contenu du message
prompt += f"{contenu}\n\n"
# Ajouter les informations sur les pièces jointes si disponibles
attachments = message.get('attachments', [])
if attachments:
prompt += f"Pièces jointes ({len(attachments)}):\n"
for attachment in attachments:
prompt += f"- {attachment.get('nom', 'Sans nom')} ({attachment.get('type', 'Type inconnu')})\n"
prompt += "\n"
# Ajouter les instructions d'analyse
prompt += "\n## INSTRUCTIONS\n"
prompt += "Analyse ce ticket selon les instructions dans ton system prompt. "
prompt += "Fournis une analyse structurée et complète qui servira de base à l'analyse des images."
return prompt