文章

给 AI 记忆留一条退路

我为 Codex 和 Hermes 整理项目记忆、私有文档与敏感配置,做了一套带版本快照和恢复演练的备份方案。

我最近做了一件看起来很像整理文件,实际更接近整理工作方式的事。

我给 Codex 和 Hermes 做了一套项目记忆备份。

起因很简单。我一直担心电脑坏掉以后,代码仓库还能从远端拿回来,可那些让 AI 理解项目的东西未必还在。一次排错留下的结论,某个项目的本地运维说明,Codex 记忆里积累的上下文,Hermes 记住的协作习惯,这些内容如果只存在本机,硬盘一坏就要重新解释一遍。

更麻烦的是,它们原来不在同一个地方。

记忆并不只有一种

我以前把 AI 的记忆想得太简单,以为只要保留一个 Memory 文件,问题就解决了。实际工作以后,至少能看到几种不同的东西。

Codex 有自己的记忆目录,里面有总结文件、原始整理和按任务留下的记录。这个目录本身还有本地 Git 历史,所以它能回到过去的版本。可本地 Git 仍然在本机里,电脑坏掉时,历史也会一起消失。

Hermes 有自己的跨会话记忆和用户资料。它们比完整聊天记录小得多,却决定了新会话能不能延续原来的协作方式。

项目仓库里的 AGENTS.md、架构文档、经验记录和 ADR,则是另一层知识。它们应该跟着代码走,不能只放进某个 Agent 的全局记忆里。

还有一类是本机专用文档。比如部署说明、回滚步骤和本地服务的操作手册。这些东西不适合提交到公开仓库,却又不能因为保密就永远只留在一台电脑上。

我最后采用了一个简单的判断。

项目的长期规则放项目里。跨项目的协作偏好放 Agent 记忆里。本机专用的运维资料放私有备份里。聊天记录和运行时数据库则单独看待,不把它们冒充成项目知识。

先建一个自己的根目录

备份一开始就遇到一个边界问题。

cc-switch 已经有自己的 WebDAV 同步目录。如果直接把 Hermes 的内容塞进去,短期很方便,长期却会让两个系统的责任混在一起。以后谁要恢复,谁负责解释里面的文件,很快就会变成问题。

所以我在私有 WebDAV 根下单独建了一个 Hermes 目录。它是 Hermes 这套恢复体系自己的根,不占用 cc-switch 的同步空间。

这个目录下面保存几种东西。

  • 当前的知识树,方便平时读取
  • 带日期和清单哈希的历史快照,方便回滚
  • 备份范围和恢复说明,方便其他 AI 接手
  • 备份与恢复脚本,避免恢复时还要重新设计工具
  • 独立的加密恢复包目录,专门放认证配置

根目录里有一份 BACKUP_AND_RESTORE.md。它写清楚来源、去向、排除项、恢复顺序和验证方式。另有一份机器可读的范围清单,脚本不靠模型猜测哪些文件应该上传。

这份文档的作用比看起来重要。换一台电脑以后,其他 AI 只要先读它,就能知道哪些内容属于 Codex,哪些内容属于 Hermes,哪些内容是项目本地资料,也能知道哪些东西当初被刻意排除。

普通知识备份要先过扫描

普通备份没有把整个用户目录打包进去。脚本按固定清单读取来源,再做两层检查。

第一层是路径检查。环境文件、认证文件、数据库、会话目录、日志、缓存、私钥和 Token 文件都不会进入普通知识树。

第二层是内容检查。即使一个文件名字看起来普通,里面出现私钥块、带值的密码字段、Token 形态的字符串或带认证信息的 URL,也会阻止这一批上传。报告只写来源、相对文件名、行号和风险类型,不把匹配到的内容打印出来。

这一步最初还拦住过恢复脚本自己的代码。脚本里有 password 这样的变量名,扫描器一开始把函数参数和 getpass 调用当成了真实秘密。修正以后,代码里的函数定义和函数返回值会被识别为代码,实际字面量赋值仍然会被拦截。还用一个合成 Token 做了反向测试,确认扫描器确实能挡住风险。

首轮全量备份包含 249 个文件,约 1.83 MB。上传以后,脚本再次从远端读取当前清单,逐个校验 SHA-256。

备份不能只有一个最新版本

只保存一个最新目录,遇到误覆盖时仍然不够。

现在的备份每六小时运行一次。没有变化时保持静默,不消耗 LLM token。内容有变化时,脚本更新当前知识树,并生成带日期和清单哈希的每日、每周快照。

清单哈希有一个实际作用。同一天内如果文档改了两次,第二次会产生新的快照目录,不会把当天第一次的版本覆盖掉。

脚本也不会主动删除旧快照。清理策略需要等恢复测试跑过几轮以后再定,不能先把回滚点删掉,再假设备份永远可靠。

我更愿意让备份稍微多占一些空间,也不愿意到了需要恢复时,发现最新版本正好是坏的那一份。

恢复要先落到临时目录

恢复脚本没有设计成一运行就覆盖本机。

它有几种模式。

--list 只读取清单。--verify 下载文件并重新计算哈希。--stage 把内容恢复到临时目录,供人或其他 AI 检查。最后的 --apply 才会写回 Codex、Hermes 和项目本地文档。

执行 --apply 之前,脚本会把本机已有文件保存到带时间的回滚目录。它不会自动删除目标文件,也不会因为某个项目目录缺失就猜一个新的位置。换了硬盘或盘符时,需要明确提供新的路径映射。

这套流程后来做了一次完整演练。当前清单里的 249 个文件全部下载到 staging 目录,哈希检查 249 个全部通过。演练目录里能找到总说明、范围清单、恢复脚本、Codex 记忆、Hermes 记忆和两个项目的本地运维文档,也确认没有混入被排除的个人资料库。

上传成功只能说明服务器收到了文件。能把文件下载回来,并且按原清单恢复到临时目录,才算验证了备份。

认证配置必须单独加密

普通知识备份已经解决了大部分连续性问题,可它不能包含账号认证。

Codex 的认证文件、cc-switch 的设置和 OAuth 状态、Hermes 的认证与环境配置,放进普通目录会让日常同步的风险扩大。它们需要另一条路径。

我做了一个最小敏感恢复包,只收集恢复这些工具所需的十个配置或认证文件,不打包整个运行目录,也不把聊天数据库、日志和缓存塞进去。

这个包使用 AES 256 GCM 加密,密码在本机终端里输入两次。密码不会进入命令行参数,不会写入脚本,不会进入清单,也不会上传到 WebDAV。脚本在内存里完成加密,写出包以后立刻在本机解密校验,再上传到独立的 recovery-encrypted 目录。

这里有一个小插曲。电脑上后来装了 7-Zip,但它的命令行密码参数会把密码放进进程参数。压缩工具可以用,密码却不应该这样传。因此最后保留了自己的 AES 256 GCM 容器和恢复脚本。以后换电脑,只要拿到加密包、恢复脚本和自己保存的密码,就能先解密到 staging,再决定是否写回配置。

加密包生成后,我又从 WebDAV 把它完整读回来。远端和本地大小都是 1,787,711 字节,SHA-256 完全一致。这个哈希只能证明文件没有被改坏,不能替代密码,也不能让丢失的密码重新出现。

有些资料仍然不应该纳入

这套备份明确排除了我的个人资料库。它有自己的管理和同步边界,不应该因为这次整理 AI 记忆就被顺手接管。

完整的 Hermes 状态数据库和 Session 也没有进入普通知识备份。它们可能包含大量原始聊天和运行时状态,适合在确实需要整机恢复时放进另一个加密包,不适合每天和项目文档一起同步。

共享知识仓库也不负责收这些内容。共享仓库里只能放脱敏、审核过、适合跨机器复用的原则和技能。私人记忆、本地服务器信息和认证文件仍然属于个人恢复范围。

备份做得越大,未必越安全。先写清楚不备份什么,恢复时反而更容易判断哪些东西需要重新配置。

AI 的记忆应该有自己的恢复入口

这件事最后留下的,除了一个远端目录,还有一套我认为更重要的工作习惯。

每个长期项目应该有自己的文档。全局记忆只保留跨项目有效的事实和指针。私人运维说明放在私有位置。普通知识做版本化备份。认证配置做单独加密。恢复先校验,再 staging,最后才 apply。

这样以后换电脑,或者换一个 AI,不必从一堆聊天记录里猜当前项目是什么。它可以先读恢复说明,再读范围清单,再读项目知识,最后根据需要恢复认证配置。

AI 记住更多内容当然有用。可长期协作能不能稳定,取决于这些内容有没有来源和边界,版本出了问题以后能不能沿着清楚的路径找回来。

记忆的价值不只是让下一次对话少解释几句。它还应该在原来的电脑坏掉以后,仍然能够被找回来。