WilliamRabuel commited on
Commit
9a2ac51
·
verified ·
1 Parent(s): b66033a

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +200 -57
agent.py CHANGED
@@ -11,30 +11,6 @@ from smolagents import CodeAgent, MultiStepAgent, AgentError, PythonInterpreterT
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:
32
- """
33
- Formate et retourne la réponse finale de l'agent.
34
- """
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,48 +22,91 @@ class UltraAgent:
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,65 +117,189 @@ class UltraAgent:
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)
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
  class BasicAgent:
162
  """
 
11
  from models import ModelManager
12
  from tools import search_web, scrape_website, read_file
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  class UltraAgent:
15
  """
16
  Agent ultra-puissant avec orchestration multi-modèles.
 
22
  print("🚀 Initialisation de l'UltraAgent...")
23
 
24
  self.hf_token = hf_token or os.getenv("HF_TOKEN")
25
+
26
+ # Gestionnaire de modèles
27
  self.model_manager = ModelManager(self.hf_token)
28
+
29
+ # Outils disponibles
30
+ self.tools = [
31
+ search_web,
32
+ scrape_website,
33
+ read_file,
34
+ PythonInterpreterTool()
35
+ ]
36
+
37
+ # Agents spécialisés
38
  self._init_specialized_agents()
39
+
40
+ # Historique des interactions
41
  self.conversation_history = []
42
+
43
  print("✅ UltraAgent initialisé avec succès!")
44
 
45
  def _init_specialized_agents(self):
46
+ """Initialise les agents spécialisés comme l'orchestrateur et l'agent de code."""
47
  try:
48
+ # Agent principal (orchestrateur)
49
+ self.orchestrator = MultiStepAgent(
50
  model=self.model_manager.get_orchestrator(),
51
  tools=self.tools,
52
  max_steps=15,
53
  planning_interval=3
54
  )
55
+
56
+ # Agent de code
57
  self.code_agent = CodeAgent(
58
  model=self.model_manager.get_code_agent(),
59
  tools=[PythonInterpreterTool()],
60
  additional_authorized_imports=["requests", "pandas", "numpy", "matplotlib", "seaborn", "scipy", "sklearn"]
61
  )
62
+
63
  print("✅ Agents spécialisés initialisés")
64
+
65
  except Exception as e:
66
  print(f"❌ Erreur lors de l'initialisation des agents: {e}")
67
  raise
68
 
69
  def __call__(self, question: str) -> str:
70
+ """
71
+ Point d'entrée principal de l'agent.
72
+ Analyse la question, détermine la stratégie et exécute la tâche.
73
+ """
74
  print("\n" + "="*80)
75
+ print("🧠 ULTRA-AGENT - Nouvelle question reçue")
76
+ print(f"Question: {question[:200]}{'...' if len(question) > 200 else ''}")
77
  print("="*80)
78
 
79
  try:
80
+ # Ajoute à l'historique
81
+ self.conversation_history.append({
82
+ "role": "user",
83
+ "content": question,
84
+ "timestamp": time.time()
85
+ })
86
+
87
+ # Analyse de la question et choix de la stratégie
88
  strategy = self._analyze_question(question)
89
  print(f"📋 Stratégie sélectionnée: {strategy['type']}")
90
+
91
+ # Exécution selon la stratégie
92
  response = self._execute_strategy(question, strategy)
93
+
94
+ # Ajoute la réponse à l'historique
95
+ self.conversation_history.append({
96
+ "role": "assistant",
97
+ "content": response,
98
+ "strategy": strategy,
99
+ "timestamp": time.time()
100
+ })
101
+
102
  print(f"✅ Réponse générée avec succ��s ({len(response)} caractères)")
103
  return response
104
+
105
  except Exception as e:
106
  error_msg = f"❌ Erreur critique dans l'UltraAgent: {e}"
107
  print(error_msg)
108
+
109
+ # Tentative de récupération avec le modèle de raisonnement
110
  try:
111
  print("🔄 Tentative de récupération avec le modèle de raisonnement...")
112
  fallback_response = self._fallback_reasoning(question, str(e))
 
117
  return final_error
118
 
119
  def _analyze_question(self, question: str) -> Dict[str, Any]:
120
+ """
121
+ Analyse la question pour déterminer la meilleure stratégie à adopter.
122
+ """
123
  question_lower = question.lower()
124
+
125
+ # Détection de mots-clés pour différents types de tâches
126
+ vision_keywords = ['image', 'photo', 'picture', 'visual', 'voir', 'regarder', 'analyser l\'image', 'screenshot', 'chess position', 'position']
127
  code_keywords = ['code', 'program', 'script', 'algorithm', 'python', 'javascript', 'sql', 'debug', 'programmer']
128
+ search_keywords = ['search', 'find', 'look up', 'recherche', 'chercher', 'trouver', 'internet', 'web', 'actualité', 'wikipedia', 'youtube', 'studio albums']
129
+ file_keywords = ['file', 'document', 'pdf', 'excel', 'csv', 'json', 'read', 'fichier', 'lire', 'ouvrir']
130
+ reasoning_keywords = ['complex', 'analyze', 'think', 'reason', 'solve', 'problem', 'complexe', 'analyser', 'résoudre', 'problème']
131
+
132
+ # Calcul des scores
133
+ scores = {
134
+ "vision": sum(1 for kw in vision_keywords if kw in question_lower),
135
+ "code": sum(1 for kw in code_keywords if kw in question_lower),
136
+ "search_web": sum(1 for kw in search_keywords if kw in question_lower),
137
+ "file_processing": sum(1 for kw in file_keywords if kw in question_lower),
138
+ "reasoning": sum(1 for kw in reasoning_keywords if kw in question_lower),
139
+ }
140
+
141
+ # Détection d'URL pour forcer la recherche web
142
+ if any(domain in question_lower for domain in ['http', 'www', '.com', '.fr', '.org', 'youtube.com', 'wikipedia']):
143
+ scores["search_web"] += 2
144
+
145
+ # Analyse de la complexité
146
+ complexity = len(question.split()) + len(re.findall(r'[.!?]', question))
147
+
148
+ # Détermination de la stratégie
149
+ if scores["vision"] > 0:
150
+ return {"type": "vision", "priority": scores["vision"], "complexity": complexity}
151
+ if scores["code"] > 1:
152
+ return {"type": "code", "priority": scores["code"], "complexity": complexity}
153
+ if scores["search_web"] > 0:
154
+ return {"type": "search_web", "priority": scores["search_web"], "complexity": complexity}
155
+ if scores["file_processing"] > 0:
156
+ return {"type": "file_processing", "priority": scores["file_processing"], "complexity": complexity}
157
+ if complexity > 50 or scores["reasoning"] > 0:
158
+ return {"type": "reasoning", "priority": scores["reasoning"], "complexity": complexity}
159
+
160
+ return {"type": "general", "priority": 0, "complexity": complexity}
161
 
162
  def _execute_strategy(self, question: str, strategy: Dict[str, Any]) -> str:
163
+ """Exécute la stratégie déterminée pour répondre à la question."""
164
  strategy_type = strategy["type"]
165
+
166
  try:
167
  if strategy_type == "vision":
168
  return self._handle_vision_task(question)
169
  elif strategy_type == "code":
170
  return self._handle_code_task(question)
171
+ elif strategy_type == "search_web":
172
+ return self._handle_web_search_task(question)
173
+ elif strategy_type == "file_processing":
174
+ return self._handle_file_task(question)
175
+ elif strategy_type == "reasoning":
176
+ return self._handle_reasoning_task(question)
177
+ else: # general
178
  return self._handle_general_task(question)
179
+
180
  except Exception as e:
181
  print(f"❌ Erreur dans l'exécution de la stratégie {strategy_type}: {e}")
182
+ # Fallback vers l'orchestrateur général en cas d'échec
183
+ return self._handle_general_task(question)
184
 
185
  def _handle_vision_task(self, question: str) -> str:
186
+ """Gère les tâches impliquant la vision."""
187
  print("👁️ Traitement avec le modèle de vision...")
188
+
189
+ try:
190
+ 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."
191
+
192
+ # CORRECTION: Appel direct du modèle avec le prompt seulement
193
+ response = self.model_manager.get_vision_model()(vision_prompt)
194
+ return f"🔍 Analyse visuelle:\n{response}"
195
+ except Exception as e:
196
+ print(f"❌ Erreur vision: {e}")
197
+ return self._handle_general_task(question)
198
 
199
  def _handle_code_task(self, question: str) -> str:
200
+ """Gère les tâches de programmation avec l'agent de code."""
201
  print("💻 Traitement avec l'agent de code...")
202
+ try:
203
+ response = self.code_agent.run(question)
204
+ return f"💻 Solution de code:\n{response}"
205
+ except Exception as e:
206
+ print(f"❌ Erreur code agent: {e}")
207
+ return self._handle_general_task(question)
208
+
209
+ def _handle_web_search_task(self, question: str) -> str:
210
+ """Gère les tâches nécessitant une recherche web."""
211
+ print("🌐 Traitement avec recherche web...")
212
+ try:
213
+ 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}"
214
+ response = self.orchestrator.run(search_prompt)
215
+ return response
216
+ except Exception as e:
217
+ print(f"❌ Erreur web search: {e}")
218
+ return self._handle_general_task(question)
219
+
220
+ def _handle_file_task(self, question: str) -> str:
221
+ """Gère les tâches impliquant la lecture de fichiers."""
222
+ print("📁 Traitement de fichiers...")
223
+ try:
224
+ 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}"
225
+ response = self.orchestrator.run(file_prompt)
226
+ return response
227
+ except Exception as e:
228
+ print(f"❌ Erreur file processing: {e}")
229
+ return self._handle_general_task(question)
230
+
231
+ def _handle_reasoning_task(self, question: str) -> str:
232
+ """Gère les tâches complexes nécessitant un raisonnement approfondi."""
233
+ print("🧠 Traitement avec le modèle de raisonnement...")
234
+ try:
235
+ 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."
236
+
237
+ # CORRECTION: Appel direct du modèle avec le prompt seulement
238
+ response = self.model_manager.get_reasoning_model()(reasoning_prompt)
239
+ return f"🧠 Analyse approfondie:\n{response}"
240
+ except Exception as e:
241
+ print(f"❌ Erreur reasoning: {e}")
242
+ return self._handle_general_task(question)
243
 
244
  def _handle_general_task(self, question: str) -> str:
245
+ """Gère les tâches générales avec l'orchestrateur principal."""
246
  print("🎯 Traitement général avec l'orchestrateur...")
247
+ try:
248
+ # CORRECTION: Utilisation directe du modèle orchestrateur au lieu de l'agent MultiStep
249
+ context = self._get_conversation_context()
250
+ enhanced_prompt = f"{context}\nQuestion actuelle: {question}\nInstructions: Analysez et répondez de manière complète à cette question."
251
+
252
+ # Appel direct du modèle au lieu de l'orchestrateur MultiStep
253
+ response = self.model_manager.get_orchestrator()(enhanced_prompt)
254
+ return response
255
+ except Exception as e:
256
+ print(f"❌ Erreur general task: {e}")
257
+ try:
258
+ # Dernière tentative simple
259
+ simple_response = self.model_manager.get_orchestrator()(question)
260
+ return simple_response
261
+ except Exception as final_e:
262
+ raise final_e # Propage l'erreur au handler principal
263
 
264
  def _fallback_reasoning(self, question: str, error: str) -> str:
265
+ """Utilise le modèle de raisonnement en cas d'erreur pour fournir une réponse de secours."""
266
+ try:
267
+ 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."
268
+
269
+ # CORRECTION: Appel direct du modèle avec le prompt seulement
270
+ response = self.model_manager.get_reasoning_model()(fallback_prompt)
271
+ return f"⚠️ Réponse de récupération:\n{response}"
272
+ except Exception as e:
273
+ raise e
274
 
275
  def _get_conversation_context(self, max_exchanges: int = 3) -> str:
276
+ """Récupère le contexte des échanges récents pour l'injecter dans le prompt."""
277
+ if not self.conversation_history:
278
+ return ""
279
+
280
  recent_history = self.conversation_history[-max_exchanges*2:]
281
  context_parts = ["Contexte de la conversation récente:"]
282
  for entry in recent_history:
283
  role = "Utilisateur" if entry["role"] == "user" else "Assistant"
284
+ content = str(entry["content"])[:200] + "..." if len(str(entry["content"])) > 200 else str(entry["content"])
285
  context_parts.append(f"{role}: {content}")
286
+
287
  return "\n".join(context_parts)
288
 
289
+ def get_status(self) -> Dict[str, Any]:
290
+ """Retourne le statut actuel de l'agent."""
291
+ return {
292
+ "status": "active",
293
+ "conversation_length": len(self.conversation_history),
294
+ "available_tools": [tool.__name__ for tool in self.tools if hasattr(tool, '__name__')],
295
+ "models_status": self.model_manager.test_models(),
296
+ }
297
+
298
+ def reset_conversation(self):
299
+ """Réinitialise l'historique de la conversation."""
300
+ self.conversation_history = []
301
+ print("🔄 Historique de conversation remis à zéro.")
302
+
303
 
304
  class BasicAgent:
305
  """