Spaces:
Sleeping
Sleeping
Update agent.py
Browse files
agent.py
CHANGED
@@ -13,6 +13,7 @@ from smolagents import CodeAgent, MultiStepAgent, AgentError, PythonInterpreterT
|
|
13 |
from models import ModelManager
|
14 |
from tools import search_web, scrape_website, read_file
|
15 |
|
|
|
16 |
# --- CLASSE ORCHESTRATEUR COMPLÈTE ---
|
17 |
class OrchestratorAgent(MultiStepAgent):
|
18 |
"""
|
@@ -37,141 +38,83 @@ class OrchestratorAgent(MultiStepAgent):
|
|
37 |
# Pour l'instant, nous retournons simplement la réponse brute du modèle.
|
38 |
return final_response
|
39 |
|
40 |
-
class
|
41 |
"""
|
42 |
-
|
43 |
-
|
44 |
"""
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
"""Initialise les agents spécialisés."""
|
59 |
try:
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
model=self.model_manager.get_code_agent(),
|
68 |
-
tools=[PythonInterpreterTool()],
|
69 |
-
additional_authorized_imports=["requests", "pandas", "numpy", "matplotlib", "seaborn", "scipy", "sklearn"]
|
70 |
)
|
71 |
-
print("✅
|
|
|
72 |
except Exception as e:
|
73 |
-
print(f"❌ Erreur lors de l'initialisation
|
74 |
-
|
75 |
|
76 |
def __call__(self, question: str) -> str:
|
77 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
78 |
print("\n" + "="*80)
|
79 |
-
print(f"
|
80 |
print("="*80)
|
81 |
-
|
82 |
-
try:
|
83 |
-
self.conversation_history.append({"role": "user", "content": question, "timestamp": time.time()})
|
84 |
-
strategy = self._analyze_question(question)
|
85 |
-
print(f"📋 Stratégie sélectionnée: {strategy['type']}")
|
86 |
-
response = self._execute_strategy(question, strategy)
|
87 |
-
self.conversation_history.append({"role": "assistant", "content": response, "strategy": strategy, "timestamp": time.time()})
|
88 |
-
print(f"✅ Réponse générée avec succès ({len(response)} caractères)")
|
89 |
-
return response
|
90 |
-
except Exception as e:
|
91 |
-
error_msg = f"❌ Erreur critique dans l'UltraAgent: {e}"
|
92 |
-
print(error_msg)
|
93 |
-
try:
|
94 |
-
print("🔄 Tentative de récupération avec le modèle de raisonnement...")
|
95 |
-
fallback_response = self._fallback_reasoning(question, str(e))
|
96 |
-
return fallback_response
|
97 |
-
except Exception as fallback_e:
|
98 |
-
final_error = f"Je rencontre des difficultés techniques. Erreur: {str(fallback_e)[:200]}"
|
99 |
-
print(f"❌ La récupération a également échoué: {fallback_e}")
|
100 |
-
return final_error
|
101 |
-
|
102 |
-
def _analyze_question(self, question: str) -> Dict[str, Any]:
|
103 |
-
"""Analyse la question pour déterminer la meilleure stratégie."""
|
104 |
-
# Cette fonction de scoring simple reste la même
|
105 |
-
question_lower = question.lower()
|
106 |
-
vision_keywords = ['image', 'photo', 'picture', 'visual', 'voir', 'regarder', 'analyser l\'image', 'screenshot']
|
107 |
-
code_keywords = ['code', 'program', 'script', 'algorithm', 'python', 'javascript', 'sql', 'debug', 'programmer']
|
108 |
-
if any(kw in question_lower for kw in vision_keywords):
|
109 |
-
return {"type": "vision"}
|
110 |
-
if any(kw in question_lower for kw in code_keywords):
|
111 |
-
return {"type": "code"}
|
112 |
-
return {"type": "general"} # Simplification de la stratégie pour le débogage
|
113 |
-
|
114 |
-
def _execute_strategy(self, question: str, strategy: Dict[str, Any]) -> str:
|
115 |
-
"""Exécute la stratégie déterminée."""
|
116 |
-
strategy_type = strategy["type"]
|
117 |
-
try:
|
118 |
-
if strategy_type == "vision":
|
119 |
-
return self._handle_vision_task(question)
|
120 |
-
elif strategy_type == "code":
|
121 |
-
return self._handle_code_task(question)
|
122 |
-
else: # general, search_web, file_processing, reasoning
|
123 |
-
return self._handle_general_task(question)
|
124 |
-
except Exception as e:
|
125 |
-
print(f"❌ Erreur dans l'exécution de la stratégie {strategy_type}: {e}")
|
126 |
-
raise e # Fait remonter l'erreur pour la gestion centrale
|
127 |
-
|
128 |
-
def _handle_vision_task(self, question: str) -> str:
|
129 |
-
"""Gère les tâches de vision."""
|
130 |
-
print("👁️ Traitement avec le modèle de vision...")
|
131 |
-
response = self.model_manager.get_vision_model()(question)
|
132 |
-
return f"🔍 Analyse visuelle:\n{response}"
|
133 |
-
|
134 |
-
def _handle_code_task(self, question: str) -> str:
|
135 |
-
"""Gère les tâches de code."""
|
136 |
-
print("💻 Traitement avec l'agent de code...")
|
137 |
-
return self.code_agent.run(question)
|
138 |
-
|
139 |
-
def _handle_general_task(self, question: str) -> str:
|
140 |
-
"""Gère toutes les autres tâches avec l'orchestrateur."""
|
141 |
-
print("🎯 Traitement général avec l'orchestrateur...")
|
142 |
-
context = self._get_conversation_context()
|
143 |
-
enhanced_prompt = f"{context}\nQuestion actuelle: {question}"
|
144 |
-
return self.orchestrator.run(enhanced_prompt)
|
145 |
-
|
146 |
-
def _fallback_reasoning(self, question: str, error: str) -> str:
|
147 |
-
"""Fallback avec le modèle de raisonnement."""
|
148 |
-
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."
|
149 |
-
return self.model_manager.get_reasoning_model()(fallback_prompt)
|
150 |
-
|
151 |
-
def _get_conversation_context(self, max_exchanges: int = 3) -> str:
|
152 |
-
"""Récupère le contexte des échanges récents."""
|
153 |
-
if not self.conversation_history: return ""
|
154 |
-
recent_history = self.conversation_history[-max_exchanges*2:]
|
155 |
-
context_parts = ["Contexte de la conversation récente:"]
|
156 |
-
for entry in recent_history:
|
157 |
-
role = "Utilisateur" if entry["role"] == "user" else "Assistant"
|
158 |
-
content = str(entry["content"])[:200]
|
159 |
-
context_parts.append(f"{role}: {content}")
|
160 |
-
return "\n".join(context_parts)
|
161 |
-
|
162 |
-
# La classe BasicAgent reste la même, elle ne fait qu'appeler UltraAgent
|
163 |
|
164 |
-
class BasicAgent:
|
165 |
-
def __init__(self):
|
166 |
try:
|
167 |
-
|
168 |
-
print("⚠️ Attention: Le token Hugging Face (HF_TOKEN) n'est pas défini.")
|
169 |
-
self.ultra_agent = UltraAgent()
|
170 |
except Exception as e:
|
171 |
-
print(f"❌ Erreur
|
172 |
-
|
173 |
-
|
174 |
-
def __call__(self, question: str) -> str:
|
175 |
-
if self.ultra_agent is None:
|
176 |
-
return "Erreur: L'agent n'a pas pu être initialisé. Vérifiez les logs et la configuration (HF_TOKEN)."
|
177 |
-
return self.ultra_agent(question)
|
|
|
13 |
from models import ModelManager
|
14 |
from tools import search_web, scrape_website, read_file
|
15 |
|
16 |
+
|
17 |
# --- CLASSE ORCHESTRATEUR COMPLÈTE ---
|
18 |
class OrchestratorAgent(MultiStepAgent):
|
19 |
"""
|
|
|
38 |
# Pour l'instant, nous retournons simplement la réponse brute du modèle.
|
39 |
return final_response
|
40 |
|
41 |
+
class MonAgent(MultiStepAgent):
|
42 |
"""
|
43 |
+
Un agent multi-étapes complet et robuste qui sait comment
|
44 |
+
planifier, utiliser des outils, et formater sa réponse finale.
|
45 |
"""
|
46 |
+
def initialize_system_prompt(self) -> str:
|
47 |
+
"""
|
48 |
+
Le prompt système. On donne un exemple très précis pour forcer le modèle
|
49 |
+
à répondre dans le bon format (JSON avec des appels d'outils).
|
50 |
+
"""
|
51 |
+
return """You are a world-class autonomous agent. Your goal is to fully answer the user's question by creating a plan and using tools.
|
52 |
+
|
53 |
+
You MUST format your response as a JSON object containing a list of tool calls.
|
54 |
+
Each tool call is a dictionary with "tool" and "args".
|
55 |
+
|
56 |
+
Example of a valid response:
|
57 |
+
{
|
58 |
+
"plan": [
|
59 |
+
{
|
60 |
+
"tool": "search_web",
|
61 |
+
"args": {
|
62 |
+
"query": "Who is the current president of France?"
|
63 |
+
}
|
64 |
+
}
|
65 |
+
]
|
66 |
+
}
|
67 |
+
|
68 |
+
If you have the final answer, respond with an empty plan:
|
69 |
+
{
|
70 |
+
"plan": []
|
71 |
+
}
|
72 |
+
"""
|
73 |
+
|
74 |
+
def render_final_answer(self, final_context: dict, final_response: str) -> str:
|
75 |
+
"""
|
76 |
+
Cette méthode est OBLIGATOIRE. Elle est appelée quand le plan est vide
|
77 |
+
pour formater la réponse finale.
|
78 |
+
"""
|
79 |
+
return final_response
|
80 |
+
|
81 |
|
82 |
+
|
83 |
+
|
84 |
+
class BasicAgent:
|
85 |
+
"""
|
86 |
+
Classe de compatibilité qui utilise notre nouvel agent simple et robuste.
|
87 |
+
"""
|
88 |
+
def __init__(self):
|
89 |
+
print("🚀 Initialisation du BasicAgent (version robuste)...")
|
|
|
90 |
try:
|
91 |
+
if not os.getenv("HF_TOKEN"):
|
92 |
+
print("⚠️ Attention: Le token Hugging Face (HF_TOKEN) n'est pas défini.")
|
93 |
+
|
94 |
+
# On instancie notre agent complet et fiable
|
95 |
+
self.agent = MonAgent(
|
96 |
+
model=ModelManager().get_orchestrator(),
|
97 |
+
tools=[search_web, scrape_website, read_file, PythonInterpreterTool()]
|
|
|
|
|
|
|
98 |
)
|
99 |
+
print("✅ BasicAgent initialisé avec succès!")
|
100 |
+
|
101 |
except Exception as e:
|
102 |
+
print(f"❌ Erreur critique lors de l'initialisation: {e}")
|
103 |
+
self.agent = None
|
104 |
|
105 |
def __call__(self, question: str) -> str:
|
106 |
+
"""
|
107 |
+
Point d'entrée. Délègue l'appel à notre agent.
|
108 |
+
"""
|
109 |
+
if self.agent is None:
|
110 |
+
return "Erreur: L'agent n'a pas pu être initialisé. Vérifiez les logs et la configuration (HF_TOKEN)."
|
111 |
+
|
112 |
print("\n" + "="*80)
|
113 |
+
print(f"🤖 NOUVELLE QUESTION POUR MONAGENT: {question}")
|
114 |
print("="*80)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
|
|
|
|
|
116 |
try:
|
117 |
+
return self.agent.run(question)
|
|
|
|
|
118 |
except Exception as e:
|
119 |
+
print(f"❌ Erreur lors du traitement par MonAgent: {e}")
|
120 |
+
return f"Une erreur s'est produite lors du traitement de votre demande: {e}"
|
|
|
|
|
|
|
|
|
|