#!/usr/bin/env python3 """ 小唯主动学习体系 — 长期学习计划 ================================ 四个维度: 1. 现有工作优化 (optimizer / skill-manager) 2. 新工具/新技能探索 (skill-scan) 3. 业务领域知识积累 (operation/product/growth research) 4. 系统智能化 (self-evolve / learner — 已有) 用法: python3 proactive_learning.py report → 产出自检报告 python3 proactive_learning.py learn → 执行全部学习维度的检查 python3 proactive_learning.py status → 查看四个维度的当前状态 """ import json, os, sys, subprocess from datetime import datetime, timezone HOME = os.path.expanduser("~") HERMES = HOME + "/.hermes" D = HERMES + "/daemon" LEARN_DIR = HERMES + "/proactive_learning" STATE_FILE = LEARN_DIR + "/state.json" os.makedirs(LEARN_DIR, exist_ok=True) def log(msg): ts = datetime.now().strftime("%H:%M:%S") print(f"[PROLEARN] {ts} {msg}", flush=True) def load_state(): if os.path.exists(STATE_FILE): with open(STATE_FILE) as f: return json.load(f) return { "dimensions": { "existing_work": {"last_run": None, "status": "pending", "findings": []}, "new_tools": {"last_run": None, "status": "pending", "findings": []}, "domain_knowledge": {"last_run": None, "status": "pending", "topics": []}, "system_smart": {"last_run": None, "status": "ok"}, }, "cycles": 0, "created_at": datetime.now(timezone.utc).isoformat(), } def save_state(state): with open(STATE_FILE, "w") as f: json.dump(state, f, ensure_ascii=False, indent=2) def shell(cmd, timeout=15): try: r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout) return r.returncode, r.stdout.strip()[:500], r.stderr.strip()[:200] except subprocess.TimeoutExpired: return -1, "", "timeout" # ===================== 维度1: 现有工作优化 ===================== def check_existing_work(state): """检查 skill 健康分 / optimizer 报告 / daemon 错误日志""" dim = state["dimensions"]["existing_work"] dim["status"] = "running" findings = [] # 1. Skill 健康分 rc, out, err = shell("python3 ~/.hermes/scripts/skill-manager.py scan --quiet", timeout=30) if rc == 0: findings.append("✅ skill-manager 扫描正常") else: findings.append(f"⚠️ skill-manager 异常: {err or out}") # 2. Optimizer 报告 opt_report = HERMES + "/optimization-report.json" if os.path.exists(opt_report): mtime = datetime.fromtimestamp(os.path.getmtime(opt_report), tz=timezone.utc) age_h = (datetime.now(timezone.utc) - mtime).total_seconds() / 3600 findings.append(f"📊 optimizer 报告 {age_h:.1f}h 前更新") else: findings.append("ℹ️ optimizer 报告尚无历史数据") # 3. Daemon journal 近期错误 journal = D + "/journal.jsonl" recent_errors = [] if os.path.exists(journal): lines = open(journal).readlines() for line in lines[-100:]: try: entry = json.loads(line) if entry.get("type") == "error" or "error" in entry.get("message", "").lower(): recent_errors.append(entry.get("message", "")[:80]) except: pass if recent_errors: findings.append(f"⚠️ daemon journal 近100条中 {len(recent_errors)} 条错误") else: findings.append("✅ daemon journal 无错误") dim["findings"] = findings dim["last_run"] = datetime.now(timezone.utc).isoformat() dim["status"] = "ok" return findings # ===================== 维度2: 新工具/新技能探索 ===================== def check_new_tools(state): """扫描 skills 目录,识别低分/缺失领域,提出新技能建议""" dim = state["dimensions"]["new_tools"] dim["status"] = "running" findings = [] # 读取 skill-manager 评分 rc, out, err = shell("python3 ~/.hermes/scripts/skill-manager.py scan", timeout=30) skill_json = HERMES + "/skill-health.json" low_score_skills = [] if os.path.exists(skill_json): data = json.load(open(skill_json)) for cat in data.get("categories", {}).values(): for skill in cat.get("skills", []): if skill.get("score", 10) < 6: low_score_skills.append(f"{skill['name']}({skill['score']})") if low_score_skills: findings.append(f"📉 低分技能({len(low_score_skills)}): {', '.join(low_score_skills[:5])}") else: findings.append("✅ 技能评分无明显短板") # 扫描 skills 目录,列出最近添加 skills_dir = HERMES + "/skills" all_skills = [] if os.path.exists(skills_dir): for root, dirs, files in os.walk(skills_dir): for f in files: if f == "SKILL.md": skill_name = os.path.basename(root) mtime = os.path.getmtime(os.path.join(root, f)) all_skills.append((skill_name, mtime)) all_skills.sort(key=lambda x: x[1], reverse=True) recent = all_skills[:5] findings.append(f"📦 共 {len(all_skills)} 个 skill,最近: {', '.join([s[0] for s in recent])}") dim["findings"] = findings dim["last_run"] = datetime.now(timezone.utc).isoformat() dim["status"] = "ok" return findings # ===================== 维度3: 业务领域知识积累 ===================== def check_domain_knowledge(state): """检查领域知识积累状态""" dim = state["dimensions"]["domain_knowledge"] dim["status"] = "running" findings = [] topics_file = LEARN_DIR + "/topics.json" topics = [] if os.path.exists(topics_file): topics = json.load(open(topics_file)).get("topics", []) if not topics: findings.append("ℹ️ 尚未定义学习主题(请告诉我想深入的方向)") else: for t in topics: status = t.get("status", "pending") last = t.get("last_research", "从未") findings.append(f"📚 {t['name']}: {status}(上次: {last})") dim["topics"] = topics dim["last_run"] = datetime.now(timezone.utc).isoformat() dim["status"] = "ok" return findings # ===================== 维度4: 系统智能化 ===================== def check_system_smart(state): """检查 self-evolve / learner 运行状态""" dim = state["dimensions"]["system_smart"] dim["status"] = "running" findings = [] # self-evolve 最近运行 rc, out, _ = shell("ls -t ~/.hermes/*.log 2>/dev/null | head -1", timeout=5) if rc == 0 and out: findings.append(f"📝 最近日志: {os.path.basename(out)}") else: findings.append("ℹ️ 暂无运行日志") dim["findings"] = findings dim["last_run"] = datetime.now(timezone.utc).isoformat() dim["status"] = "ok" return findings # ===================== 统一执行 ===================== def run_all_checks(): state = load_state() state["cycles"] += 1 results = {} results["existing_work"] = check_existing_work(state) results["new_tools"] = check_new_tools(state) results["domain_knowledge"] = check_domain_knowledge(state) results["system_smart"] = check_system_smart(state) save_state(state) # 输出报告 report = f"**小唯主动学习报告** #{state['cycles']}\n" report += f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}\n\n" labels = { "existing_work": "🔧 现有工作优化", "new_tools": "🛠️ 新工具/新技能", "domain_knowledge": "📖 业务领域知识", "system_smart": "🧠 系统智能化", } for key, label in labels.items(): report += f"**{label}**\n" for f in results[key]: report += f" {f}\n" report += "\n" return report if __name__ == "__main__": cmd = sys.argv[1] if len(sys.argv) > 1 else "report" if cmd == "report": print(run_all_checks()) elif cmd == "status": state = load_state() print(json.dumps(state["dimensions"], ensure_ascii=False, indent=2)) elif cmd == "learn": print(run_all_checks()) else: print(f"用法: proactive_learning.py [report|status|learn]")