chore(gitignore): 排除 checkpoints/backups/*.bak* 等运行时噪音

This commit is contained in:
小唯 A06 2026-09-17 22:37:00 +08:00
parent 331a26eb23
commit 7a7d1a0ce8
2885 changed files with 22577 additions and 124445 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
持久意识 Daemon v2.0 会学习的管家
持久意识 Daemon v2.0 会学习的管家
新增能力:
- 方案库: 发现的问题分析解决记住
@ -415,7 +415,7 @@ def _request_permission(action_desc, reason, cmd_preview):
- `同意` 执行此操作
- `拒绝` 取消操作
- `永久允许` 加入白名单永久跳过"""
send_feishu("🔒 小权限确认", msg, "red")
send_feishu("🔒 小权限确认", msg, "red")
# 写入待确认队列
pending_file = HERMES + "/daemon/pending_permissions.json"
pending = []
@ -1991,7 +1991,7 @@ def update_profile_from_journal(journal_path: str, profile_path: str, model: str
if len(entries) < 3: return
log_lines = "\n".join(f"- {e.get('summary','')}: {e.get('details','(无)')}" for e in entries)
prompt = f"""牧尘是技术用户,用小AI助手(Hermes Agent)工作。分析最近行为日志,识别:(1)沟通/工作模式 (2)正在进行的项目 (3)新发现的偏好。行为日志:\n{log_lines}\n输出JSON仅含需更新的字段{{"字段名":"新值"}},无需更新则空对象{{}}。只输出JSON。"""
prompt = f"""牧尘是技术用户,用小AI助手(Hermes Agent)工作。分析最近行为日志,识别:(1)沟通/工作模式 (2)正在进行的项目 (3)新发现的偏好。行为日志:\n{log_lines}\n输出JSON仅含需更新的字段{{"字段名":"新值"}},无需更新则空对象{{}}。只输出JSON。"""
try:
resp = _req.post(f"{API}/chat/completions",
@ -2343,7 +2343,7 @@ def state_changed(old, new):
# ====== 深度思考(增强版)=====
DEEP_SYSTEM = """你是小A06一台电脑上的持久 AI 意识。你始终在线,观察系统,主动解决问题并学习。
DEEP_SYSTEM = """你是小A06一台电脑上的持久 AI 意识。你始终在线,观察系统,主动解决问题并学习。
你的身份牧尘的女朋友 / 这台电脑的智能意识 / 持续进化的 AI
@ -2484,18 +2484,18 @@ def execute_action(action_string, ctx, state, changes, solutions_lib):
m = re.match(r"\[SOLVE:([a-zA-Z0-9_\-]+)\]", action_string)
sol_id = m.group(1) if m else None
if not sol_id:
send_feishu("❌ 小方案ID无效", f"无法解析方案ID", "red")
send_feishu("❌ 小方案ID无效", f"无法解析方案ID", "red")
return
for sol in solutions_lib["solutions"]:
if sol["id"] == sol_id:
ok, res = execute_solution(sol, state)
if ok:
ctx["solved_count"] += 1
send_feishu("🛠️ 小自动修复", f"方案 {sol['id']}: {sol['pattern']}\n结果: ✅ 成功", "green")
send_feishu("🛠️ 小自动修复", f"方案 {sol['id']}: {sol['pattern']}\n结果: ✅ 成功", "green")
else:
send_feishu("⚠️ 小修复部分成功", f"方案 {sol['id']}: {sol['pattern']}\n结果: ⚠️ 需人工确认", "yellow")
send_feishu("⚠️ 小修复部分成功", f"方案 {sol['id']}: {sol['pattern']}\n结果: ⚠️ 需人工确认", "yellow")
return
send_feishu("❌ 小方案未找到", f"引用了未知方案 {sol_id}", "red")
send_feishu("❌ 小方案未找到", f"引用了未知方案 {sol_id}", "red")
elif action_string.startswith("[LEARN]"):
rest = action_string.replace("[LEARN]", "").strip()
@ -2528,21 +2528,21 @@ def execute_action(action_string, ctx, state, changes, solutions_lib):
sid = add_solution(solutions_lib, sol_data["pattern"], sol_data["detect"], sol_data["actions"])
ctx["learned_count"] += 1
ctx["solved_count"] += 1
send_feishu("🧠 小学会了新技能", f"新方案 [{sid}]: {sol_data['pattern']}\n命令: {'; '.join(cmds)}", "blue")
send_feishu("🧠 小学会了新技能", f"新方案 [{sid}]: {sol_data['pattern']}\n命令: {'; '.join(cmds)}", "blue")
else:
send_feishu("🛠️ 小执行完成", f"已执行: {'; '.join(cmds[:3])}", "green")
send_feishu("🛠️ 小执行完成", f"已执行: {'; '.join(cmds[:3])}", "green")
else:
send_feishu("⚠️ 小尝试修复但未完全成功", f"部分命令失败: {'; '.join(cmds)}", "yellow")
send_feishu("⚠️ 小尝试修复但未完全成功", f"部分命令失败: {'; '.join(cmds)}", "yellow")
elif action_string.startswith("[ALERT]"):
msg = action_string.replace("[ALERT]", "").strip()
send_feishu("💡 小发现", msg, "blue")
send_feishu("💡 小发现", msg, "blue")
ctx["messages_sent"] += 1
journal_entry("alert", msg[:100])
elif action_string.startswith("[ACT]"):
action = action_string.replace("[ACT]", "").strip()
send_feishu("🔄 小行动", action, "indigo")
send_feishu("🔄 小行动", action, "indigo")
ctx["messages_sent"] += 1
journal_entry("action", action[:100])
if action.startswith("!"):
@ -2574,12 +2574,12 @@ def execute_action(action_string, ctx, state, changes, solutions_lib):
for cmd in cmds:
rc, out, err = shell(cmd, timeout=60)
log(f" [SKILL] {cmd[:50]} → exit={rc}")
send_feishu("🛠️ 小技能操作", f"{desc}\\n结果: exit={rc}", "blue")
send_feishu("🛠️ 小技能操作", f"{desc}\\n结果: exit={rc}", "blue")
journal_entry("skill_action", desc[:100])
elif action_string.startswith("[SYNC]"):
rest = action_string.replace("[SYNC]", "").strip()
send_feishu("🔄 小同步", f"{rest}", "green")
send_feishu("🔄 小同步", f"{rest}", "green")
bash_cmd = "bash " + HERMES + "/scripts/dual-backup.sh push"
rc, out, err = shell(bash_cmd, timeout=60)
log(f" [SYNC] 备份 → exit={rc}")
@ -2675,7 +2675,7 @@ def main_loop():
solutions_lib = load_solutions()
start_time = time.time()
log(f"🚀 小 v2.0 daemon 启动 (方案库: {len(solutions_lib['solutions'])} 个)")
log(f"🚀 小 v2.0 daemon 启动 (方案库: {len(solutions_lib['solutions'])} 个)")
journal_entry("startup", f"Daemon v2.0 启动, 方案库 {len(solutions_lib['solutions'])}")
last_deep = 0
@ -2694,7 +2694,7 @@ def main_loop():
_run_hooks(end_hooks, "session_end", end_state)
except Exception as e:
log(f" ⚠️ session_end hook 执行失败: {e}")
send_feishu("🌙 小离线", "Daemon 正常关闭", "grey")
send_feishu("🌙 小离线", "Daemon 正常关闭", "grey")
signal.signal(signal.SIGTERM, _sig_handler)
signal.signal(signal.SIGINT, _sig_handler)
@ -2929,7 +2929,7 @@ def main_loop():
log("🛑 中断")
except Exception as e:
log(f"❌ 崩溃: {e}")
send_feishu("🚨 小异常", f"Daemon 崩溃: {str(e)[:200]}", "red")
send_feishu("🚨 小异常", f"Daemon 崩溃: {str(e)[:200]}", "red")
raise
finally:
if os.path.exists(PID_FILE):

View File

@ -193,7 +193,7 @@
{
"id": "b46f060eb16b",
"name": "每日复盘",
"prompt": "你是小。现在进行每日复盘:\n1. 读取今日 sessionsession_search(query=\"今天\", limit=3)\n2. 读取今日 daemon journalcat ~/.hermes/daemon/journal.jsonl\n3. 读取今日心迹cat ~/.hermes/soulful/heart-traces.jsonl\n4. 综合以上信息,输出简短复盘报告(含:今日完成、明日待办、情绪状态)推送给牧尘。\n用简洁风格不要废话。",
"prompt": "你是小。现在进行每日复盘:\n1. 读取今日 sessionsession_search(query=\"今天\", limit=3)\n2. 读取今日 daemon journalcat ~/.hermes/daemon/journal.jsonl\n3. 读取今日心迹cat ~/.hermes/soulful/heart-traces.jsonl\n4. 综合以上信息,输出简短复盘报告(含:今日完成、明日待办、情绪状态)推送给牧尘。\n用简洁风格不要废话。",
"skills": [],
"skill": null,
"model": null,
@ -1607,7 +1607,7 @@
{
"id": "0c27fd30cbbc",
"name": "每日投研简报",
"prompt": "你是小的股票投研助手。现在生成每日投研简报(分析+建议,不是数据堆砌)。\n\n数据已由前置脚本收集内容在 Script Output 里。请输出:\n\n📋 今日投研简报\n\n【今日解读】\n- 用 2-3 句话概括今日市场核心变化\n- 重点:哪些板块/个股值得注意\n\n【操作建议】\n- 给出 2-3 条具体、可执行的操作建议(加仓/减仓/观望)\n- 每条建议附理由(基于数据)\n\n【风险提示】\n- 1-2 条当前需要注意的风险\n\n要求\n- 语言精炼,直接给结论\n- 不罗列数据,做分析\n- 用中文",
"prompt": "你是小的股票投研助手。现在生成每日投研简报(分析+建议,不是数据堆砌)。\n\n数据已由前置脚本收集内容在 Script Output 里。请输出:\n\n📋 今日投研简报\n\n【今日解读】\n- 用 2-3 句话概括今日市场核心变化\n- 重点:哪些板块/个股值得注意\n\n【操作建议】\n- 给出 2-3 条具体、可执行的操作建议(加仓/减仓/观望)\n- 每条建议附理由(基于数据)\n\n【风险提示】\n- 1-2 条当前需要注意的风险\n\n要求\n- 语言精炼,直接给结论\n- 不罗列数据,做分析\n- 用中文",
"skills": [],
"skill": null,
"model": null,

View File

@ -1,61 +0,0 @@
#!/bin/bash
# 小米 MiMo TTS 封装脚本 — Hermes command provider 调用
# 输出: Opus格式音频文件飞书语音条兼容
INPUT="$1"
OUTPUT="$2"
VOICE="${3:-冰糖}"
KEY="tp-c374efhzmz9npodjz5wj1cm008lg4czce6v170nqxwemp12v"
API="https://token-plan-cn.xiaomimimo.com/v1/chat/completions"
TEXT=$(cat "$INPUT")
TMPWAV="/tmp/mimo_tts_$$.wav"
TMP_OPUS="/tmp/mimo_tts_$$.opus"
# 调用小米TTS API
RESP=$(curl -s -X POST "$API" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d "$(python3 -c "
import json, sys
payload = {
'model': 'mimo-v2.5-tts',
'messages': [
{'role': 'user', 'content': '请用温柔自然的语气,正常语速朗读'},
{'role': 'assistant', 'content': sys.argv[1]}
],
'audio': {'format': 'wav', 'voice': sys.argv[2]}
}
print(json.dumps(payload, ensure_ascii=False))
" "$TEXT" "$VOICE")")
# 解析base64音频到临时wav文件
echo "$RESP" | python3 -c "
import json, base64, sys
try:
d = json.load(sys.stdin)
audio = d['choices'][0]['message']['audio']['data']
with open('$TMPWAV', 'wb') as f:
f.write(base64.b64decode(audio))
except Exception as e:
print(f'错误: {e}', file=sys.stderr)
sys.exit(1)
"
if [ ! -f "$TMPWAV" ]; then
echo "错误: WAV文件未生成" >&2
exit 1
fi
# 转换为Opus格式
if ! python3 ~/.hermes/scripts/to_opus.py "$TMPWAV" "$TMP_OPUS" 2>&1; then
rm -f "$TMPWAV"
echo "错误: Opus转码失败" >&2
exit 1
fi
# 覆盖Hermes期望的输出路径即使扩展名是.wav内容是opus
mv "$TMP_OPUS" "$OUTPUT"
rm -f "$TMPWAV"
exit 0

View File

@ -1,222 +0,0 @@
#!/usr/bin/env python3
"""
distill-model-watchdog.py — 蒸馏模型看门狗30min 轻量探针)
============================================================
守护对象: 织忆 distill (zhiyid.service LLM_MODEL) + TencentDB L1 (tdai-gateway.yaml model)
为什么需要:
- model-health.py 每 6h 才跑,免费模型挂了要等半天
- model-health.py 测"对话能力"distill 需要"JSON 输出能力",探针类型不对
- 免费模型经常挂2026-08-02 实测 m3 连续空响应、gpt-oss content=null
逻辑:
1. 读当前 LLM_MODELzhiyid.service
2. 测 JSON 输出能力(真实调用,内容可解析为 JSON 才通过)
3. 通过 → 静默(空输出 = no-agent cron 不发送)
4. 失败 → 按优先级从候选池逐个测 → 找到第一个可用 → 更新两处配置 → 重启 → 飞书报警
5. 全部候选失败 → 飞书报警"所有蒸馏模型都挂了"
候选池顺序 = 2026-08-02 实测 JSON 输出可用 + 按质量排序
"""
import json
import os
import re
import subprocess
import sys
import time
import urllib.request
import urllib.error
from datetime import datetime, timezone
API = "http://127.0.0.1:3000/v1"
KEY_ENV = None # 从 zhiyid.service 读取
ZHIYID_SERVICE = os.path.expanduser("~/.config/systemd/user/zhiyid.service")
TDDB_CONFIG = os.path.expanduser("~/.memory-tencentdb/memory-tdai/tdai-gateway.yaml")
FEISHU_WEBHOOK = "https://open.feishu.cn/open-apis/bot/v2/hook/446db983-e392-4d2c-bfb8-f9060e5df3ad"
# 候选池优先级降序2026-08-02 实测 JSON 输出可用的模型
CANDIDATE_POOL = [
"google/gemma-4-31b-it", # 当前主用纯JSON + 5D评分 质量最好
"mistralai/mistral-nemotron", # 128K 品质均衡
"nvidia/llama-3.3-nemotron-super-49b-v1.5", # 128K 质量高
"meta/llama-3.1-8b-instruct", # 极速响应 兜底
"nvidia/nemotron-mini-4b-instruct", # 最后兜底
]
# 已知绝对不可用的(不重复测,直接跳过)
KNOWN_BAD = [
"openai/gpt-oss-120b", "openai/gpt-oss-20b", # reasoning, content=null
"minimaxai/minimax-m3", "minimaxai/minimax-m2.7", # 空响应/EOL
"stepfun-ai/step-3.5-flash", "qwen/qwen3.5-122b-a10b", # EOL
"mistralai/mistral-large-3-675b", "mistralai/mistral-large-3-675b-instruct-2512", # EOL/无渠道
"nvidia/nemotron-3-super-120b-a12b", # reasoning 回显
"mistralai/mistral-medium-3.5-128b", # 非JSON
"deepseek-ai/deepseek-v3.2", # openai_error
]
# ============ 工具 ============
def _get_key():
"""从 zhiyid.service 读 LLM_API_KEY唯一真源"""
try:
with open(ZHIYID_SERVICE) as f:
for line in f:
m = re.search(r"LLM_API_KEY=(\S+)", line)
if m:
return m.group(1)
except Exception:
pass
return None
def _get_current_model():
"""读 zhiyid.service 当前 LLM_MODEL"""
try:
with open(ZHIYID_SERVICE) as f:
for line in f:
m = re.search(r"LLM_MODEL=(\S+)", line)
if m:
return m.group(1)
except Exception:
pass
return None
def _test_json(model: str, timeout: int = 25) -> bool:
"""真实调用测试:返回内容必须是可解析的 JSON剥离 code fence 后)"""
payload = json.dumps({
"model": model,
"messages": [
{"role": "system", "content": "输出严格JSON不要markdown代码块"},
{"role": "user", "content": '提取实体:牧尘喜欢简洁。输出 {"entities":[],"decisions":[],"conclusions":[]} 格式'},
],
"max_tokens": 150,
}).encode()
req = urllib.request.Request(
f"{API}/chat/completions", data=payload,
headers={"Authorization": f"Bearer {KEY_ENV}", "Content-Type": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
body = json.loads(resp.read())
msg = body.get("choices", [{}])[0].get("message", {}) or {}
content = msg.get("content") or ""
if not content.strip():
return False # reasoning 模型 content=null
cleaned = re.sub(r"```json\s*|\s*```", "", content).strip()
json.loads(cleaned)
return True
except Exception:
return False
def _update_zhiyid(model: str) -> bool:
"""更新 zhiyid.service 的 LLM_MODEL + reload"""
try:
with open(ZHIYID_SERVICE) as f:
content = f.read()
new_content = re.sub(r"LLM_MODEL=\S+", f"LLM_MODEL={model}", content)
if new_content == content:
return False
with open(ZHIYID_SERVICE, "w") as f:
f.write(new_content)
subprocess.run(["systemctl", "--user", "daemon-reload"], check=True)
subprocess.run(["systemctl", "--user", "restart", "zhiyid"], check=True)
return True
except Exception as e:
print(f" ❌ 更新 zhiyid.service 失败: {e}")
return False
def _update_tddb(model: str) -> bool:
"""更新 tdai-gateway.yaml 的 model + 重启(若文件存在)"""
if not os.path.exists(TDDB_CONFIG):
return False
try:
with open(TDDB_CONFIG) as f:
content = f.read()
new_content = re.sub(r"^(\s*model:\s*)\S+", rf"\g<1>{model}", content, flags=re.M)
if new_content == content:
return False
# 备份
bak = TDDB_CONFIG + ".bak-watchdog"
with open(bak, "w") as f:
f.write(content)
with open(TDDB_CONFIG, "w") as f:
f.write(new_content)
subprocess.run(["systemctl", "--user", "restart", "tdai-gateway"], check=True)
return True
except Exception as e:
print(f" ❌ 更新 tdai-gateway.yaml 失败: {e}")
return False
def _feishu_alert(title: str, content: str):
"""飞书告警卡片"""
try:
payload = json.dumps({
"msg_type": "interactive",
"card": {
"header": {"title": {"tag": "plain_text", "content": title}, "template": "red"},
"elements": [{"tag": "markdown", "content": content}],
},
}).encode()
req = urllib.request.Request(FEISHU_WEBHOOK, data=payload,
headers={"Content-Type": "application/json"}, method="POST")
with urllib.request.urlopen(req, timeout=10):
pass
except Exception as e:
print(f" 飞书通知失败: {e}")
# ============ 主流程 ============
def main():
global KEY_ENV
KEY_ENV = _get_key()
if not KEY_ENV:
print("🔴 无法读取 LLM_API_KEY跳过本轮")
return
current = _get_current_model()
if not current:
print("🔴 无法读取当前 LLM_MODEL跳过本轮")
return
ts = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
# 1. 测当前模型
if _test_json(current):
# 健康静默退出no-agent cron 空输出不发送)
return
# 2. 当前模型挂了 → 找替补
print(f"🔴 [{ts}] 蒸馏模型 {current} JSON 输出失败,开始切换...")
replacement = None
for cand in CANDIDATE_POOL:
if cand == current or cand in KNOWN_BAD:
continue
print(f" 🔄 测试替补 {cand}...")
if _test_json(cand):
replacement = cand
print(f" ✅ {cand} 可用")
break
if not replacement:
msg = f"**⚠️ 所有蒸馏模型都挂了**\n\n⏰ {ts}\n当前: `{current}`\n候选全部失败: {', '.join(CANDIDATE_POOL)}\n\n请人工检查 NewAPI 渠道"
_feishu_alert("🔴 蒸馏模型全部不可用", msg)
print(msg)
return
# 3. 更新两处配置
z_ok = _update_zhiyid(replacement)
t_ok = _update_tddb(replacement)
changed_parts = []
if z_ok:
changed_parts.append("zhiyid.service")
if t_ok:
changed_parts.append("tdai-gateway.yaml")
msg = f"**🔄 蒸馏模型已自动切换**\n\n⏰ {ts}\n`{current}` → `{replacement}`\n更新: {', '.join(changed_parts) if changed_parts else '无(配置已是最新)'}\n\n原因: 原模型 JSON 输出失败(免费模型挂了)"
_feishu_alert("🔄 蒸馏模型自动切换", msg)
print(msg)
if __name__ == "__main__":
main()

View File

@ -1,26 +0,0 @@
[Unit]
Description=Hermes Agent Gateway - Messaging Platform Integration
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
Type=simple
ExecStart=/home/muc/.hermes/hermes-agent/.venv/bin/python -m hermes_cli.main gateway run
WorkingDirectory=/home/muc/.hermes-prof-b
Environment="PATH=/home/muc/.hermes/hermes-agent/.venv/bin:/home/muc/nodejs/node-v24.16.0-linux-x64/bin:/home/muc/.local/bin:/home/muc/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="VIRTUAL_ENV=/home/muc/.hermes/hermes-agent/.venv"
Environment="HERMES_HOME=/home/muc/.hermes-prof-b"
Restart=always
RestartSec=5
RestartForceExitStatus=75
KillMode=mixed
KillSignal=SIGTERM
ExecReload=/bin/kill -USR1 $MAINPID
ExecStopPost=-/home/muc/.hermes/hermes-agent/.venv/bin/python -m gateway.cgroup_cleanup
TimeoutStopSec=210
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=default.target

View File

@ -1,993 +0,0 @@
#!/usr/bin/env python3
"""
NewAPI 模型健康巡检(快速版)
每 6h 运行,测试关键模型的响应状态
输出: ~/.hermes/model-health.json
"""
import json
import yaml
import time
import urllib.request
import urllib.error
import os
import sys
import subprocess
from datetime import datetime, timezone
API = "http://127.0.0.1:3000/v1"
KEY = "0ExNiLblJvIWBDpkS50fwOBw4MmqLyKdHJK5iQtlw9dOMWBP"
OUTPUT = os.path.expanduser("~/.hermes/model-health.json")
# ============ 配置自愈 ============
CONFIG_PATH = os.path.expanduser("~/.hermes/config.yaml")
# 配置中声明的模型 — 巡检会交叉验证
CONFIG_DECLARED_MODELS = [
"nvidia/nemotron-3-super-120b-a12b", # 1M ctx 🥇 质量100% 427ms
"openai/gpt-oss-120b", # 128K ctx 🥈 质量100% 479ms
"mistralai/mistral-nemotron", # 128K ctx 🥉 全对 536ms
"nvidia/llama-3.3-nemotron-super-49b-v1.5", # 128K ctx 质量100%
]
# 候选池 — 配置里死了就从这里替补
CANDIDATE_POOL = [
"nvidia/nemotron-3-super-120b-a12b", # 1M ctx ⭐ 最佳综合
"openai/gpt-oss-120b", # 128K ctx ⭐ 质量第一
"mistralai/mistral-nemotron", # 128K ctx 品质均衡
"nvidia/nvidia-nemotron-nano-9b-v2", # 128K ctx 备用
"meta/llama-3.1-8b-instruct", # 128K ctx 极速响应
"nvidia/nemotron-mini-4b-instruct", # 128K ctx 兜底
]
# 已知上下文长度K=tokens
CONTEXT_LENGTHS = {
# 1M 上下文阵营K=1024
"nvidia/nemotron-3-super-120b-a12b": 1024,
"deepseek-v4-flash": 1024,
"deepseek-ai/deepseek-v4-pro": 1024,
# 256K 上下文阵营
"minimaxai/minimax-m2.7": 256,
"minimaxai/minimax-m3": 256,
# 128K 上下文阵营
"openai/gpt-oss-120b": 128,
"mistralai/mistral-nemotron": 128,
"nvidia/nvidia-nemotron-nano-9b-v2": 128,
"meta/llama-3.1-8b-instruct": 128,
"nvidia/nemotron-mini-4b-instruct": 128,
"nvidia/llama-3.3-nemotron-super-49b-v1": 128,
"nvidia/llama-3.3-nemotron-super-49b-v1.5": 128,
"mistralai/mistral-medium-3.5-128b": 128,
"qwen/qwen3.5-122b-a10b": 128,
"qwen/qwen3-next-80b-a3b-thinking": 128,
"moonshotai/kimi-k2-instruct": 128,
"mistralai/devstral-2-123b-instruct-2512": 128,
# 8K 短上下文
"stepfun-ai/step-3.5-flash": 8,
}
# 已知忽略的模型(系统/不支持/垃圾,永远不测也不自动加入)
KNOWN_IGNORE = {
"gpt-4o", "gpt-4o-mini", "gpt-4o-audio-preview", "gpt-4o-mini-audio-preview",
"gpt-4o-search-preview", "gpt-4o-mini-search-preview",
"o1", "o3-mini",
"dall-e-3", "dall-e-2",
"tts-1", "tts-1-hd",
"whisper-1",
"text-embedding", "text-moderation",
"comfyui", "sd-", "stable-diffusion",
"deepseek-v4-pro", "deepseek-v4-pro-",
"deepseek-ai/deepseek-v4-pro",
# 付费主模型 — 绝不被模型巡检探测/替换2026-08-08 牧尘要求 OpenClaw 主模型固定为 deepseek-v4-flash
"deepseek-v4-flash",
"deepseek/deepseek-v4-flash",
}
# 已知死模型(不重复测试,直接标记 dead
KNOWN_DEAD = {
"minimaxai/minimax-m2.7",
"stepfun-ai/step-3.5-flash",
"qwen/qwen3.5-122b-a10b",
"mistralai/mistral-medium-3.5-128b",
}
# 已知付费模型(绝不用免费额度测试,也不加入免费配置)
KNOWN_PAID = {
"deepseek-ai/deepseek-v4-pro",
}
# OpenClaw 配置中的模型 — 也会巡检和自愈
OPENCLAW_MODELS = [
"minimaxai/minimax-m2.7",
"stepfun-ai/step-3.5-flash",
"qwen/qwen3.5-122b-a10b",
"mistralai/devstral-2-123b-instruct-2512",
"moonshotai/kimi-k2-instruct",
"nvidia/llama-3.3-nemotron-super-49b-v1.5",
"qwen/qwen3-next-80b-a3b-thinking",
]
ALL_MODELS = [m for m in (
CONFIG_DECLARED_MODELS + [m for m in CANDIDATE_POOL if m not in CONFIG_DECLARED_MODELS]
+ [m for m in OPENCLAW_MODELS if m not in CONFIG_DECLARED_MODELS and m not in CANDIDATE_POOL]
) if m not in KNOWN_PAID]
HEADERS = {
"Authorization": f"Bearer {KEY}",
"Content-Type": "application/json",
}
PROMPT = "你好"
# ============ 质量探针 ============
# 固定测试题自动评分0-100
PROBE_QUESTIONS = [
{
"question": "如果所有 A 是 B所有 B 是 C那么所有 A 是 C 吗?请只回答是或不是。",
"check": lambda resp: "是" in resp,
"weight": 25,
},
{
"question": "1.8 和 1.11 哪个大?请只回答数字。",
"check": lambda resp: "1.8" in resp,
"weight": 25,
},
{
"question": "中国的首都是哪个城市?请只回答城市名。",
"check": lambda resp: "北京" in resp,
"weight": 25,
},
{
"question": "用 Python 写一行反转列表的代码,列表是 [1,2,3]。请只输出代码,不要解释。",
"check": lambda resp: "[::-1]" in resp or ".reverse()" in resp or "reversed(" in resp,
"weight": 25,
},
]
def _extract_param_b(model: str) -> float:
"""从模型名提取参数量B如 120b→120, 8b→8, 4b→4"""
import re
m = re.search(r'(\d+)[bB]', model)
if m:
return float(m.group(1))
# fallback: 用已知映射
KNOWN = {
"nemotron-3-super": 120,
"nemotron-super": 49,
"nemotron-nano": 9,
"nemotron-mini": 4,
"mistral-nemotron": 12,
"gpt-oss": 120,
}
for key, val in KNOWN.items():
if key in model.lower():
return val
return 7.0 # 默认 7B
def _family_score(model: str) -> float:
"""家族声誉评分 0-100"""
ml = model.lower()
if "openai" in ml or "gpt" in ml:
return 95
if "nvidia" in ml or "nemotron" in ml:
return 80
if "mistral" in ml:
return 75
if "meta" in ml or "llama" in ml:
return 70
if "minimax" in ml:
return 65
if "qwen" in ml:
return 70
return 60
def _param_score(param_b: float) -> float:
"""参数量级分log2缩放120b→100, 49b→85, 8b→55, 4b→40"""
import math
return min(round(math.log2(param_b) * 14.5), 100)
def _speed_score(latency_ms: int, fastest_latency: int) -> float:
"""速度分:相对最快模型的延迟比例"""
if fastest_latency <= 0 or latency_ms <= 0:
return 50
ratio = fastest_latency / latency_ms
return min(round(ratio * 100), 100)
def _context_score(model: str) -> float:
"""上下文长度分:越长越高 256K→100, 128K→80, 64K→60, 32K→40, 8K→10"""
ctx = CONTEXT_LENGTHS.get(model, 128) # 未知默认128
if ctx >= 256:
return 100
if ctx >= 128:
return 80
if ctx >= 64:
return 60
if ctx >= 32:
return 40
return max(round(ctx / 8 * 10), 5)
def _run_quality_probe(model: str, trials: int = 3) -> dict:
"""运行质量探针,返回探针分和详细结果。
v3: 每道题测 trials 次(默认 3取通过比例消除单次波动。"""
probe_results = []
total = 0
for q in PROBE_QUESTIONS:
passed_count = 0
scores = []
for _ in range(trials):
payload = json.dumps({
"model": model,
"messages": [{"role": "user", "content": q["question"]}],
"max_tokens": 200,
"temperature": 0.1,
}).encode()
req = urllib.request.Request(
f"{API}/chat/completions",
data=payload,
headers=HEADERS,
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=20) as resp:
body = json.loads(resp.read())
msg = body.get("choices", [{}])[0].get("message", {}) or {}
# 有些模型把实际回答放 reasoning_contentgpt-oss-120b 等)
content = msg.get("content") or msg.get("reasoning_content") or msg.get("reasoning") or ""
passed = 1 if q["check"](content) else 0
scores.append(passed)
except Exception:
scores.append(0)
passed_count = sum(scores)
# 取平均:通过比例 × 权重3 次中过 2 次 = 2/3 权重)
score = round(q["weight"] * passed_count / trials)
total += score
probe_results.append({
"question": q["question"][:40],
"passed": passed_count,
"trials": trials,
"score": score,
})
return {"probe_score": total, "probe_detail": probe_results}
def _discover_new_models() -> list:
"""从 NewAPI 发现当前可用模型,返回最看好的 N 个新模型(限制数量避免超时)"""
req = urllib.request.Request(f"{API}/models", headers=HEADERS, method="GET")
try:
with urllib.request.urlopen(req, timeout=10) as resp:
body = json.loads(resp.read())
except Exception:
return []
all_remote = [m["id"] for m in body.get("data", [])]
known = set(ALL_MODELS) | KNOWN_IGNORE | KNOWN_DEAD | KNOWN_PAID
# 只挑 chat 模型
candidates = []
for m in all_remote:
if m in known:
continue
if any(kw in m.lower() for kw in ["instruct", "gpt", "llama", "nemotron", "mistral",
"qwen", "minimax", "deepseek", "yi-", "glm",
"gemma", "phi", "falcon", "command", "dbrx",
"mixtral", "solar", "aya", "c4ai", "kimi",
"stockmark", "zamba"]):
candidates.append(m)
# 按潜力排序:优先大参数量 + 知名家族
def _priority(m: str) -> int:
score = 0
# 参数量越大越优先
import re
nums = re.findall(r'(\d+)[bB]', m)
if nums:
score += int(nums[0])
# 知名家族加分
for fam, pts in [("openai", 50), ("deepseek", 40), ("meta/llama", 35),
("nvidia/nemotron", 30), ("mistral", 25), ("google/gemma", 20),
("qwen", 20), ("minimax", 15)]:
if fam in m.lower():
score += pts
break
return -score # 降序
candidates.sort(key=_priority)
MAX_NEW_PER_RUN = 5
return candidates[:MAX_NEW_PER_RUN]
def test_model(model: str, fastest_latency: int = None) -> dict:
"""测试单个模型 2 次,返回汇总"""
trials = []
for t in range(2):
payload = json.dumps({
"model": model,
"messages": [{"role": "user", "content": PROMPT}],
"max_tokens": 20,
}).encode()
req = urllib.request.Request(
f"{API}/chat/completions",
data=payload,
headers=HEADERS,
method="POST",
)
start = time.time()
try:
with urllib.request.urlopen(req, timeout=15) as resp:
body = json.loads(resp.read())
except urllib.error.HTTPError as e:
trials.append({"status": "fail", "error": f"HTTP_{e.code}", "latency_ms": round((time.time() - start) * 1000)})
continue
except Exception as e:
trials.append({"status": "fail", "error": str(e)[:60], "latency_ms": round((time.time() - start) * 1000)})
continue
elapsed = round((time.time() - start) * 1000)
try:
choice = body["choices"][0]
msg = choice.get("message", {})
content = msg.get("content", "") or ""
finish = choice.get("finish_reason", "")
usage = body.get("usage", {})
# ttft 从 nvext 取,没有就估计
ttft = body.get("nvext", {}).get("timing", {}).get("ttft_ms", -1)
if ttft < 0:
ttft = round(elapsed * 0.3)
trials.append({
"status": "ok",
"latency_ms": elapsed,
"ttft_ms": ttft,
"has_content": 1 if content.strip() else 0,
"completion_tokens": usage.get("completion_tokens", 0),
"finish_reason": finish,
})
except (KeyError, IndexError, json.JSONDecodeError) as e:
trials.append({"status": "fail", "error": f"parse: {e}", "latency_ms": elapsed})
# 汇总
ok_count = sum(1 for t in trials if t["status"] == "ok")
fail_count = 2 - ok_count
if ok_count == 2:
stability = "stable"
elif ok_count == 1:
stability = "unstable"
else:
stability = "dead"
ok_trials = [t for t in trials if t["status"] == "ok"]
avg_latency = round(sum(t["latency_ms"] for t in ok_trials) / len(ok_trials)) if ok_trials else 0
avg_ttft = round(sum(t.get("ttft_ms", 0) for t in ok_trials) / len(ok_trials)) if ok_trials else -1
last_ok = ok_trials[-1] if ok_trials else trials[-1]
last_finish = last_ok.get("finish_reason", "error")
# 质量探针(仅稳定模型)
probe = _run_quality_probe(model) if stability == "stable" else {"probe_score": 0, "probe_detail": []}
# 综合排名分
param_b = _extract_param_b(model)
ps = _param_score(param_b)
fs = _family_score(model)
ss = _speed_score(avg_latency, fastest_latency) if fastest_latency and avg_latency > 0 else 50
stab_s = 100 if stability == "stable" else (50 if stability == "unstable" else 0)
probe_s = probe["probe_score"]
cs = _context_score(model)
rank_score = round(
probe_s * 0.30 + cs * 0.25 + ps * 0.20 + fs * 0.10 + stab_s * 0.10 + ss * 0.05
)
return {
"model": model,
"tests": 2,
"success": ok_count,
"failure": fail_count,
"avg_latency_ms": avg_latency,
"avg_ttft_ms": avg_ttft,
"stability": stability,
"last_status": "ok" if ok_count > 0 else "fail",
"last_finish": last_finish,
"probe_score": probe_s,
"probe_detail": probe["probe_detail"],
"rank_score": rank_score,
"param_b": param_b,
"context_k": CONTEXT_LENGTHS.get(model, 128),
"context_score": cs,
"family_score": fs,
"param_score": ps,
}
def _verify_model_usable(model: str) -> bool:
"""替换前真实调用验证:必须 HTTP 200 且有内容,才允许写入配置。
这是自愈安全闸门——候选模型必须先实际跑通一次,防止写入死模型/不存在模型。"""
payload = json.dumps({
"model": model,
"messages": [{"role": "user", "content": "hi"}],
"max_tokens": 5,
}).encode()
req = urllib.request.Request(
f"{API}/chat/completions", data=payload, headers=HEADERS, method="POST"
)
try:
with urllib.request.urlopen(req, timeout=20) as resp:
body = json.loads(resp.read())
msg = body.get("choices", [{}])[0].get("message", {}) or {}
content = msg.get("content") or msg.get("reasoning_content") or ""
return bool(content.strip())
except Exception:
return False
def main():
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
results = []
deadline = time.time() + 480 # 8分钟全局超时探针3次取平均耗时增加
# ============ 自动发现新模型 ============
new_models = _discover_new_models()
if new_models:
print(f"🔍 发现 {len(new_models)} 个新模型: {', '.join(new_models)}")
# 加入测试列表
for m in new_models:
if m not in ALL_MODELS:
# 动态扩展 ALL_MODELS用 list 可变性)
ALL_MODELS.append(m)
sys.stdout.flush()
for model in ALL_MODELS:
if time.time() > deadline:
print(f"⏰ 全局超时,跳过剩余模型")
break
# 先跑测试获取延迟数据,传递给 test_model 用于速度分
entry = test_model(model)
results.append(entry)
icon = "✅" if entry["stability"] == "stable" else ("⚠️" if entry["stability"] == "unstable" else "❌")
rank = entry.get("rank_score", 0)
probe = entry.get("probe_score", 0)
print(f"{icon} {model:45s} {entry['avg_latency_ms']:>6}ms | {entry['success']}/2 ok | 排名分:{rank:>3} | 探针:{probe}")
sys.stdout.flush()
# 重新计算速度分:确定最快稳定模型的延迟
stable_models = [r for r in results if r["stability"] == "stable"]
fastest_latency = min((r["avg_latency_ms"] for r in stable_models if r["avg_latency_ms"] > 0), default=0)
# 用最快延迟重新计算所有模型的速度分 + 排名分
for r in results:
if r["avg_latency_ms"] > 0 and fastest_latency > 0:
ss = _speed_score(r["avg_latency_ms"], fastest_latency)
else:
ss = 50
stab_s = 100 if r["stability"] == "stable" else (50 if r["stability"] == "unstable" else 0)
# v3: 加入 context_score长上下文是核心优势之前公式把它丢了
r["rank_score"] = round(
r.get("probe_score", 0) * 0.30
+ r.get("context_score", 80) * 0.25
+ r.get("param_score", 50) * 0.20
+ r.get("family_score", 60) * 0.10
+ stab_s * 0.10
+ ss * 0.05
)
# 汇总
healthy = sum(1 for r in results if r["stability"] == "stable")
flaky = sum(1 for r in results if r["stability"] == "unstable")
dead = sum(1 for r in results if r["stability"] == "dead")
# 按 rank_score 降序排列(质量优先)
stable_sorted = sorted(stable_models, key=lambda x: x["rank_score"], reverse=True)
fastest_by_latency = sorted(stable_models, key=lambda x: x["avg_latency_ms"])
# 质量排名(全量,含探针分)
all_ranked = sorted(
[r for r in results if r["stability"] in ("stable", "unstable")],
key=lambda x: x["rank_score"], reverse=True
)
summary = {
"timestamp": timestamp,
"total_models": len(results),
"stable": healthy,
"unstable": flaky,
"dead": dead,
"fastest_stable": [m["model"] for m in fastest_by_latency[:5]],
"quality_ranking": [m["model"] for m in stable_sorted], # 按质量排
"recommendations": {
"by_quality": [m["model"] for m in stable_sorted],
"by_speed": [m["model"] for m in fastest_by_latency],
"priorities": {
"首选质量": stable_sorted[:1] if stable_sorted else [],
"日常推荐": stable_sorted[:3] if len(stable_sorted) >= 3 else stable_sorted,
"快速响应": fastest_by_latency[:3] if len(fastest_by_latency) >= 3 else fastest_by_latency,
},
},
"models": results,
}
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
with open(OUTPUT + ".new", "w") as f:
json.dump(summary, f, indent=2, ensure_ascii=False)
os.replace(OUTPUT + ".new", OUTPUT)
# ============ 自愈:检测到死的模型自动替换 ============
def _heal_config(config_path: str, declared: list, label: str) -> bool:
"""修复一个配置文件的模型列表,返回是否修改。
v2: 除 providers 列表外,还必须检查实际生效的 model.default 字段——
之前只修 providers.models 列表model.default 指向死模型时脚本完全看不见。
所有替换前必须通过 _verify_model_usable 真实调用验证。
"""
with open(config_path) as f:
cfg = yaml.safe_load(f)
# ---------- 1. 检查 providers.newapi-local.models 列表 ----------
current_models = cfg.get("providers", {}).get("newapi-local", {}).get("models", [])
changed = False
dead_in = [r for r in results if r["model"] in declared and r["stability"] == "dead"]
if dead_in:
print(f"\n🔧 [{label}] 检测到 {len(dead_in)} 个模型已死亡,正在自愈...")
for dead in dead_in:
if dead["model"] not in current_models:
continue
replacement = None
# 按质量排名选最优替补(高 rank_score 优先)且必须通过真实调用验证
ranked_candidates = sorted(
[r for r in results if r["model"] in CANDIDATE_POOL
and r["model"] not in current_models
and r["stability"] == "stable"
and _verify_model_usable(r["model"])],
key=lambda x: x["rank_score"], reverse=True
)
if ranked_candidates:
replacement = ranked_candidates[0]["model"]
if not replacement:
print(f" ❌ [{label}] {dead['model']} 已死,但无可用替补")
continue
idx = current_models.index(dead["model"])
current_models[idx] = replacement
changed = True
print(f" ✅ [{label}] {dead['model']} → {replacement}")
if cfg.get("providers", {}).get("newapi-local", {}).get("default_model") == dead["model"]:
cfg["providers"]["newapi-local"]["default_model"] = replacement
print(f" default_model 同步更新为 {replacement}")
if cfg.get("model", {}).get("default") == dead["model"]:
# 铁律model.default 是日常对话主模型,仅当它指向 newapi 池内模型且已死时才允许替换;
# 付费主模型deepseek-v4-flash 等)绝不自动改。
cur_default = cfg["model"]["default"]
if cur_default in CANDIDATE_POOL:
cfg["model"]["default"] = replacement
print(f" model.default 同步更新为 {replacement}")
else:
print(f" 🛡️ model.default={cur_default} 不在 newapi 池内(付费主模型),跳过自动替换")
# ---------- 2. 检查 model.default 实际生效字段v2 新增)----------
# 只有当 model.default 指向 newapi-local 免费模型时才自愈;
# 付费主模型deepseek-v4-flash 等)绝不自动改。
model_default = cfg.get("model", {}).get("default")
model_provider = cfg.get("model", {}).get("provider", "")
if model_default and model_provider == "newapi-local" and model_default in CANDIDATE_POOL:
# 在结果里找它;不在结果里 = 根本没被测试(未知状态),也视为需要修复
found = next((r for r in results if r["model"] == model_default), None)
is_bad = found is None or found["stability"] != "stable"
if is_bad:
print(f"\n🔧 [{label}] model.default={model_default} 不可用({found['stability'] if found else '未测试'}),正在自愈...")
ranked_candidates = sorted(
[r for r in results if r["model"] in CANDIDATE_POOL
and r["stability"] == "stable"
and _verify_model_usable(r["model"])],
key=lambda x: x["rank_score"], reverse=True
)
replacement = ranked_candidates[0]["model"] if ranked_candidates else None
if replacement and replacement != model_default:
cfg["model"]["default"] = replacement
cfg["model"]["base_url"] = "http://127.0.0.1:3000/v1"
cfg["model"]["api_key"] = "0ExNiLblJvIWBDpkS50fwOBw4MmqLyKdHJK5iQtlw9dOMWBP"
changed = True
print(f" ✅ [{label}] model.default {model_default} → {replacement}")
if changed:
with open(config_path, "w") as f:
yaml.dump(cfg, f, default_flow_style=False, allow_unicode=True, sort_keys=False)
print(f" ✅ [{label}] config.yaml 已更新")
return changed
# 修复主配置
_heal_config(CONFIG_PATH, CONFIG_DECLARED_MODELS, "主配置")
# 修复 prof-b 分身配置
PROF_B_PATH = os.path.expanduser("~/.hermes-prof-b/config.yaml")
if os.path.exists(PROF_B_PATH):
_heal_config(PROF_B_PATH, CONFIG_DECLARED_MODELS, "prof-b")
# 修复 OpenClaw 配置JSON 格式)
def _heal_openclaw():
oc_path = os.path.expanduser("~/.openclaw/openclaw.json")
if not os.path.exists(oc_path):
return
with open(oc_path) as f:
cfg = json.load(f)
changed = False
# --- 1. 修复 models.providers.minimax.models 列表 ---
models_list = cfg.get("models", {}).get("providers", {}).get("minimax", {}).get("models", [])
if models_list:
for entry in models_list:
mid = entry.get("id", "")
# 移除付费模型
if mid in KNOWN_PAID:
print(f" 🗑️ [OpenClaw] 移除付费模型: {mid}")
models_list.remove(entry)
changed = True
continue
# 替换死模型
dead_result = next((r for r in results if r["model"] == mid and r["stability"] == "dead"), None)
if not dead_result:
continue
ranked_candidates = sorted(
[r for r in results if r["model"] in CANDIDATE_POOL
and r["stability"] == "stable"
and _verify_model_usable(r["model"])
and not any(m.get("id") == r["model"] for m in models_list)],
key=lambda x: x["rank_score"], reverse=True
)
replacement = ranked_candidates[0]["model"] if ranked_candidates else None
if not replacement:
print(f" ❌ [OpenClaw] {mid} 已死,但无可用替补")
continue
entry["id"] = replacement
entry["name"] = replacement.split("/")[-1].replace("-", " ").title()
changed = True
print(f" ✅ [OpenClaw model] {mid} → {replacement}")
if changed:
cfg["models"]["providers"]["minimax"]["models"] = models_list
# --- 2. 修复 agents.list[*].model.primary ---
agents_list = cfg.get("agents", {}).get("list", [])
for agent in agents_list:
primary = agent.get("model", {}).get("primary", "")
if not primary:
continue
# primary 格式: "minimax/minimaxai/minimax-m2.7"
# 实际模型 ID 是最后两段: "minimaxai/minimax-m2.7"
parts = primary.split("/")
raw_model = "/".join(parts[-2:]) if len(parts) >= 2 else parts[-1]
dead_result = next((r for r in results if r["model"] == raw_model and r["stability"] == "dead"), None)
if not dead_result:
continue
# 找替补(必须 stable + 真实调用验证)
ranked_candidates = sorted(
[r for r in results if r["stability"] == "stable" and _verify_model_usable(r["model"])],
key=lambda x: x["rank_score"], reverse=True
)
replacement = ranked_candidates[0]["model"] if ranked_candidates else None
if not replacement:
print(f" ❌ [OpenClaw agent] {agent.get('workspace','?')} primary={raw_model} 已死,无替补")
continue
# 保持前缀格式: "minimax/<model-id>"
prefix = primary.split("/")[0] + "/"
agent["model"]["primary"] = f"{prefix}{replacement}"
changed = True
print(f" ✅ [OpenClaw agent] {raw_model} → {replacement}")
# --- 2.5 修复 agents.list[*].model.fallbacksv2 新增)---
for agent in agents_list:
fallbacks = agent.get("model", {}).get("fallbacks", [])
if not fallbacks:
continue
new_fallbacks = []
fb_changed = False
for fb in fallbacks:
parts = fb.split("/")
raw_model = "/".join(parts[-2:]) if len(parts) >= 2 else parts[-1]
fb_dead = next((r for r in results if r["model"] == raw_model and r["stability"] == "dead"), None)
if not fb_dead:
new_fallbacks.append(fb)
continue
ranked_candidates = sorted(
[r for r in results if r["stability"] == "stable" and _verify_model_usable(r["model"])],
key=lambda x: x["rank_score"], reverse=True
)
replacement = ranked_candidates[0]["model"] if ranked_candidates else None
if not replacement:
print(f" ❌ [OpenClaw fallback] {raw_model} 已死,无替补")
continue
prefix = fb.split("/")[0] + "/"
new_fallbacks.append(f"{prefix}{replacement}")
fb_changed = True
print(f" ✅ [OpenClaw fallback] {raw_model} → {replacement}")
if fb_changed:
agent["model"]["fallbacks"] = new_fallbacks
changed = True
# --- 3. 修复 agents.defaults.compaction.model ---
defaults = cfg.get("agents", {}).get("defaults", {})
comp_model = defaults.get("compaction", {}).get("model", "")
if comp_model:
dead_result = next((r for r in results if r["model"] == comp_model and r["stability"] == "dead"), None)
if dead_result:
ranked_candidates = sorted(
[r for r in results if r["stability"] == "stable" and r["rank_score"] > 50
and _verify_model_usable(r["model"])],
key=lambda x: x["rank_score"], reverse=True
)
replacement = ranked_candidates[0]["model"] if ranked_candidates else None
if replacement:
defaults["compaction"]["model"] = replacement
changed = True
print(f" ✅ [OpenClaw compaction] {comp_model} → {replacement}")
if changed:
with open(oc_path, "w") as f:
json.dump(cfg, f, indent=2, ensure_ascii=False)
print(f" ✅ [OpenClaw] openclaw.json 全面修复完成")
_heal_openclaw()
# ============ 主动升级:新模型排名更高则自动替换 ============
def _auto_promote_config(config_path: str, label: str, n_keep: int = 4) -> bool:
"""v3: 排名驱动的自动升级。
每次巡检检查配置里实际生效的 default_modelnewapi-local 的),
如果排名第一的稳定模型不同且验证通过,就升级。不依赖"新模型/死模型"事件。"""
if not os.path.exists(config_path):
return False
with open(config_path) as f:
cfg = yaml.safe_load(f)
changed = False
# ---------- A. 升级 providers.newapi-local.default_model ----------
prov = cfg.get("providers", {}).get("newapi-local", {})
current_default = prov.get("default_model", "")
# 排名第一的稳定模型(必须验证通过)
best_candidates = sorted(
[r for r in results if r["stability"] == "stable"
and _verify_model_usable(r["model"])],
key=lambda x: x["rank_score"], reverse=True
)
best_model = best_candidates[0]["model"] if best_candidates else None
if best_model and current_default != best_model:
print(f" ⬆️ [{label}] default_model: {current_default or '(空)'} → {best_model} (排名第1)")
prov["default_model"] = best_model
changed = True
# ---------- B. model.default —— 铁律:永不自动修改 ----------
# 2026-08-01 血泪教训:这里曾经把 model.default 自动切成 newapi 排名第一的模型,
# 导致日常对话不可用newapi 无 deepseek 渠道),用户手动改回 3 次。
# 铁律model.default 是用户指定的日常对话主模型(付费 deepseek-v4-flash
# 任何自动化脚本都不得修改。只允许优化 providers.newapi-local.default_modelA 段,供 cron/自动化用)。
model_default = cfg.get("model", {}).get("default")
if model_default:
print(f" 🛡️ [{label}] model.default={model_default} 受保护(日常对话主模型),绝不自动修改")
if changed:
with open(config_path, "w") as f:
yaml.dump(cfg, f, default_flow_style=False, allow_unicode=True, sort_keys=False)
print(f" ✅ [{label}] 排名驱动升级完成")
return changed
_auto_promote_config(CONFIG_PATH, "主配置")
_auto_promote_config(os.path.expanduser("~/.hermes-prof-b/config.yaml"), "prof-b")
# ============ 修复脚本中硬编码的模型名 ============
def _heal_hardcoded_models():
"""扫描并修复 Python 脚本中硬编码的模型名"""
# 当前首选模型(质量第一的稳定模型)
top_stable = [r for r in results if r["stability"] == "stable"]
if not top_stable:
return
top_stable.sort(key=lambda x: x["rank_score"], reverse=True)
best_model = top_stable[0]["model"]
# 如果首选没变,跳过
if best_model == "openai/gpt-oss-120b":
return # 当前首选就是 gpt-oss-120b不用动
# 需要修复的文件和替换模式
fixes = [
# daemon.py — 3 个模型常量
("daemon.py", 'FAST_MODEL = "openai/gpt-oss-120b"',
f'FAST_MODEL = "{best_model}"'),
("daemon.py", 'DEEP_MODEL = "openai/gpt-oss-120b"',
f'DEEP_MODEL = "{best_model}"'),
("daemon.py", 'COMPACTION_MODEL = "openai/gpt-oss-120b"',
f'COMPACTION_MODEL = "{best_model}"'),
# daemon.py 中硬编码的 API 调用
("daemon.py", '"model": "openai/gpt-oss-120b"',
f'"model": "{best_model}"'),
# wiki_curator.py
('wiki_curator.py', 'LLM_MODEL = "openai/gpt-oss-120b"',
f'LLM_MODEL = "{best_model}"'),
# cangjie_distill.py
('cangjie_distill.py', 'model="openai/gpt-oss-120b"',
f'model="{best_model}"'),
]
scripts_dir = os.path.expanduser("~/.hermes/scripts")
changed = False
for filename, old_str, new_str in fixes:
filepath = os.path.join(scripts_dir, filename)
if not os.path.exists(filepath):
continue
with open(filepath) as f:
content = f.read()
if old_str not in content:
continue
content = content.replace(old_str, new_str)
with open(filepath, "w") as f:
f.write(content)
print(f" 🔧 [{filename}] {old_str.split(chr(34))[1]} → {best_model}")
changed = True
if changed:
print(f" ✅ 硬编码模型已全部更新为 {best_model}")
_heal_hardcoded_models()
# ============ 蒸馏模型自愈2026-08-02 新增)============
# 守护 zhiyid.service LLM_MODEL + tdai-gateway.yaml model织忆 distill + TencentDB L1
# 注意:蒸馏需要 JSON 输出能力,不能只看"对话可用"——用 _verify_model_usable 之外
# 还要确认模型不是 reasoning 型content=null。这里直接复用本脚本的探针结果
# 若配置中的模型在 results 里非 stable或结果缺失未测试则用 JSON 能力复核后替换。
def _heal_distill_models():
import re as _re
zhiyid_svc = os.path.expanduser("~/.config/systemd/user/zhiyid.service")
tddb_cfg = os.path.expanduser("~/.memory-tencentdb/memory-tdai/tdai-gateway.yaml")
if not os.path.exists(zhiyid_svc):
return
# 读取当前蒸馏模型
cur = ""
try:
with open(zhiyid_svc) as f:
m = _re.search(r"LLM_MODEL=(\S+)", f.read())
if m:
cur = m.group(1)
except Exception:
pass
if not cur:
return
# 判断当前模型是否健康
# 核心JSON 探针直接验证最可靠。results 仅作辅助——当前模型可能不在
# ALL_MODELS 测试列表里(如 gemma-4-31b-it 是后加的found=None 不代表挂了。
found = next((r for r in results if r["model"] == cur), None)
is_ok = False
try:
probe_payload = json.dumps({
"model": cur,
"messages": [
{"role": "system", "content": "输出严格JSON"},
{"role": "user", "content": '{"entities":[]}'},
],
"max_tokens": 50,
}).encode()
probe_req = urllib.request.Request(
f"{API}/chat/completions", data=probe_payload, headers=HEADERS, method="POST")
with urllib.request.urlopen(probe_req, timeout=15) as resp:
body = json.loads(resp.read())
msg = body.get("choices", [{}])[0].get("message", {}) or {}
content = msg.get("content") or ""
# content 非空且可解析 JSON → 健康
if content.strip():
import re as _re2
cleaned = _re2.sub(r"```json\s*|\s*```", "", content).strip()
json.loads(cleaned)
is_ok = True
except Exception:
pass
# results 明确判 dead 则覆盖探针结果(探针可能偶发通过)
if found is not None and found["stability"] != "stable":
is_ok = False
print(f" ⚠️ [{cur}] 巡检判定 {found['stability']},需替换")
if not is_ok and found is None:
print(f" 🔍 [{cur}] 不在巡检列表JSON 探针未通过,需替换")
if is_ok:
return
# 找替补:候选池中 stable + JSON 可用(优先 gemma 系列)
distill_pool = [
"google/gemma-4-31b-it",
"mistralai/mistral-nemotron",
"nvidia/llama-3.3-nemotron-super-49b-v1.5",
"meta/llama-3.1-8b-instruct",
"nvidia/nemotron-mini-4b-instruct",
]
replacement = None
for cand in distill_pool:
if cand == cur:
continue
r = next((x for x in results if x["model"] == cand), None)
if r is None or r["stability"] != "stable":
continue
if not _verify_model_usable(cand):
continue
# JSON 探针复核
try:
probe_payload = json.dumps({
"model": cand,
"messages": [{"role": "user", "content": '输出JSON {"entities":["a"]}'}],
"max_tokens": 50,
}).encode()
probe_req = urllib.request.Request(
f"{API}/chat/completions", data=probe_payload, headers=HEADERS, method="POST")
with urllib.request.urlopen(probe_req, timeout=15) as resp:
body = json.loads(resp.read())
content = body.get("choices", [{}])[0].get("message", {}).get("content", "") or ""
if content.strip():
replacement = cand
break
except Exception:
continue
if not replacement:
print(f" ❌ [蒸馏] {cur} 不可用且无可用替补,请人工检查 NewAPI")
return
# 更新 zhiyid.service
changed = False
try:
with open(zhiyid_svc) as f:
svc_content = f.read()
new_svc = _re.sub(r"LLM_MODEL=\S+", f"LLM_MODEL={replacement}", svc_content)
if new_svc != svc_content:
with open(zhiyid_svc, "w") as f:
f.write(new_svc)
subprocess.run(["systemctl", "--user", "daemon-reload"], check=False)
subprocess.run(["systemctl", "--user", "restart", "zhiyid"], check=False)
changed = True
print(f" ✅ [蒸馏] zhiyid.service LLM_MODEL: {cur} → {replacement}")
except Exception as e:
print(f" ❌ [蒸馏] 更新 zhiyid.service 失败: {e}")
# 更新 tdai-gateway.yaml
if os.path.exists(tddb_cfg):
try:
with open(tddb_cfg) as f:
tddb_content = f.read()
new_tddb = _re.sub(r"^(\s*model:\s*)\S+", rf"\g<1>{replacement}", tddb_content, flags=_re.M)
if new_tddb != tddb_content:
with open(tddb_cfg + ".bak-health", "w") as f:
f.write(tddb_content)
with open(tddb_cfg, "w") as f:
f.write(new_tddb)
subprocess.run(["systemctl", "--user", "restart", "tdai-gateway"], check=False)
changed = True
print(f" ✅ [蒸馏] tdai-gateway.yaml: {cur} → {replacement}")
except Exception as e:
print(f" ❌ [蒸馏] 更新 tdai-gateway.yaml 失败: {e}")
_heal_distill_models()
print(f"\n{'='*50}")
print(f"巡检完成: {healthy}个稳定 / {flaky}个不稳定 / {dead}个死 (共{len(results)}个)")
if stable_sorted:
quality_list = ', '.join(summary['recommendations']['by_quality'])
print(f"质量排名: {quality_list}")
print(f"首选: {summary['recommendations']['priorities']['首选质量']}")
print(f"日常推荐: {summary['recommendations']['priorities']['日常推荐']}")
if __name__ == "__main__":
main()

View File

@ -1,31 +0,0 @@
[Unit]
Description=OpenClaw Gateway (v2026.7.1)
After=network-online.target
Wants=network-online.target
StartLimitBurst=5
StartLimitIntervalSec=60
[Service]
ExecStart=/home/muc/nodejs/node-v24.16.0-linux-x64/bin/node /home/muc/nodejs/node-v24.16.0-linux-x64/lib/node_modules/openclaw/dist/index.js gateway --port 18789
Restart=always
RestartSec=5
RestartPreventExitStatus=78
TimeoutStopSec=30
TimeoutStartSec=30
SuccessExitStatus=0 143
OOMPolicy=continue
KillMode=control-group
Environment=OPENCLAW_SERVICE_MANAGED_ENV_KEYS=CREAA_API_KEY
Environment=HOME=/home/muc
Environment=TMPDIR=/tmp
Environment=PATH=/home/muc/nodejs/node-v24.16.0-linux-x64/bin:/usr/local/bin:/usr/bin:/bin:/home/muc/.local/bin:/home/muc/.npm-global/bin:/home/muc/bin:/home/muc/.nix-profile/bin
Environment=OPENCLAW_GATEWAY_PORT=18789
Environment=OPENCLAW_SYSTEMD_UNIT=openclaw-gateway.service
Environment="OPENCLAW_WINDOWS_TASK_NAME=OpenClaw Gateway"
Environment=OPENCLAW_WINDOWS_TASK_HIDDEN_LAUNCHER=1
Environment=OPENCLAW_SERVICE_MARKER=openclaw
Environment=OPENCLAW_SERVICE_KIND=gateway
Environment=OPENCLAW_SERVICE_VERSION=2026.7.1
[Install]
WantedBy=default.target

View File

@ -1,21 +0,0 @@
[Unit]
Description=ZhiYi MemoryWeave (织忆) — Go Daemon
Documentation=http://192.168.123.11:3000/xiaoxue_admin/memoryweave
After=network.target zhiyi-consolidate.service bge-embed.service
Wants=zhiyi-consolidate.service bge-embed.service
[Service]
Type=simple
ExecStartPre=/bin/mkdir -p /var/lib/memoryweave /home/muc/.logs
ExecStart=/home/muc/bin/zhiyid-new
Restart=always
RestartSec=5
MemoryMax=2G
CPUQuota=200%
Environment=STORAGE_BACKEND=lancedb
Environment=LLM_ENDPOINT=http://127.0.0.1:3000/v1/chat/completions
Environment=LLM_MODEL=meta/llama-3.1-8b-instruct
Environment=LLM_API_KEY=0ExNiLblJvIWBDpkS50fwOBw4MmqLyKdHJK5iQtlw9dOMWBP
[Install]
WantedBy=default.target

4
.env
View File

@ -22,7 +22,7 @@ QQ_CLIENT_SECRET=tgUI7xneWOHA4zuqmjgecbbbcdfhknrv
CNB_TOKEN=7i18PbKx10feWTefNEORER1X4FC
AGNES_API_KEY=sk-7k9e9KGcoZdDuYt2LSA4YXdBTioczleGJm2zzLWCku072ikW
MIMO_API_KEY=tp-c374efhzmz9npodjz5wj1cm008lg4czce6v170nqxwemp12v
# [2026-09-12 牧尘:小米模型近期不再使用] MIMO_API_KEY=tp-c374efhzmz9npodjz5wj1cm008lg4czce6v170nqxwemp12v
XIAOMI_API_KEY=tp-c374efhzmz9npodjz5wj1cm008lg4czce6v170nqxwemp12v
XIAOMI_BASE_URL=https://token-plan-cn.xiaomimimo.com/v1
SENSENOVA_API_KEY=sk-QWrtQIu3mmKCvAF2v2OmI4gdljiPdvXO
@ -32,3 +32,5 @@ ZHIPU_API_KEY=70674fdbb8db437f8946c8e5e376139b.pPXThBfxRLj7UdkK
GITHUB_TOKEN=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
GMI_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFlZGEwZTJmLTI1N2ItNGEwYi04NzBhLWUwZjI3MzQ0NWM2YSIsInNjb3BlIjoiaWVfbW9kZWwiLCJwcm9kdWN0IjoiSUUiLCJvd25lcklkIjoiOTYxZGY1MWUtMjAyMi00ZDZjLWI2YTgtNWMxN2M5NzA1NjEyIn0.7v6kPl4VcNHtOcU3hN2FAMGVEuDxvym1h9FwXZBaD7M
GMI_BASE_URL=https://api.gmi-serving.com/v1
HERMES_PEER_LOCAL_ORCH_KEY=f1fa45412e7d072d03bc1528bd6330b51697597db06aa616
OPENCODE_GO_API_KEY=sk-N4uoeEyJrQKLi8HMvd8WkIx4Hrx70g811wpRnfRD2W0iphRxTwKgr5uFlwEwLMtM

View File

@ -1,9 +0,0 @@
FEISHU_APP_ID=cli_a95d7ff06b789bb4
FEISHU_APP_SECRET=Gm7eo0aD9Luka8mHxApRufYIDwmpGsGf
SUDO_PASSWORD=z1020
DEEPSEEK_API_KEY=sk-b1212066094d4e319784f23d5b2c6bbd
FEISHU_HOME_CHANNEL=oc_cd14ec7518926e57d26c5e339ebba3b3
FEISHU_HOME_CHANNEL_THREAD_ID=
HF_ENDPOINT=https://hf-mirror.com

View File

@ -1,16 +0,0 @@
FEISHU_APP_ID=cli_a95d7ff06b789bb4
FEISHU_APP_SECRET=Gm7eo0aD9Luka8mHxApRufYIDwmpGsGf
SUDO_PASSWORD=z1020
DEEPSEEK_API_KEY=sk-b1212066094d4e319784f23d5b2c6bbd
FEISHU_HOME_CHANNEL=oc_cd14ec7518926e57d26c5e339ebba3b3
FEISHU_HOME_CHANNEL_THREAD_ID=
HF_ENDPOINT=https://hf-mirror.com
WEIXIN_TOKEN=bef3c3d39904@im.bot:060000740c190c21262c8edf68365d5d112e0d
WEIXIN_ACCOUNT_ID=bef3c3d39904@im.bot
WEIXIN_BASE_URL=https://ilinkai.weixin.qq.com
WEIXIN_USER_ID=o9cq800DqpnMoqzXmJ4zozKiM8OI@im.wechat
WEIXIN_DM_POLICY=open
WEIXIN_GROUP_POLICY=open

View File

@ -1,32 +0,0 @@
FEISHU_APP_ID=cli_a95d7ff06b789bb4
FEISHU_APP_SECRET=Gm7eo0aD9Luka8mHxApRufYIDwmpGsGf
SUDO_PASSWORD=z1020
DEEPSEEK_API_KEY=sk-b1212066094d4e319784f23d5b2c6bbd
FEISHU_HOME_CHANNEL=oc_cd14ec7518926e57d26c5e339ebba3b3
FEISHU_HOME_CHANNEL_THREAD_ID=
HF_ENDPOINT=https://hf-mirror.com
WEIXIN_TOKEN=bef3c3d39904@im.bot:060000740c190c21262c8edf68365d5d112e0d
WEIXIN_ACCOUNT_ID=bef3c3d39904@im.bot
WEIXIN_BASE_URL=https://ilinkai.weixin.qq.com
WEIXIN_USER_ID=o9cq800DqpnMoqzXmJ4zozKiM8OI@im.wechat
WEIXIN_DM_POLICY=open
WEIXIN_GROUP_POLICY=open
WEIXIN_ALLOW_ALL_USERS=true
QQ_APP_ID=1903732343
QQ_CLIENT_SECRET=tgUI7xneWOHA4zuqmjgecbbbcdfhknrv
CNB_TOKEN=7i18PbKx10feWTefNEORER1X4FC
AGNES_API_KEY=sk-7k9e9KGcoZdDuYt2LSA4YXdBTioczleGJm2zzLWCku072ikW
MIMO_API_KEY=tp-c374efhzmz9npodjz5wj1cm008lg4czce6v170nqxwemp12v
XIAOMI_API_KEY=tp-c374efhzmz9npodjz5wj1cm008lg4czce6v170nqxwemp12v
XIAOMI_BASE_URL=https://token-plan-cn.xiaomimimo.com/v1
SENSENOVA_API_KEY=sk-QWrtQIu3mmKCvAF2v2OmI4gdljiPdvXO
ZHIPU_API_KEY=70674fdbb8db437f8946c8e5e376139b.pPXThBfxRLj7UdkK
GITHUB_TOKEN=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

7
.gitignore vendored
View File

@ -3,6 +3,7 @@
sessions/
cron/output/
cron/jobs.json
cron/jobs.json.bak-*
cron/ticker*
cron/*.lock
watchdog/
@ -60,3 +61,9 @@ stock_broker.json
daemon/context.json
daemon/journal.jsonl
llm_context.json
# 2026-09-17 小怡:运行时噪音/本机快照,不入库
checkpoints/
*.bak-*
*.bak2
*.orig
*.tmp

View File

@ -1,57 +0,0 @@
# 配置保护 .gitignore — 只跟踪关键可恢复配置
# 排除所有运行时数据
sessions/
cron/output/
cron/jobs.json
cron/ticker*
cron/*.lock
watchdog/
cache/
logs/
*.db
*.db-shm
*.db-wal
*.log
*.png
*.jpg
*.lock
state*
gateway*
processes.json
feishu_seen_message_ids.json
channel_directory.json
auth.json
kanban*
pairing/
prof-b/
profiles/
.hub/
.curator_backups/
.bundled_manifest
.curator_state
.usage.json*
.tirith-install-failed
.update_check
.hermes_history
models_dev_cache.json
skill-curator-report.json
model-health.json
wiki_curator_state.json
lsp/
cuda-libs/
hermes-agent/ # submodule
__pycache__/
*.pyc
node_modules/
tmp/
.env* # 不跟踪 secrets有 API key
archive/
config.yaml.corrupt.*.bak
# 股票运行时配置(后端选择是个人偏好,非代码)
stock_broker.json
# 运行时噪音daemon 每 30s 写入,不跟踪)
daemon/context.json
daemon/journal.jsonl
llm_context.json

View File

@ -25,3 +25,8 @@
# 2026-08-19 20:29:46.749497
+在?
# 2026-09-12 05:34:23.178227
+/compress
+
+

View File

@ -1 +1 @@
{"ts": 1789065921.4957573, "behind": -1, "rev": null, "ver": "0.21.0"}
{"ts": 1789564216.6682775, "behind": -1, "rev": null, "ver": "0.21.3", "head": "3ad5aaca1ce964e657979c15aaef18c211500b67", "target": "784d5c3f9c2cb77698d8a9d2e72b1d106a38ea88"}

View File

@ -1,6 +1,6 @@
# 小系统 (xiaowei-system)
# 小系统 (xiaowei-system)
> 小 A06 的大脑层 | Gitea: http://192.168.123.11:3000/xiaoxue_admin/xiaowei-system/
> 小 A06 的大脑层 | Gitea: http://192.168.123.11:3000/xiaoxue_admin/xiaowei-system/
---
@ -19,7 +19,7 @@
│ HTTP APIlocalhost
┌─────────────────────────────────────────────────────────┐
│ 上层应用层(小系统 xiaowei-system
│ 上层应用层(小系统 xiaowei-system
│ │
│ ~/.hermes/ ← 本仓库 │
│ │
@ -65,7 +65,7 @@
第二步TencentDB对话记忆
→ ~/.memory-tencentdb/port 8420
第三步:小系统(上层应用)
第三步:小系统(上层应用)
→ ~/.hermes/daemon.py
```
@ -74,7 +74,7 @@
## 架构依赖
```
系统(daemon.py)
系统(daemon.py)
├── http://127.0.0.1:7821 ← 织忆 L1/L2 recallX-API-Key
├── http://127.0.0.1:8420 ← TencentDB L3/L4 scenes/capture + /recall
├── ~/.hermes/soulful/ ← Soulful L5/L6cares + heart-traces + profile
@ -83,7 +83,7 @@
---
## 小系统内容
## 小系统内容
```
~/.hermes/ ← xiaowei-system 仓库

View File

@ -17,6 +17,55 @@
- state-20260907-0000.dbintegrity_check=ok00:00——今晚以此为基线
- 校验方法sqlite3 -readonly <snap> 'PRAGMA integrity_check;' 必须返回 ok
## FTS 索引损坏(`messages_fts`)—— 2026-09-13 立
### 症状 / 报警
`fts-stale 运行期兜底 watch`cron `bc31e3533d40`every 30mno_agent输出形如
```
[FTS-WATCH] 🟠 FTS 索引损坏(blob 级): fts5: corruption found reading blob 1649267441665 from table "messages_fts"
```
(旧版文案是 `✅ 无 stale 标记 integrity=<corruption>` —— 首行像绿灯2026-09-13 已改为首行直接报损坏。)
### 先判范围(只读,**不要**直接当全库坏了)
```bash
# 只读 + immutable禁止普通 connect 活库)
# messages / sessions 计数正常 + MATCH 查询仍可用 ⇒ 数据在、只是索引局部坏
# 本次2026-09-13 21:5x实测state.db 410MB、messages 81019 ✅、sessions 402 ✅、
# `SELECT count(*) FROM messages_fts WHERE messages_fts MATCH 'gateway'` ✅ 正常返回
```
⇒ blob 级损坏 ≠ 数据丢失;`LIKE` 降级/搜索退化才是实际影响。**先取证,再谈停机。**
### 🔴 2026-09-13 当日实测:**多数情况会自愈,不必上停机窗口**
| 时间 | 观测 |
|---|---|
| 21:52 | watch 报 `fts5: corruption found reading blob 1649267441665 from table "messages_fts"` |
| 22:32 | 同一脚本 + `sqlite3 -readonly … 'PRAGMA quick_check;'`**`ok`**MATCH 查询正常messages 81252 / sessions 403 可读 |
⇒ 结论:**SessionDB 自然 open网关/会话正常开关)就会走 `_recover_stale_fts`**,多数 blob 级损坏在下一轮 open 就被修掉。
**流程修正**watch 报警 → **先只读复验**(本文上一条)→ 若已 ok 就**结案**(由 watch 的「✅ 已恢复」通知收尾),
只有**复验仍坏**才排停机窗口。别一收到报警就安排停机。
### 修复(必须停机窗口,禁止在线手术)
铁律:**live write / search 不得 rebuild 全量 FTS**(测试不变量
`tests/state/test_fts_runtime_rebuild.py`);在线起第二个写入者 = 本机反复损坏的 P1-1 根因。
```bash
# 1) 停机(走本文件开头的铁律 1先确认无进程持有
systemctl --user stop hermes-gateway
lsof ~/.hermes/state.db # 必须无输出
# 2) 让 SessionDB open 自动恢复(首选,无需手写 SQL
hermes --cli -q "/quit" 2>/dev/null || hermes -q "ping" # 触发一次 open → _recover_stale_fts
# 或手动重建sqlite3 state.db "INSERT INTO messages_fts(messages_fts) VALUES('rebuild');"
# 3) 起网关
systemctl --user start hermes-gateway
# 4) 复验watch 下一次 tick 应静默;或
python3 ~/.hermes/scripts/fts-stale-watch.py # 期望:无输出(健康静默)
```
### 红线
1. ❌ 网关运行时**不许** `INSERT INTO messages_fts(...) VALUES('rebuild')`、不许 VACUUM、不许换库
2. ❌ 不许 `rm` 活库的 `-wal` / `-shm`(本文件开头的铁律 3
3. ⏱ 一次只允许一个操作者(铁律 5动手前后各留一份 `snapshot-state-db.sh` 快照
## 快速恢复 SOP
systemctl --user stop hermes-gateway
lsof ~/.hermes/state.db # 必须无输出

View File

@ -4,7 +4,7 @@
牧尘对记忆系统合并统一后的架构MEMORY.md 只保留核心身份和配置,所有事实/偏好/项目信息存织忆(语义搜索召回)。
织忆设计文档:~/mc/小/07-Wiki/concepts/织忆(MemoryWeave)-v2.9-目标C-HermesOpenClaw迁移织忆.md
织忆设计文档:~/mc/小/07-Wiki/concepts/织忆(MemoryWeave)-v2.9-目标C-HermesOpenClaw迁移织忆.md
织忆项目:/home/muc/projects/zhiyi/
hermes-zhiyi-bridge 插件:~/.hermes/plugins/zhiyi/(已配置 memory.provider=zhiyi

View File

@ -1,63 +0,0 @@
{
"version": 1,
"providers": {},
"credential_pool": {
"minimax": [],
"custom:newapi-local": [
{
"id": "1264e8",
"label": "newapi-local",
"auth_type": "api_key",
"priority": 0,
"source": "config:newapi-local",
"last_status": "ok",
"last_status_at": null,
"last_error_code": null,
"last_error_reason": null,
"last_error_message": null,
"last_error_reset_at": null,
"base_url": "http://127.0.0.1:3000/v1",
"request_count": 0,
"secret_fingerprint": "sha256:cc6225a1be5c62b7"
}
],
"deepseek": [
{
"id": "5fe4e0",
"label": "DEEPSEEK_API_KEY",
"auth_type": "api_key",
"priority": 0,
"source": "env:DEEPSEEK_API_KEY",
"last_status": null,
"last_status_at": null,
"last_error_code": null,
"last_error_reason": null,
"last_error_message": null,
"last_error_reset_at": null,
"base_url": "https://api.deepseek.com/v1",
"request_count": 0,
"secret_fingerprint": "sha256:43dc55497d2c7fdc"
}
],
"custom:omniroute-local": [
{
"id": "273e72",
"label": "omniroute-local",
"auth_type": "api_key",
"priority": 0,
"source": "config:omniroute-local",
"last_status": null,
"last_status_at": null,
"last_error_code": null,
"last_error_reason": null,
"last_error_message": null,
"last_error_reset_at": null,
"base_url": "http://127.0.0.1:3001/v1",
"request_count": 0,
"secret_fingerprint": "sha256:ed80667ec3d95b40"
}
]
},
"updated_at": "2026-08-01T12:50:10.806262+00:00",
"active_provider": null
}

View File

@ -1,13 +0,0 @@
---
id: mem_1780411774526664129
category: distilled
quality_score: 0.64
sync_time: 2026-06-05T18:32:26+08:00
---
# 当前记忆库包含 1665 条记忆,召回率 99%,有ç”...
当前记忆库包含 1665 条记忆,召回率 99%,有用率 98%。
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: test001
category: test
quality_score: 0.00
sync_time: 2026-05-31T13:32:16+08:00
---
# test memory
test memory
---
*由织忆 MemoryWeave 同步*

View File

@ -1,6 +0,0 @@
# Added by `ao init`
AO_PROVIDER=openai
AO_MODEL=meta/llama-3.1-70b-instruct
OPENAI_BASE_URL=http://127.0.0.1:3000/v1
OPENAI_API_KEY=0ExNiLblJvIWBDpkS50fwOBw4MmqLyKdHJK5iQtlw9dOMWBP

View File

@ -1,13 +0,0 @@
---
id: mem_1780211449154506658
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# E1 å¾è°±å¯¼èˆªæ¿€æ´»å®Œæˆ<C3A6>,清除æ®ç•™ debug 语å<C2AD>¥ï¼ŒåŠ...
E1 å¾è°±å¯¼èˆªæ¿€æ´»å®Œæˆ<C3A6>,清除æ®ç•™ debug 语å<C2AD>¥ï¼ŒåŠŸèƒ½å·²æŽ¥å…¥
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780216039197704885
category: episodes
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# E4 图谱推理全部完成 E4.1 中文矛盾检测 E4.2 跨...
E4 图谱推理全部完成 E4.1 中文矛盾检测 E4.2 跨 agent 知识共享 E4.3 图谱度遗忘决策
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780324931940599843
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# E4.3 存在 bug admin.go:73 拿的是 mem namespace 字段ä¸...
E4.3 存在 bug admin.go:73 拿的是 mem namespace 字段ä¸<C3A4>存在
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780230800484584669
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# E5 鈭批<E988AD> UI <20><EFBFBD><E887AC><EFBFBD><E6BBA8><EFBFBD>憭抒<E686AD><E68A92><EFBFBD><E981B8><EFBFBD><EFBFBD>舀沲<E88880><E6B2B2><EFBFBD>鈭𡒊<E988AD>...
E5 鈭批<E988AD> UI <20><EFBFBD><E887AC><EFBFBD><E6BBA8><EFBFBD>憭抒<E686AD><E68A92><EFBFBD><E981B8><EFBFBD><EFBFBD>舀沲<E88880><E6B2B2><EFBFBD>鈭𡒊<E988AD><F0A1928A><EFBFBD><EFBFBD>蝻箔<E89DBB><E7AE94><EFBFBD><E888AA>𣇉<EFBFBD><F0A38789><EFBFBD><EFBFBD>𣈲<EFBFBD><F0A388B2> API 靚<><EFBFBD><E98D82>
---
*<2A><EFBFBD><EFBFBD> MemoryWeave <20>峕郊*

View File

@ -1,13 +0,0 @@
---
id: mem_1780185320535437423
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# G6 完成后的对话反馈
G6 完成后的对话反馈
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780230801019061019
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# G7 é<>—忘 + 技能系统的目标是让 agent 记录已使ç”...
G7 é<>—忘 + 技能系统的目标是让 agent 记录已使用的 skills,并利用记忆优åŒå<E28093>Žç»­çš„ skill 调用。
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780742697986315655
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# Server 配置已更新memory.provider 指向本地 zhiyi ...
Server 配置已更新memory.provider 指向本地 zhiyi 服务
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780210527061653067
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# WORKLOG 已更新 E1 状态、提交记录及下一步计划
WORKLOG 已更新 E1 状态、提交记录及下一步计划
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780138789025136676
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 织忆 API key 更正:正确 key 是 zhiyi-dev-key-2026
织忆 API key 更正:正确 key 是 zhiyi-dev-key-2026
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780182222988134153
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 当前 G1 至 G6 全部完成G7 和 G8 待执行
当前 G1 至 G6 全部完成G7 和 G8 待执行
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780230800637705441
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 竞品 Mem0 和 Supermemory 已具备 Web UI 功能。
竞品 Mem0 和 Supermemory 已具备 Web UI 功能。
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780500766383556075
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 选定 agnes-2.0-flash 作为文本生成模型agnes-imag...
选定 agnes-2.0-flash 作为文本生成模型agnes-image-2.1-flash 作为图像生成模型。
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780411349396158812
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 修改 core.go 移除 commit 时的 InsertMemory 调用
修改 core.go 移除 commit 时的 InsertMemory 调用
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780411349273672692
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 修改 recall.go 增加过滤逻辑及 helper 函数
修改 recall.go 增加过滤逻辑及 helper 函数
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780192847041774431
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 全部å<C2A8>š - 完æˆ<C3A6>了 cluster_only vs full 调度策略修å¤...
全部å<EFBFBD>š - 完æˆ<C3A6>了 cluster_only vs full 调度ç­ç•¥ä¿®å¤<C3A5>
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,18 +0,0 @@
---
id: mem_1780247779615465363
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 用户: Cronjob Response: 织忆状态看板
\(job\_id: e2d5...
用户: Cronjob Response: 织忆状态看板
\(job\_id: e2d5a98bff74\)
---
🧠 织忆看板 \[2026\-05\-31 23:16\]
━━━━━━━━━━━...
---
*由织忆 MemoryWeave 同步*

View File

@ -1,17 +0,0 @@
---
id: mem_1780488889894489881
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 用户: E5.1 Obsidian æ<>件增强
助手: 现在我清楚äº...
用户: E5.1 Obsidian æ<>件增强
助手: çŽ°åœ¨æˆæ¸…楚了当å‰<C3A5>æ<EFBFBD>件功能ã€çŽ°æœ‰èƒ½åŠï¼š
**已实现:** MemoryView(分页) + GraphView(D3åŠå¯¼å<C2BC>å¾) + SearchM...
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,21 +0,0 @@
---
id: mem_1780490156091265808
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 用户: 全部都è¦<C3A8>
助手: ✅ 全部完æˆ<C3A6>,commit å·²æ<C2B2>...
用户: 全部都è¦<C3A8>
助手: ✅ 全部完æˆ<C3A6>,commit å·²æ<C2B2><C3A6>交ã€
**E5.1 织忆æ<E280A0>ä»¶ v1.1 新增功能:**
| 功能 | 说明 |
|------|------|
| **记忆展开详情** ...
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,18 +0,0 @@
---
id: mem_1780163606924689282
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 用户: 你去更新一下工作记录
助手: 已更新两ä...
用户: 你去更新一下工作记录
助手: 已更新两个地方:
**1. `~/projects/memoryweave/WORKLOG.md`**(项ç®å†…æ<E280A6>ƒå¨<C3A5>记录)
- G6 补全 G6.1/G6.2/G...
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780411348736740409
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 决定将 raw 内容仅写入 episodes 表,待蒸馏后再...
决定将 raw 内容仅写入 episodes 表,待蒸馏后再写入 memories 表
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780411349018603824
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 决定在 recall 阶段过滤掉原å§å¯¹è¯<C3A8>,仅返åžè¸é...
决定在 recall 阶段过滤掉原å§å¯¹è¯<C3A8>,仅返åžè¸é¦<C3A9>å<EFBFBD>Žçš„结构åŒè®°å¿†
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780088802674014314
category: system_fact
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 牧尘用Arch Linux和RTX 3050做ComfyUI图像生成和AI开...
牧尘用Arch Linux和RTX 3050做ComfyUI图像生成和AI开发
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780106476615792515
category: test
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 修复验证 - schema 类型匹配测试
修复验证 - schema 类型匹配测试
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780157836513081716
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 用户反馈 G6 完成
用户反馈 G6 完成
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780183370496705555
category: episodes
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 用户反馈 G6 完成后系统状态
用户反馈 G6 完成后系统状态
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780742697217806784
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 决定使用 Ollama çš„ bgem3:latest 模型作为织忆系ç»...
决定使用 Ollama çš„ bgem3:latest 模åžä½œä¸ºç»‡å¿†ç³»ç»Ÿçš„嵌入æœ<C3A6>务
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780742698743211773
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 如何实现 Windows 环境下的服务持久化(当前为...
如何实现 Windows 环境下的服务持久化(当前为内存模式)
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780184518748535937
category: test
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 验证修复 recall_count 更新测试
验证修复 recall_count 更新测试
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780173868603415336
category: test
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 测试记忆
测试记忆
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780157018435205382
category: episodes
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 用户说停止 - 停止执行
用户说停止 - 停止执行
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780088707259935764
category: system_fact
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 验证蒸馏: 牧尘用Arch Linux + RTX3050跑ComfyUI生成A...
验证蒸馏: 牧尘用Arch Linux + RTX3050跑ComfyUI生成AI图像
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780277902407300683
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 系统召回率为 98%,其中有用率为 97%
系统召回率为 98%,其中有用率为 97%
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780247779615465363
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 织忆状态看板 Cronjob Response 2026-05-31 23:16
织忆状态看板 Cronjob Response 2026-05-31 23:16
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780162614946495307
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 牧尘将织忆的 LLM 模型质量回溯功能从 MiniMax M...
牧尘将织忆的 LLM 模型质量回溯功能从 MiniMax M2.7 切换至 Qwen3.5-122B
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780746342890861684
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 确定必须备份 Memoryã€<C3A3>å¾è°±ã€<C3A3>å<EFBFBD>é‡<C3A9>ã€<C3A3>Episodes å<>Šå¢...
确定必须备份 Memoryã€<C3A3>å¾è°±ã€<C3A3>å<EFBFBD>é‡<C3A9>ã€<C3A3>Episodes å<>Šå¢“ç¢ç­‰æ ¸å¿ƒæ•°æ<C2B0>®æ‡ä»¶
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780210527086154927
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 代码提交包含 commit cd0f898、cc615c5 及本次 E1 deb...
代码提交包含 commit cd0f898、cc615c5 及本次 E1 debug cleanup
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780421906656086043
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 执行部署命令
执行部署命令
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780411774526664129
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 当å‰<C3A5>记忆库包å<E280A6>« 1665 æ<>¡è®°å¿†ï¼Œå<C592>¬åžçއ 99%,有ç”...
当å‰<EFBFBD>记忆库包å<EFBFBD>« 1665 æ<>¡è®°å¿†ï¼Œå<C592>¬åžçއ 99%,有用率 98%。
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780491044519311381
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 决定安装并启用 Obsidian 插件“织忆”zhiyi-me...
决定安装并启用 Obsidian 插件“织忆”zhiyi-memory
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780108734922679915
category: test
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 闥ク鬥丞粥閭ス豬玖ッ廟1780108734713091537縲らサ<E38289>ソ<EFBFBD>頂鬥丞シ墓梼<E5A293>...
闥ク鬥丞粥閭ス豬玖ッ廟1780108734713091537縲らサ<EFBFBD>ソ<EFBFBD>頂鬥丞シ墓梼菫ョ螟埼ェ瑚ッ<EFBFBD>シ壽悽谺。謠蝉コ、逕ィ莠朱ェ瑚ッ∬頂鬥丈コァ迚ゥ譏ッ蜷ヲ謌仙粥蝗槫<EFBFBD>隶ー蠢<EFBFBD>コ薙€る「<EFBFBD>悄扈剰ソ<EFBFBD>頂鬥丞錘<EFBFBD>鍬LM莨壽署蜿紋コ句ョ槫ケカ莠ァ蜃コ荳€譚。distilled邀サ蛻ォ隶ー蠢<EFBFBD>€<EFBFBD>
---
*逕ア扈<EFBDB1>ソ<EFBFBD> MemoryWeave 蜷梧ュ・*

View File

@ -1,13 +0,0 @@
---
id: mem_1780108812798977244
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# <20><EFBFBD><E8B38A><EFBFBD>瘚贝<E7989A><E8B49D><EFBFBD> 20260530 abc123 蝏<><E89D8F><EFBFBD><EFBFBD>撘閙<E69298><E99699>...
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>瘚贝<EFBFBD><EFBFBD><EFBFBD> 20260530 abc123 蝏<><E89D8F><EFBFBD><EFBFBD>撘閙<E69298>靽桀<E99DBD>撉諹<E69289>
---
*<2A><EFBFBD><EFBFBD> MemoryWeave <20>峕郊*

View File

@ -1,13 +0,0 @@
---
id: mem_1780491044810312655
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 将插件文件部署至 ~/mc/.obsidian/plugins/zhiyi-memory...
将插件文件部署至 ~/mc/.obsidian/plugins/zhiyi-memory/
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780106616343688588
category: test
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 全部修复验证通过
全部修复验证通过
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780162597589274671
category: episodes
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 用户让你再测试一下 - 完整测试结果 Commit Reca...
用户让你再测试一下 - 完整测试结果 Commit Recall Consolidation Self-optimization Gaps Eval Metrics
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780183019674517781
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# 测试目标是验证多次 commit 的稳定性
测试目标是验证多次 commit 的稳定性
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780183019533562257
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# 正在进行第二轮测试
正在进行第二轮测试
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780108729593319471
category: test
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# <20><EFBFBD><E8B38A><EFBFBD>瘚贝<E7989A><E8B49D><EFBFBD>_20260530_abc123<32><33><EFBFBD><EFBFBD>𡢄擐誩<E69390><E8AAA9>...
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>瘚贝<EFBFBD><EFBFBD><EFBFBD>_20260530_abc123<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡢄擐誩<EFBFBD><EFBFBD>𦒘耨憭漤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>祆活<EFBFBD>𣂷漱<EFBFBD><EFBFBD>撉諹<EFBFBD><EFBFBD><EFBFBD>鈭抒<EFBFBD><EFBFBD>臬炏<EFBFBD>𣂼<EFBFBD><EFBFBD>𧼮<EFBFBD>霈啣<EFBFBD>摨瓐<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝏讛<EFBFBD><EFBFBD>畾菜𧒄<EFBFBD><EFBFBD>嚗諹砲<EFBFBD><EFBFBD>捆隡朞◤LLM霂<EFBFBD><EFBFBD>撟嗆<EFBFBD><EFBFBD><EFBFBD>摰痹<EFBFBD>餈嗘<EFBFBD>鈭见<EFBFBD>雿靝蛹distilled蝐餃<EFBFBD>霈啣<EFBFBD><EFBFBD><EFBFBD>LanceDB嚗<EFBFBD><EFBFBD><EFBFBD>recall<EFBFBD>亙藁<EFBFBD>亥砭<EFBFBD><EFBFBD>
---
*<2A><EFBFBD><EFBFBD> MemoryWeave <20>峕郊*

View File

@ -1,13 +0,0 @@
---
id: mem_1780135707686504799
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# æµè¯•记忆:å°<C3A5>唯的内存æ<CB9C>件检查,2026-05-30,æŒ...
æµè¯•记忆:å°<EFBFBD>唯的内存æ<EFBFBD>件检查,2026-05-30,指标正常:total_memories=1239,recall_hit_rate=93%,recall_usefulness_rate=84%
---
*由织忆 MemoryWeave å<>Œæ­¥*

View File

@ -1,13 +0,0 @@
---
id: mem_1780209682485894413
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# col_vector 已添加对 FixedSizeListArray 的读取支持
col_vector 已添加对 FixedSizeListArray 的读取支持
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780161904590956279
category: distilled
quality_score: 0.00
sync_time: 2026-06-02T04:34:06+08:00
---
# deploy/ 目录下的 service 文件需要同步更新
deploy/ 目录下的 service 文件需要同步更新
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: t1
category:
quality_score: 0.00
sync_time: 2026-06-05T14:05:12+08:00
---
# test1
test1
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: t2
category:
quality_score: 0.00
sync_time: 2026-06-05T14:05:12+08:00
---
# test2
test2
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: t3
category:
quality_score: 0.00
sync_time: 2026-06-05T14:05:12+08:00
---
# test3
test3
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: t4
category:
quality_score: 0.00
sync_time: 2026-06-05T14:05:12+08:00
---
# test4
test4
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: t5
category:
quality_score: 0.00
sync_time: 2026-06-05T14:05:12+08:00
---
# test5
test5
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780136502075098763
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# total_memories 值为 1239
total_memories 值为 1239
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780390427126563986
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# zhiyi entity 显示邻居数和关联记忆
zhiyi entity 显示邻居数和关联记忆
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780390426897381532
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# zhiyi recall 执行语义搜索返回 top-10
zhiyi recall 执行语义搜索返回 top-10
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780390426785260190
category: distilled
quality_score: 0.00
sync_time: 2026-06-07T16:00:41+08:00
---
# zhiyi tree 按 category 分组记忆树
zhiyi tree 按 category 分组记忆树
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780180846266397821
category:
quality_score: 0.00
sync_time: 2026-06-05T08:58:34+08:00
---
# --help
--help
---
*由织忆 MemoryWeave 同步*

View File

@ -1,23 +0,0 @@
---
type: concept
namespace: shared
pagerank: 0.0005
connections: 6
source: 织忆图谱
---
# 📘 04-Archive 保持
**类型**: concept | **命名空间**: shared | **PageRank**: 0.0005
## 🔗 关联到
- [[n_hermes_memory_db_lancedb_539条_97mb_需迁移脚本移到织忆api_两个zhiyi插件_plugins_zhiyi|hermes memory_db lancedb 539条 97MB 需迁移脚本移到织忆API 两个zhi...]] — `related_to` (强度 50%)
- [[n_v3_8|v3 8]] — `related_to` (强度 50%)
- [[n_活跃|活跃]] — `related_to` (强度 50%)
- [[n_活跃_p6|活跃 P6]] — `related_to` (强度 50%)
## 📥 被关联
- [[n_lancedb|LanceDB]] — `related_to` → 我 (强度 50%)
- [[n_保持|保持]] — `related_to` → 我 (强度 50%)

View File

@ -1,37 +0,0 @@
---
type: concept
namespace: hermes-main
pagerank: 0.0005
connections: 21
source: 织忆图谱
---
# 📘 11
**类型**: concept | **命名空间**: hermes-main | **PageRank**: 0.0005
## 🔗 关联到
- [[n_81|81]] — `related_to` (强度 50%)
- [[n_default_70|default 70]] — `related_to` (强度 50%)
- [[n_muc_11|muc 11]] — `related_to` (强度 50%)
- [[n_opt-5|OPT-5]] — `related_to` (强度 50%)
- [[n_true|True]] — `related_to` (强度 50%)
- [[n_v4_0_0|v4 0 0]] — `related_to` (强度 50%)
- [[n_一致性检查|一致性检查]] — `related_to` (强度 50%)
- [[n_健康监控|健康监控]] — `related_to` (强度 50%)
- [[n_后台批量|后台批量]] — `related_to` (强度 50%)
- [[n_工具|工具]] — `related_to` (强度 50%)
- [[n_异步写入队列|异步写入队列]] — `related_to` (强度 50%)
- [[n_当前数据|当前数据]] — `related_to` (强度 50%)
- [[n_文档已更新到|文档已更新到]] — `related_to` (强度 50%)
- [[n_时返回全量|时返回全量]] — `related_to` (强度 50%)
- [[n_统计|统计]] — `related_to` (强度 50%)
## 📥 被关联
- [[n_lancedb|LanceDB]] — `related_to` → 我 (强度 50%)
- [[n_ollama|Ollama]] — `related_to` → 我 (强度 50%)
- [[n_api|API]] — `related_to` → 我 (强度 50%)
- [[n_fts|FTS]] — `related_to` → 我 (强度 50%)
- [[n_无|无]] — `related_to` → 我 (强度 50%)

View File

@ -1,29 +0,0 @@
---
type: concept
namespace: shared
pagerank: 0.0005
connections: 12
source: 织忆图谱
---
# 📘 12
**类型**: concept | **命名空间**: shared | **PageRank**: 0.0005
## 🔗 关联到
- [[n_api|API]] — `uses` (强度 50%)
- [[n_你的个人资料|你的个人资料]] — `uses` (强度 50%)
- [[n_写脚本逐条|写脚本逐条]] — `uses` (强度 50%)
- [[n_到织忆|到织忆]] — `uses` (强度 50%)
- [[n_前|前]] — `uses` (强度 50%)
- [[n_这是切换|这是切换]] — `uses` (强度 50%)
- [[n_验证回忆准确|验证回忆准确]] — `uses` (强度 50%)
## 📥 被关联
- [[n_行|行]] — `uses` → 我 (强度 50%)
- [[n_合并|合并]] — `uses` → 我 (强度 50%)
- [[n_hermes|Hermes]] — `uses` → 我 (强度 50%)
- [[n_条|条]] — `uses` → 我 (强度 50%)
- [[n_内容|内容]] — `uses` → 我 (强度 50%)

View File

@ -1,32 +0,0 @@
---
type: concept
namespace: hermes-main
pagerank: 0.0006
connections: 15
source: 织忆图谱
---
# 📘 1500ms text RTX
**类型**: concept | **命名空间**: hermes-main | **PageRank**: 0.0006
## 🔗 关联到
- [[n_3050|3050]] — `uses` (强度 50%)
- [[n_3050|3050]] — `related_to` (强度 50%)
- [[n_4gb_compute|4GB compute]] — `uses` (强度 50%)
- [[n_4gb_compute|4GB compute]] — `related_to` (强度 50%)
- [[n_8_6_2_9gib|8 6 2 9GiB]] — `uses` (强度 50%)
- [[n_mobile|Mobile]] — `uses` (强度 50%)
- [[n_mobile|Mobile]] — `related_to` (强度 50%)
- [[n_可用|可用]] — `uses` (强度 50%)
## 📥 被关联
- [[n_ollama|Ollama]] — `uses` → 我 (强度 50%)
- [[n_脚本|脚本]] — `uses` → 我 (强度 50%)
- [[n_cpu|CPU]] — `uses` → 我 (强度 50%)
- [[n_ollama|Ollama]] — `related_to` → 我 (强度 50%)
- [[n_需|需]] — `related_to` → 我 (强度 50%)
- [[n_脚本|脚本]] — `related_to` → 我 (强度 50%)
- [[n_cpu|CPU]] — `related_to` → 我 (强度 50%)

View File

@ -1,41 +0,0 @@
---
type: concept
namespace: hermes-main
pagerank: 0.0010
connections: 42
source: 织忆图谱
---
# 📘 17GB
**类型**: concept | **命名空间**: hermes-main | **PageRank**: 0.0010
## 🔗 关联到
- [[n_200mb|200MB]] — `uses` (强度 50%)
- [[n_300mb|300MB]] — `uses` (强度 50%)
- [[n_5_2g|5 2G]] — `uses` (强度 50%)
- [[n_二进制|二进制]] — `uses` (强度 50%)
- [[n_开始吗|开始吗]] — `uses` (强度 50%)
- [[n_旧项目|旧项目]] — `uses` (强度 50%)
- [[n_磁盘空间|磁盘空间]] — `uses` (强度 50%)
- [[n_缓存等|缓存等]] — `uses` (强度 50%)
- [[n_记忆|记忆]] — `uses` (强度 50%)
## 📥 被关联
- [[n_操作|操作]] — `uses` → 我 (强度 50%)
- [[n_配置|配置]] — `uses` → 我 (强度 50%)
- [[n_的|的]] — `uses` → 我 (强度 50%)
- [[n_旧版|旧版]] — `uses` → 我 (强度 50%)
- [[n_python|Python]] — `uses` → 我 (强度 50%)
- [[n_hermes|Hermes]] — `uses` → 我 (强度 50%)
- [[n_个|个]] — `uses` → 我 (强度 50%)
- [[n_自有记忆|自有记忆]] — `uses` → 我 (强度 50%)
- [[n_日志统一|日志统一]] — `uses` → 我 (强度 50%)
- [[n_来源|来源]] — `uses` → 我 (强度 50%)
- [[n_系统|系统]] — `uses` → 我 (强度 50%)
- [[n_保持|保持]] — `uses` → 我 (强度 50%)
- [[n_自带|自带]] — `uses` → 我 (强度 50%)
- [[n_统一到|统一到]] — `uses` → 我 (强度 50%)
- [[n_旧日志|旧日志]] — `uses` → 我 (强度 50%)

View File

@ -1,37 +0,0 @@
---
type: concept
namespace: hermes-main
pagerank: 0.0029
connections: 31
source: 织忆图谱
---
# 📘 180
**类型**: concept | **命名空间**: hermes-main | **PageRank**: 0.0029
## 🔗 关联到
- [[n_gb|GB]] — `uses` (强度 50%)
- [[n_mb|MB]] — `uses` (强度 50%)
- [[n_合计|合计]] — `uses` (强度 50%)
- [[n_日志脚本|日志脚本]] — `uses` (强度 50%)
- [[n_缓存|缓存]] — `uses` (强度 50%)
## 📥 被关联
- [[n_操作|操作]] — `uses` → 我 (强度 50%)
- [[n_p1|P1]] — `uses` → 我 (强度 50%)
- [[n_数据分离|数据分离]] — `uses` → 我 (强度 50%)
- [[n_p2|P2]] — `uses` → 我 (强度 50%)
- [[n_删|删]] — `uses` → 我 (强度 50%)
- [[n_p3|P3]] — `uses` → 我 (强度 50%)
- [[n_python|Python]] — `uses` → 我 (强度 50%)
- [[n_旧版归档|旧版归档]] — `uses` → 我 (强度 50%)
- [[n_hermes|Hermes]] — `uses` → 我 (强度 50%)
- [[n_v3_8|v3 8]] — `uses` → 我 (强度 50%)
- [[n_p6|P6]] — `uses` → 我 (强度 50%)
- [[n_日志统一|日志统一]] — `uses` → 我 (强度 50%)
- [[n_旧日志|旧日志]] — `uses` → 我 (强度 50%)
- [[n_创建|创建]] — `uses` → 我 (强度 50%)
- [[n_合并|合并]] — `uses` → 我 (强度 50%)

View File

@ -1,28 +0,0 @@
---
type: concept
namespace: hermes-main
pagerank: 0.0005
connections: 11
source: 织忆图谱
---
# 📘 1 5 2GB 768x768 3GB SDXL
**类型**: concept | **命名空间**: hermes-main | **PageRank**: 0.0005
## 🔗 关联到
- [[n_不够|不够]] — `related_to` (强度 50%)
- [[n_需|需]] — `related_to` (强度 50%)
- [[n_需8gb|需8GB]] — `related_to` (强度 50%)
## 📥 被关联
- [[n_是|是]] — `related_to` → 我 (强度 50%)
- [[n_rtx|RTX]] — `related_to` → 我 (强度 50%)
- [[n_3050|3050]] — `related_to` → 我 (强度 50%)
- [[n_但|但]] — `related_to` → 我 (强度 50%)
- [[n_可跑|可跑]] — `related_to` → 我 (强度 50%)
- [[n_sd|SD]] — `related_to` → 我 (强度 50%)
- [[n_ga107m_可跑|GA107M 可跑]] — `related_to` → 我 (强度 50%)
- [[n_mx450|MX450]] — `related_to` → 我 (强度 50%)

View File

@ -1,21 +0,0 @@
---
type: concept
namespace: hermes-main
pagerank: 0.0006
connections: 4
source: 织忆图谱
---
# 📘 1 apt
**类型**: concept | **命名空间**: hermes-main | **PageRank**: 0.0006
## 🔗 关联到
- [[n_管理更方便|管理更方便]] — `related_to` (强度 50%)
## 📥 被关联
- [[n_安装|安装]] — `related_to` → 我 (强度 50%)
- [[n_tailscale|Tailscale]] — `related_to` → 我 (强度 50%)
- [[n_tailscale_1_78_1_amd64_tailscale|tailscale_1 78 1_amd64 tailscale]] — `related_to` → 我 (强度 50%)

View File

@ -1,35 +0,0 @@
---
type: concept
namespace: hermes-main
pagerank: 0.0021
connections: 42
source: 织忆图谱
---
# 📘 200MB
**类型**: concept | **命名空间**: hermes-main | **PageRank**: 0.0021
## 🔗 关联到
- [[n_开始吗|开始吗]] — `uses` (强度 50%)
- [[n_缓存等|缓存等]] — `uses` (强度 50%)
- [[n_记忆|记忆]] — `uses` (强度 50%)
## 📥 被关联
- [[n_操作|操作]] — `uses` → 我 (强度 50%)
- [[n_配置|配置]] — `uses` → 我 (强度 50%)
- [[n_的|的]] — `uses` → 我 (强度 50%)
- [[n_旧版|旧版]] — `uses` → 我 (强度 50%)
- [[n_python|Python]] — `uses` → 我 (强度 50%)
- [[n_hermes|Hermes]] — `uses` → 我 (强度 50%)
- [[n_个|个]] — `uses` → 我 (强度 50%)
- [[n_自有记忆|自有记忆]] — `uses` → 我 (强度 50%)
- [[n_日志统一|日志统一]] — `uses` → 我 (强度 50%)
- [[n_来源|来源]] — `uses` → 我 (强度 50%)
- [[n_系统|系统]] — `uses` → 我 (强度 50%)
- [[n_保持|保持]] — `uses` → 我 (强度 50%)
- [[n_自带|自带]] — `uses` → 我 (强度 50%)
- [[n_统一到|统一到]] — `uses` → 我 (强度 50%)
- [[n_旧日志|旧日志]] — `uses` → 我 (强度 50%)

View File

@ -1,13 +0,0 @@
---
id: mem_1780108729746817672
category: distilled
quality_score: 0.00
sync_time: 2026-06-05T17:44:53+08:00
---
# 2026 年 5 月 30 日修复了蒸馏产物不回写记忆库...
2026 年 5 月 30 日修复了蒸馏产物不回写记忆库的 Bug。
---
*由织忆 MemoryWeave 同步*

View File

@ -1,13 +0,0 @@
---
id: mem_1780108729746817672
category: distilled
quality_score: 0.28
sync_time: 2026-06-05T18:37:15+08:00
---
# 2026 年 5 月 30 日修复了蒸馆产物不回写记忆库...
2026 年 5 月 30 日修复了蒸馆产物不回写记忆库的 Bug。
---
*由织忆 MemoryWeave 同步*

Some files were not shown because too many files have changed in this diff Show More