会话管理深度解析
深度解析:会话存储 + 转录、生命周期和(自动)压缩内部机制
本文档解释了 OpenClaw 如何端到端地管理会话:
- 会话路由(入站消息如何映射到 sessionKey)
- 会话存储(sessions.json)及其跟踪内容
- 转录持久化(*.jsonl)及其结构
- 转录卫生(运行前的提供程序特定修复)
- 上下文限制(上下文窗口 vs 跟踪的令牌)
- 压缩(手动 + 自动压缩)以及在哪里挂钩预压缩工作
- 静默维护(例如,不应产生用户可见输出的内存写入)
如果您想先了解更高级别的概述,请从以下内容开始:
- /concepts/session
- /concepts/compaction
- /concepts/session-pruning
- /reference/transcript-hygiene
两个持久化层
OpenClaw 在两个层中持久化会话:
1. 会话存储(sessions.json)
- 键/值映射:sessionKey -> SessionEntry
- 小、可变、可以安全编辑(或删除条目)
- 跟踪会话元数据(当前会话 ID、最后活动、切换、令牌计数器等)
2. Transcript (<sessionId>.jsonl)
- 具有树结构的仅追加转录(条目具有 id + parentId)
- 存储实际对话 + 工具调用 + 压缩摘要
- 用于为未来的轮次重建模型上下文
会话键(`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。
会话存储架构(`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:最后一次刷新运行时的压缩计数
存储可以安全编辑,但网关是权威:它可能会在会话运行时重写或重新填充条目。
上下文窗口 vs 跟踪的令牌
两个不同的概念很重要:
1. 模型上下文窗口:每个模型的硬上限(模型可见的令牌)
2. 会话存储计数器:写入 sessions.json 的滚动统计信息(用于 /status 和仪表板)
如果您正在调整限制:
- 上下文窗口来自模型目录(可以通过配置覆盖)。
- 存储中的 contextTokens 是运行时估计/报告值;不要将其视为严格保证。
有关更多信息,请参阅 /token-use。
自动压缩何时发生(Pi 运行时)
在嵌入式 Pi 代理中,自动压缩在两种情况下触发:
1. 溢出恢复:模型返回上下文溢出错误 → 压缩 → 重试。
2. 阈值维护:成功轮次后,当:
contextTokens > contextWindow - reserveTokens
其中:
- contextWindow 是模型的上下文窗口
- reserveTokens 是为提示 + 下一个模型输出保留的余量
这些是 Pi 运行时语义(OpenClaw 消费事件,但 Pi 决定何时压缩)。
用户可见的界面
您可以通过以下方式观察压缩和会话状态:
- /status(在任何聊天会话中)
- openclaw status(CLI)
- openclaw sessions / sessions --json
- 详细模式:🧹 Auto-compaction complete + 压缩计数
预压缩"内存刷新"(已实现)
目标:在自动压缩发生之前,运行一个静默的代理轮次,将持久化状态写入磁盘(例如代理工作区中的 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 的刷新逻辑目前位于网关端。
故障排除清单
- 会话键错误?从 /concepts/session 开始,并确认 /status 中的 /status。
- 存储与转录不匹配?从 openclaw status 确认网关主机和存储路径。
- 压缩垃圾邮件?检查:
- 模型上下文窗口(太小)
- 压缩设置(reserveTokens 对于模型窗口太高,可能导致更早的压缩)
- 工具结果膨胀:启用/调整会话修剪
- 静默轮次泄漏?确认回复以 NO_REPLY(精确令牌)开头,并且您使用的是包含流抑制修复的构建。