Files
openclaw/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

289 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
read_when:
- 你需要调试会话 ID、对话记录 JSONL 或 sessions.json 字段
- 你正在修改自动压缩行为或添加"压缩前"清理逻辑
- 你想要实现记忆刷写或静默系统轮次
summary: 深入解析:会话存储 + 对话记录、生命周期及(自动)压缩内部机制
title: 会话管理深入解析
x-i18n:
generated_at: "2026-02-01T21:37:55Z"
model: claude-opus-4-5
provider: pi
source_hash: bf3715770ba634363933f6038117b6a91af11c62f5191aaaf97e6bce099bc120
source_path: reference/session-management-compaction.md
workflow: 15
---
# 会话管理与压缩(深入解析)
本文档解释 OpenClaw 如何端到端管理会话:
- **会话路由**(入站消息如何映射到 `sessionKey`
- **会话存储**`sessions.json`)及其跟踪的内容
- **对话记录持久化**`*.jsonl`)及其结构
- **对话记录清理**(运行前的提供商特定修复)
- **上下文限制**(上下文窗口 vs 跟踪的 token 数)
- **压缩**(手动 + 自动压缩)以及压缩前工作的挂钩位置
- **静默清理**(例如不应产生用户可见输出的记忆写入)
如果你想先了解更高层级的概览,请从以下内容开始:
- [/concepts/session](/concepts/session)
- [/concepts/compaction](/concepts/compaction)
- [/concepts/session-pruning](/concepts/session-pruning)
- [/reference/transcript-hygiene](/reference/transcript-hygiene)
---
## 数据源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/Slack`agent:<agentId>:<channel>:channel:<id>``...:room:<id>`
- 定时任务:`cron:<job.id>`
- Webhook`hook:<uuid>`(除非被覆盖)
规范规则详见 [/concepts/session](/concepts/session)。
---
## 会话 ID`sessionId`
每个 `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`:可选的显式对话记录路径覆盖
- `chatType``direct | group | room`(帮助 UI 和发送策略)
- `provider``subject``room``space``displayName`:群组/频道标签的元数据
- 开关:
- `thinkingLevel``verboseLevel``reasoningLevel``elevatedLevel`
- `sendPolicy`(每会话覆盖)
- 模型选择:
- `providerOverride``modelOverride``authProfileOverride`
- Token 计数器(尽力而为 / 依赖提供商):
- `inputTokens``outputTokens``totalTokens``contextTokens`
- `compactionCount`:该会话键的自动压缩完成次数
- `memoryFlushAt`:上次压缩前记忆刷写的时间戳
- `memoryFlushCompactionCount`:上次刷写运行时的压缩计数
存储可安全编辑,但 Gateway网关是权威来源随着会话运行它可能重写或重新注入条目。
---
## 对话记录结构(`*.jsonl`
对话记录由 `@mariozechner/pi-coding-agent``SessionManager` 管理。
文件格式为 JSONL
- 第一行:会话头(`type: "session"`,包含 `id``cwd``timestamp`、可选 `parentSession`
- 之后:带 `id` + `parentId` 的会话条目(树结构)
主要条目类型:
- `message`:用户/助手/工具结果消息
- `custom_message`:扩展注入的消息,*会*进入模型上下文(可从 UI 隐藏)
- `custom`:扩展状态,*不会*进入模型上下文
- `compaction`:持久化的压缩摘要,包含 `firstKeptEntryId``tokensBefore`
- `branch_summary`:导航树分支时的持久化摘要
OpenClaw 有意**不**"修复"对话记录Gateway网关使用 `SessionManager` 来读写它们。
---
## 上下文窗口 vs 跟踪的 token
两个不同的概念很重要:
1. **模型上下文窗口**:每个模型的硬上限(模型可见的 token 数)
2. **会话存储计数器**:写入 `sessions.json` 的滚动统计(用于 /status 和仪表板)
如果你正在调整限制:
- 上下文窗口来自模型目录(可通过配置覆盖)。
- 存储中的 `contextTokens` 是运行时估算/报告值;不要将其视为严格保证。
更多信息请参阅 [/token-use](/token-use)。
---
## 压缩:什么是压缩
压缩将较旧的对话总结为对话记录中的持久化 `compaction` 条目,并保持最近的消息不变。
压缩后,后续轮次会看到:
- 压缩摘要
- `firstKeptEntryId` 之后的消息
压缩是**持久化的**(不同于会话修剪)。参阅 [/concepts/session-pruning](/concepts/session-pruning)。
---
## 自动压缩何时触发Pi 运行时)
在嵌入式 Pi 智能体中,自动压缩在两种情况下触发:
1. **溢出恢复**:模型返回上下文溢出错误 → 压缩 → 重试。
2. **阈值维护**:在成功的轮次之后,当:
`contextTokens > contextWindow - reserveTokens`
其中:
- `contextWindow` 是模型的上下文窗口
- `reserveTokens` 是为提示词 + 下一次模型输出预留的余量
这些是 Pi 运行时语义OpenClaw 消费事件,但由 Pi 决定何时压缩)。
---
## 压缩设置(`reserveTokens`、`keepRecentTokens`
Pi 的压缩设置位于 Pi 设置中:
```json5
{
compaction: {
enabled: true,
reserveTokens: 16384,
keepRecentTokens: 20000,
},
}
```
OpenClaw 还为嵌入式运行强制执行安全下限:
- 如果 `compaction.reserveTokens < reserveTokensFloor`OpenClaw 会将其提升。
- 默认下限为 `20000` token。
- 设置 `agents.defaults.compaction.reserveTokensFloor: 0` 可禁用下限。
- 如果已经更高OpenClaw 不做修改。
原因:为压缩不可避免之前的多轮"清理"(如记忆写入)留出足够余量。
实现:`src/agents/pi-settings.ts` 中的 `ensurePiCompactionReserveTokens()`
(从 `src/agents/pi-embedded-runner.ts` 调用)。
---
## 用户可见界面
你可以通过以下方式观察压缩和会话状态:
- `/status`(在任何聊天会话中)
- `openclaw status`CLI
- `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"`)时跳过刷写。
- 工作区文件布局和写入模式参阅[记忆](/concepts/memory)。
Pi 也在扩展 API 中暴露了 `session_before_compact` 钩子,但 OpenClaw 的刷写逻辑目前在 Gateway网关侧。
---
## 故障排除清单
- 会话键错误?从 [/concepts/session](/concepts/session) 开始,确认 `/status` 中的 `sessionKey`
- 存储与对话记录不匹配?确认 Gateway网关主机以及 `openclaw status` 中的存储路径。
- 压缩过于频繁?检查:
- 模型上下文窗口(太小)
- 压缩设置(`reserveTokens` 相对于模型窗口过高可能导致更早触发压缩)
- 工具结果膨胀:启用/调整会话修剪
- 静默轮次泄露?确认回复以 `NO_REPLY`(精确 token开头且你使用的构建版本包含流式传输抑制修复。