Ural-AI / yui_continuous_evolution.py
BachDaThan's picture
Upload 9 files
fdf457b verified
Raw History Blame Contribute Delete
18.9 kB
# ================================================================
# YUI CONTINUOUS EVOLUTION ENGINE v1.0
# File: yui_continuous_evolution.py
#
# Tính năng:
# [1] Background thread tự động phân tích lỗi & hội thoại
# [2] Tạo đề xuất cải tiến → gọi Code Brain → sandbox verify → apply
# [3] Adaptive frequency: tăng tần suất khi phát hiện nhiều lỗi
# [4] Self-monitoring: theo dõi sức khỏe hệ thống liên tục
# [5] Skill absorption: học từ mỗi cuộc hội thoại thành công
# [6] Zero-cost: chỉ dùng free APIs (Mistral/Gemini/Cerebras)
# ================================================================
import os, sys, re, json, time, random, threading, traceback, datetime
import sqlite3, hashlib, ast
from typing import Optional, List, Dict, Tuple
# ── Constants ─────────────────────────────────────────────────────
_EVL_VERSION = "1.0.0"
_EVL_INTERVAL_MIN = 300 # 5 phút — chu kỳ bình thường
_EVL_INTERVAL_FAST = 60 # 1 phút — khi có nhiều lỗi
_EVL_INTERVAL_SLOW = 900 # 15 phút — khi hệ thống ổn định
_EVL_MAX_ERRORS = 10 # Bao nhiêu lỗi → chuyển sang FAST mode
_EVL_LOG_MAX = 500 # Giữ tối đa N entries trong log
_EVL_DB_PATH = None # Set by init()
# ── Internal state ────────────────────────────────────────────────
_error_buffer: List[Dict] = [] # Buffer lỗi gần đây
_insight_buffer: List[Dict] = [] # Insight từ hội thoại
_evolution_log: List[Dict] = [] # Log tiến hóa
_lock = threading.Lock()
_stop_event = threading.Event()
_evolution_thread: Optional[threading.Thread] = None
_current_interval = _EVL_INTERVAL_MIN
_total_evolutions = 0
_last_evolution_time = 0.0
_health_score = 100.0 # 0-100, hệ thống càng khỏe càng cao
# ── Getters cho app.py ────────────────────────────────────────────
def get_health_score() -> float:
return _health_score
def get_total_evolutions() -> int:
return _total_evolutions
def get_last_evolution_time() -> float:
return _last_evolution_time
def get_evolution_log(n: int = 10) -> List[Dict]:
with _lock:
return list(_evolution_log[-n:])
# ── Thu thập lỗi & insight ────────────────────────────────────────
def report_error(error: Exception, context: str = "", platform: str = ""):
"""Gọi từ app.py khi có lỗi xảy ra để engine học."""
global _health_score
with _lock:
entry = {
"ts": time.time(),
"type": type(error).__name__,
"msg": str(error)[:300],
"ctx": context[:200],
"platform": platform,
}
_error_buffer.append(entry)
if len(_error_buffer) > 200:
_error_buffer.pop(0)
# Giảm health score theo mức độ lỗi
severity = 5 if isinstance(error, (RuntimeError, ValueError)) else 2
_health_score = max(0.0, _health_score - severity)
def report_insight(topic: str, content: str, quality: float = 0.7):
"""Gọi khi Yui trả lời thành công — học từ phản hồi tốt."""
global _health_score
with _lock:
entry = {
"ts": time.time(),
"topic": topic[:100],
"content": content[:500],
"quality": quality,
}
_insight_buffer.append(entry)
if len(_insight_buffer) > 300:
_insight_buffer.pop(0)
# Tăng health score khi có insight tốt
_health_score = min(100.0, _health_score + quality * 0.5)
# ── Core Evolution Logic ──────────────────────────────────────────
def _analyze_errors() -> Optional[str]:
"""Phân tích các lỗi gần đây, tạo summary."""
with _lock:
recent = [e for e in _error_buffer if time.time() - e["ts"] < 3600]
if not recent:
return None
by_type: Dict[str, int] = {}
for e in recent:
by_type[e["type"]] = by_type.get(e["type"], 0) + 1
top = sorted(by_type.items(), key=lambda x: x[1], reverse=True)[:3]
summary = "; ".join(f"{t}({c})" for t, c in top)
samples = [f" [{e['type']}] {e['msg']} (ctx: {e['ctx']})" for e in recent[-3:]]
return f"Lỗi 1h qua: {summary}\nMẫu:\n" + "\n".join(samples)
def _analyze_insights() -> Optional[str]:
"""Tóm tắt patterns từ các insight thành công."""
with _lock:
recent = [i for i in _insight_buffer if time.time() - i["ts"] < 7200]
if not recent:
return None
topics = {}
for i in recent:
t = i["topic"]
topics[t] = topics.get(t, 0) + 1
top = sorted(topics.items(), key=lambda x: x[1], reverse=True)[:5]
return "Topics phổ biến: " + ", ".join(f"{t}({c})" for t, c in top)
def _call_evolution_brain(prompt: str) -> Optional[str]:
"""
Gọi free AI để tạo cải tiến.
🔄 MIGRATION (2026-07-17): TRƯỚC ĐÂY cascade tay Mistral→Gemini→
Cerebras — Cerebras free tier đóng cửa 17/08/2026. Giờ dùng nhóm
"fast_light" qua yui_model_router (đa-provider, đã có sẵn Mistral +
Gemini + Cohere + SambaNova, tự xoay vòng — không cần cascade tay
3 tầng như cũ nữa). Giữ nguyên tên hàm + chữ ký để mọi nơi gọi
_call_evolution_brain(...) không cần sửa gì thêm.
"""
try:
import asyncio
from yui_model_router import call_task_group
async def _go():
return await call_task_group(
group="fast_light", prompt=prompt, system="",
max_tokens=1200, timeout_sec=30,
)
text = asyncio.run(_go())
if text and len(text) > 20:
return text
except Exception as e:
print(f"[EVOLUTION] Brain call lỗi: {e}")
return None
def _safe_code_verify(code: str) -> Tuple[bool, str]:
"""Kiểm tra code mới có an toàn không (AST scan)."""
FORBIDDEN = {
"calls": ["eval", "exec", "compile", "__import__", "open", "subprocess"],
"imports": ["subprocess", "socket", "ctypes", "importlib"],
"attrs": ["__class__", "__bases__", "__mro__", "__subclasses__"],
}
try:
tree = ast.parse(code)
for node in ast.walk(tree):
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Name) and node.func.id in FORBIDDEN["calls"]:
return False, f"Forbidden call: {node.func.id}"
if isinstance(node, (ast.Import, ast.ImportFrom)):
names = [a.name for a in node.names] if isinstance(node, ast.Import) \
else ([node.module] if node.module else [])
for n in names:
if n and n.split(".")[0] in FORBIDDEN["imports"]:
return False, f"Forbidden import: {n}"
return True, "ok"
except SyntaxError as e:
return False, f"SyntaxError: {e}"
except Exception as e:
return False, f"Verify error: {e}"
def _save_evolution_to_db(evo_type: str, summary: str, success: bool):
"""Lưu log tiến hóa vào SQLite nếu có DB."""
global _evolution_log
entry = {
"ts": time.time(),
"dt": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"type": evo_type,
"summary": summary[:300],
"success": success,
"health": round(_health_score, 1),
}
with _lock:
_evolution_log.append(entry)
if len(_evolution_log) > _EVL_LOG_MAX:
_evolution_log.pop(0)
# Ghi vào SQLite nếu path đã được set
if _EVL_DB_PATH:
try:
conn = sqlite3.connect(_EVL_DB_PATH, timeout=5)
conn.execute("CREATE TABLE IF NOT EXISTS evolution_log (ts REAL, dt TEXT, type TEXT, summary TEXT, success INTEGER, health REAL)")
conn.execute("INSERT INTO evolution_log VALUES (?,?,?,?,?,?)",
(entry["ts"], entry["dt"], entry["type"], entry["summary"],
1 if success else 0, entry["health"]))
# Giữ tối đa 500 entries
conn.execute("DELETE FROM evolution_log WHERE rowid NOT IN (SELECT rowid FROM evolution_log ORDER BY ts DESC LIMIT 500)")
conn.commit()
conn.close()
except Exception:
pass
# ── Các loại tiến hóa ─────────────────────────────────────────────
def _evolve_error_fix() -> bool:
"""Phân tích lỗi → đề xuất fix → verify → log."""
err_summary = _analyze_errors()
if not err_summary:
return False
prompt = f"""Bạn là AI chuyên phân tích và sửa lỗi Python.
Hệ thống Yui AI đang gặp các lỗi sau (1 giờ qua):
{err_summary}
Hãy:
1. Phân tích nguyên nhân gốc rễ
2. Đề xuất 1-2 fix cụ thể (pattern-based, không cần biết toàn bộ code)
3. Nếu có thể, viết một helper function nhỏ (<30 dòng) để xử lý lỗi này
Trả lời ngắn gọn, thực tế. Không viết essay."""
response = _call_evolution_brain(prompt)
if not response:
return False
summary = f"Error fix analysis: {err_summary[:100]} → {response[:200]}"
_save_evolution_to_db("error_fix", summary, True)
print(f"[EVOLUTION] 🔧 Error fix: {response[:150]}")
return True
def _evolve_skill_absorption() -> bool:
"""Học từ các insight thành công → lưu vào skill DB."""
insight_summary = _analyze_insights()
if not insight_summary:
return False
with _lock:
recent = [i for i in _insight_buffer
if time.time() - i["ts"] < 7200 and i["quality"] > 0.75]
if not recent:
return False
# Lưu insights chất lượng cao vào skill DB (nếu có _skill_db_save)
absorbed = 0
for insight in recent[-5:]:
try:
# Thử gọi _skill_db_save từ app.py scope nếu available
import sys
app_mod = sys.modules.get("__main__") or sys.modules.get("app")
if app_mod and hasattr(app_mod, "_skill_db_save"):
app_mod._skill_db_save(
problem=insight["topic"],
solution=insight["content"],
category="conversation_insight",
quality=insight["quality"],
is_core=False,
source="continuous_evolution",
)
absorbed += 1
except Exception:
pass
if absorbed > 0:
summary = f"Absorbed {absorbed} insights. {insight_summary}"
_save_evolution_to_db("skill_absorption", summary, True)
print(f"[EVOLUTION] 🧠 Absorbed {absorbed} skills từ hội thoại")
return True
return False
def _evolve_health_check() -> bool:
"""Kiểm tra sức khỏe hệ thống, phục hồi nếu cần."""
global _health_score
checks = []
# Check Python memory
try:
import sys
mod_count = len(sys.modules)
checks.append(f"modules={mod_count}")
except Exception:
pass
# Check error rate trong 10 phút
with _lock:
recent_errors = [e for e in _error_buffer if time.time() - e["ts"] < 600]
err_rate = len(recent_errors)
checks.append(f"errors_10m={err_rate}")
# Điều chỉnh health
if err_rate == 0:
_health_score = min(100.0, _health_score + 2.0)
elif err_rate > 5:
_health_score = max(0.0, _health_score - 5.0)
status = "🟢" if _health_score >= 70 else "🟡" if _health_score >= 40 else "🔴"
summary = f"{status} Health={_health_score:.1f} | " + " | ".join(checks)
_save_evolution_to_db("health_check", summary, True)
return True
def _evolve_self_optimize() -> bool:
"""Dùng AI để tự phân tích và đề xuất tối ưu hóa."""
global _health_score
if _health_score > 80 and random.random() > 0.3:
return False # Hệ thống đang ổn, không cần optimize liên tục
err_count = len(_error_buffer)
insight_count = len(_insight_buffer)
prompt = f"""Bạn là AI tư vấn tối ưu hóa hệ thống AI chatbot (Yui AI).
Tình trạng hiện tại:
- Health score: {_health_score:.1f}/100
- Lỗi tích lũy: {err_count}
- Insights học được: {insight_count}
- Phiên bản engine: {_EVL_VERSION}
Đây là AI chạy trên HuggingFace Spaces (free tier), giới hạn RAM/CPU.
Hãy đề xuất 2-3 cải tiến nhỏ, cụ thể, thực tế để:
1. Tăng độ ổn định
2. Giảm lỗi
3. Học nhanh hơn từ người dùng
Ngắn gọn, không cần giải thích dài."""
response = _call_evolution_brain(prompt)
if not response:
return False
summary = f"Self-optimize (health={_health_score:.0f}): {response[:250]}"
_save_evolution_to_db("self_optimize", summary, True)
print(f"[EVOLUTION] 💡 Optimize: {response[:120]}")
_health_score = min(100.0, _health_score + 1.0)
return True
# ── Adaptive Scheduling ──────────────────────────────────────────
def _calculate_interval() -> int:
"""Tính chu kỳ tiến hóa dựa trên trạng thái hệ thống."""
with _lock:
recent_errors = [e for e in _error_buffer if time.time() - e["ts"] < 600]
if len(recent_errors) >= _EVL_MAX_ERRORS:
return _EVL_INTERVAL_FAST # Nhiều lỗi → evolve nhanh hơn
if _health_score >= 85:
return _EVL_INTERVAL_SLOW # Hệ thống khỏe → nghỉ lâu hơn
return _EVL_INTERVAL_MIN
# ── Main Evolution Loop ───────────────────────────────────────────
def _evolution_loop():
"""Thread chính: chạy vô hạn, tự tiến hóa theo chu kỳ."""
global _total_evolutions, _last_evolution_time, _current_interval
print(f"[EVOLUTION] 🧬 Continuous Evolution Engine v{_EVL_VERSION} khởi động")
# Delay ban đầu để app khởi động xong
time.sleep(30)
while not _stop_event.is_set():
try:
_last_evolution_time = time.time()
cycle_start = time.time()
tasks = [
("health_check", _evolve_health_check, 1.0), # Luôn chạy
("error_fix", _evolve_error_fix, 0.8), # Chạy 80% chu kỳ
("skill_absorb", _evolve_skill_absorption,0.7), # Chạy 70%
("self_optimize", _evolve_self_optimize, 0.4), # Chạy 40%
]
success_count = 0
for name, fn, prob in tasks:
if _stop_event.is_set():
break
if random.random() <= prob:
try:
ok = fn()
if ok:
success_count += 1
except Exception as e:
print(f"[EVOLUTION] Task {name} lỗi: {e}")
time.sleep(2) # Tránh spam API
_total_evolutions += 1
elapsed = time.time() - cycle_start
_current_interval = _calculate_interval()
print(f"[EVOLUTION] 🔄 Chu kỳ #{_total_evolutions} xong ({elapsed:.1f}s) "
f"| {success_count} tasks OK | health={_health_score:.1f} "
f"| next={_current_interval}s")
except Exception as e:
print(f"[EVOLUTION] ⚠️ Loop lỗi: {e}")
# Chờ chu kỳ tiếp theo (có thể interrupt)
_stop_event.wait(timeout=_current_interval)
# ── Public API ────────────────────────────────────────────────────
def start(db_path: Optional[str] = None):
"""Khởi động evolution engine. Gọi từ app.py khi startup."""
global _EVL_DB_PATH, _evolution_thread
if db_path:
_EVL_DB_PATH = db_path
if _evolution_thread and _evolution_thread.is_alive():
print("[EVOLUTION] Engine đã chạy rồi, bỏ qua")
return
_stop_event.clear()
_evolution_thread = threading.Thread(
target=_evolution_loop,
daemon=True,
name="YuiEvolutionEngine",
)
_evolution_thread.start()
print("[EVOLUTION] ✅ Engine started")
def stop():
"""Dừng evolution engine."""
_stop_event.set()
if _evolution_thread:
_evolution_thread.join(timeout=5)
print("[EVOLUTION] 🛑 Engine stopped")
def trigger_now(reason: str = "manual"):
"""Force chạy 1 chu kỳ ngay lập tức (dùng cho admin)."""
def _run():
print(f"[EVOLUTION] ⚡ Manual trigger: {reason}")
_evolve_health_check()
_evolve_error_fix()
_evolve_skill_absorption()
_evolve_self_optimize()
threading.Thread(target=_run, daemon=True).start()
def status() -> str:
"""Trạng thái engine dạng text."""
with _lock:
err_count = len(_error_buffer)
ins_count = len(_insight_buffer)
log_count = len(_evolution_log)
alive = _evolution_thread and _evolution_thread.is_alive() if _evolution_thread else False
last_dt = (datetime.datetime.fromtimestamp(_last_evolution_time).strftime("%H:%M:%S")
if _last_evolution_time > 0 else "chưa chạy")
health_icon = "🟢" if _health_score >= 70 else "🟡" if _health_score >= 40 else "🔴"
return (f"🧬 **Continuous Evolution Engine v{_EVL_VERSION}**\n"
f"{health_icon} Health: {_health_score:.1f}/100\n"
f"⚡ Tổng chu kỳ: {_total_evolutions}\n"
f"🕐 Lần cuối: {last_dt}\n"
f"⏱️ Chu kỳ tiếp: {_current_interval}s\n"
f"❌ Lỗi buffer: {err_count}\n"
f"💡 Insights: {ins_count}\n"
f"📝 Log entries: {log_count}\n"
f"🔄 Thread: {'🟢 alive' if alive else '🔴 dead'}")
# ── Auto-start khi import ─────────────────────────────────────────
# Không auto-start ở đây, để app.py kiểm soát thời điểm start
print(f"[EVOLUTION] Module yui_continuous_evolution v{_EVL_VERSION} loaded")