Files
Moltbot/docs/zh-CN/reference/session-management-compaction.md
Josh Palmer 5676a6b38d Docs: normalize zh-CN terminology + tone
What: switch to 你/你的 tone; standardize Skills/Gateway网关/local loopback/私信 wording
Why: align zh-CN docs with issue 6995 feedback + idiomatic tech style
Tests: pnpm docs:build
2026-02-02 16:38:25 +01:00

10 KiB
Raw Blame History

read_when, summary, title, x-i18n
read_when summary title x-i18n
你需要调试会话 ID、对话记录 JSONL 或 sessions.json 字段
你正在修改自动压缩行为或添加"压缩前"清理逻辑
你想要实现记忆刷写或静默系统轮次
深入解析:会话存储 + 对话记录、生命周期及(自动)压缩内部机制 会话管理深入解析
generated_at model provider source_hash source_path workflow
2026-02-01T21:37:55Z claude-opus-4-5 pi bf3715770ba634363933f6038117b6a91af11c62f5191aaaf97e6bce099bc120 reference/session-management-compaction.md 15

会话管理与压缩(深入解析)

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

  • 会话路由(入站消息如何映射到 sessionKey
  • 会话存储sessions.json)及其跟踪的内容
  • 对话记录持久化*.jsonl)及其结构
  • 对话记录清理(运行前的提供商特定修复)
  • 上下文限制(上下文窗口 vs 跟踪的 token 数)
  • 压缩(手动 + 自动压缩)以及压缩前工作的挂钩位置
  • 静默清理(例如不应产生用户可见输出的记忆写入)

如果你想先了解更高层级的概览,请从以下内容开始:


数据源Gateway网关

OpenClaw 围绕单个 Gateway网关进程设计,该进程拥有会话状态。

  • UImacOS 应用、Web 控制界面、TUI应向 Gateway网关查询会话列表和 token 计数。
  • 在远程模式下,会话文件位于远程主机上;"检查本地 Mac 文件"不会反映 Gateway网关正在使用的内容。

两个持久化层

OpenClaw 通过两个层持久化会话:

  1. 会话存储(sessions.json

    • 键值映射:sessionKey -> SessionEntry
    • 体积小、可变、可安全编辑(或删除条目)
    • 跟踪会话元数据(当前会话 ID、最后活动时间、开关、token 计数器等)
  2. 对话记录(<sessionId>.jsonl

    • 具有树结构的追加写入对话记录(条目包含 id + parentId
    • 存储实际对话 + 工具调用 + 压缩摘要
    • 用于重建未来轮次的模型上下文

磁盘位置

每个智能体,在 Gateway网关主机上

  • 存储:~/.openclaw/agents/<agentId>/sessions/sessions.json
  • 对话记录:~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
    • Telegram 话题会话:.../<sessionId>-topic-<threadId>.jsonl

OpenClaw 通过 src/config/sessions.ts 解析这些路径。


会话键(sessionKey

sessionKey 标识你所在的对话桶(路由 + 隔离)。

常见模式:

  • 主/直接聊天(每个智能体):agent:<agentId>:<mainKey>(默认 main
  • 群组:agent:<agentId>:<channel>:group:<id>
  • 房间/频道Discord/Slackagent:<agentId>:<channel>:channel:<id>...:room:<id>
  • 定时任务:cron:<job.id>
  • Webhookhook:<uuid>(除非被覆盖)

规范规则详见 /concepts/session


会话 IDsessionId

每个 sessionKey 指向一个当前的 sessionId(继续对话的对话记录文件)。

经验法则:

  • 重置/new/reset)为该 sessionKey 创建新的 sessionId
  • 每日重置(默认为 Gateway网关主机本地时间凌晨 4:00在重置边界后的下一条消息时创建新的 sessionId
  • 空闲过期session.reset.idleMinutes 或旧版 session.idleMinutes)在空闲窗口后收到消息时创建新的 sessionId。当每日重置和空闲过期同时配置时,先到期的优先。

实现细节:决策发生在 src/auto-reply/reply/session.ts 中的 initSessionState() 函数。


会话存储结构(sessions.json

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

关键字段(非完整列表):

  • sessionId:当前对话记录 ID文件名由此派生除非设置了 sessionFile
  • updatedAt:最后活动时间戳
  • sessionFile:可选的显式对话记录路径覆盖
  • chatTypedirect | group | room(帮助 UI 和发送策略)
  • providersubjectroomspacedisplayName:群组/频道标签的元数据
  • 开关:
    • thinkingLevelverboseLevelreasoningLevelelevatedLevel
    • sendPolicy(每会话覆盖)
  • 模型选择:
    • providerOverridemodelOverrideauthProfileOverride
  • Token 计数器(尽力而为 / 依赖提供商):
    • inputTokensoutputTokenstotalTokenscontextTokens
  • compactionCount:该会话键的自动压缩完成次数
  • memoryFlushAt:上次压缩前记忆刷写的时间戳
  • memoryFlushCompactionCount:上次刷写运行时的压缩计数

存储可安全编辑,但 Gateway网关是权威来源随着会话运行它可能重写或重新注入条目。


对话记录结构(*.jsonl

对话记录由 @mariozechner/pi-coding-agentSessionManager 管理。

文件格式为 JSONL

  • 第一行:会话头(type: "session",包含 idcwdtimestamp、可选 parentSession
  • 之后:带 id + parentId 的会话条目(树结构)

主要条目类型:

  • message:用户/助手/工具结果消息
  • custom_message:扩展注入的消息,进入模型上下文(可从 UI 隐藏)
  • custom:扩展状态,不会进入模型上下文
  • compaction:持久化的压缩摘要,包含 firstKeptEntryIdtokensBefore
  • branch_summary:导航树分支时的持久化摘要

OpenClaw 有意"修复"对话记录Gateway网关使用 SessionManager 来读写它们。


上下文窗口 vs 跟踪的 token

两个不同的概念很重要:

  1. 模型上下文窗口:每个模型的硬上限(模型可见的 token 数)
  2. 会话存储计数器:写入 sessions.json 的滚动统计(用于 /status 和仪表板)

如果你正在调整限制:

  • 上下文窗口来自模型目录(可通过配置覆盖)。
  • 存储中的 contextTokens 是运行时估算/报告值;不要将其视为严格保证。

更多信息请参阅 /token-use


压缩:什么是压缩

压缩将较旧的对话总结为对话记录中的持久化 compaction 条目,并保持最近的消息不变。

压缩后,后续轮次会看到:

  • 压缩摘要
  • firstKeptEntryId 之后的消息

压缩是持久化的(不同于会话修剪)。参阅 /concepts/session-pruning


自动压缩何时触发Pi 运行时)

在嵌入式 Pi 智能体中,自动压缩在两种情况下触发:

  1. 溢出恢复:模型返回上下文溢出错误 → 压缩 → 重试。
  2. 阈值维护:在成功的轮次之后,当:

contextTokens > contextWindow - reserveTokens

其中:

  • contextWindow 是模型的上下文窗口
  • reserveTokens 是为提示词 + 下一次模型输出预留的余量

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


压缩设置(reserveTokenskeepRecentTokens

Pi 的压缩设置位于 Pi 设置中:

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

OpenClaw 还为嵌入式运行强制执行安全下限:

  • 如果 compaction.reserveTokens < reserveTokensFloorOpenClaw 会将其提升。
  • 默认下限为 20000 token。
  • 设置 agents.defaults.compaction.reserveTokensFloor: 0 可禁用下限。
  • 如果已经更高OpenClaw 不做修改。

原因:为压缩不可避免之前的多轮"清理"(如记忆写入)留出足够余量。

实现:src/agents/pi-settings.ts 中的 ensurePiCompactionReserveTokens() (从 src/agents/pi-embedded-runner.ts 调用)。


用户可见界面

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

  • /status(在任何聊天会话中)
  • openclaw statusCLI
  • openclaw sessions / sessions --json
  • 详细模式:🧹 Auto-compaction complete + 压缩计数

静默清理(NO_REPLY

OpenClaw 支持用于后台任务的"静默"轮次,用户不应看到中间输出。

约定:

  • 助手以 NO_REPLY 开始其输出,表示"不要向用户传递回复"。
  • OpenClaw 在传递层中剥离/抑制此标记。

2026.1.10 起,当部分块以 NO_REPLY 开头时OpenClaw 还会抑制草稿/输入中的流式传输,因此静默操作不会在轮次中途泄露部分输出。


压缩前"记忆刷写"(已实现)

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

OpenClaw 使用预阈值刷写方法:

  1. 监控会话上下文使用量。
  2. 当超过"软阈值"(低于 Pi 的压缩阈值)时,向智能体运行静默的"立即写入记忆"指令。
  3. 使用 NO_REPLY 使用户看不到任何内容。

配置(agents.defaults.compaction.memoryFlush

  • enabled(默认:true
  • softThresholdTokens(默认:4000
  • prompt(刷写轮次的用户消息)
  • systemPrompt(刷写轮次追加的额外系统提示词)

备注:

  • 默认的 prompt/systemPrompt 包含 NO_REPLY 提示以抑制传递。
  • 每个压缩周期刷写运行一次(在 sessions.json 中跟踪)。
  • 刷写仅在嵌入式 Pi 会话中运行CLI 后端跳过)。
  • 当会话工作区为只读(workspaceAccess: "ro""none")时跳过刷写。
  • 工作区文件布局和写入模式参阅记忆

Pi 也在扩展 API 中暴露了 session_before_compact 钩子,但 OpenClaw 的刷写逻辑目前在 Gateway网关侧。


故障排除清单

  • 会话键错误?从 /concepts/session 开始,确认 /status 中的 sessionKey
  • 存储与对话记录不匹配?确认 Gateway网关主机以及 openclaw status 中的存储路径。
  • 压缩过于频繁?检查:
    • 模型上下文窗口(太小)
    • 压缩设置(reserveTokens 相对于模型窗口过高可能导致更早触发压缩)
    • 工具结果膨胀:启用/调整会话修剪
  • 静默轮次泄露?确认回复以 NO_REPLY(精确 token开头且你使用的构建版本包含流式传输抑制修复。