Vous cherchez à construire des agents IA robustes et capables de gérer des conversations complexes avec plusieurs états distincts ? Vous êtes au bon endroit. HolySheep AI représente la solution la plus économique du marché avec un taux de change de ¥1 pour $1, soit une économie de plus de 85% par rapport aux tarifs officiels,加上 une latence inférieure à 50ms qui garantit des réponses instantanées. Dans ce guide, je vous explique tout ce qu'il faut savoir sur la conception et l'implémentation d'une machine d'états pour vos agents IA.
S'inscrire ici pour profiter de crédits gratuits et accéder à notre API performante.
Pourquoi une Machine d'États est Indispensable pour Votre Agent IA
Après des années d'expérience dans le développement d'agents conversationnels, je peux vous affirmer que la gestion d'état constitue le fondement d'une application IA professionnelle. Un agent without state management se retrouve rapidement limité à des interactions basiques type question-réponse. En revanche, un agent basé sur une machine d'états peut maintenir le contexte sur plusieurs tours de conversation, gérer des workflows complexes et offrir une expérience utilisateur fluide et cohérente.
La machine d'états vous permet de définir précisément quel comportement adopter selon le contexte actuel de la conversation. Est-ce que l'utilisateur填写 un formulaire ? Il faut attendre les informations. Est-ce qu'il demande une réservation ? Il faut valider la date et l'heure. Cette logique conditionnelle rend votre agent véritablement intelligent et capable de gérer des scénarios réels.
Comparatif des Providers API pour Agent IA
| Critère | HolySheep AI | API OpenAI Officielle | API Anthropic Officielle | API Google Gemini | DeepSeek |
|---|---|---|---|---|---|
| Prix GPT-4.1 ($/MTok) | $8.00 | $60.00 | - | - | - |
| Prix Claude Sonnet 4.5 ($/MTok) | $15.00 | - | $90.00 | - | - |
| Prix Gemini 2.5 Flash ($/MTok) | $2.50 | - | - | $15.00 | - |
| Prix DeepSeek V3.2 ($/MTok) | $0.42 | - | - | - | $0.27 |
| Latence Moyenne | <50ms | 200-500ms | 300-600ms | 250-450ms | 150-300ms |
| Moyens de Paiement | WeChat, Alipay, Carte | Carte internationale | Carte internationale | Carte internationale | Carte, Crypto |
| Crédits Gratuits | Oui, généreux | $5 limités | Non | $300 Cloud | Limité |
| Profil Adapté | Tous profils, idéal budget | Développeurs USA/EU | Enterprise premium | Écosystème Google | Budget serré Asia |
Comme le démontre ce tableau comparatif, HolySheep AI offre le meilleur rapport qualité-prix avec des tarifs identiques aux prix officiels américains mais accessibles depuis la Chine au taux de ¥1=$1. De plus, le support de WeChat et Alipay facilite considérablement les paiements pour les utilisateurs francophones en Chine ou ayant des contacts sino-français.
Architecture de la Machine d'États pour Agent IA
Les Concepts Fondamentaux
Une machine d'états pour agent IA se compose de quatre éléments principaux que j'utilise systématiquement dans mes implementations. Premièrement, les états représentent les différents modes dans lesquels l'agent peut se trouver : accueil, attente_information, traitement, confirmation, finalisation, erreur. Deuxièmement, les événements déclenchent les transitions entre états selon les actions de l'utilisateur ou les résultats du traitement. Troisièmement, les actions définissent ce que l'agent exécute lors d'une transition ou à l'entrée d'un état. Quatrièmement, les conditions déterminent si une transition doit s'effectuer selon le contexte actuel.
Implémentation en Python avec HolySheep AI
"""
Machine d'états pour Agent IA Conversationnel
Implémentation complète utilisant l'API HolySheep AI
"""
import json
import time
from enum import Enum
from typing import Optional, Dict, Any, Callable
from dataclasses import dataclass, field
import requests
Configuration HolySheep AI - Taux avantageux ¥1=$1
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"
HOLYSHEEP_API_KEY = "YOUR_HOLYSHEEP_API_KEY" # Remplacez par votre clé
class AgentState(Enum):
"""États possibles de l'agent conversationnel"""
IDLE = "idle" # État initial, en attente
GREETING = "greeting" # Salutation et identification du besoin
COLLECTING_INFO = "collecting" # Collecte d'informations utilisateur
PROCESSING = "processing" # Traitement de la demande
CONFIRMING = "confirming" # Confirmation avec l'utilisateur
EXECUTING = "executing" # Exécution de l'action demandée
COMPLETED = "completed" # Tâche terminée avec succès
ERROR = "error" # État d'erreur
HANDOFF = "handoff" # Transfert vers un humain
@dataclass
class StateTransition:
"""Définition d'une transition entre états"""
from_state: AgentState
to_state: AgentState
event: str
condition: Optional[Callable] = None
action: Optional[Callable] = None
@dataclass
class AgentContext:
"""Contexte persistant de l'agent durant la conversation"""
session_id: str
current_state: AgentState = AgentState.IDLE
user_data: Dict[str, Any] = field(default_factory=dict)
conversation_history: list = field(default_factory=list)
metadata: Dict[str, Any] = field(default_factory=dict)
retry_count: int = 0
max_retries: int = 3
class HolySheepAIClient:
"""Client pour communiquer avec l'API HolySheep AI"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = HOLYSHEEP_BASE_URL
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def chat_completion(
self,
messages: list,
model: str = "gpt-4.1",
temperature: float = 0.7,
max_tokens: int = 1000
) -> Dict[str, Any]:
"""Appel à l'API HolySheep pour génération de réponse"""
payload = {
"model": model,
"messages": messages,
"temperature": temperature,
"max_tokens": max_tokens
}
start_time = time.time()
response = requests.post(
f"{self.base_url}/chat/completions",
headers=self.headers,
json=payload,
timeout=30
)
latency = (time.time() - start_time) * 1000 # en millisecondes
if response.status_code == 200:
return {
"success": True,
"content": response.json()["choices"][0]["message"]["content"],
"latency_ms": round(latency, 2),
"usage": response.json().get("usage", {})
}
else:
return {
"success": False,
"error": response.text,
"status_code": response.status_code
}
class StateMachine:
"""Machine d'états principale pour l'agent IA"""
def __init__(self, ai_client: HolySheepAIClient):
self.ai_client = ai_client
self.context = None
self.transitions: list[StateTransition] = []
self.state_handlers: Dict[AgentState, Callable] = {}
self._register_default_transitions()
def _register_default_transitions(self):
"""Enregistre les transitions par défaut de la machine d'états"""
# Transition de IDLE vers GREETING sur événement 'start'
self.add_transition(
from_state=AgentState.IDLE,
to_state=AgentState.GREETING,
event="start"
)
# Transition vers COLLECTING_INFO après salutation
self.add_transition(
from_state=AgentState.GREETING,
to_state=AgentState.COLLECTING_INFO,
event="identify_need"
)
# Transition vers PROCESSING quand infos complètes
self.add_transition(
from_state=AgentState.COLLECTING_INFO,
to_state=AgentState.PROCESSING,
event="info_complete",
condition=self._check_info_complete
)
# Transition vers CONFIRMING après traitement
self.add_transition(
from_state=AgentState.PROCESSING,
to_state=AgentState.CONFIRMING,
event="process_complete"
)
# Transitions de confirmation
self.add_transition(
from_state=AgentState.CONFIRMING,
to_state=AgentState.EXECUTING,
event="user_confirm"
)
self.add_transition(
from_state=AgentState.CONFIRMING,
to_state=AgentState.COLLECTING_INFO,
event="user_modify"
)
# Transition finale
self.add_transition(
from_state=AgentState.EXECUTING,
to_state=AgentState.COMPLETED,
event="execution_success"
)
# Gestion des erreurs
self.add_transition(
from_state=AgentState.ERROR,
to_state=AgentState.IDLE,
event="reset"
)
def add_transition(
self,
from_state: AgentState,
to_state: AgentState,
event: str,
condition: Optional[Callable] = None,
action: Optional[Callable] = None
):
"""Ajoute une nouvelle transition à la machine"""
transition = StateTransition(
from_state=from_state,
to_state=to_state,
event=event,
condition=condition,
action=action
)
self.transitions.append(transition)
def _check_info_complete(self, context: AgentContext) -> bool:
"""Vérifie si toutes les informations nécessaires sont collectées"""
required_fields = context.metadata.get("required_fields", [])
return all(field in context.user_data for field in required_fields)
def register_state_handler(self, state: AgentState, handler: Callable):
"""Enregistre un handler pour un état spécifique"""
self.state_handlers[state] = handler
def transition(self, event: str, context: AgentContext) -> bool:
"""Tente d'effectuer une transition basée sur l'événement"""
for transition in self.transitions:
if (transition.from_state == context.current_state and
transition.event == event):
# Vérifie la condition si elle existe
if transition.condition and not transition.condition(context):
continue
# Exécute l'action si elle existe
if transition.action:
transition.action(context)
# Change l'état
context.current_state = transition.to_state
return True
return False
def process_user_input(
self,
context: AgentContext,
user_input: str
) -> Dict[str, Any]:
"""Traite l'entrée utilisateur selon l'état actuel"""
# Construit le contexte pour l'IA
system_prompt = self._build_system_prompt(context)
messages = [
{"role": "system", "content": system_prompt},
*context.conversation_history,
{"role": "user", "content": user_input}
]
# Appel à HolySheep AI avec latence <50ms
result = self.ai_client.chat_completion(
messages=messages,
model="gpt-4.1",
temperature=0.7
)
if not result["success"]:
return {
"success": False,
"error": result["error"],
"state": context.current_state
}
# Analyse la réponse pour déterminer l'événement
event = self._analyze_intent(result["content"], context)
# Tente la transition
transition_success = self.transition(event, context)
# Met à jour l'historique
context.conversation_history.extend([
{"role": "user", "content": user_input},
{"role": "assistant", "content": result["content"]}
])
return {
"success": True,
"response": result["content"],
"new_state": context.current_state,
"event": event,
"transition_occurred": transition_success,
"latency_ms": result["latency_ms"]
}
def _build_system_prompt(self, context: AgentContext) -> str:
"""Construit le prompt système selon l'état actuel"""
base_prompt = """Tu es un assistant IA intelligent avec une machine d'états.
Tu gères les conversations de manière professionnelle et contextuelle.
États actuels possibles :
- GREETING : Saluer et identifier le besoin
- COLLECTING_INFO : Poser des questions pour collecter les informations
- PROCESSING : Traiter la demande
- CONFIRMING : Confirmer les détails avec l'utilisateur
- EXECUTING : Exécuter l'action
- COMPLETED : Terminer avec succès
- ERROR : Gérer les erreurs
- HANDOFF : Transférer vers un humain si nécessaire
Règles importantes :
1. Réponds de manière concise et utile
2. Indique clairement quand tu passes à un nouvel état
3. Demande les informations manquantes de manière naturelle
4. Propose une confirmation avant toute action irreversible"""
state_specific = {
AgentState.COLLECTING_INFO: "\n\nÉtat actuel : COLLECTING_INFO - Collecte les informations nécessaires.",
AgentState.CONFIRMING: "\n\nÉtat actuel : CONFIRMING - Confirme les détails avec l'utilisateur.",
AgentState.PROCESSING: "\n\nÉtat actuel : PROCESSING - Informe l'utilisateur du traitement en cours."
}
return base_prompt + state_specific.get(
context.current_state,
f"\n\nÉtat actuel : {context.current_state.value}"
)
def _analyze_intent(self, response: str, context: AgentContext) -> str:
"""Analyse la réponse pour déterminer l'événement de transition"""
response_lower = response.lower()
if "confirme" in response_lower or "d'accord" in response_lower:
return "user_confirm"
elif "modifier" in response_lower or "changer" in response_lower:
return "user_modify"
elif context.current_state == AgentState.COLLECTING_INFO:
if self._check_info_complete(context):
return "info_complete"
return "continue_collection"
elif "erreur" in response_lower or "impossible" in response_lower:
return "error_occurred"
elif "terminé" in response_lower or "complet" in response_lower:
return "execution_success"
return "continue_conversation"
Exemple d'utilisation
def main():
# Initialisation du client HolySheep
client = HolySheepAIClient(api_key=HOLYSHEEP_API_KEY)
# Création de la machine d'états
state_machine = StateMachine(ai_client=client)
# Création du contexte pour une session
context = AgentContext(
session_id="session_001",
current_state=AgentState.IDLE
)
context.metadata["required_fields"] = ["nom", "email", "demande"]
# Démarrage de la conversation
state_machine.transition("start", context)
print(f"État initial : {context.current_state.value}")
# Simulation d'une conversation
user_messages = [
"Bonjour, je voudrais faire une réservation",
"Mon nom est Jean Dupont",
"Mon email est [email protected]",
"Je souhaite réserver une table pour 4 personnes ce soir",
"Oui, c'est correct"
]
for message in user_messages:
print(f"\n--- Message utilisateur : {message}")
result = state_machine.process_user_input(context, message)
if result["success"]:
print(f"Réponse IA : {result['response']}")
print(f"Nouvel état : {result['new_state'].value}")
print(f"Latence : {result['latency_ms']}ms")
else:
print(f"Erreur : {result['error']}")
if __name__ == "__main__":
main()
Implémentation Avancée : Gestion des Erreurs et Récupération
Dans mes implementations en production, j'ai constaté que la gestion robuste des erreurs distingue un agent professionnel d'un prototype fragile. Voici une implementation complète du subsystem de gestion d'erreurs.
"""
Subsystem de Gestion d'Erreurs et Récupération
pour Agent IA avec Machine d'États HolySheep
"""
import logging
from datetime import datetime
from typing import Optional, List
from dataclasses import dataclass, field
from enum import Enum
Configuration du logging pour debugging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class ErrorType(Enum):
"""Types d'erreurs gérés par l'agent"""
API_ERROR = "api_error" # Erreur de l'API HolySheep
NETWORK_ERROR = "network_error" # Erreur de connectivité
TIMEOUT_ERROR = "timeout_error" # Dépassement de délai
INVALID_RESPONSE = "invalid_response" # Réponse incohérente
CONTEXT_OVERFLOW = "context_overflow" # Contexte trop long
VALIDATION_ERROR = "validation_error" # Données invalides
RATE_LIMIT = "rate_limit" # Limitation de taux
AUTH_ERROR = "auth_error" # Erreur d'authentification
@dataclass
class ErrorRecord:
"""Enregistrement d'une erreur pour analyse"""
timestamp: datetime
error_type: ErrorType
error_message: str
state_at_error: AgentState
context_snapshot: dict
retry_attempt: int
resolution: Optional[str] = None
class ErrorRecoveryStrategy:
"""Stratégies de récupération selon le type d'erreur"""
@staticmethod
def get_strategy(error_type: ErrorType) -> dict:
"""Retourne la stratégie de récupération pour un type d'erreur"""
strategies = {
ErrorType.API_ERROR: {
"retry": True,
"max_retries": 3,
"backoff_factor": 2,
"fallback_model": "deepseek-v3.2", # Plus économique
"user_message": "Je rencontre un problème technique, je réessaie..."
},
ErrorType.NETWORK_ERROR: {
"retry": True,
"max_retries": 5,
"backoff_factor": 1.5,
"fallback_model": None,
"user_message": "Problème de connexion détecté, reconnexion en cours..."
},
ErrorType.TIMEOUT_ERROR: {
"retry": True,
"max_retries": 2,
"backoff_factor": 1,
"fallback_model": "gpt-4.1-mini", # Plus rapide
"user_message": "La requête prend plus de temps que prévu, simplification..."
},
ErrorType.INVALID_RESPONSE: {
"retry": True,
"max_retries": 3,
"backoff_factor": 1,
"fallback_model": "claude-sonnet-4.5",
"user_message": "Réponse inattendue, analyse approfondie en cours..."
},
ErrorType.CONTEXT_OVERFLOW: {
"retry": False,
"max_retries": 0,
"backoff_factor": 0,
"fallback_model": None,
"action": "summarize_and_continue",
"user_message": "Conversation longue, synthèse en cours pour continuer..."
},
ErrorType.VALIDATION_ERROR: {
"retry": False,
"max_retries": 0,
"backoff_factor": 0,
"fallback_model": None,
"action": "request_correction",
"user_message": "Information invalide, pouvez-vous reformuler ?"
},
ErrorType.RATE_LIMIT: {
"retry": True,
"max_retries": 10,
"backoff_factor": 5,
"fallback_model": None,
"action": "wait_and_retry",
"user_message": "Moment de haute affluence, merci de patienter..."
},
ErrorType.AUTH_ERROR: {
"retry": False,
"max_retries": 0,
"backoff_factor": 0,
"fallback_model": None,
"action": "request_auth_refresh",
"user_message": "Session expirée, reconnexion nécessaire."
}
}
return strategies.get(error_type, strategies[ErrorType.API_ERROR])
class ErrorHandler:
"""Gestionnaire centralisé des erreurs pour l'agent"""
def __init__(self, state_machine: StateMachine):
self.state_machine = state_machine
self.error_history: List[ErrorRecord] = []
self.recovery_strategy = ErrorRecoveryStrategy()
def handle_error(
self,
error: Exception,
error_type: ErrorType,
context: AgentContext
) -> dict:
"""Gère une erreur selon le type et le contexte"""
# Enregistre l'erreur
error_record = ErrorRecord(
timestamp=datetime.now(),
error_type=error_type,
error_message=str(error),
state_at_error=context.current_state,
context_snapshot=context.user_data.copy(),
retry_attempt=context.retry_count
)
self.error_history.append(error_record)
logger.error(f"Erreur détectée : {error_type.value} - {error}")
# Récupère la stratégie de récupération
strategy = self.recovery_strategy.get_strategy(error_type)
# Bascule en état d'erreur
context.current_state = AgentState.ERROR
# Vérifie si on peut réessayer
if strategy["retry"] and context.retry_count < strategy["max_retries"]:
return self._retry_with_backoff(context, strategy, error_record)
else:
return self._handle_irrecoverable(context, strategy, error_record)
def _retry_with_backoff(
self,
context: AgentContext,
strategy: dict,
error_record: ErrorRecord
) -> dict:
"""Effectue une nouvelle tentative avec backoff exponentiel"""
import time
import random
# Calcule le délai avec backoff
delay = strategy["backoff_factor"] * (2 ** context.retry_count)
delay += random.uniform(0, 1) # Ajoute du jitter
delay = min(delay, 60) # Maximum 60 secondes
logger.info(f"Tentative {context.retry_count + 1}, attente {delay:.2f}s")
time.sleep(delay)
context.retry_count += 1
return {
"action": "retry",
"delay_seconds": delay,
"retry_attempt": context.retry_count,
"fallback_model": strategy.get("fallback_model"),
"user_message": strategy["user_message"]
}
def _handle_irrecoverable(
self,
context: AgentContext,
strategy: dict,
error_record: ErrorRecord
) -> dict:
"""Gère les erreurs non récupérables"""
action = strategy.get("action", "handoff")
if action == "summarize_and_continue":
# Réduit le contexte et continue
return self._summarize_context(context)
elif action == "request_correction":
# Demande une correction à l'utilisateur
return {
"action": "request_correction",
"user_message": strategy["user_message"]
}
elif action == "request_auth_refresh":
# Demande une reconnexion
return {
"action": "request_auth_refresh",
"user_message": strategy["user_message"]
}
else:
# Transfert vers un humain
return self._initiate_handoff(context, error_record)
def _summarize_context(self, context: AgentContext) -> dict:
"""Résumé le contexte pour éviter le dépassement"""
# Construit le résumé
summary_prompt = """Résume cette conversation en conservant les informations essentielles :
Contexte actuel :
- État : {state}
- Données collectées : {data}
Conversation récente :
{history}
Fournis un résumé structuré avec :
1. Informations clés de l'utilisateur
2. Progression de la conversation
3. Objectif actuel
Sois concis mais complet.""".format(
state=context.current_state.value,
data=context.user_data,
history="\n".join([
f"{m['role']}: {m['content'][:100]}..."
for m in context.conversation_history[-6:]
])
)
# Appel API pour générer le résumé
response = self.state_machine.ai_client.chat_completion(
messages=[{"role": "user", "content": summary_prompt}],
model="gpt-4.1",
max_tokens=500
)
if response["success"]:
summary = response["content"]
# Remplace l'historique par le résumé
context.conversation_history = [
{"role": "system", "content": f"RESUME_CONVERSATION: {summary}"}
]
return {
"action": "continue_with_summary",
"summary": summary,
"user_message": "J'ai résumé notre conversation pour continuer efficacement."
}
else:
return self._initiate_handoff(context, None)
def _initiate_handoff(
self,
context: AgentContext,
error_record: Optional[ErrorRecord]
) -> dict:
"""Initie le transfert vers un agent humain"""
context.current_state = AgentState.HANDOFF
# Génère le rapport de transfert
handoff_report = f"""
=== RAPPORT DE TRANSFERT ===
Session : {context.session_id}
Heure : {datetime.now().isoformat()}
État au transfert : {error_record.state_at_error.value if error_record else 'N/A'}
Dernière erreur : {error_record.error_message if error_record else 'N/A'}
Données collectées :
{json.dumps(context.user_data, indent=2, ensure_ascii=False)}
Conversation récente :
{chr(10).join([
f"{m['role']}: {m['content']}"
for m in context.conversation_history[-10:]
])}
============================
"""
logger.warning(f"Transfert vers humain:\n{handoff_report}")
return {
"action": "handoff",
"handoff_report": handoff_report,
"user_message": "Je vous connecte avec un de nos conseillers pour résoudre ce problème."
}
def get_error_statistics(self) -> dict:
"""Retourne des statistiques sur les erreurs"""
if not self.error_history:
return {"total_errors": 0}
stats = {
"total_errors": len(self.error_history),
"by_type": {},
"recovery_rate": 0,
"average_retries": 0
}
recovered = 0
total_retries = 0
for error in self.error_history:
type_name = error.error_type.value
stats["by_type"][type_name] = stats["by_type"].get(type_name, 0) + 1
if error.resolution:
recovered += 1
total_retries += error.retry_attempt
stats["recovery_rate"] = (recovered / len(self.error_history)) * 100
stats["average_retries"] = total_retries / len(self.error_history)
return stats
class CircuitBreaker:
"""Pattern Circuit Breaker pour éviter les cascading failures"""
def __init__(
self,
failure_threshold: int = 5,
recovery_timeout: int = 60,
expected_exception: type = Exception
):
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.expected_exception = expected_exception
self.failure_count = 0
self.last_failure_time: Optional[datetime] = None
self.state = "CLOSED" # CLOSED, OPEN, HALF_OPEN
def call(self, func, *args, **kwargs):
"""Exécute la fonction avec protection circuit breaker"""
if self.state == "OPEN":
if self._should_attempt_reset():
self.state = "HALF_OPEN"
else:
raise Exception("Circuit Breaker OPEN - requête bloquée")
try:
result = func(*args, **kwargs)
self._on_success()
return result
except self.expected_exception as e:
self._on_failure()
raise
def _should_attempt_reset(self) -> bool:
"""Vérifie si on doit tenter une réinitialisation"""
if not self.last_failure_time:
return False
elapsed = (datetime.now() - self.last_failure_time).total_seconds()
return elapsed >= self.recovery_timeout
def _on_success(self):
"""Gère le succès"""
self.failure_count = 0
self.state = "CLOSED"
def _on_failure(self):
"""Gère l'échec"""
self.failure_count += 1
self.last_failure_time = datetime.now()
if self.failure_count >= self.failure_threshold:
self.state = "OPEN"
logger.warning(f"Circuit Breaker OPEN après {self.failure_count} échecs")
Intégration complète avec monitoring
class AgentWithErrorHandling:
"""Agent IA complet avec gestion d'erreurs et monitoring"""
def __init__(self, api_key: str):
self.client = HolySheepAIClient(api_key)
self.state_machine = StateMachine(self.client)
self.error_handler = ErrorHandler(self.state_machine)
self.circuit_breaker = CircuitBreaker(
failure_threshold=5,
recovery_timeout=60
)
# Configuration du monitoring
self.metrics = {
"total_requests": 0,
"successful_requests": 0,
"failed_requests": 0,
"average_latency": 0,
"total_cost": 0
}
def process_message(self, session_id: str, user_message: str) -> dict:
"""Traite un message avec gestion complète des erreurs"""
self.metrics["total_requests"] += 1
# Récupère ou crée le contexte
context = self._get_or_create_context(session_id)
try:
# Utilise le circuit breaker
result = self.circuit_breaker.call(
self.state_machine.process_user_input,
context,
user_message
)
if result["success"]:
self.metrics["successful_requests"] += 1
# Met à jour les métriques de latence
self._update_latency_metrics(result.get("latency_ms", 0))
# Met à jour les coûts (estimation)
self._update_cost_metrics(result.get("usage", {}))
return result
except Exception as e:
self.metrics["failed_requests"] += 1
# Détermine le type d'erreur
error_type = self._classify_error(e)
# Gère l'erreur
error_result = self.error_handler.handle_error(e, error_type, context)
return {
"success": False,
"error_type": error_type.value,
"error_message": str(e),
"recovered": error_result["action"] != "handoff",
**error_result
}
def _classify_error(self, error: Exception) -> ErrorType:
"""Classification automatique du type d'erreur"""
error_str = str(error).lower()
if "401" in error_str or "403" in error_str or "unauthorized" in error_str:
return ErrorType.AUTH_ERROR
elif "429" in error_str or "rate limit" in error_str:
return ErrorType.RATE_LIMIT
elif "timeout" in error_str or "timed out" in error_str:
return ErrorType.TIMEOUT_ERROR
elif "network" in error_str or "connection" in error_str:
return ErrorType.NETWORK_ERROR
elif "invalid" in error_str or "malformed" in error_str:
return ErrorType.INVALID_RESPONSE
else:
return ErrorType.API_ERROR
def _get_or_create_context(self, session_id: str) -> AgentContext:
"""Récupère ou crée un contexte de session"""
# Implémentation simplifiée - en production, utiliser Redis ou DB
if not hasattr(self, '_contexts'):
self._contexts = {}
if session_id not in self._contexts:
self._contexts[session_id] = AgentContext(
session_id=session_id,
current_state=AgentState.IDLE
)
return self._contexts[session_id]
def _update_latency_metrics(self, latency_ms: float):
"""Met à jour les métriques de latence"""
current_avg = self.metrics["average_latency"]
total = self.metrics["total_requests"]
self.metrics["average_latency"] = (
(current_avg * (total - 1) + latency_ms) / total
)
def _update_cost_metrics(self, usage: dict):
"""Met à jour les métriques de coût"""
# Estimation basée sur les tokens utilisés
prompt_tokens = usage.get("prompt_tokens", 0)
completion_tokens = usage.get("completion_tokens", 0)
total_tokens = prompt_tokens + completion_tokens
# Coût au million de