OpenClaw会话重置失忆原因分析

今天在使用 OpenClaw 的过程中遇到一个现象:正在进行的会话突然“失忆”了,助手对不久前做过的操作完全不知情。经过日志追溯和源码分析,弄清了整个链路。记录如下。

现象

一次完整的会话链涉及了 3 个关联的 session:

时间 Session 内容 结果
20:25 639ede17 Agent宕机诊断 → 发布博客 → iNove主题排版调整 被 abort
20:32 6520c2c3 继续iNove主题调整,找CSS文件 被 abort
20:38 7f1f9d61 当前会话,全新开始,对之前一无所知 正常运行

两个前序 session 在 abort 后被 reset,新 session 从零开始,对过去 13 分钟内的所有操作完全没有记忆。

直接原因:手抖多打了一个 0

openclaw.json 的模型配置中,deepseek-v4-flashmaxTokens 值被设为了 3840000

{
  "id": "deepseek-v4-flash",
  "name": "deepseek-v4-flash",
  "contextWindow": 1000000,
  "maxTokens": 3840000,    ← 多了一个 0
  "compat": { "supportsTools": false }
}

这个值应该是 393216(火山引擎 deepseek-v4 实际支持的 max_completion_tokens 上限),但配置时多输入了一个 0,变成了 384 万。OpenClaw 的计算逻辑是:

max_completion_tokens = min(maxTokens, contextWindow - 已用token数)

当上下文膨胀后,contextWindow - 已用token数 约 90 万,min(3840000, 90万) 取了 90 万,远超火山引擎 393216 的上限,直接 400 拒绝:

400 The parameter `max_completion_tokens` specified in the request are not valid:
expected a value <= 393216, but got 966158 instead.

也就是说,整条调用链 OpenClaw → handai(newapi) → 火山引擎 本身没有兼容性问题,根因就是配置错误

链式崩溃经过

第 1 轮:连番 400 错误 + 大量重试

用户在 webchat 上发送了 Agent 宕机诊断请求,模型连续返回 400 format error。每次 failover(handai→deepseek→alibaba)都持续失败——因为模型提供商本身没问题,是请求参数超标了。用户因看不到响应,在 webchat 上反复发送同一条消息 30 多次,每一次都触发新的 400 错误,形成恶性循环。

最终用户手动 abort 当前请求,但 abort 的回收超时了:

embedded abort settle timed out: timeoutMs=2000

同时 session 文件已被修改,触发保护机制:

session file changed while embedded prompt lock was released

结果:session 639ede17 被标记为 .reset.,视为被接管放弃。

第 2 轮:CSS 文件查找也 abort

新 session 启动后,用户继续讨论 iNove 主题的 CSS 调整。助手在 /var/www//www/ 等路径远程查找 CSS 文件,全部失败(路径不存在)。用户再次 abort,同样的 chat.abort + settle timeout → session 6520c2c3 也被 reset。

OpenClaw 的 Session Reset 机制

从日志可以看出 OpenClaw 在这类场景下的行为:

  1. 模型 400 错误 → 触发 failover(handai → alibaba → deepseek),但 failover 同样失败(请求参数依然超标)
  2. 用户手动 abort → 调用 chat.abort WebSocket 接口
  3. Abort settle timeout(2秒) → 如果在 2 秒内 abort 不能被嵌入层清理完成,触发 session takeover
  4. Session takeover → 旧的 session 文件被重命名为 .reset.,新请求从新 session 开始
  5. 失忆 → 新 session 没有历史消息,模型看到的是一块空白画布

如何重建记忆

当前这个 session 恢复“记忆”的方式并非真正记住了,而是通过以下步骤从文件系统中重新构建了上下文:

  1. 搜 session 文件:用 grep -rl "retailsolution|xmlrpc" 在所有 session 文件中找到相关记录
  2. 读 trajectory 日志:从 reset 过的 session 的 .trajectory.jsonl 中提取助手回复文本和用户消息
  3. 找残留证据/tmp/publish_xmlrpc.py 等脚本还躺在文件系统上
  4. 翻日志确认崩溃原因/tmp/openclaw/openclaw-YYYY-MM-DD.log 中的 failover 和 abort 记录

这种方式的问题很明显:它依赖助手在运行时主动去“考古”,且只能找到轨迹日志中残留的信息,并非系统级的内存持久化。

启示

这次事件揭示了几个值得注意的问题:

  1. 配置错误是最隐蔽的故障源:多输入一个 0,就能让整套系统反复崩溃。模型配置中的 maxTokens 要与最终提供商的实际支持上限对齐,不能写理论最大值。
  2. Abort 回收的可靠窗口:2 秒的 settle timeout 在复杂场景下偏短,一旦超时就导致整个 session 上下文丢失。这是 OpenClaw 的一个设计缺陷(Issue #98156)。
  3. 长期记忆 vs 会话记忆:OpenClaw 的 memory 系统保存的是长期语义记忆,但会话级的工作记忆在 session reset 后彻底消失。即使这次是配置错误触发的,其他场景(网络波动、模型超时等)同样会触发 session takeover,导致同样的失忆问题。

作者: Jack.shang

jack.shang 程序员->项目经理->技术总监->项目总监->部门总监->事业部总经理->子公司总经理->集团产品运营支持