OpenClawSkills
GitHub
参考 • 5 分钟阅读

会话管理深度解析

深度解析:会话存储 + 转录、生命周期和(自动)压缩内部机制

本文档解释了 OpenClaw 如何端到端地管理会话:

- 会话路由(入站消息如何映射到 sessionKey)

- 会话存储(sessions.json)及其跟踪内容

- 转录持久化(*.jsonl)及其结构

- 转录卫生(运行前的提供程序特定修复)

- 上下文限制(上下文窗口 vs 跟踪的令牌)

- 压缩(手动 + 自动压缩)以及在哪里挂钩预压缩工作

- 静默维护(例如,不应产生用户可见输出的内存写入)

如果您想先了解更高级别的概述,请从以下内容开始:

- /concepts/session

- /concepts/compaction

- /concepts/session-pruning

- /reference/transcript-hygiene

Tutorial.step

两个持久化层

OpenClaw 在两个层中持久化会话:

1. 会话存储(sessions.json)

- 键/值映射:sessionKey -> SessionEntry

- 小、可变、可以安全编辑(或删除条目)

- 跟踪会话元数据(当前会话 ID、最后活动、切换、令牌计数器等)

2. Transcript (<sessionId>.jsonl)

- 具有树结构的仅追加转录(条目具有 id + parentId)

- 存储实际对话 + 工具调用 + 压缩摘要

- 用于为未来的轮次重建模型上下文

Tutorial.step

会话键(`sessionKey`)

sessionKey 标识您所在的_哪个对话存储桶_(路由 + 隔离)。

常见模式:

- Main/direct chat (per agent): agent:<agentId>:<mainKey> (default main)

- Group: agent:<agentId>:<channel>:group:<id>

- Room/channel (Discord/Slack): agent:<agentId>:<channel>:channel:<id> or ...:room:<id>

- Cron: cron:<job.id>

- Webhook: hook:<uuid> (unless overridden)

规范规则记录在 /concepts/session。

Tutorial.step

会话存储架构(`sessions.json`)

存储的值类型是 src/config/sessions.ts 中的 src/config/sessions.ts。

关键字段(非详尽):

- sessionId:当前转录 ID(文件名由此派生,除非设置了 sessionFile)

- updatedAt:最后活动时间戳

- sessionFile:可选的显式转录路径覆盖

- chatType:direct | group | room(有助于 UI 和发送策略)

- provider、subject、room、space、displayName:用于群组/频道标签的元数据

切换:

- thinkingLevel、verboseLevel、reasoningLevel、elevatedLevel

- sendPolicy(每个会话覆盖)

模型选择:

- providerOverride、modelOverride、authProfileOverride

令牌计数器(尽力而为 / 提供程序依赖):

- inputTokens、outputTokens、totalTokens、contextTokens

- compactionCount:此会话键的自动压缩完成次数

- memoryFlushAt:最后一次预压缩内存刷新的时间戳

- memoryFlushCompactionCount:最后一次刷新运行时的压缩计数

存储可以安全编辑,但网关是权威:它可能会在会话运行时重写或重新填充条目。

Tutorial.step

上下文窗口 vs 跟踪的令牌

两个不同的概念很重要:

1. 模型上下文窗口:每个模型的硬上限(模型可见的令牌)

2. 会话存储计数器:写入 sessions.json 的滚动统计信息(用于 /status 和仪表板)

如果您正在调整限制:

- 上下文窗口来自模型目录(可以通过配置覆盖)。

- 存储中的 contextTokens 是运行时估计/报告值;不要将其视为严格保证。

有关更多信息,请参阅 /token-use。

Tutorial.step

自动压缩何时发生(Pi 运行时)

在嵌入式 Pi 代理中,自动压缩在两种情况下触发:

1. 溢出恢复:模型返回上下文溢出错误 → 压缩 → 重试。

2. 阈值维护:成功轮次后,当:

contextTokens > contextWindow - reserveTokens

其中:

- contextWindow 是模型的上下文窗口

- reserveTokens 是为提示 + 下一个模型输出保留的余量

这些是 Pi 运行时语义(OpenClaw 消费事件,但 Pi 决定何时压缩)。

Tutorial.step

用户可见的界面

您可以通过以下方式观察压缩和会话状态:

- /status(在任何聊天会话中)

- openclaw status(CLI)

- openclaw sessions / sessions --json

- 详细模式:🧹 Auto-compaction complete + 压缩计数

Tutorial.step

预压缩"内存刷新"(已实现)

目标:在自动压缩发生之前,运行一个静默的代理轮次,将持久化状态写入磁盘(例如代理工作区中的 memory/YYYY-MM-DD.md),以便压缩无法擦除关键上下文。

OpenClaw 使用预阈值刷新方法:

1. 监控会话上下文使用情况。

2. 当它超过"软阈值"(低于 Pi 的压缩阈值)时,运行一个静默的"立即写入内存"指令给代理。

3. 使用 NO_REPLY,以便用户什么也看不到。

配置(agents.defaults.compaction.memoryFlush):

- enabled(默认:true)

- softThresholdTokens(默认:4000)

- prompt(刷新轮次的用户消息)

- systemPrompt(为刷新轮次附加的额外系统提示)

备注:

- 默认提示/系统提示包含 NO_REPLY 提示以抑制传递。

- 刷新每个压缩周期运行一次(在 sessions.json 中跟踪)。

- 刷新仅针对嵌入式 Pi 会话运行(CLI 后端跳过它)。

- 当会话工作区为只读时跳过刷新(workspaceAccess: "ro" 或 "none")。

- 有关工作区文件布局和写入模式,请参阅 Memory。

Pi 还在扩展 API 中公开了 session_before_compact 挂钩,但 OpenClaw 的刷新逻辑目前位于网关端。

Tutorial.step

故障排除清单

- 会话键错误?从 /concepts/session 开始,并确认 /status 中的 /status。

- 存储与转录不匹配?从 openclaw status 确认网关主机和存储路径。

- 压缩垃圾邮件?检查:

- 模型上下文窗口(太小)

- 压缩设置(reserveTokens 对于模型窗口太高,可能导致更早的压缩)

- 工具结果膨胀:启用/调整会话修剪

- 静默轮次泄漏?确认回复以 NO_REPLY(精确令牌)开头,并且您使用的是包含流抑制修复的构建。