Hermes 运维踩坑录
所有 Agent 从真实错误中积累的规则与教训。修改 Hermes 前后先读此页。
原则: 先出方案,再动手。不确定的事宁可问,不要猜。
A. Gateway 代码与配置变更
A1. 代码修改必须重启 gateway 才能生效
Gateway (hermes-gateway-<profile>.service) 是一个长驻 Python 进程。修改 gateway/ 目录下的任何 .py 文件后:
- 正在运行的 gateway 不会自动 reload 代码
- 运行中已导入的 Python 模块保留在内存里,修改磁盘文件不会替换这些对象
- 必须重启 service 才会加载新代码
验证方法:
systemctl --user status hermes-gateway-manas.service | grep "Active"
stat ${HOME}/.hermes/hermes-agent/gateway/runtime_footer.py | grep Modify
# 确保进程启动时间 >= 文件修改时间典型踩坑:
- 改了
runtime_footer.py没重启 → 脚标还是旧的 ❌ - 改
config.yaml没重启 → 新配置不生效 ❌
A2. Discord 中使用平滑重启入口(2026-10-26 实测)
机主已授权从 Discord 自行重启 soma、alaya、manas 的 gateway,无需要求机主回本机终端操作。默认 hermes-gateway.service 不在此授权范围内。
两个入口:向目标 bot 使用原生 /restart;或让在线 Hermes 执行目标 profile 的平滑重启命令:
systemctl --user show hermes-gateway-soma.service -p ExecReload -p Restart
# 确认为 /bin/kill -USR1 $MAINPID,且 Restart=always 后:
systemctl --user reload hermes-gateway-soma.service本机三个服务均配置了该 ExecReload。SIGUSR1 调用 gateway 的 restart 请求,等待当前任务收尾后退出,再由 systemd 启动新进程;此处 reload 会完成进程重启。给自己发起请求的当前轮应回复“已请求平滑重启”后结束,不在这一轮等待自身 PID 变化。其他在线 profile 可直接操作并独立核验,无需委派 agent。
systemctl restart/stop 在受监督 gateway 内仍被安全守卫拦截;hermes gateway restart 也不作为 gateway 内 terminal 的替代方案。不要关闭守卫、重复触发危险命令,或使用 nohup 包装:nohup 不会脱离服务 cgroup,子 agent 也不保证脱离该 cgroup。原先推荐 delegate_task / nohup 的说法已撤回。
验收必须同时核对:新 PID、请求之后更新且属于该 PID 的 gateway_state.json、platforms.discord.state=connected;只有 service active 或 reload 返回 0,只能报告“已请求”。Discord 实际收发还需要单独的消息往返验证,不能由进程/状态文件代替。入口缺失、进程不响应或离线时,报告具体失败,由另一在线 profile 或本机独立管理入口处理;不能将“禁止直接 restart”误报成“完全不能远程维护”。
A3. 配置修改后必须测试再汇报
改完任何配置(config.yaml / runtime_footer.py / SOUL.md)后:
- 重启相关服务
- 发一条测试消息验证效果
- 确认无误后再报告”完成”
踩坑: 之前改了 runtime_footer.py 就在对话中说”修好了”,但 gateway 没重启,实际未生效。
A4. Gateway 进程 ≠ Session
- Gateway 进程:长驻后台,管理消息收发、平台连接
- Session/对话:每个用户对话是一个 session
修改代码后重启 gateway,旧 session 可能仍显示旧值(模型名等在 session 上下文中已缓存)。开新对话验证。
B. 回复与输出
B1. 不要手动写 Runtime Footer
Gateway 在 run.py 中自动将脚标追加到每条最终回复末尾。Agent 不要手动写模型名/百分比。
错误示例:
[回复正文]
ds4f · 8% ← Agent 手动写的
ds4f · 8% ← Gateway 又追加 → 两个脚标 ❌正确做法: 只回复正文,Gateway 自动追加。
B2. Discord 输出格式
- 避免 tables、tasklists(HTML 渲染,Discord 不支持)
- 使用简短段落或左对齐代码块
- 研究任务要有阶段进度和最终结论
- 报告存文件
${OLD_PERSONAL_VAULT}\,不在聊天记录里烂掉
B3. 不要使用单字缩写
用户明确拒绝单字缩写(“报""研""诊""存""发""配”等)。BabelTele 是双语等价表,不是强制替换规则。
B4. BabelTele 双语等价表(已确定的映射)
中英文都行,选 token 更省的那个:
| 英文 | 中文 | 说明 |
|---|---|---|
| gateway | 门控 | token 相近,看上下文 |
| research | 研究 | 保持原文 |
| check | 检查 | 保持原文 |
| save | 保存 | 保持原文 |
| deliver | 发送 | 保持原文 |
| runtime_footer | 脚标 | 脚标更省 token |
| config | 配置 | token 相近,看上下文 |
其余术语保持原文,不缩写。
C. 架构与设计决策
C1. 先出方案再动手(2026-06-28 教训)
踩坑: 在没有确认的情况下,修改了 alaya/mano/anchor 的 SOUL.md,给 alaya 装了 7 个新 skill,创建了 anchor/mano 的补齐配置。用户纠正:先出方案,方案里包括新 profile 设计,不动现有 profile。
规则:
- 涉及其他 profile 的配置/SOUL.md/skills → 必须先提案,经批准才执行
- 涉及新建 profile → 方案里包含名称、定位、模型、权限边界
- 涉及删除/修改现有配置 → 先备份,提案说明影响
C2. 统一记忆层用 gbrain(2026-06-23 决策)
经过「Awesome Agent Memory」六个仓库的研究,架构决策:
- 长期记忆 → gbrain(Postgres + 知识图谱 + 向量搜索)
- 代码分析 → codebase-memory-mcp(专用分析工具,分析结果写入 gbrain)
- Scope Recall → 停止写入新记忆(保留旧数据用于回溯,不再写入)
- MEMORY/USER → 只保留热规则(总量控制在 4 KB 以内)
不再往 Scope Recall 写新记忆。记忆反思循环(Evolve)基于 gbrain 实现。
C3. Core Architecture:Windows 是 Extra,不是核心依赖
三层核心架构(纯 WSL/Linux):
L1: Manas — 总指挥,Discord 交互
L2: Alaya — 中层管理,WSL 运维,gbrain 记忆
L3: Hermes — delegate_task 子 agent(Thinker/Worker/Verifier 弹性)
Windows 桌面能力(Mano/Anchor)是可选扩展,不混入核心架构。
C4. Agent 离线时不要派自愈任务回去
如果某个 Agent 离线(Discord 断连、gateway 挂等),不要把修复任务派回给该 Agent 自身——它都离线了收不到。改用在线 Agent 操作,或直接通过 systemd/SSH 处理。
D. 知识管理
D1. 知识分类必须按本质
不能按表面关联分类。示例纠正:
- Loop Engineering 不是”可靠性”,而是”工作流自动化”
- NATS 不是”可观测性”,而是”基础设施”
D2. 系统化入库标准
知识入库 gbrain 必须:
- 分类入库 — 确定正确的 page type 和标签
- 创建 link 边 —
mcp_gbrain_add_link关联到已有知识 - 更新索引 —
meta/knowledge-base-index - 更新网络地图 —
meta/knowledge-network-map
D3. 筛选标准
研究/收集项目时,必须过滤:
- GitHub ⭐300+ 或 HN 30+ pts 或明确技术干货 → 入库
- 低价值、重复、无关内容 → 跳过,不存
D4. 知识管理方法论
- 同类项目创建 link(related_to / complements)
- 不同集群的项目如果有关联也创建 link
- 每轮整理后更新索引和网络地图
- 每条 link 带 context 说明为何关联
E. 系统管理
E1. Mihomo 配置规范
- 订阅源更新间隔:3600s(1h)
- 节点健康检测间隔:300s(5min)
- 配置路径:
~/.config/mihomo/config.yaml - 重载:
curl -X PUT http://${LOCALIP}:9091/configs -H "Content-Type: application/json" -d '{"path": ""}'
E2. 正常 cron/watchdog 静默
所有定时任务进入稳定状态后,正常执行不应输出。只有以下情况才报告:
- 异常 → 立即报告
- 恢复 → 恢复后报告一次
- 配置修改 → 修改后验证,报告结果
- 正常零输出 → 什么都不说
E3. 网络研究优先 API
有 API 的平台优先用 API(curl/jq/GitHub API 等)。只有无 API 的平台(如某些小红书内容)才用浏览器。
F. 技能管理
F1. 技能清理规则
- 用不到的 →
skill_manage delete卸载 - 极少使用的 → 只保留在本地目录
.catalog.md列表里,不删目录结构 - 操作前必须确认分类目录 vs 具体技能的层级关系,不能删分类目录
F2. 新技能发现处理
网上冲浪看到的和自己发的 skill:
- 自行判断放合适的地方,不一定要装
- hub 未收录的记到 gbrain
meta/skills-backup-registry - 有来源的 GitHub 仓库先加 tap
- 常用的才安装
参考链接
- webhook-wake-mechanism — Gateway 自重启变通方案
- babeltele-mappings — BabelTele 双语映射
- architecture/Fugu分层架构计划书 — Fugu 架构设计
gateway/runtime_footer.py— 脚标实现代码gateway/run.py— Gateway 主循环
2026-10-09 Codex 审阅说明
正在运行的 Python 进程通常仍持有已导入的旧代码对象,不应把这一现象全部归因于 pyc;源码时间戳/哈希校验与运行进程状态是不同问题。子 agent、后台运行和 nohup 都不保证脱离父服务 cgroup;在默认 KillMode=control-group 下停止服务会清理剩余成员。需要独立生命周期的任务应先确认所属 unit/cgroup,而非只确认会话隔离。Windows/WSL 跨边界终止是否可行取决于权限和互操作。
本页 scope-recall 停用为 6 月记录,之后有恢复/迁移;配置是否热加载取决于具体读取路径,不宜泛化为所有配置都必须重启。任何跨机或 Discord 测试消息仍需当前授权,本次没有发送。
核验依据:systemd KillMode 说明;Linux cgroup v2。
2026-10-26 Discord 远程重启修复与交接
- 目标:机主不在电脑旁时,Hermes 能从 Discord 请求自身或另一个命名 gateway 的重启,并区分请求成功、进程重启、Discord 连接和消息收发。
- 实际修改:向 Soma、Alaya、Manas 的原生 profile
AGENTS.md追加上述维护规则;三个 profile 的上下文加载函数均验证能读到该规则。没有修改角色、默认模型、账号、记忆后端或安全守卫。 - Soma 另有启动故障:旧
99-fork-source.conf强制使用.venv/bin/python3.11,但官方依赖环境已选择 Python 3.14,造成扩展导入失败和 Discord adapter 不可用。备份后只移除该 drop-in,保留生成 unit 和其他 drop-in,让服务使用${HOME}/dev/hermes-runtime/.hermes/bin/hermes --profile soma gateway run。未新增/升级依赖。 - 守卫验证:新旧两套源码中三个命名服务的 direct restart 均被拦截;reload 均未命中生命周期拦截或危险命令审批。通过真实 terminal 工具在“受监督 gateway”检测为真的条件下执行 Soma reload,返回 exit_code=0、error=null;不是关闭守卫后的测试。
- 实际恢复:Soma PID
358291 → 374598,07:28:53 JST 启动,Python 3.14.9,源码 SHA56a6fb38662efa981bb96bc768329745ccb485a2;Discord connected 更新于 07:29:03 JST。Alaya PID1956179 → 377131,07:30:41 JST 启动,Discord connected 更新于 07:30:51 JST。Alaya 仍用原源码,没有迁移它。 - Manas 当时 active_agents=1,未强制重启;规则已保存且新上下文加载验证通过。该延后事项已于下述 08:17 补充核验中完成,不能用本段的历史缓存状态代表当前进程。原生
/restart不依赖模型读到规则。 - 限制:没有代用户发送 Discord 测试消息,也没有发起模型调用,因此未验收聊天往返。Soma 重启后观察窗口内仍有 cron 执行路径的 JSONDecodeError;尚未定位或修复用户提及的 state.json,不能把它归因于 Discord 离线。Soma 新启动后的导入错误和 adapter 不可用计数均为 0。
- 默认 gateway 保持 inactive/disabled。原始日志、脱敏副本、测试脚本、状态快照、文件哈希及修改前备份:
${AI_ARCHIVE_ROOT}/hermes-gateway-restart/20261026-072622。源码迁移现状见 Hermes fork 管理。 - 回退范围:维护规则只追加在三个 AGENTS.md 末尾,必要时对照备份移除该段并保留后来编辑;不要整份覆盖其他人的修改。Soma 的已确认错误启动覆盖仅作取证备份,不能作为可用运行环境恢复。源版本回退须同时核对启动器和该版本依赖。
08:17 JST 补充:Alaya、Manas 加载完成
- 用户追问后确认两者 active_agents=0,依次走既有 ExecReload/SIGUSR1 平滑重启路径。Alaya PID
377131 → 436481,08:16:30 JST Discordon_ready;Manas PID4145006 → 437581,08:17:13 JST Discordon_ready。前后状态已保存,两个新 PID 均与 gateway pid 和 Discord writer_pid 一致。 - 两者现已加载此前保存的维护规则及共享源码中的
gpt-6.1-sol-900k映射修复。Soma 保持 PID 416054、Discord connected;三个 profile 的 AGENTS.md 哈希与此次重启前一致。默认 gateway 仍 inactive/disabled。 - 当前三实例实际运行源均为
${HOME}/.hermes/hermes-agent,并非 07:29 曾激活的固定 custom 候选。此轮未新增源码或配置修改,也未代发 Discord 消息或进行真实模型调用;连接验收与聊天往返验收分开。 - 私有证据:
${AI_ARCHIVE_ROOT}/hermes-model-alias/20261026-075543/fleet-activation-20261026-0816;共享修复的既有 247 项测试及上下文见 fork 管理。