如果你用AI Agent做过长时间任务,你可能遇到过这种情况:
模型突然不响应了
你被迫按/reset,但担心之前的工作全丢了
你重新开始,但AI不知道之前做到了哪一步
这就是Session-Memory Hook要解决的问题。
─────────────────
一那个让我愣了三秒的场景
我这两天正在准备一个高考前的分享材料,核心内容和框架已经写完了,需要AI补充数据、优化个别案例内容,然后配图和优化格式样式。
执行到配图环节,我说:"为最终内容,配几张图。"
然后它开始展示:
封面图✅
科举时代✅
1977年知青✅
第三张:现代考生❌[assistant turn failed before producing content]
就停在第三张图。模型开始"死循环"——连续4次,每次都是同样的报错。我追问"出了什么问题",得到的全是同样的空内容。
我手动说了"暂停当前任务",它才停下来告诉我:"图片都存好了,是 read 工具读取展示时中断了。"
但为时已晚。模型已经进入某种损坏状态,每次尝试继续都产生空内容。
于是果断执行了 /reset 操作...
Agent恢复,并继续之前的任务。而这大部分功劳得益于Session-Memory Hook。
───────────────
二Session-Memory Hook 做了什么
Session-Memory Hook 是在 /reset 时自动运行的一个"事件钩子"。
它的触发条件只有一个:你发送 /new 或 /reset 命令。
当 agent 被重置的瞬间,它做了这么几件事:
定位到刚才那个损坏的 session 文件 读取文件,提取最后 20 条有效对话(过滤了命令、工具、系统消息) 写入 ~/.openclaw/workspace-tspj/memory/2026-06-04-1700.md
这个文件现在还在。打开看,是这样的:
~/.openclaw/workspace-tspj/memory/2026-06-04-1700.md
# Session: 2026-06-04 17:00:48 GMT+8- **Session Key**: agent:tspj:main- **Session ID**: 43588306-2628-491b-99f5-41c5c01d8f9d- **Source**: webchat### Conversation Summaryassistant: [文章内容]user: 能找到适合的图片吗?配合内容需要插入几张图片和封面assistant: [图片生成过程]从你设定条数的第一条到最后一次回复,全部记录在案。💡 关键洞察
Session-Memory Hook 的关键价值,不在于"记录",而在于"可复原"。模型崩溃≠工作丢失,memory 文件是最后一道防线。
────────────────
三为什么模型崩溃了,但记忆没丢
这里有一个设计上的巧思。
Session-Memory Hook 不是"每句话都记录"的实时日志——它只在"换档"的时候做快照。
模型持续运行的过程中,有另一套机制 LCM(Lossless Context Management) 在负责上下文压缩。当 session 太长时,LCM 会自动压缩对话,保留核心上下文。
但当 LCM 也无法压缩(上下文损坏到无法处理),session 就会进入"重置"状态。
Session-Memory Hook 就是在重置的瞬间,把最后一块拼图补上。
LCM 与 Session-Memory 互补机制
两套机制互补:
| LCM | ||
| Session-Memory |
💡 关键洞察
两套机制各自守住了自己的边界。LCM 管持续压缩,Session-Memory 管换档快照。模型可以崩溃,但记忆永远有备份。
────────────────
四messages: 20 是怎么算的
你配置了 messages: 20,但这 20 条不是从上往下数那么简单。
Hook 读取 session 文件后,会经过一个 6步过滤 pipeline:
1
解析 session 文件每一行 JSON
→ 只保留 type === "message" 的行→ 跳过 type="custom"/"session"/"model_change"
2
角色过滤
→ 只保留 role === "user" 或 "assistant"→ 跳过 role="system"/"tool"
3
跨会话过滤(user 专属)
→ 如果 hasInterSessionUserProvenance(msg) === true,跳过→ 防止把其他 session 的消息算进来
4
提取文本内容
→ 从 content 数组中只取 type="text" 的 text 字段→ 跳过 image/toolCall 等 block
5
排除命令消息
→ 如果 text.startsWith("/"),跳过→ /new//reset 命令本身不计入
6
取最后 N 条
→ allMessages.slice(-messageCount)→ 消息总数不足 20 条时,全部保留
💡 关键洞察
所以你配置的 20 条,是经过5层过滤之后,剩下的最后 20 条有效对话。messages 配置是一个权衡。太大了(50+)文件膨胀、价值密度低;太小了(5)丢失关键上下文。20 是一个合理的中间值。
───────────────
五完整流程图
用户发送 /reset 后,Session-Memory Hook 的完整执行流程:

─────────────────
六真实数据:tspj 17:00 发生了什么
我调出了实际数据,让你们看看 session 重置前后的真实对比:
重置前的 session(conv 23)

LCM 尝试压缩了 6 次,都因为"live context still exceeds target"失败。
重置后的新 session(conv 24)

干净得像一张白纸。
但 memory 文件保存了所有内容:
$ ls -lh ~/.openclaw/workspace-tspj/memory/2026-06-04-1700.md-rw------- 6.1K Jun 4 17:00 /home/family/.openclaw/workspace-tspj/memory/...这就是 Session-Memory Hook 的作用——它不阻止崩溃,但它确保崩溃之后,你的工作不会消失。
─────────────────────
七Session-Memory Hook 的输出格式
这是它写入 memory/ 目录的文件格式:
memory/YYYY-MM-DD-HHMM.md
# Session: 2026-06-04 17:00:48 GMT+8- **Session Key**: agent:tspj:main- **Session ID**: 43588306-2628-491b-99f5-41c5c01d8f9d- **Source**: webchat## Conversation Summary[对话内容片段...]文件命名规则:
默认使用时间戳 slug( HHMM= 重置时刻的 时+分)可选开启 llmSlug: true让 AI 生成描述性文件名(如2026-06-04-图片生成.md)
────────────────
八配置项一览
{ "hooks": { "internal": { "entries": { "session-memory": { "enabled": true, "messages": 20, "llmSlug": false } } } }}enabled | ||
messages | ||
llmSlug |
前提条件:每个 agent 的 workspace.dir 必须已配置(安装时自动完成)。
──────────────────
九关键认知
🎯 核心认知
Session-Memory Hook 不是日志系统,是一个断点保护机制。当你让 AI 做一个复杂的任务,中途 AI 崩溃了,你重新开始一个新 session——之前的上下文不会凭空消失。它们被压缩成一段记忆文件,存在 memory/ 目录。新 session 开始时,AI 可以读取这个文件,了解之前发生了什么,然后继续。这就是 AI Agent 的记忆连续性。
下次遇到 AI "死机"时,别急着叹气。先去 memory/ 目录看看——你的工作,可能比你想象中更安全。
───────────────
📁 相关文件
Hook 源码: `~/.npm-global/lib/node_modules/openclaw/dist/bundled/session-memory/handler.js`
夜雨聆风