xiaowei-system/scripts/proactive_learning.py

252 lines
8.2 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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]")