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)后:

  1. 重启相关服务
  2. 发一条测试消息验证效果
  3. 确认无误后再报告”完成”

踩坑: 之前改了 runtime_footer.py 就在对话中说”修好了”,但 gateway 没重启,实际未生效。

A4. Gateway 进程 ≠ Session

  • Gateway 进程:长驻后台,管理消息收发、平台连接
  • Session/对话:每个用户对话是一个 session

修改代码后重启 gateway,旧 session 可能仍显示旧值(模型名等在 session 上下文中已缓存)。开新对话验证。


B. 回复与输出

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 必须:

  1. 分类入库 — 确定正确的 page type 和标签
  2. 创建 link 边 — mcp_gbrain_add_link 关联到已有知识
  3. 更新索引 — meta/knowledge-base-index
  4. 更新网络地图 — meta/knowledge-network-map

D3. 筛选标准

研究/收集项目时,必须过滤:

  • GitHub ⭐300+ 或 HN 30+ pts 或明确技术干货 → 入库
  • 低价值、重复、无关内容 → 跳过,不存

D4. 知识管理方法论

  1. 同类项目创建 link(related_to / complements)
  2. 不同集群的项目如果有关联也创建 link
  3. 每轮整理后更新索引和网络地图
  4. 每条 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
  • 常用的才安装

参考链接

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/python 3.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,源码 SHA 56a6fb38662efa981bb96bc768329745ccb485a2;Discord connected 更新于 07:29:03 JST。Alaya PID 1956179 → 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 Discord on_ready;Manas PID 4145006 → 437581,08:17:13 JST Discord on_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 管理。