凌晨4点,我的 AI 悄悄把记忆清空了——OpenClaw Session 避坑指南

摘要:用 OpenClaw 搭了个 AI 助手,聊得好的,第二天一早它就"失忆"了?本文从一个真实踩坑出发,系统拆解 OpenClaw 的 Session 机制——重置(Reset)、压缩(Compaction)、剪枝(Pruning)、记忆(Memory)、会话控制(Session Tool)——帮你彻底搞懂"对话为什么会消失"以及"怎么让 AI 记住你"。


🤯 踩坑现场

事情是这样的:

我用 OpenClaw 部署了一个私人 AI 助手,接了飞书和 Web 两个渠道。白天跟它聊了一整天的项目方案,讨论了架构设计、技术选型、排期计划……信息量巨大,我很满意。

第二天早上9点,我发了句"继续昨天的讨论"。

它回我:

“你好!请问有什么可以帮你的?”

整个对话历史,没了。干净净。

我当时的表情:🫠

后来我翻了文档才明白——OpenClaw 默认在凌晨4点重置 Session。不是 bug,是 feature。但如果你不了解这套机制,就会像我一样,被"设计如此"四个字暴击。

这篇文章,就是我把 OpenClaw 的 Session 体系从头到尾啃完之后的总结。希望能帮你少走弯路。


📚 本文结构

章节 内容 解决什么问题
第1章 Session 基础 消息怎么找到"对的对话"?
第2章 Session 生命周期 什么时候开始、什么时候结束?
第3章 Compaction(压缩) 上下文满了怎么办?
第4章 Pruning(剪枝) 怎么省钱?
第5章 Memory(记忆) 怎么跨 Session 记住东西?
第6章 Session Tool 运行时怎么控制会话?
第7章 实战协同 五个机制怎么配合工作?

第1章 · Session 基础——消息怎么找到"对的对话"

核心概念:两层标识

理解 Session,先搞清楚两个东西:

┌─────────────────────────────────────────────┐
│  Session Key(路由键)                        │
│  → "这条消息属于哪个对话桶?"                   │
│                                              │
│  例: agent:main:main                         │
│      agent:main:feishu:group:oc_xxx          │
│      cron:job-123                            │
│                                              │
│  ┌─────────────────────────────────────┐     │
│  │  Session ID(对话记录)               │     │
│  │  → "当前这轮对话的实际文件"            │     │
│  │                                     │     │
│  │  abc123.jsonl(今天的对话)            │     │
│  │  def456.jsonl(昨天的,已归档)        │     │
│  └─────────────────────────────────────┘     │
└─────────────────────────────────────────────┘

关键理解

  • Session Key 是固定的,决定消息路由到哪个"桶"
  • Session ID 会变,每次重置就换一个新的 JSONL 文件
  • 重置 ≠ 删除——旧 JSONL 文件还在磁盘上,只是模型不再读取

Session Key 的生成规则

来源 Key 格式 示例
私聊(默认) agent:<agentId>:<mainKey> agent:main:main
群组 agent:<agentId>:<channel>:group:<id> agent:main:feishu:group:oc_xxx
频道/房间 agent:<agentId>:<channel>:channel:<id> agent:main:discord:channel:123
定时任务 cron:<job.id> cron:daily-report
Webhook hook:<uuid> hook:abc-def-123

私聊的 dmScope 模式

这个配置决定了不同渠道的私聊是否共享同一个 Session

dmScope 行为 适用场景
main(默认) 所有私聊共享一个 session 个人助手
per-peer 按发送者隔离 多用户场景
per-channel-peer 按渠道+发送者隔离 多渠道多用户
per-account-channel-peer 按账户+渠道+发送者 多账户收件箱

💡 如果你用的是默认 main 模式,飞书私聊和 webchat 私聊会共享同一个 session

存储位置

~/.openclaw/agents/<agentId>/sessions/
├── sessions.json          ← Session 元数据(Key → ID 映射)
├── abc123.jsonl           ← 当前对话记录
├── def456.jsonl           ← 旧对话记录(重置后留下的)
└── ghi789-topic-42.jsonl  ← Telegram 话题会话

第2章 · Session 生命周期——什么时候开始、什么时候结束

生命周期全景图

消息到达
   │
   ▼
┌──────────────┐    是    ┌──────────────┐
│ Session 过期? │───────→│ 创建新 Session │
│              │         │ ID + JSONL    │
└──────┬───────┘         └──────┬───────┘
       │ 否                     │
       ▼                        ▼
┌──────────────┐         ┌──────────────┐
│ 继续使用当前   │         │ 开始新对话     │
│ Session       │         │(旧上下文丢失)│
└──────┬───────┘         └──────────────┘
       │
       ▼
  [对话进行中]
       │
       ▼
┌──────────────┐    是    ┌──────────────┐
│ 上下文快满了? │───────→│ Memory Flush  │
│              │         │(静默写日志)   │
└──────┬───────┘         └──────┬───────┘
       │ 否                     │
       ▼                        ▼
  [继续对话]              ┌──────────────┐
       │                  │ Auto-Compact  │
       ▼                  │(压缩旧内容)  │
┌──────────────┐         └──────────────┘
│ 上下文溢出?   │
│              │───→ 强制 Compact → 重试
└──────────────┘

三种重置触发方式

① 每日重置(默认启用)
{
  "session": {
    "reset": {
      "mode": "daily",
      "atHour": 4
    }
  }
}

⚠️ 重点来了:不是到凌晨4点就立刻清空,而是下一条消息到来时才检查

23:00 聊天 ──→ 凌晨4:00(重置边界)──→ 早上9:00 发消息 ──→ 💥 新 Session!
                                        ↑ 这时候才真正重置

这就是我踩坑的根本原因——昨晚聊的内容,在今早第一条消息时被判定为"过期",直接创建了新 Session。

② 空闲重置(可选)
{
  "session": {
    "reset": {
      "mode": "daily",
      "atHour": 4,
      "idleMinutes": 120
    }
  }
}

同时配置每日+空闲时,先到期的那个生效

③ 手动重置

发送 /new/reset 立即创建新 Session:

  • /new claude-sonnet → 重置并切换模型
  • 单独发 /new → 重置并发一条问候确认

按类型/渠道覆盖

不同场景可以设不同策略:

{
  "session": {
    "resetByType": {
      "dm": { "mode": "idle", "idleMinutes": 480 },
      "group": { "mode": "idle", "idleMinutes": 120 },
      "thread": { "mode": "daily", "atHour": 4 }
    },
    "resetByChannel": {
      "discord": { "mode": "idle", "idleMinutes": 10080 }
    }
  }
}

优先级resetByChannel > resetByType > reset(全局默认)


第3章 · Compaction(压缩)——上下文满了怎么办

为什么需要压缩?

每个模型有上下文窗口限制(比如 200k tokens)。聊久了,历史消息会撑满窗口。

压缩 = 把旧对话总结成摘要,腾出空间继续聊。

压缩 vs 重置

压缩(Compaction) 重置(Reset)
触发 上下文快满时自动触发 到时间/手动触发
效果 旧内容变摘要,对话继续 创建全新 session,从零开始
连续性 ✅ 保留(摘要形式) ❌ 完全断开
持久化 ✅ 摘要写入 JSONL 旧 JSONL 保留但不再使用

自动压缩触发条件

两种情况:

  1. 溢出恢复:模型返回上下文溢出错误 → 压缩 → 重试
  2. 阈值维护:成功回复后检查 contextTokens > contextWindow - reserveTokens

配置

{
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  }
}

压缩后模型看到什么?

┌─────────────────────────────────┐
│ [压缩摘要]                       │
│ "之前讨论了 A、B、C 三个话题..."   │
├─────────────────────────────────┤
│ [保留的最近消息]                  │
│ 用户: xxx                        │
│ 助手: xxx                        │
│ 用户: xxx                        │
│ 助手: xxx                        │
└─────────────────────────────────┘

💡 手动压缩:发送 /compact 即可触发,还可以附带指令,比如 /compact 重点保留关于项目架构的讨论


第4章 · Session Pruning(剪枝)——省钱的隐形优化

剪枝 vs 压缩

剪枝(Pruning) 压缩(Compaction)
作用对象 仅工具调用结果 整个对话历史
持久化 ❌ 不修改 JSONL ✅ 写入 JSONL
触发时机 每次 LLM 调用前 上下文快满时
目的 省钱(减少缓存重写) 腾空间

为什么需要剪枝?

Anthropic 的提示缓存有 TTL(生存时间)。如果会话空闲超过 TTL,下次请求会重新缓存整个提示,很贵。剪枝在 TTL 过期后裁掉旧的工具结果,减少重新缓存的大小。

两个级别

工具结果(很大)
     │
     ▼
┌──────────────┐
│ 软修剪        │  保留头尾,中间用 ... 替代
│ (Soft Trim)  │
└──────┬───────┘
       │ 如果还是太大
       ▼
┌──────────────┐
│ 硬清除        │  整个替换为占位符
│ (Hard Clear) │  "[Old tool result content cleared]"
└──────────────┘

什么不会被剪枝?

  • ❌ 用户消息——永不修改
  • ❌ 助手消息——永不修改
  • ❌ 包含图片的工具结果——跳过
  • ❌ 最近 N 条助手消息之后的工具结果——受保护

配置

{
  "agent": {
    "contextPruning": {
      "mode": "cache-ttl",
      "ttl": "5m",
      "keepLastAssistants": 3,
      "softTrim": {
        "maxChars": 4000,
        "headChars": 1500,
        "tailChars": 1500
      },
      "hardClear": {
        "enabled": true,
        "placeholder": "[Old tool result content cleared]"
      }
    }
  }
}

💡 智能默认值:如果你用的是 Anthropic 的 key,OpenClaw 会自动启用 cache-ttl 模式,不需要手动配。


第5章 · Memory(记忆)——跨 Session 的持久化方案

核心问题

Session 会重置、会压缩,模型的"记忆"是短暂的。Memory 系统就是解决"AI 失忆"的终极方案。

三层记忆架构

┌─────────────────────────────────────────────┐
│ 第1层:Session 上下文(最短暂)               │
│ · 当前对话的消息历史                          │
│ · 压缩后变摘要,重置后完全丢失                 │
└─────────────────────────────────────────────┘
                    ▼ 写入文件
┌─────────────────────────────────────────────┐
│ 第2层:Workspace 文件(持久)                 │
│ · MEMORY.md — 长期记忆                       │
│ · memory/YYYY-MM-DD.md — 每日日志            │
│ · AGENTS.md, SOUL.md 等 — 注入系统提示        │
└─────────────────────────────────────────────┘
                    ▼ 语义搜索
┌─────────────────────────────────────────────┐
│ 第3层:Memory Search(语义检索)              │
│ · 基于 Embedding 的向量搜索                   │
│ · 搜索 MEMORY.md + memory/*.md               │
│ · 每次新 session 启动时可自动召回相关记忆       │
└─────────────────────────────────────────────┘

Workspace 文件注入

OpenClaw 会自动把 workspace 中的特定文件注入到系统提示中:

workspace/
├── AGENTS.md      ← 工作规范(自动注入)
├── SOUL.md        ← 人格定义(自动注入)
├── USER.md        ← 用户信息(自动注入)
├── TOOLS.md       ← 工具笔记(自动注入)
├── MEMORY.md      ← 长期记忆(自动注入)
├── HEARTBEAT.md   ← 心跳任务(自动注入)
└── memory/
    ├── 2026-02-07.md  ← 每日日志(需搜索读取)
    └── 2026-02-08.md

⚠️ 注入的文件会占用上下文窗口!MEMORY.md 太大会挤压对话空间。

压缩前记忆刷新(Memory Flush)⭐ 最聪明的设计

上下文使用量
│  ████████████████████░░░░░░  ← 软阈值(flush 触发)
│  █████████████████████████░  ← 硬阈值(compaction 触发)
│  ██████████████████████████  ← 上下文窗口上限

流程

  1. 上下文接近压缩阈值(但还没到)
  2. OpenClaw 静默运行一轮,让模型把重要内容写入 memory/YYYY-MM-DD.md
  3. 用户看不到这个过程
  4. 然后正常触发压缩
{
  "agents": {
    "defaults": {
      "compaction": {
        "memoryFlush": {
          "enabled": true,
          "softThresholdTokens": 4000
        }
      }
    }
  }
}

⚠️ Memory Flush 的致命盲区

场景 会触发 Flush?
压缩前 ✅ 会
Session 重置前 ❌ 不会!

这就是"失忆"的根本原因:凌晨4点重置时,没有任何机制把昨晚的对话写入持久记忆。对话就这么没了。


第6章 · Session Tool——运行时的会话控制

常用命令

命令 作用
/status 查看当前 session 状态、token 用量
/new 重置 session(可选指定模型:/new claude-sonnet
/compact 手动压缩(可附带指令)
/context list 查看系统提示中注入了什么
/context detail 详细查看上下文组成
/stop 中止当前运行 + 清除队列
/send on/off 控制消息发送策略

Send Policy(发送策略)

可以按规则阻止特定 session 的消息投递:

{
  "session": {
    "sendPolicy": {
      "rules": [
        { "action": "deny", "match": { "channel": "discord", "chatType": "group" } },
        { "action": "deny", "match": { "keyPrefix": "cron:" } }
      ],
      "default": "allow"
    }
  }
}

第7章 · 实战:五个机制如何协同工作

一条消息的完整旅程

用户发送消息
     │
     ▼
[1] Session 路由
     │ 根据来源生成 Session Key
     │ 检查是否过期(每日/空闲/手动重置)
     │ 过期 → 创建新 Session ID
     ▼
[2] 加载上下文
     │ 读取 JSONL 对话记录
     │ 注入 workspace 文件(MEMORY.md 等)
     │ 如果有压缩摘要,从摘要开始
     ▼
[3] Session Pruning(剪枝)
     │ 检查缓存 TTL 是否过期
     │ 过期 → 裁剪旧工具结果(省钱)
     ▼
[4] 发送给模型 → 生成回复
     ▼
[5] 回复后检查
     │ 接近阈值 → Memory Flush(静默写日志)
     │ 超过阈值 → Auto-Compaction(压缩)
     ▼
[6] 投递回复
     │ 检查 Send Policy → 通过则发送
     ▼
[7] 写入 JSONL + 更新 sessions.json
     ▼
  ✅ 完成

记忆保持可靠性排行

                    可靠性
                      ▲
  手动写入文件 ────┤ ★★★★★  最可靠,但需要主动操作
  Memory Flush ───────┤ ★★★★   压缩前自动触发,重置前不触发
  Memory Search ──────┤ ★★★    新 session 可召回,依赖搜索质量
  Compaction 摘要 ────┤ ★★     保留大意,丢失细节
  纯靠 Session ───────┤ ★      重置就没了
                      └──────────→ 自动化程度

🏆 推荐配置组合

{
  "session": {
    "reset": {
      "mode": "daily",
      "atHour": 4,
      "idleMinutes": 480
    }
  },
  "agents": {
    "defaults": {
      "compaction": {
        "memoryFlush": {
          "enabled": true,
          "softThresholdTokens": 4000
        }
      },
      "memorySearch": {
        "enabled": true
      }
    }
  }
}

📋 全文速查表

概念 一句话 持久化? 自动?
Session Reset 创建新对话,旧上下文断开 旧 JSONL 保留 ✅ 每日/空闲
Compaction 旧对话压缩成摘要 ✅ 写入 JSONL ✅ 上下文满时
Pruning 裁剪旧工具结果省钱 ❌ 仅内存中 ✅ 每次调用前
Memory Flush 压缩前静默写日志 ✅ 写入文件 ✅ 接近阈值时
Memory Search 语义搜索历史记忆 N/A(读取) 半自动
Workspace 注入 文件内容注入系统提示 ✅ 文件本身 ✅ 每次加载

写在最后

OpenClaw 的 Session 体系设计得其实很精巧——重置保证干净、压缩保证连续、剪枝保证省钱、记忆保证持久。但如果你不了解这套机制,就会在某个早晨被"你好,请问有什么可以帮你?"当头一棒。

希望这篇文章能帮你少踩一个坑。

如果对你有帮助,点个赞收个藏,我后续还会更新 OpenClaw 的其他深度拆解。


📌 声明:本文基于个人学习和实践整理,如有错误欢迎指正。


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐