WilliamRabuel commited on
Commit
249c80d
·
verified ·
1 Parent(s): 610cbcd

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +40 -235
agent.py CHANGED
@@ -11,20 +11,21 @@ from smolagents import CodeAgent, MultiStepAgent, AgentError, PythonInterpreterT
11
  from models import ModelManager
12
  from tools import search_web, scrape_website, read_file
13
 
14
-
15
  class OrchestratorAgent(MultiStepAgent):
16
  """
17
- Agent orchestrateur qui hérite de MultiStepAgent et implémente
18
  les méthodes requises pour le prompt système et la réponse finale.
19
  """
20
  def initialize_system_prompt(self) -> str:
21
  """Définit le prompt système pour l'agent orchestrateur."""
22
  return (
23
- "You are an expert orchestrator agent. Your primary role is to understand a user's question, "
24
- "devise a multi-step plan, and use the available tools to find the answer. "
25
- "Think step-by-step. Analyze the results of each tool call. "
26
- "When you have gathered all the necessary information, formulate a clear and comprehensive final answer. "
27
- "Cite your sources if you used the search or scrape tools."
 
28
  )
29
 
30
  def render_final_answer(self, final_context: dict, final_response: str) -> str:
@@ -34,7 +35,6 @@ class OrchestratorAgent(MultiStepAgent):
34
  # Pour l'instant, nous retournons simplement la réponse brute du modèle.
35
  return final_response
36
 
37
-
38
  class UltraAgent:
39
  """
40
  Agent ultra-puissant avec orchestration multi-modèles.
@@ -46,93 +46,48 @@ class UltraAgent:
46
  print("🚀 Initialisation de l'UltraAgent...")
47
 
48
  self.hf_token = hf_token or os.getenv("HF_TOKEN")
49
-
50
- # Gestionnaire de modèles
51
  self.model_manager = ModelManager(self.hf_token)
52
-
53
- # Outils disponibles
54
- self.tools = [
55
- search_web,
56
- scrape_website,
57
- read_file,
58
- PythonInterpreterTool()
59
- ]
60
-
61
- # Agents spécialisés
62
  self._init_specialized_agents()
63
-
64
- # Historique des interactions
65
  self.conversation_history = []
66
-
67
  print("✅ UltraAgent initialisé avec succès!")
68
 
69
  def _init_specialized_agents(self):
70
- """Initialise les agents spécialisés comme l'orchestrateur et l'agent de code."""
71
  try:
72
-
73
- # Utiliser la nouvelle classe OrchestratorAgent au lieu de MultiStepAgent
74
  self.orchestrator = OrchestratorAgent(
75
  model=self.model_manager.get_orchestrator(),
76
  tools=self.tools,
77
  max_steps=15,
78
  planning_interval=3
79
  )
80
-
81
-
82
- # Agent de code
83
  self.code_agent = CodeAgent(
84
  model=self.model_manager.get_code_agent(),
85
  tools=[PythonInterpreterTool()],
86
  additional_authorized_imports=["requests", "pandas", "numpy", "matplotlib", "seaborn", "scipy", "sklearn"]
87
  )
88
-
89
  print("✅ Agents spécialisés initialisés")
90
-
91
  except Exception as e:
92
  print(f"❌ Erreur lors de l'initialisation des agents: {e}")
93
  raise
94
 
95
  def __call__(self, question: str) -> str:
96
- """
97
- Point d'entrée principal de l'agent.
98
- Analyse la question, détermine la stratégie et exécute la tâche.
99
- """
100
  print("\n" + "="*80)
101
- print("🧠 ULTRA-AGENT - Nouvelle question reçue")
102
- print(f"Question: {question[:200]}{'...' if len(question) > 200 else ''}")
103
  print("="*80)
104
 
105
  try:
106
- # Ajoute à l'historique
107
- self.conversation_history.append({
108
- "role": "user",
109
- "content": question,
110
- "timestamp": time.time()
111
- })
112
-
113
- # Analyse de la question et choix de la stratégie
114
  strategy = self._analyze_question(question)
115
  print(f"📋 Stratégie sélectionnée: {strategy['type']}")
116
-
117
- # Exécution selon la stratégie
118
  response = self._execute_strategy(question, strategy)
119
-
120
- # Ajoute la réponse à l'historique
121
- self.conversation_history.append({
122
- "role": "assistant",
123
- "content": response,
124
- "strategy": strategy,
125
- "timestamp": time.time()
126
- })
127
-
128
  print(f"✅ Réponse générée avec succès ({len(response)} caractères)")
129
  return response
130
-
131
  except Exception as e:
132
  error_msg = f"❌ Erreur critique dans l'UltraAgent: {e}"
133
  print(error_msg)
134
-
135
- # Tentative de récupération avec le modèle de raisonnement
136
  try:
137
  print("🔄 Tentative de récupération avec le modèle de raisonnement...")
138
  fallback_response = self._fallback_reasoning(question, str(e))
@@ -143,211 +98,61 @@ class UltraAgent:
143
  return final_error
144
 
145
  def _analyze_question(self, question: str) -> Dict[str, Any]:
146
- """
147
- Analyse la question pour déterminer la meilleure stratégie à adopter.
148
- """
149
  question_lower = question.lower()
150
-
151
- # Détection de mots-clés pour différents types de tâches
152
  vision_keywords = ['image', 'photo', 'picture', 'visual', 'voir', 'regarder', 'analyser l\'image', 'screenshot']
153
  code_keywords = ['code', 'program', 'script', 'algorithm', 'python', 'javascript', 'sql', 'debug', 'programmer']
154
- search_keywords = ['search', 'find', 'look up', 'recherche', 'chercher', 'trouver', 'internet', 'web', 'actualité']
155
- file_keywords = ['file', 'document', 'pdf', 'excel', 'csv', 'json', 'read', 'fichier', 'lire', 'ouvrir']
156
- reasoning_keywords = ['complex', 'analyze', 'think', 'reason', 'solve', 'problem', 'complexe', 'analyser', 'résoudre', 'problème']
157
-
158
- # Calcul des scores
159
- scores = {
160
- "vision": sum(1 for kw in vision_keywords if kw in question_lower),
161
- "code": sum(1 for kw in code_keywords if kw in question_lower),
162
- "search_web": sum(1 for kw in search_keywords if kw in question_lower),
163
- "file_processing": sum(1 for kw in file_keywords if kw in question_lower),
164
- "reasoning": sum(1 for kw in reasoning_keywords if kw in question_lower),
165
- }
166
-
167
- # Détection d'URL pour forcer la recherche web
168
- if any(domain in question_lower for domain in ['http', 'www', '.com', '.fr', '.org']):
169
- scores["search_web"] += 2
170
-
171
- # Analyse de la complexité
172
- complexity = len(question.split()) + len(re.findall(r'[.!?]', question))
173
-
174
- # Détermination de la stratégie
175
- if scores["vision"] > 0:
176
- return {"type": "vision", "priority": scores["vision"], "complexity": complexity}
177
- if scores["code"] > 1:
178
- return {"type": "code", "priority": scores["code"], "complexity": complexity}
179
- if scores["search_web"] > 0:
180
- return {"type": "search_web", "priority": scores["search_web"], "complexity": complexity}
181
- if scores["file_processing"] > 0:
182
- return {"type": "file_processing", "priority": scores["file_processing"], "complexity": complexity}
183
- if complexity > 50 or scores["reasoning"] > 0:
184
- return {"type": "reasoning", "priority": scores["reasoning"], "complexity": complexity}
185
-
186
- return {"type": "general", "priority": 0, "complexity": complexity}
187
 
188
  def _execute_strategy(self, question: str, strategy: Dict[str, Any]) -> str:
189
- """Exécute la stratégie déterminée pour répondre à la question."""
190
  strategy_type = strategy["type"]
191
-
192
  try:
193
  if strategy_type == "vision":
194
  return self._handle_vision_task(question)
195
  elif strategy_type == "code":
196
  return self._handle_code_task(question)
197
- elif strategy_type == "search_web":
198
- return self._handle_web_search_task(question)
199
- elif strategy_type == "file_processing":
200
- return self._handle_file_task(question)
201
- elif strategy_type == "reasoning":
202
- return self._handle_reasoning_task(question)
203
- else: # general
204
  return self._handle_general_task(question)
205
-
206
  except Exception as e:
207
  print(f"❌ Erreur dans l'exécution de la stratégie {strategy_type}: {e}")
208
- # Fallback vers l'orchestrateur général en cas d'échec
209
- return self._handle_general_task(question)
210
 
211
  def _handle_vision_task(self, question: str) -> str:
212
- """Gère les tâches impliquant la vision."""
213
  print("👁️ Traitement avec le modèle de vision...")
214
-
215
- try:
216
- vision_prompt = f"Analyse visuelle experte requise pour la question suivante : {question}. Si une image est mentionnée ou nécessaire, décris précisément ce que tu dois analyser."
217
- response = self.model_manager.get_vision_model()(vision_prompt)
218
- return f"🔍 Analyse visuelle:\n{response}"
219
- except Exception as e:
220
- print(f"❌ Erreur vision: {e}")
221
- return self._handle_general_task(question)
222
 
223
  def _handle_code_task(self, question: str) -> str:
224
- """Gère les tâches de programmation avec l'agent de code."""
225
  print("💻 Traitement avec l'agent de code...")
226
- try:
227
- response = self.code_agent.run(question)
228
- return f"💻 Solution de code:\n{response}"
229
- except Exception as e:
230
- print(f"❌ Erreur code agent: {e}")
231
- return self._handle_general_task(question)
232
-
233
- def _handle_web_search_task(self, question: str) -> str:
234
- """Gère les tâches nécessitant une recherche web."""
235
- print("🌐 Traitement avec recherche web...")
236
- try:
237
- search_prompt = f"Répondez à cette question en utilisant une recherche web approfondie. Utilisez les outils de recherche et de scraping, et citez vos sources. Question : {question}"
238
- response = self.orchestrator.run(search_prompt)
239
- return response
240
- except Exception as e:
241
- print(f"❌ Erreur web search: {e}")
242
- return self._handle_general_task(question)
243
-
244
- def _handle_file_task(self, question: str) -> str:
245
- """Gère les tâches impliquant la lecture de fichiers."""
246
- print("📁 Traitement de fichiers...")
247
- try:
248
- file_prompt = f"Traitez les fichiers nécessaires pour répondre à cette question. Utilisez l'outil `read_file` pour analyser les fichiers mentionnés et extraire les informations pertinentes. Question : {question}"
249
- response = self.orchestrator.run(file_prompt)
250
- return response
251
- except Exception as e:
252
- print(f"❌ Erreur file processing: {e}")
253
- return self._handle_general_task(question)
254
-
255
- def _handle_reasoning_task(self, question: str) -> str:
256
- """Gère les tâches complexes nécessitant un raisonnement approfondi."""
257
- print("🧠 Traitement avec le modèle de raisonnement...")
258
- try:
259
- reasoning_prompt = f"En tant qu'expert en résolution de problèmes complexes, analysez et répondez de manière structurée à la question suivante : {question}. Décomposez le problème, analysez chaque partie et proposez une solution étape par étape."
260
- response = self.model_manager.get_reasoning_model()(reasoning_prompt)
261
- return f"🧠 Analyse approfondie:\n{response}"
262
- except Exception as e:
263
- print(f"❌ Erreur reasoning: {e}")
264
- return self._handle_general_task(question)
265
 
266
  def _handle_general_task(self, question: str) -> str:
267
- """Gère les tâches générales avec l'orchestrateur principal."""
268
  print("🎯 Traitement général avec l'orchestrateur...")
269
- try:
270
- context = self._get_conversation_context()
271
- enhanced_prompt = f"{context}\nQuestion actuelle: {question}\nInstructions: Analysez et répondez de manière complète, en utilisant les outils si nécessaire."
272
- response = self.orchestrator.run(enhanced_prompt)
273
- return response
274
- except Exception as e:
275
- print(f"❌ Erreur general task: {e}")
276
- try:
277
- # Dernière tentative simple
278
- simple_response = self.model_manager.get_orchestrator()(question)
279
- return simple_response
280
- except Exception as final_e:
281
- raise final_e # Propage l'erreur au handler principal
282
 
283
  def _fallback_reasoning(self, question: str, error: str) -> str:
284
- """Utilise le modèle de raisonnement en cas d'erreur pour fournir une réponse de secours."""
285
- try:
286
- fallback_prompt = f"Une erreur s'est produite en traitant la question. Question: '{question}'. Erreur: '{error}'. Fournissez la meilleure réponse possible en expliquant les limitations dues à l'erreur."
287
- response = self.model_manager.get_reasoning_model()(fallback_prompt)
288
- return f"⚠️ Réponse de récupération:\n{response}"
289
- except Exception as e:
290
- raise e
291
 
292
  def _get_conversation_context(self, max_exchanges: int = 3) -> str:
293
- """Récupère le contexte des échanges récents pour l'injecter dans le prompt."""
294
- if not self.conversation_history:
295
- return ""
296
-
297
  recent_history = self.conversation_history[-max_exchanges*2:]
298
  context_parts = ["Contexte de la conversation récente:"]
299
  for entry in recent_history:
300
  role = "Utilisateur" if entry["role"] == "user" else "Assistant"
301
- content = str(entry["content"])[:200] + "..." if len(str(entry["content"])) > 200 else str(entry["content"])
302
  context_parts.append(f"{role}: {content}")
303
-
304
- return "\n".join(context_parts)
305
-
306
- def get_status(self) -> Dict[str, Any]:
307
- """Retourne le statut actuel de l'agent."""
308
- return {
309
- "status": "active",
310
- "conversation_length": len(self.conversation_history),
311
- "available_tools": [tool.__name__ for tool in self.tools],
312
- "models_status": self.model_manager.test_models(),
313
- }
314
-
315
- def reset_conversation(self):
316
- """Réinitialise l'historique de la conversation."""
317
- self.conversation_history = []
318
- print("🔄 Historique de conversation remis à zéro.")
319
-
320
-
321
- class BasicAgent:
322
- """
323
- Classe de compatibilité pour remplacer l'ancien BasicAgent dans app.py.
324
- Elle utilise l'UltraAgent en arrière-plan pour toute la logique.
325
- """
326
-
327
- def __init__(self):
328
- """Initialise le BasicAgent en créant une instance de l'UltraAgent."""
329
- print("🚀 Initialisation du BasicAgent (powered by UltraAgent)...")
330
- try:
331
- # Assurez-vous que le token HF est disponible (via les secrets de l'espace HF)
332
- if not os.getenv("HF_TOKEN"):
333
- print("⚠️ Attention: Le token Hugging Face (HF_TOKEN) n'est pas défini. L'initialisation pourrait échouer.")
334
-
335
- self.ultra_agent = UltraAgent()
336
- print("✅ BasicAgent initialisé avec succès!")
337
- except Exception as e:
338
- print(f"❌ Erreur critique lors de l'initialisation de l'UltraAgent: {e}")
339
- self.ultra_agent = None
340
-
341
- def __call__(self, question: str) -> str:
342
- """
343
- Point d'entrée compatible avec l'interface de app.py.
344
- Délègue l'appel à l'UltraAgent.
345
- """
346
- if self.ultra_agent is None:
347
- return "Erreur: L'agent n'a pas pu être initialisé correctement. Veuillez vérifier les logs et la configuration (notamment le HF_TOKEN)."
348
-
349
- try:
350
- return self.ultra_agent(question)
351
- except Exception as e:
352
- print(f"❌ Erreur lors du traitement par l'UltraAgent: {e}")
353
- return f"Une erreur s'est produite lors du traitement de votre demande: {str(e)[:200]}"
 
11
  from models import ModelManager
12
  from tools import search_web, scrape_website, read_file
13
 
14
+ # --- CLASSE ORCHESTRATEUR COMPLÈTE ---
15
  class OrchestratorAgent(MultiStepAgent):
16
  """
17
+ Agent orchestrateur qui hérite de MultiStepAgent et implémente
18
  les méthodes requises pour le prompt système et la réponse finale.
19
  """
20
  def initialize_system_prompt(self) -> str:
21
  """Définit le prompt système pour l'agent orchestrateur."""
22
  return (
23
+ "You are a world-class autonomous agent. Your goal is to fully answer the user's question. "
24
+ "To do so, you have access to a set of tools. "
25
+ "First, think step-by-step and lay out a plan to solve the problem. "
26
+ "Then, execute the plan by calling the tools in the required sequence. "
27
+ "Analyze the results of each tool call. If the plan is not working, reassess and create a new plan. "
28
+ "When you have the final answer, present it clearly to the user."
29
  )
30
 
31
  def render_final_answer(self, final_context: dict, final_response: str) -> str:
 
35
  # Pour l'instant, nous retournons simplement la réponse brute du modèle.
36
  return final_response
37
 
 
38
  class UltraAgent:
39
  """
40
  Agent ultra-puissant avec orchestration multi-modèles.
 
46
  print("🚀 Initialisation de l'UltraAgent...")
47
 
48
  self.hf_token = hf_token or os.getenv("HF_TOKEN")
 
 
49
  self.model_manager = ModelManager(self.hf_token)
50
+ self.tools = [search_web, scrape_website, read_file, PythonInterpreterTool()]
 
 
 
 
 
 
 
 
 
51
  self._init_specialized_agents()
 
 
52
  self.conversation_history = []
 
53
  print("✅ UltraAgent initialisé avec succès!")
54
 
55
  def _init_specialized_agents(self):
56
+ """Initialise les agents spécialisés."""
57
  try:
 
 
58
  self.orchestrator = OrchestratorAgent(
59
  model=self.model_manager.get_orchestrator(),
60
  tools=self.tools,
61
  max_steps=15,
62
  planning_interval=3
63
  )
 
 
 
64
  self.code_agent = CodeAgent(
65
  model=self.model_manager.get_code_agent(),
66
  tools=[PythonInterpreterTool()],
67
  additional_authorized_imports=["requests", "pandas", "numpy", "matplotlib", "seaborn", "scipy", "sklearn"]
68
  )
 
69
  print("✅ Agents spécialisés initialisés")
 
70
  except Exception as e:
71
  print(f"❌ Erreur lors de l'initialisation des agents: {e}")
72
  raise
73
 
74
  def __call__(self, question: str) -> str:
75
+ """Point d'entrée principal de l'agent."""
 
 
 
76
  print("\n" + "="*80)
77
+ print(f"🧠 ULTRA-AGENT - Nouvelle question reçue\nQuestion: {question[:200]}{'...' if len(question) > 200 else ''}")
 
78
  print("="*80)
79
 
80
  try:
81
+ self.conversation_history.append({"role": "user", "content": question, "timestamp": time.time()})
 
 
 
 
 
 
 
82
  strategy = self._analyze_question(question)
83
  print(f"📋 Stratégie sélectionnée: {strategy['type']}")
 
 
84
  response = self._execute_strategy(question, strategy)
85
+ self.conversation_history.append({"role": "assistant", "content": response, "strategy": strategy, "timestamp": time.time()})
 
 
 
 
 
 
 
 
86
  print(f"✅ Réponse générée avec succès ({len(response)} caractères)")
87
  return response
 
88
  except Exception as e:
89
  error_msg = f"❌ Erreur critique dans l'UltraAgent: {e}"
90
  print(error_msg)
 
 
91
  try:
92
  print("🔄 Tentative de récupération avec le modèle de raisonnement...")
93
  fallback_response = self._fallback_reasoning(question, str(e))
 
98
  return final_error
99
 
100
  def _analyze_question(self, question: str) -> Dict[str, Any]:
101
+ """Analyse la question pour déterminer la meilleure stratégie."""
102
+ # Cette fonction de scoring simple reste la même
 
103
  question_lower = question.lower()
 
 
104
  vision_keywords = ['image', 'photo', 'picture', 'visual', 'voir', 'regarder', 'analyser l\'image', 'screenshot']
105
  code_keywords = ['code', 'program', 'script', 'algorithm', 'python', 'javascript', 'sql', 'debug', 'programmer']
106
+ if any(kw in question_lower for kw in vision_keywords):
107
+ return {"type": "vision"}
108
+ if any(kw in question_lower for kw in code_keywords):
109
+ return {"type": "code"}
110
+ return {"type": "general"} # Simplification de la stratégie pour le débogage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
  def _execute_strategy(self, question: str, strategy: Dict[str, Any]) -> str:
113
+ """Exécute la stratégie déterminée."""
114
  strategy_type = strategy["type"]
 
115
  try:
116
  if strategy_type == "vision":
117
  return self._handle_vision_task(question)
118
  elif strategy_type == "code":
119
  return self._handle_code_task(question)
120
+ else: # general, search_web, file_processing, reasoning
 
 
 
 
 
 
121
  return self._handle_general_task(question)
 
122
  except Exception as e:
123
  print(f"❌ Erreur dans l'exécution de la stratégie {strategy_type}: {e}")
124
+ raise e # Fait remonter l'erreur pour la gestion centrale
 
125
 
126
  def _handle_vision_task(self, question: str) -> str:
127
+ """Gère les tâches de vision."""
128
  print("👁️ Traitement avec le modèle de vision...")
129
+ response = self.model_manager.get_vision_model()(question)
130
+ return f"🔍 Analyse visuelle:\n{response}"
 
 
 
 
 
 
131
 
132
  def _handle_code_task(self, question: str) -> str:
133
+ """Gère les tâches de code."""
134
  print("💻 Traitement avec l'agent de code...")
135
+ return self.code_agent.run(question)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  def _handle_general_task(self, question: str) -> str:
138
+ """Gère toutes les autres tâches avec l'orchestrateur."""
139
  print("🎯 Traitement général avec l'orchestrateur...")
140
+ context = self._get_conversation_context()
141
+ enhanced_prompt = f"{context}\nQuestion actuelle: {question}"
142
+ return self.orchestrator.run(enhanced_prompt)
 
 
 
 
 
 
 
 
 
 
143
 
144
  def _fallback_reasoning(self, question: str, error: str) -> str:
145
+ """Fallback avec le modèle de raisonnement."""
146
+ fallback_prompt = f"An error occurred while processing the question. Question: '{question}'. Error: '{error}'. Provide the best possible answer, explaining the limitations due to the error."
147
+ return self.model_manager.get_reasoning_model()(fallback_prompt)
 
 
 
 
148
 
149
  def _get_conversation_context(self, max_exchanges: int = 3) -> str:
150
+ """Récupère le contexte des échanges récents."""
151
+ if not self.conversation_history: return ""
 
 
152
  recent_history = self.conversation_history[-max_exchanges*2:]
153
  context_parts = ["Contexte de la conversation récente:"]
154
  for entry in recent_history:
155
  role = "Utilisateur" if entry["role"] == "user" else "Assistant"
156
+ content = str(entry["content"])[:200]
157
  context_parts.append(f"{role}: {content}")
158
+ return "\n".join(context_parts)