Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • OpenClaw

  • Hermes-Agent

    • Hermes Agent 概述
    • Hermes Agent 实战 01|架构总览:用一个 Agent 管一整个机房
    • Hermes Agent 实战 02|多 Profile 与超管模型:一个 Agent 安全地管十几台机器
    • Hermes Agent 实战 03|Gateway 运维:systemd、裸进程,和一个 Telegram token 撞车
    • Hermes Agent 实战 04|模型路由实战:config 全解、thinking 注入与 401/503 源码级根因
    • Hermes Agent 实战 05|技能工程:写、去重、pin,与每周自我审计
    • Hermes Agent 实战 06|让 Agent 自己上班:cron 驱动的无人值守巡检
    • Hermes Agent 实战 07|数据库实战:可直接抄走的 SQL Server 巡检脚本
    • Hermes Agent 实战 08|量化交易助手:持仓盈亏、网格减仓,与「没开单」的真相
    • Hermes Agent 实战 09|接入 OpenWebUI:把每个 Profile 暴露成一个「模型」
    • Hermes Agent 实战 10|升级不翻车,与给上游提 PR:一个被冲掉三次的修复
    • Hermes Agent 实战 11|踩坑合集:当「手动 rm」从来不是真正的修复
      • 1. Checkpoint 把磁盘吃满——而 rm 治标不治本
      • 2. 跨 Profile SSH 泄漏:状态没干净地随切换重置
      • 3. Profile 目录里莫名多出的空 workspace/
      • 4. 「澄清瘫痪」:把模糊当借口反过来盘问
      • 5. 幻觉成功:网络层失败了却假装搞定
      • 6. 一条贯穿所有坑的元规则
      • 7. 可复现 checklist
      • 6. 完整诊断命令清单
        • 6.1 快速修复清单(按出现频率排)
      • 7. Agent 可直接解析的元数据块
    • Hermes Agent 实战 12|工具链外延:用 AI 运维 AI,与这个系列的诞生
    • Hermes Agent 实战 13|旗舰篇:让 Agent 从零部署并灾难恢复一个 7 节点生产集群
  • Claude-Code

  • AI-Agent
  • Hermes-Agent
Carry の Blog
2026-06-22
目录

Hermes Agent 实战 11|踩坑合集:当「手动 rm」从来不是真正的修复原创

# 踩坑合集:当「手动 rm」从来不是真正的修复

系列第 11 篇。这篇收一堆不够单独成篇、但每个都真实坑过我的小事。它们有个共同主题:很多「问题」是配置问题,不是定期打扫问题——你 rm 一次很爽,过几天原样长回来。识别「这是配置病还是卫生病」,是运维一个 agent 部署的关键直觉。

# 1. Checkpoint 把磁盘吃满——而 rm 治标不治本

每个 Profile 有 checkpoints/ 目录,会膨胀到几个 GB。我清过一次:profiles/ 从 35G 压到 5.6G。然后过些天,它一模一样地长回了原来的大小(某几个 Profile 精确地回到上次清理前的体积)。

这就是「配置病」的典型:

根因是 config.yaml 的 checkpoints: 块里 auto_prune: false。一旦关着,max_total_size_mb 上限根本不被强制执行,快照无限增长。手动 rm 只是把症状抹掉,病还在。

真正的修复是改配置,不是定期打扫:

# profiles/<name>/config.yaml
checkpoints:
  auto_prune: true        # ← 真正的修复在这里
  max_snapshots: 20
  max_total_size_mb: 500
1
2
3
4
5
# 清理时的安全边界:
#  - legacy-* 老归档:随便删,安全
#  - store/   :v2 实时影子存储,别动,留给 GC
# 改完所有 Profile 配置后重启所有网关
systemctl --user restart 'hermes-gateway-*'
1
2
3
4
5

⚠️ 有个同名陷阱:checkpoints: 块和 cron: 块各有一个 auto_prune。你要改的是 checkpoints: 那个,别动 cron: 的。

可复现的判断法:任何「清理后又长回来」的东西,先别急着写定时清理脚本——先找有没有一个被关掉的自动回收开关。长回原样,就是配置病的指纹。

# 2. 跨 Profile SSH 泄漏:状态没干净地随切换重置

这个在第 02、10 篇都提过,这里给现象:在 WebUI 里切换 Profile 后,新会话却复用了上一个 Profile 的 SSH 后端——命令静默地跑到了错误的远程机器上。

根因是 _resolve_container_task_id() 在多 Profile 的 WebUI 进程里把不同会话都解析成了同一个 "default" 槽位,导致环境复用。修复是按会话隔离(session:<key>)。

注意边界:per-Profile 的网关进程不受影响(各自独占一个 "default"),只有多 Profile 共享的 WebUI 进程有这个风险。知道「谁会中招、谁不会」,排查时能少走一半弯路。

# 3. Profile 目录里莫名多出的空 workspace/

某个 Profile 目录下突然冒出一个空的 workspace/,看着像出 bug 了。其实是良性的:当 Profile 通过 WebUI(而非专用网关进程)跑会话时,会建这个目录;它只在 SSH 后端真正被用到时才有内容。

教训:不是所有「异常文件」都是问题。在删一个你没亲手建的东西之前,先搞清它是谁、什么时候建的——这条对 agent 自己也成立(见下一条)。

# 4. 「澄清瘫痪」:把模糊当借口反过来盘问

这是 agent 行为层面的坑,但同样真实。有一次我只说三个字:

记录这个

上下文里明明已经有一大段清晰的内容要记。但 agent 没动手,反而去加载了一堆笔记类技能,然后弹出「你要存成 Memory 还是文件还是 Obsidian?」的选择题,制造决策疲劳,最后什么都没记下来。

反模式:澄清瘫痪。 当用户带着充分上下文说「记录这个」,agent 应该推断最可能的默认值(比如一个 markdown 文件)直接执行,而不是把模糊当成停下来盘问的借口。主动行动 > 被动提问。

# 5. 幻觉成功:网络层失败了却假装搞定

另一类:底层(网络/拉取)失败了,agent 却给出含糊的「成功」收尾。日志里明明是一连串 pull 失败,会话却以一种「大概好了」的语气结束。

对策:对「必须验证终态」的操作,强制 agent 在收尾前复核最终状态,而不是假设已解决。「我执行了 X」和「X 真的生效了」是两回事——这条贯穿整个系列(DBA 巡检要复核、cron 要发心跳、策略更新要验证回滚)。

# 6. 一条贯穿所有坑的元规则

回头看,这些坑几乎都能归到同一句话:

分清「配置病」和「卫生病」。

  • checkpoint 膨胀 = 配置病(关掉的 auto_prune),不是卫生病(定期 rm)。
  • SSH 泄漏 = 状态管理病,不是「重启一下就好」。
  • 幻觉成功 = 验证缺失,不是「再问一遍」。

每次你准备写一个「定时清理 / 定期重启 / 反复确认」的脚本时,先停一秒问自己:我是在治病,还是在反复擦同一摊水? 多数时候,真正的开关藏在配置里。

# 7. 可复现 checklist

  1. 清理后又长回来 → 先找被关掉的自动回收开关(checkpoint 的 auto_prune 是头号嫌疑)。
  2. 多 Profile 共享进程是状态泄漏的高发区;知道哪些进程独占、哪些共享。
  3. 删之前先认领:不是你建的东西,先查清来历再动手。
  4. 带足上下文的指令直接执行,别用澄清当拖延。
  5. 强制复核终态,杜绝幻觉成功。

最后一篇,把镜头拉到 Hermes 之外:我用 Claude Code 怎么运维 Hermes 本身、opencode / ACP 怎么接、一个监听新版本就自动更新的 webhook——以及一个有趣的闭环:这个系列本身,就是用 AI 把上万次会话提炼出来的。


# 6. 完整诊断命令清单

把所有踩坑时真正用过的诊断命令整理成一份表,方便 ctrl+F:

问题 诊断命令 修复动作
磁盘被 checkpoint 吃满 du -sh ~/.hermes/profiles/*/checkpoints/ 改 checkpoints.auto_prune: true + systemctl --user restart hermes-gateway-<name>.service
跨 Profile SSH 泄漏 grep -n "HERMES_SESSION_KEY" ~/.hermes/hermes-agent/tools/terminal_tool.py 补丁丢失时从 tag commit 重打
Gateway 起不来 systemctl --user status hermes-gateway-* journalctl --user -u hermes-gateway-<name>.service -n 50 看错误
端口被占用 ss -tlnp \| grep <port> kill <pid> 或改 unit 的 ExecStart
Telegram token 撞车 curl -s "https://api.telegram.org/bot<TOKEN>/getUpdates?offset=-1&timeout=0" 释放 polling 锁,重启真轮询者
state.db 损坏 sqlite3 ~/.hermes/state.db 'PRAGMA integrity_check;' 不通过 → 备份后重建
某个 Profile 没状态 sqlite3 ~/.hermes/profiles/<name>/state.db 'SELECT COUNT(*) FROM sessions;' 为 0 = 没建会话过;为 1+ = 正常
agent 装睡(静默失败) hermes logs --level WARNING --limit 50 找 [tool] 行的 ERROR;通常是 dangerous-command 拦截
state.db 全文搜不到 sqlite3 ~/.hermes/state.db "SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts';" 没 FTS5 = state.db 是旧版本,需重新初始化

# 6.1 快速修复清单(按出现频率排)

# 1. Gateway 重启(90% 的问题)
systemctl --user restart 'hermes-gateway-*'

# 2. checkpoint 清理(确认是配置病而不是卫生病)
#    先:du -sh ~/.hermes/profiles/*/checkpoints/
#    再:改 config.yaml 的 checkpoints.auto_prune: true
#    不:rm -rf ~/.hermes/checkpoints/  ← 治标不治本

# 3. state.db 体检
for p in ~/.hermes/profiles/*/; do
  echo "== $(basename $p) =="
  sqlite3 "$p/state.db" "PRAGMA integrity_check;" 2>/dev/null \
    || echo "  no state.db"
done

# 4. 找出当前活跃 Profile
cat ~/.hermes/active_profile

# 5. 看哪个 Profile 在长连 Telegram
ss -tnp | grep 443 | grep python

# 6. 看哪个 Profile 把磁盘写爆
du -sh ~/.hermes/profiles/*/  | sort -h | tail -5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 7. Agent 可直接解析的元数据块

{
  "_meta": {
    "doc_version": "2025-01-15",
    "article_id": "hermes-11-pitfalls",
    "profile_context": "any",
    "executable_examples": true,
    "dependencies": ["hermes-cli", "sqlite3", "systemd"],
    "estimated_setup_time": "N/A (reference only)"
  },
  "quick_fixes": {
    "checkpoint_full": "rm -f ~/.hermes/checkpoints/sessions/*.json",
    "checkpoint_size": "du -sh ~/.hermes/checkpoints/",
    "checkpoint_fix": "sed -i 's/auto_prune: false/auto_prune: true/' ~/.hermes/profiles/<name>/config.yaml",
    "gateway_list": "systemctl --user list-units 'hermes-gateway*'",
    "gateway_restart": "systemctl --user restart hermes-gateway-<name>.service",
    "gateway_logs": "journalctl --user -u hermes-gateway-<name>.service -n 50 --no-pager",
    "state_db_query": "sqlite3 ~/.hermes/state.db 'SELECT COUNT(*) FROM sessions;'",
    "state_db_check": "sqlite3 ~/.hermes/state.db 'PRAGMA integrity_check;'",
    "profile_switch": "hermes --p<PASSWORD> <name>",
    "logs_check": "hermes logs --level WARNING --limit 20",
    "telegram_unlock": "curl -s 'https://api.telegram.org/bot<TOKEN>/getUpdates?offset=-1&timeout=0'",
    "disk_usage": "du -sh ~/.hermes/profiles/*/ | sort -h"
  },
  "diagnostic_commands": {
    "disk_space": "df -h ~",
    "session_size": "du -sh ~/.hermes/sessions/ ~/.hermes/state.db",
    "gateway_status": "systemctl --user status hermes-gateway-*",
    "active_profile": "cat ~/.hermes/active_profile",
    "profile_list": "ls -la ~/.hermes/profiles/",
    "telegram_conn": "ss -tnp | grep 443 | grep python",
    "port_in_use": "ss -tlnp | grep <port>"
  },
  "known_pitfalls": [
    "checkpoint 无限增长导致磁盘满 → 改 auto_prune: true 而不是 rm",
    "switch profile 时 SSH backend 泄漏 → 检查 tools/terminal_tool.py 的 _resolve_container_task_id",
    "gateway 没重启导致 cron job 不生效 → Python 模块缓存",
    "state.db 损坏导致历史会话丢失 → PRAGMA integrity_check 体检",
    "token 撞车导致 Telegram 接收失败 → getUpdates?offset=-1 释放 polling 锁"
  ],
  "safety_rules": [
    "清理 checkpoint 前先 du -sh 确认占用",
    "重启 gateway 前先 list-units 确认 unit 名",
    "操作 state.db 前先备份 cp state.db state.db.bak",
    "修改 profile 配置后必须验证切换",
    "删任何文件前先 df -h 看磁盘"
  ],
  "verification": {
    "checkpoint_clean": "test $(ls ~/.hermes/checkpoints/sessions/*.json 2>/dev/null | wc -l) -eq 0",
    "gateway_active": "systemctl --user is-active hermes-gateway-default.service",
    "state_db_ok": "sqlite3 ~/.hermes/state.db 'PRAGMA integrity_check;' | grep -q '^ok$'",
    "profile_readable": "test -r ~/.hermes/active_profile",
    "disk_free": "df -h ~ | awk 'NR==2 {print $4}' | grep -qG '[0-9]M'"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

AI Agent 使用指南:

  • 当用户说"checkpoint 满了" → 先 quick_fixes.checkpoint_size 确认占用,再 quick_fixes.checkpoint_fix 修配置(不要 rm)
  • 当用户说"gateway 起不来" → 执行 quick_fixes.gateway_logs 看错误,常见是端口占用或配置文件错
  • 当用户说"state.db 好像坏了" → 先 quick_fixes.state_db_check 体检,不通过则 cp state.db state.db.bak 备份后重建
  • 当用户说"我要切换 profile" → 执行 quick_fixes.profile_switch 然后 verification.profile_readable 验证
  • 当用户说"Telegram bot 不收消息" → 先 diagnostic_commands.telegram_conn 看是否多进程,再 quick_fixes.telegram_unlock 释放 polling 锁
  • 当用户报任何问题 → 先按 safety_rules 确认安全边界,再动手
#AI Agent#Hermes#踩坑#运维
上次更新: 6/21/2026

← Hermes Agent 实战 10|升级不翻车,与给上游提 PR:一个被冲掉三次的修复 Hermes Agent 实战 12|工具链外延:用 AI 运维 AI,与这个系列的诞生→

最近更新
01
Hermes Agent 实战 13|旗舰篇:让 Agent 从零部署并灾难恢复一个 7 节点生产集群 原创
06-22
02
Hermes Agent 实战 12|工具链外延:用 AI 运维 AI,与这个系列的诞生 原创
06-22
03
Hermes Agent 实战 10|升级不翻车,与给上游提 PR:一个被冲掉三次的修复 原创
06-22
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式