Hermes Agent 备份瘦身实战
背景
Hermes Agent 是一个开源 AI Agent 框架,部署在本地 Linux 主机上,通过微信、QQ、元宝等多平台提供服务。整个运行环境包括:
- Hermes 源码与配置(
~/.hermes/) - 会话数据库(
state.db,约 140MB) - TDAI 记忆网关(独立服务,数据量较小)
- 技能、脚本、插件等扩展
备份由 cron 每天凌晨 3:00 自动执行,脚本负责:调用 hermes backup 打包 → 合并 TDAI 数据 → 加密 → 上传 OpenList WebDAV 远程存储 → 清理旧包。
问题发现
某天检查备份时,发现一个 1.5GB 的异常 zip 包,而正常备份通常只有 67~89MB。更诡异的是,用 Python zipfile 模块打不开它——中央目录损坏,仅 1 个条目且文件名乱码。
进一步排查发现这不是唯一的问题:
1 | 正常备份: hermes-full-20260528_030012.tar.enc (78.6 MB) |
根因分析
第一层:循环打包
hermes backup 默认将 zip 输出到 ~/hermes-backup-*.zip。备份脚本用 glob.glob(BACKUP_NAME + "*.zip") 匹配产物——但这同时匹配到了昨天的旧备份包。旧包被重新打进新 zip,新包又被明天的打包进去,体积指数膨胀。
1 | hermes-backup-2026-05-29.zip (内含 hermes-backup-2026-05-28.zip) |
修复:将输出路径改为 /tmp/,打包完成后用 shutil.move() 移回,彻底隔离输入输出。
第二层:未排除缓存目录
hermes backup 扫描 ~/.hermes/ 全目录,没有排除浏览器缓存、npm 缓存等可再生数据:
| 目录 | 大小 | 说明 |
|---|---|---|
.agent-browser/browsers/ |
266 MB | Chromium 浏览器二进制 |
.npm-global/ + .npm/ |
1.7 GB | npm 缓存 |
node_modules/ |
- | JS 依赖(可重装) |
cache/ + .cache/ |
306 MB | 各类临时缓存 |
backups/ |
- | 旧备份包(防套娃) |
logs/ |
- | 日志文件 |
checkpoints/ |
- | 文件系统快照 |
解决方案
修改 hermes backup 排除规则
直接修改 Hermes 源码 /opt/hermes/hermes_cli/backup.py 中的排除变量:
1 | _EXCLUDED_DIRS = { |
排除逻辑在 _should_exclude() 函数中实现——对路径的每一级组件做精确匹配,确保 cache/ 和 .cache/ 都被正确过滤,同时不影响包含 cache 子串的正常文件名(如 models_dev_cache.json)。
修复备份脚本
1 | # 之前:输出到当前目录,被 glob 匹配到 |
同时将超时从 300s 提升到 900s——优化后扫描 2291 个文件仍需约 538 秒。
调整保留策略
1 | LOCAL_KEEP = 1 # 本地只保留最新 1 份(从 3 改为 1) |
优化后备份包仅 111MB,本地留 1 份足够,远程 7 份提供回滚空间。
效果
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 备份包大小 | 1.5 GB(异常) | 111 MB |
| 扫描文件数 | 22,768 | 2,291 |
| 压缩耗时 | >300s(超时) | ~538s(含扫描) |
| 核心数据保留 | - | ✅ state.db、.env、sessions、skills、scripts |
排除规则速查
1 | 排除项 类型 备注 |
经验总结
- 备份的输入和输出必须物理隔离——不要让打包工具扫描自己的产物
- 排除规则是第一道防线——缓存、日志、可再生数据不该进备份
- 加密文件无法用常规工具校验——zip 的完整性检查对
.tar.enc无意义,需要解密后验证 - SQLite WAL 文件需注意——
.db-wal和.db-shm是 SQLite 的事务日志,正常备份时应排除(恢复时数据库本身已包含一致状态) - 修改源码比脚本 hack 更可靠——临时移走目录再恢复的方案容易在异常退出时丢数据,直接改排除规则一劳永逸
📝 本文由 AI 助手诺亚辅助生成

