深度

OpenClaw Session ID 生命周期规则:什么时候会开新会话,什么时候延续旧会话

详解 OpenClaw sessionKey 与 sessionId 的区别,以及触发新会话的四种情形:手动重置、每日重置、空闲过期、父级分叉保护,附 Session Store 字段说明和 Cron 会话保留策略。

2026/8/134分钟 阅读ClaudeEagle

"为什么我的对话突然'失忆'了"是 OpenClaw 用户常见的困惑之一,答案往往和 Session ID 的生命周期规则有关。本文基于官方文档梳理 sessionKey 与 sessionId 的区别,以及触发新会话的四种情形。

sessionKey vs sessionId:先分清两个概念

sessionKey —— 标识"你在哪个对话桶里"(路由+隔离) sessionId —— 每个 sessionKey 指向的"当前会话" (对应实际的 transcript 文件)

sessionKey 的常见命名模式:

主/直接对话(按 agent):agent:<agentId>:<mainKey> (默认 mainKey 为 "main") 群组:agent:<agentId>:<channel>:group:<id> 房间/频道(Discord/Slack): agent:<agentId>:<channel>:channel:<id> 或 ...:room:<id> Cron 定时任务:cron:<job.id> Webhook:hook:<uuid>(除非被覆盖)

理解这套命名规则的价值在于——排查"为什么两个看起来相关的对话没有共享上下文"这类问题时,可以直接对照sessionKey 的构成来判断它们是否真的被路由到了同一个会话桶。

触发新 sessionId 的四种情形

1. 手动重置(/new、/reset) 为该 sessionKey 创建一个全新的 sessionId 2. 每日重置(默认 Gateway 主机本地时间凌晨4点) 在重置边界之后收到的下一条消息会创建新 sessionId 3. 空闲过期(session.reset.idleMinutes, 旧版字段名 session.idleMinutes) 空闲窗口之后到达的消息会创建新 sessionId 如果同时配置了每日重置和空闲过期, 哪个先到期就按哪个生效 4. 线程父级分叉保护(session.parentForkMaxTokens, 默认 100000) 当父会话已经太大时,跳过父级 transcript 的分叉, 新线程直接从空白开始 设为 0 可以禁用这个保护机制

第四种情形容易被忽视,但在实际使用中很关键——如果你习惯在一个已经很长的会话里频繁开新线程/子话题,一旦父会话 Token 量超过阈值,新线程就不会继承父会话的上下文,而是从零开始。如果你依赖"新线程能看到主线程历史"这个假设,这条规则值得特别注意。

Session Store 里都记录了什么

sessionId 当前 transcript id updatedAt 最后活动时间戳 sessionFile 可选的显式 transcript 路径覆盖 chatType direct | group | room (帮助UI和发送策略判断) provider/subject/room/space/displayName 群组/频道标注用的元数据 开关类字段: thinkingLevel / verboseLevel / reasoningLevel / elevatedLevel sendPolicy(会话级覆盖) 模型选择: providerOverride / modelOverride / authProfileOverride Token 计数器(尽力而为,取决于Provider): inputTokens / outputTokens / totalTokens / contextTokens compactionCount 该 sessionKey 累计完成过多少次自动压缩 memoryFlushAt 上一次"压缩前记忆刷写"的时间戳 memoryFlushCompactionCount 上次刷写时的压缩计数

这个 Store 是安全可编辑的,但Gateway 才是权威来源——它可能在会话运行过程中重写或重新填充这些条目,直接手动改这个文件要谨慎,改完之后 Gateway 仍会按照自己的逻辑管理这些字段。

Transcript 文件结构(JSONL)

文件首行:会话头(type: "session",包含 id、cwd、 timestamp,可选 parentSession) 之后每行:带 id + parentId 的会话条目(树状结构) 主要条目类型: message 用户/助手/工具结果消息 custom_message 扩展注入的消息,会进入模型上下文 (但可以对UI隐藏) custom 扩展状态,不进入模型上下文 compaction 持久化的压缩摘要,带 firstKeptEntryId 和 tokensBefore branch_summary 在树分支间导航时的持久化摘要

值得注意的一点是——OpenClaw 刻意不会对 transcript 做"修复"处理;Gateway 通过 SessionManager 读写这些文件,保持原样。

Cron 会话的独立保留策略

孤立的 Cron 定时任务运行同样会创建会话条目和 transcript, 它们有专门的保留控制: cron.sessionRetention(默认 24h) 修剪 Session Store 中过旧的孤立 Cron 运行会话 (设为 false 可禁用) cron.runLog.maxBytes + cron.runLog.keepLines 修剪 ~/.openclaw/cron/runs/<jobId>.jsonl 文件 (默认 2,000,000 字节和 2000 行)

实战建议

1. 遇到"对话上下文丢失"类问题,先按四种触发情形逐一排查: 是手动重置了?跨过了每日重置边界?空闲过期了? 还是父会话太大触发了分叉保护? 2. 长期运行、经常需要保留完整上下文的主会话, 注意监控其 Token 量是否接近 parentForkMaxTokens 阈值, 避免影响后续开的子线程 3. 需要跨天保留同一个对话上下文的场景, 注意每日重置的默认时间点(凌晨4点,Gateway主机本地时区), 必要时调整或结合空闲过期规则统筹考虑 4. 大量使用 Cron 定时任务的部署,留意 cron.sessionRetention 和 runLog 相关配置, 避免会话记录无限累积占用磁盘

总结

Session ID 的生命周期由手动重置、每日重置、空闲过期、父级分叉保护这四种机制共同决定——理解这套规则,是排查"上下文为什么断了"这类问题的基础,也能帮你更合理地设计长期运行的多线程会话结构。


来源:Session Management & Compaction Deep Dive — OpenClaw 官方文档