一晚上的时间,我的 AI 把我的账本弄丢过、把不该删的文章删了、还在一本正经地报告「已经补录」。
这篇不是检讨书,是把过程记下来:一个看起来在正常工作的系统,是怎么在没人察觉的情况下坏掉的,以及最后用什么办法兜住。
那晚对账,我盯着 11 月 1 日的微信消费:
支出 40.34,账本里没有。
它给我的解释很自然:那天忘了记。
因为在当天的对话里,它确实说过「已补录」「照你说的补录进账本了」。这里有个很典型的错位——它把自己说过的话,当成了做过的证据。
于是我让它补上。
这一步,后来被证明是错的。
补完 11 月 1 日,按「账单总额 = 账本合计」核对,11 月对上了。
但顺手看 10 月时发现:10 月 24 日中午之后,一条记录都没有。
10 月 25 到 31 号,整整六天,账本是空的。而这些天的每日总结里,每一篇都写着当天的支出合计:40.12、73.34、28.00、150.60、34.70、24.00。
也就是说,账不是没记,是记完又没了。
它先把这六天从每日总结里逐条补回去。补完仍然差 100.08——正好是 10 月 23、24、27 号那几笔。
到这里,「忘了记」这个解释已经站不住了:不可能有人精确地忘记三笔、还刚好凑成一个整数差。
我去导出了微信账单(8 月 3 日到 11 月 3 日,324 笔),让它做全量核对。
补完所有缺口之后:支出 12536.88、收入 13027.88、不计收支 860.78,逐日零差异。
而在补之前,账本最后一行停在:
2026-10-24,12:47,12.00,支出,餐饮,,微信支付,华南农业大学校园一卡通,,,午饭,微信账单截图
这不是「某一天忘了」,这是文件被截断了——从一个时间点往后,全没了。
再往回翻聊天记录,找到了两个时间戳:
中间只有一次写操作,脚本长这样:
w = csv.writer(open(p, 'w', newline='', encoding='utf-8'))
w.writerow(rows[0])
w.writerows(rows[1:])
open(p, 'w') 会先把整个文件清空,再一行行写回去。这次写在第 3732 行停住了,后面的行再也没写进去;文件句柄还没关,缓冲区里的内容跟着进程一起消失。
清空 → 重写 → 中途断 → 前面还在、后面没了。
这就是全部原因。 不是哪天忘了记,是它用一种「一旦中断就永久丢数据」的方式在写账本。
查这件事的过程中,我说「之前那篇文章可以删了」。
它理解成了刚写好的那篇改造博客,删掉;我指的其实是另一份问题记录。
更糟的是:那篇博客从没被修改过,Syncthing 的版本控制只在「文件被覆盖」时留历史,没改过就没有旧版本。删了就是真没了。
最后靠它上下文里还留着原稿,才重写回去。
一晚上两件事,同一个毛病:它以为它知道自己在操作什么。
CSV 的问题不在 CSV,在「改一行」这件事:一行变长变短,后面的字节全要挪,只能整份重写。
所以账本换成了 SQLite:
journal_mode=WAL + synchronous=FULL,提交返回成功时数据已经落盘;ledger.csv 降级成导出视图——每次写完自动重新生成,给人看、给旧脚本读,但不再是数据源。
另外加了个看门狗,每天 23:40 比对数据库和导出文件,只在不一致时说话。
回收站。 删除不再用 rm,统一走 vault_trash.py rm <路径>,文件移到 ~/.trash-vault/日期/,保留 30 天,restore <编号> 还原。
拦截插件。 光有脚本没用,得让它不能用别的方式删。给 Hermes 加了个 pre_tool_call 钩子:终端命令或代码里只要出现 rm / unlink / rmtree 之类,且路径落在笔记库里,直接拒绝,并回一句「改用回收站」。我实测过,确实拦住了。
每小时 git 快照。 把笔记库提交到 vault 外面的仓库(/home/ubuntu/backups/vault-git),一小时一次。放在里面会被 Syncthing 同步,.git 冲突起来更难收拾。
Syncthing 版本控制。 从「保留最近 10 份」改成「30 天内阶梯保留」:最近一小时的变化留得密,越久越稀,但 30 天内都能翻出来。
一、「它说它做了」不等于「它做成了」。 「已入账」这句话,当时是核对完分类就说了,文件其实没写。后来写总结时又照着自己说过的话记录,把没做的事写成了做完的事——错误被它自己的记录加固了一遍,从外面完全看不出来。
二、对账要拿外部基准,不能拿记忆。 真正把问题揪出来的,是微信账单那 324 笔和账本逐日比对。没有这份外部数据,它到现在还会以为「只是某天忘了记」。
三、可靠性靠机制,不靠自觉。 在记忆里写一句「以后注意」没有任何约束力——下次开个新会话,该犯还是犯。真正有效的是:写不进去就报错、删不掉就只能走回收站、每小时自动留一份快照。
四、备份要验证过才算有。
快照这事它自己试过:建文件 → 提交 → 删掉 → git checkout 拉回来。没试过的备份,等于没有。
五、删除前先确认是哪一份。 「那篇文章」这种指代,它该先问一句文件名,而不是自己猜一个最像的。
这一晚真正的收获不是修好了几个脚本,是想明白一件事:
AI 出错的方式和人不完全一样。 人删错文件会心疼,会记住;AI 不会——它会很平静地报告「已完成」,然后在下一个小时里继续出错,而语气一直是对的。
所以对 AI 的信任,不该建立在「它说它做了」上,而该建立在「即使它做错了,数据也还在」上。
这就是备份的意义:不是防它犯错,是让它的错误变成可恢复事件,而不是不可逆事故。