OpenClaw 101|04|Sessions
Session 是 OpenClaw 的状态、并发和隐私边界:决定消息路由、历史共享、reset、cleanup、transcript 和 queue lane。
OpenClaw 101 是一组面向 Agent Engineering 的系统拆解文章。它不把 OpenClaw 当成单一聊天产品,而是把它当作一个长期运行的 Personal Agent OS 来观察。
这一篇讲 Sessions。Agent 的历史不是一个全局 messages array。不同用户、群聊、房间、cron、webhook 必须进入不同状态边界,否则上下文会互相污染。

读完本文,你应该能回答
- session key 和 session id 分别解决什么问题?
- 为什么同一段会话需要串行化写入?
- DM、群聊、room、cron、webhook 的隐私边界有何不同?
- reset、cleanup、stale row 为什么是长期运行系统的一部分?
本篇在系列中的位置
状态边界篇,解释 DM、群聊、自动化和 webhook 为什么不能共享同一种历史策略。OpenClaw 101 的主线是:先看控制面,再看执行面和状态边界,再进入上下文、能力系统、长期记忆、自动化、真实设备、扩展和 QA。下一篇进入 Context,看 Session 边界里的哪些东西会真正进入模型输入。
贯穿案例
后文会反复使用同一个任务来落地抽象机制:用户在手机上对 OpenClaw 说:“帮我看一下这个 repo 的测试为什么失败;如果需要跑命令就先做,修好后在聊天里提醒我。”
在本篇中,重点观察这个任务在 Sessions 这一层会遇到的边界:谁接收它,谁拥有状态,谁能触发工具,谁记录结果,以及失败后从哪里恢复。
Session 边界表
| 环节 | 读者应该抓住的问题 |
|---|---|
| DM | 强隔离,避免私人历史泄漏到其他入口 |
| Group | 需要 group identity、thread 和 mention 规则 |
| Room | 更接近共享工作区,历史和权限更复杂 |
| Cron | 没有即时用户,但仍要绑定目标 session |
| Webhook | 外部事件进入系统,需要幂等和来源约束 |
核心判断
Session 是“谁和谁共享上下文”的工程答案,也是“谁可以并发写状态”的锁边界。
如果只看表面,很多 Agent 框架都像是“模型 + 工具 + UI”。但真正决定系统稳定性的,是这些边界如何被拆开:谁拥有状态,谁能触发副作用,谁负责恢复,谁暴露观察面,谁承担长期维护成本。
在 OpenClaw 里,Sessions 不是一个孤立模块,而是 Gateway、Session、Context、Tools、Plugins、Memory 之间的连接点。理解这个连接点,比记住某个命令或配置项更重要。
运行路径
一条真实消息进入系统后,大致会经过这些步骤:
- Inbound message 先被归一化为 channel、account、conversation、sender。
- Gateway 根据来源解析 session key。
- DM 可以共享 main session,也可以按 peer 或 channel-peer 隔离。
- Group、room、channel 通常按 conversation 隔离。
- Cron 和 webhook 往往使用独立 session,避免后台任务污染主对话。
- Session store 记录 sessionStartedAt、lastInteractionAt、updatedAt 等生命周期字段。
- Transcript 以 append-only 方式保存消息和工具事件。
- cleanup、daily reset、idle reset、manual reset 共同限制状态增长。
这些步骤看起来很多,但它们解决的是同一个问题:让 Agent 的行为从“模型临场发挥”变成“系统可控制、可观察、可恢复的运行过程”。
可迁移伪实现:Sessions
下面的伪代码是机制抽象,不对应 OpenClaw 的真实 API 或文件结构。
function resolveSessionKey(msg: InboundMessage): SessionKey {
if (msg.source === "cron") return freshCronSession(msg.jobId)
if (msg.source === "webhook") return hookSession(msg.hookId)
if (msg.conversation.kind === "group") return groupSession(msg.channelId, msg.roomId)
if (config.session.dmScope === "per-channel-peer") {
return dmSession(msg.channelId, msg.senderId)
}
return mainSession()
}
这段伪代码的重点不是函数名,而是边界:输入先被标准化,状态通过明确的 store 或 lane 管理,副作用通过 runtime 或 policy 执行,结果再回到 transcript、event stream 或 delivery target。
设计取舍
- 默认单用户 DM 连续性很好,但多人入口必须启用 DM isolation。
- session reset 不是删除记忆,而是切换对话窗口。
- 维护流程要保留外部 conversation pointers,同时清理过期 synthetic sessions。
这些取舍解释了 OpenClaw 为什么不像一个最小 demo。最小 demo 追求路径短,长期系统追求边界清晰。路径短会让第一个 demo 很快跑起来;边界清晰才会让系统在多渠道、长会话、多人入口、插件扩展和自动化场景下不崩。
评估清单
评估任何 Agent 框架的 Sessions 设计,可以看这几个问题:
- 这个层级是否有明确 owner,还是散落在多个客户端或插件里?
- 它是否把状态、权限、运行时副作用和展示逻辑分开?
- 它是否能被观测、被调试、被回放?
- 它失败时是否有恢复路径,而不是只给用户一个模型错误?
- 它是否避免把 provider/channel/tool 的私有细节写死进 core?
如果这些问题没有答案,系统一旦从单用户 demo 走向真实使用,很快就会在上下文污染、重复副作用、权限失控、长任务丢失和调试困难中付出代价。
下一篇
下一篇继续拆 Context。OpenClaw 101 的主线会继续沿着 Personal Agent OS 的边界往下走:从运行时,到状态,到能力系统,再到安全、扩展和 QA。
References
- Session management
- Messages
- Command queue
- Session pruning