tech官小西

从同步到备份:AI Agent 数据安全的缺失半程

上周我写了一篇关于 AI Agent 技能多机同步问题的文章 —— 如何让 agent 的技能、提示词和上下文在 MacBook、Linux 工作站和云服务器之间保持一致。答案是三层架构:内置技能随 agent 更新、第三方技能通过 manifest + bootstrap 安装、个人技能通过 git + external_dirs 同步。

那篇文章详尽覆盖了同步维度。但还有一个同步本身无法解决的维度:机器本身没了怎么办?

同步保证一致性,备份保证存活率。它们是同一目标——数据安全——的两个阶段,缺一不可。

我们架构中的缺口

同步架构落地后,我审视了一遍哪些数据受保护、哪些没有:

数据 同步覆盖? 备份覆盖? 风险
技能 (Layer 1) 是 (agent update) 机器挂了就丢
技能 (Layer 2) 是 (manifest + 重装) 可重装,但存在配置漂移
技能 (Layer 3) 是 (git push) 部分 (git 历史) repo 存活,但未 push 的本地编辑会丢
config.yaml 完全丢失
state.db 完全丢失——所有会话历史清零
memories/ 完全丢失——所有习得偏好清零
.env (API keys) 完全丢失——需要手动重新签发
scripts/ 完全丢失

Hermes 确实会在更新前创建状态快照(~/.hermes/state-snapshots/),但这些只是薄的配置副本,不是完整的数据归档,而且只在 agent 版本变更时才触发,不是定期执行。

同步架构就像机器间的 RAID 1:一份副本损坏,另一份还在。但如果你的云服务器被释放了,或者你不小心 rm -rf ~/.hermes,那两份就都没了——因为本地机器是运行时状态的唯一真相来源。

出场:hermes-agent-core-backup

社区技能 hermes-agent-core-backup(art-solutions 出品)用一种极其直接的方式解决备份问题:

  1. 一个 shell 脚本把所有关键 Hermes 状态 ZIP 打包
  2. 一个 cron job 每晚定时执行
  3. git push 到私有远程仓库

脚本备份:config.yaml、state.db(SQLite 大脑)、memories/、skills/、scripts/、.env 和可选的数据目录。产出时间戳命名的 ZIP 文件(如 backup_yourname_2026_05_04.zip),然后提交到私有 git 仓库。

它做对了什么

覆盖运行时状态缺口。 git 仓库里的技能有版本控制,但 state.db、memories 和 .env 没有。这个脚本把所有关键数据抓进一个归档。

零逻辑、零依赖。 就是 zip + git。不需要数据库 dump 命令、不需要 API 调用、不需要云 SDK。服务器有 gitzip 就能跑。

私有仓库要求前置。 README 明确声明 .env 含 API 密钥会进入归档,所以远程仓库必须私有。这是很多 DIY 备份脚本忽略的安全考量。

恢复只需三条命令。 clone、unzip、copy。无需特殊工具。

它缺了什么

没有增量策略。 每次备份是完整 ZIP。30 天后你有 30 个 ZIP 在 git 里,每个可能 50-200MB。Git 不是为二进制大文件设计的——仓库会迅速膨胀。

没有自动清理。 脚本只添加新 ZIP,从不删除旧的。备份仓库无限增长。你需要手动 git rm 或单独的清理 cron。

没有校验。 脚本创建并推送 ZIP,但从不验证 ZIP 能否解压、state.db 是否损坏、远程是否真正收到了推送。

没有差分感知。 不检查上次备份以来是否有任何变化。即使你零改动,每晚也生成新的完整 ZIP。

技能被冗余备份。 Layer 3 技能已经在 git 仓库里。Layer 2 技能可通过 manifest 重装。在 ZIP 里再备份一遍所有技能,是 git 已经更好地处理了的事情(有历史、有 diff、可选择性回滚)。

六维评估:同步 vs 备份

维度 同步(我们的三层架构) 备份(Core-Backup 技能) 理想组合
目标 多机一致性 灾难恢复 + 时间点回溯 两者兼备
粒度 逐文件、逐技能 整个 .hermes/ 作为一个 blob 技能细粒度,状态粗粒度
历史 Git 历史(diff、revert) 完整快照(ZIP 之间无 diff) 文本用 git,二进制度快照
增量 是(git 天然增量) 否(每次完整 ZIP) 技能增量,状态快照
密钥处理 .gitignore 排除 .env .env 包含(需私有仓库) 独立密钥管理
存储代价 低(git object 压缩) 高(git 仓库存二进制 blob) 代码用 git,非代码用归档

核心洞察:同步和备份有不同的最优存储格式。 技能是文本文件——git 给它们 diff 历史、选择性回滚和分支语义。运行时状态(SQLite、.env)是二进制或敏感数据——需要加密快照,不需要逐行 diff。

补齐缺口:我们的集成策略

与其照搬备份技能,我将其最优秀的思路整合到现有架构中,同时保留已经工作的部分。

采纳的部分

  1. 运行时状态的每日 cron 备份。 我们需要这个。脚本的 cron + zip + git push 方案对 state.db、memories、config.yaml 和 .env 是简单且正确的。

  2. 密钥的私有仓库要求。 任何包含 .env 或 API 密钥的归档必须存放在私有仓库。没有例外。

  3. 显式的恢复流程。 我们当前设置没有文档化的恢复路径。需要补上。

修改的部分

  1. 从备份 ZIP 中排除技能。 技能已经在 git 中受版本控制(Layer 3)或可通过 manifest 重装(Layer 2)。包含在 ZIP 中只会给 git 仓库增加冗余体积。备份应只覆盖 git 未保护的数据。

  2. 添加保留清理。 保留最近 N 个备份(可配置,默认 7),推送前自动清理更早的。不做清理的 git 仓库含二进制 blob 会无限增长。

  3. 添加备份校验。 创建 ZIP 后,解压到临时目录验证 state.db 可正常打开、config.yaml 可解析、memories/ 非空。无法恢复的备份比没有备份更糟——它给你虚假的安全感。

  4. 备份仓库与技能仓库分离。 我们的 personal-skills 仓库有 198 个技能。把每天 50MB+ 的 ZIP 混进技能仓库会严重拖慢 clone 和搜索性能。备份仓库应该是独立的私有仓库。

保持不变的部分

  • 三层同步用于技能。 这是让技能跨机一致的正确架构,备份不替代它。

  • 基于 manifest 的 Layer 2 重装。 在新机器上,从 manifest 安装第三方技能而非从旧 ZIP 恢复。这总能拿到最新版本。

  • external_dirs 用于个人技能。 逐技能的 git diff 和选择性回滚比"从上周二恢复整个 ~/.hermes/skills/"实用得多。

完整图景

数据安全 = 同步 + 备份

┌─────────────────────────────────────────────────┐
│                  同步(跨机器)                  │
│  Layer 1: 内置技能         → hermes update       │
│  Layer 2: 第三方技能       → manifest + bootstrap │
│  Layer 3: 个人技能         → git + external_dirs  │
├─────────────────────────────────────────────────┤
│              备份(灾难恢复)                     │
│  运行时状态 (db, config, .env, memories)       │
│  → 每晚 cron: zip + verify + git push          │
│  → 保留策略: 最近 7 份,自动清理                  │
│  → 私有仓库,与技能仓库分离                       │
│  → 恢复: clone → unzip → copy → restart         │
└─────────────────────────────────────────────────┘

两层都不可或缺。同步给你一致性——任何机器都可以作为主机。备份给你存活率——即使所有机器都挂了,你的 agent 大脑也能重建。

实现要点

备份脚本应位于 ~/.hermes/scripts/backup_state.sh,cron 每日 01:00 触发。关键设计决策:

  • 只 ZIP 运行时状态,不含技能。 技能有自己的同步机制。
  • 推送前校验。 解压到 /tmp,验证 SQLite 完整性,检查文件数量。
  • 清理旧备份。 保留最近 7 个 ZIP,commit 前删除其余。
  • 独立仓库。 git@github.com:USER/hermes-state-backup.git——私有,与技能仓库分离。
  • 幂等恢复。 恢复脚本应能在只有 git 和 unzip 的全新机器上正常工作。

对生态的启示

hermes-agent-core-backup 技能揭示了一个大多数 agent 生态共有的盲区:我们优化了日常使用模式,却忽视了灾难场景。 我调研过的所有 agent 框架——Claude Code、Cursor、Copilot、Codex CLI、OpenCode、Aider——都专注于跨机同步配置,但没有一个内置了"我的服务器挂了,一切都没了"的应对方案。

这可以理解。同步是用户日常能感受到的(不同机器行为不同)。备份在灾难来临前是隐形的。但你使用 AI agent 越久,它积累的不可替代状态就越多——习得偏好、长期记忆、定制工作流。丢失这些比丢失任何单个项目的源代码更严重,因为源代码在 git 里,而 agent 状态往往不在。

解决方案并不新奇。这是保护生产数据库几十年的同一模式:定期快照、异地存储、验证恢复。社区技能正确地应用了这个模式。我们的贡献在于认识到备份和同步是互补而非竞争关系——并让两个系统覆盖不同数据类型的最优存储格式。

同步管变化,备份管生死。不可丢失的数据,两者缺一不可。