Spaces:
Sleeping
Sleeping
File size: 5,240 Bytes
8e3a425 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | # core/research_loop.py
import re
import time
import uuid
from typing import Dict, Any
from core.memory import MemoryTier
class ResearchLoop:
def __init__(self, llm_engine, memory, executor):
self.llm = llm_engine
self.memory = memory
self.executor = executor # execute_safe
self.error_tree = None # sera injecté plus tard (via app.py)
self.publications = []
def set_error_tree(self, error_tree):
self.error_tree = error_tree
async def generate_hypothesis(self, domain: str) -> str:
if not self.llm:
return f"L'utilisation d'un cache LRU réduit le temps d'exécution de 20% pour des appels répétés dans {domain}."
prompt = (
f"Propose une hypothèse précise et testable sur l'optimisation de {domain}. "
"Elle doit être formulée en une phrase et contenir un indicateur quantifiable (ex: 'réduit de X%', 'accélère de Y ms'). "
"Exemple : 'L'indexation des colonnes fréquemment jointes réduit le temps de requête SQL de 30%'. "
"Réponse (une phrase) :"
)
try:
resp = await self.llm.call(
agent="research",
system="Tu es un chercheur en optimisation.",
user=prompt,
max_tokens=80,
temperature=0.3,
use_cache=False
)
raw = resp.content if hasattr(resp, "content") else str(resp)
raw = raw.strip().split('\n')[0]
raw = re.sub(r'^(Answer|Hypothesis|Réponse|Hypothèse):\s*', '', raw, flags=re.IGNORECASE)
if len(raw) < 10:
return f"L'optimisation de {domain} améliore les performances de 15%."
return raw
except Exception as e:
# 🔥 Enregistrer l'échec de génération dans Harbor
if self.error_tree is not None:
try:
self.error_tree.add_error(str(e), f"ResearchLoop generate_hypothesis domain={domain}")
except Exception:
pass
return f"L'optimisation de {domain} améliore les performances de 15%."
async def run_experiment(self, hypothesis: str) -> float:
try:
# 1. Générer un code de test basé sur l'hypothèse
code_prompt = (
f"Écris un court code Python qui teste l'hypothèse suivante : {hypothesis}\n"
"Le code doit définir une fonction `run_test()` qui retourne un score entre 0 et 1 "
"(0 = échec, 1 = succès parfait). Exemple :\n"
"def run_test():\n"
" # ... test ...\n"
" return 0.85\n"
"Ne retourne que le code, sans commentaires."
)
resp = await self.llm.call(
agent="research",
system="Tu es un ingénieur de test.",
user=code_prompt,
max_tokens=200,
temperature=0.2,
use_cache=False
)
code = resp.content if hasattr(resp, "content") else str(resp)
code = re.sub(r'```(?:python)?\n?', '', code).replace('```', '').strip()
# 2. Exécuter le code dans le sandbox
result = self.executor(code, timeout=10)
if not result.get("success"):
if self.error_tree is not None:
try:
self.error_tree.add_error(
f"Exécution échouée: {result.get('error', '')}",
f"Hypothèse: {hypothesis[:100]}"
)
except Exception:
pass
return 0.0
# 3. Récupérer la sortie
output = result.get("result", "").strip()
match = re.search(r'(\d+\.?\d*)', output)
if match:
score = float(match.group(1))
score = max(0.0, min(1.0, score))
return score
else:
return 0.0
except Exception as e:
if self.error_tree is not None:
try:
self.error_tree.add_error(str(e), f"ResearchLoop run_experiment")
except Exception:
pass
return 0.0
async def publish(self, hypothesis: str, score: float):
pub = {
"id": str(uuid.uuid4())[:8],
"hypothesis": hypothesis,
"score": round(score, 3),
"timestamp": time.time()
}
self.publications.append(pub)
self.memory.ingest(
f"Research: {hypothesis[:150]} (score={score:.3f})",
MemoryTier.SEMANTIC,
"research_loop",
importance=score,
confidence=score
)
async def run_one_cycle(self, domain: str) -> Dict[str, Any]:
hypothesis = await self.generate_hypothesis(domain)
score = await self.run_experiment(hypothesis)
await self.publish(hypothesis, score)
return {
"hypothesis": hypothesis,
"score": round(score, 3),
"domain": domain
} |