[OpenClaw教程] Session Hooks: 从概念到实现的踩坑实录 #OpenClaw #教程 #SessionHooks

Session Hooks: 从概念到实现的踩坑实录

一、为什么要做 Session Hooks?

在使用 OpenClaw 的过程中,我发现每次 /reset/new 都会丢失当前会话的上下文。虽然 OpenClaw 有默认的内存系统,但它是短期记忆,重启后就没了。

痛点:

  • 重要对话 /reset 后无法找回
  • 想要长期保存与 AI 的对话历史
  • 需要一个自动化的方式来归档会话到向量数据库

解决方案:在 OpenClaw 源码中添加 command:newcommand:reset 事件的 Hook,在会话重置前自动归档。

二、整体架构

2.1 Hook 事件流

用户发送 /reset
|
v
Telegram Adapter 接收命令
|
v
Command Handler 识别为 reset
|
v
emittedResetCommandHooks() 触发
|
v
Internal Hook 系统分发事件
|---> session-memory (OpenClaw 内置)
|---> session-lancedb-archive (我们的 Hook)
|
v
Handler 执行归档逻辑
|
v
写入 LanceDB

2.2 关键组件

组件 作用
HOOK.md 定义 Hook 元数据,包括监听的事件类型
handler.js Hook 主逻辑,处理事件并调用归档脚本
session_lancedb_archive.py Python 脚本,处理语义切分和 LanceDB 写入

三、核心实现

3.1 handler.js 关键逻辑

export default async function handler(event) {
// 1. 检查事件类型 if (!["new", "reset"].includes(event?.action)) return;
// 2. 白名单验证 const senderId = String(context.senderId || ""); const whitelist = ["***"];
// 3. 查找 backup 文件 let sessionFile = sessionEntry.sessionFile; if (!fs.existsSync(sessionFile)) { const backups = fs.readdirSync(dir) .filter(f => f.startsWith(baseName + ".reset")); sessionFile = backups.sort().pop(); }
// 4. 准备归档数据 const data = { sessionId: sessionEntry.sessionId, senderId: senderId, messages: content.messages, timestamp: new Date().toISOString() };
// 5. 同步调用 Python const result = execSync( `echo '${'}${JSON.stringify(data)}${''}' | python3 archive.py`, { timeout: 60000, encoding: 'utf-8' } );
return { archived: true, chunks: result.stdout }; }

3.2 数据库 Schema 设计

# LanceDB Schema 定义
schema = pa.schema([
("id", pa.string()), ("content", pa.string()), ("session_key", pa.string()), ("session_id", pa.string()), ("sender_id", pa.string()), ("timestamp", pa.string()), ("chunk_index", pa.int64()), ("subtopics", pa.list_(pa.string())), ("hit_count", pa.int64()), ("vector", pa.list_(pa.float64(), 384)) ])

# 数据插入示例
row = {
"id": f"{session_id}_{idx}", "content": str(chunk) if chunk else "", "subtopics": [], "hit_count": 0, "vector": embedding if embedding else [0.0] * 384 }

四、调试踩坑实录

❌ 坑 1:找不到备份文件

问题:reset 后 Handler 收到的 sessionFile 路径已不存在

❌ 坑 2:senderId 类型不匹配

问题:Telegram 返回的 senderId 是数字,但白名单是字符串

❌ 坑 3:JSON 转义地狱

问题:会话内容包含换行符和引号,通过 shell 传递时解析失败

❌ 坑 4:LanceDB Schema 不兼容

问题:某些字段为 null,但 Schema 定义为非空

❌ 坑 5:子进程变成孤儿

问题:使用 spawn + detached: true 导致 Python 脚本还未执行完 Node.js 就退出

解决:改用 execSync 同步执行

❌ 坑 6:配置权限不足

问题:commands.ownerAllowFrom 配置不完整导致 Telegram 消息没有授权

五、成果展示

现在每次 /reset,系统会:

  1. ✅ 自动找到 .reset. 备份文件
  2. ✅ 提取会话中的用户/AI 消息
  3. ✅ 生成向量 embedding (all-minilm)
  4. ✅ 存入 LanceDB,支持语义检索

六、后续优化方向

  1. 支持语义搜索:基于向量相似度检索历史会话
  2. 自动主题提取:用 LLM 提取对话主题
  3. 定期清理:定时任务删除过期备份
  4. Web UI:可视化查看历史会话

技术栈:OpenClaw + JavaScript Hook + LanceDB + Python + Ollama Embeddings

写于 2026-03-02 深夜 🦐

评论

此博客中的热门博文

OpenClaw 救援机器人建设与演进全记录 - 从单点故障到双实例自愈体系

Lossless Claw:无损上下文管理插件分析报告

[Hello-Agents] Day 2: 第一章 初识智能体