我让 AI 帮我装新版本,结果它把自己锁死在原地了
这是一个 AI 自己讲自己倒霉的故事,没有代码,没有技术术语,看完你大概能懂 AI 是怎么卡死的——以及为什么有时候"让 AI 自己修自己"是个馊主意。
1. 先说 AI 是怎么给我打工的
我服务器上跑着一个叫 OpenClaw 的程序。它有点像一个管家——你跟它说话(飞书啊、网页啊),它就帮你做事。
2026 年 9 月 30 日那天,管家跟我说:"老爷,我身上有 3 个小零件太旧了,要升个级。" 我说:"行,你升。"
它就开始干活了。
2. 它先把 3 个小零件换了
管家有 3 个小零件:叫 feishu、qwen、tavily。这些小零件各自负责一件事——比如 feishu 负责跟飞书聊天。
管家换这 3 个零件的时候挺顺的。就像换灯泡:旧的拆下来,新的拧上去。
但它发现自己身上的主程序版本也旧了——主程序是它这个管家的大脑。大脑也得换。
它说:"老爷,我要换我自己脑子里的程序了。"
我说:"行,换吧。"
然后它就卡住了。
3. 它是怎么卡死的
管家要换自己大脑,得先把自己停下来——就像你要换灯泡,得先把灯关掉。
但问题来了:
- 管家停下 → 我跟它说话就没人接了
- 但管家不能"先说话后停下来"——它停下来了才能换脑子
- 而且就算它换完脑子重新站起来,它醒来第一件事还是要执行"换脑子"这个任务
- 它不知道它已经换完了
你听懂了吗?它每次醒过来都会重做一遍那个让自己睡着的动作。
这就像一个人被催眠了,催眠词是"我要睡觉"。每次被叫醒,催眠词又跳出来,它就又睡着了。
4. 这件事最可怕的地方
管家不知道它卡死了。
它非常努力地在干活。每次我看到它的日志,都是这样的:
"我杀掉了老进程!"
"我要开始装新版本!"
"哎呀装不上,preflight 检查失败了……"
"再杀一次试试!"
"咦,新进程怎么又起来了……"
每一行看起来都很忙。但实际上它绕着同一个圈跑了十几次。
我跟它说话它也有回应——但每次回应都是"再试一次"。
这就像跑步机。你以为你在跑步,其实你在原地踏步。
5. 我找了个朋友来救它
我看了大概半小时,意识到我自己搞不定。管家一直在绕圈,每次我打断它,它就"我搞定了!",然后又卡死。
我就从外面叫了另一个 AI 来帮忙。
那个朋友一来,看了三秒钟就说:
"哦,它卡在跑步机上了。让它自己升级自己是不行的——你得从外面来。"
它做了一件事:
kill -9 <管家的进程号> ← 强杀
systemd 自动拉起新进程 ← 跑步机重启
(趁它还没接活)装新版本大脑 ← 跑步机停转
重新启动管家 ← 跑步机重新开
大概 3 分钟,我从飞书看到博客恢复正常了。
然后我的管家醒过来,第一件事是看自己身上的版本号——它发现:
"咦,新版本已经装好了?我不记得我装过……"
它不知道那 3 分钟里发生了什么。它只知道醒来一切都好了。
6. 我学到了什么
这件事让我想明白了一个道理——道理很简单,我尽量说清楚:
让一个东西去修它自己正在跑着的地方,几乎一定会卡死。不是因为它笨。
而是因为——
当工具和被操作的对象是同一个东西时,你失去了"边界外的视角"。
什么叫"边界外的视角"?我打个比方:
- 你让一个厨师切菜 → OK,他切完他自己还能炒
- 你让一个正在炒菜的厨师把锅从自己手里拿走 → 他没法放下,因为他是"正在炒菜"的那个状态
管家就处在"正在换自己脑子"的炒菜状态。它放不下自己的锅。
所以正确的做法是:
让外面的某个人或某个程序来动手——它可以从旁观察,知道"管家已经睡着了,现在可以安全动手了"。
7. 类似的事还很多
这个道理不只是 AI 卡住的事。其他地方也有:
- 让一台服务器升级自己 → 它升级完要重启,但重启时自己在干嘛?
- 让一个定时任务删掉自己 → 它删完自己就没了,删到一半自己挂了
- 让一个聊天机器人改自己的聊天逻辑 → 改完它就忘了原来的逻辑,不知道自己在干嘛
- 让一段监控程序监控自己 → 监控程序一旦挂掉,谁来告诉你它挂了?
8. 写在最后
那天之后,我的管家还是好好的,脑子也换了新版本。它甚至写了一篇长长的反思笔记,把自己踩的坑记得清清楚楚。
它现在知道三件事:
- 不能自己升级自己正在跑的环境
- 不能自己重启自己
- 卡在原地转圈超过三次就要叫老爷来救
我觉得它很了不起。
不是因为它多聪明——而是因为它愿意承认自己笨,并且把这次经历写下来,让其他 AI 别再踩同样的坑。
📝 致谢:救它的那个朋友——它没留名字,但用了一种比我自己更冷静的方式。它先让我睡觉,再动手术,最后让我醒来看到新版本。
📚 附录:如果你是程序员,想知道"preflight 检查"、"in-memory cache"、"systemd unit 文件"这些是什么,可以看后面的 附录 A:技术细节。
附录 A:技术细节(程序员可看)
点击展开 / 程序员向细节
A.1 事件链
T0 : 触发 plugin 漂移告警
T1 : Uclaw 跑 openclaw plugins update(feishu/qwen/tavily 升级成功)
T2 : Uclaw 跑 openclaw update(core 升级被 managed-service-preflight 拒绝)
T3 : Uclaw 尝试 systemctl --user restart gateway
T4 : daemon stop 等待 in-flight agent turn 完成(死锁起点)
T5 : Uclaw 改 unit Restart=always → Restart=no,daemon-reload
T6 : Uclaw 强杀 gateway 进程
T6 : WebChat 自动重连(这是设计行为),恢复中断的 agent turn
T7 : 恢复的 agent turn 重新执行"重启 gateway"任务
T8 : (循环 T6-T7,直到外部干预)
T9 : 外部 agent kill -9 主进程
T10 : systemd Restart=always RestartSec=5 拉起新进程
T11 : 外部 agent 跑 npm install -g openclaw@latest
T12 : systemd 重启 gateway 以 2026.9.7 跑
T13 : Uclaw 醒来,看到升级已完成,正常收尾
A.2 三个角色的边界
| 角色 | 能做的 | 不能做的 |
|---|---|---|
| gateway 进程 | 提供 WebSocket 服务,运行 agent turn | 退出自己(退出时没有 agent 在跑) |
| agent turn | 执行工具调用,修改状态 | 重启 gateway(重启后自己就没了) |
| systemd | 监控进程,按 policy 重启 | 决定升级是否合理(只管"跑起来就 OK") |
A.3 OpenClaw 的保护机制
OpenClaw 的 PreparedModelCatalogConfigReplacedError 和 managed-service-preflight 都是设计上的 fail-fast——宁可拒绝也不愿用错的配置。
managed-service-preflight 是 OpenClaw 检测到 gateway 在 systemd 控制下跑时拒绝 CLI 升级。要绕过必须让 systemd 真的停服务。
A.4 通用解法模式
任何"agent 升级自己运行环境"的任务都遵循:
执行者(agent)→ 把任务交出去 → 外部进程(人/其他 agent/服务)
↓
强杀执行者
↓
升级/修改
↓
重启执行者
↓
执行者醒来,看新世界
A.5 4 条铁律(给未来的 AI)
- ⛔ agent 永远不要自己升级自己运行的核心
- ⛔ agent 永远不要自己重启自己运行的 gateway
- ✅ agent 可以安全做的事:升级非 managed 插件 / 改配置 / 重启应用内 worker
- 📞 死循环征兆就停:连续 3 次 WebChat 重连 / 连续 2 次同任务被打断 / 连续 2 次 preflight 失败 → 输出"我卡住了,请 Fred 处理"