chore(i18n): refresh zh-CN translations
This commit is contained in:
parent
18000497d8
commit
3dd12cf212
@ -1,65 +1,123 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想了解自动压缩和 /compact
|
||||
- 你正在调试因长会话触及上下文限制的问题
|
||||
summary: OpenClaw 如何总结长对话以保持在模型限制之内
|
||||
title: Compaction
|
||||
- 你正在排查达到上下文限制的长会话
|
||||
summary: OpenClaw 如何总结长对话以保持在模型限制范围内
|
||||
title: 压缩
|
||||
x-i18n:
|
||||
generated_at: "2026-04-05T08:20:48Z"
|
||||
generated_at: "2026-04-07T17:57:26Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 4c6dbd6ebdcd5f918805aafdc153925efef3e130faa3fab3c630832e938219fc
|
||||
source_hash: e6590b82a8c3a9c310998d653459ca4d8612495703ca0a8d8d306d7643142fd1
|
||||
source_path: concepts/compaction.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# Compaction
|
||||
# 压缩
|
||||
|
||||
每个模型都有一个上下文窗口——即它最多能处理的 token 数量。
|
||||
每个模型都有一个上下文窗口——即它能够处理的最大 token 数量。
|
||||
当对话接近这个限制时,OpenClaw 会将较早的消息**压缩**为摘要,
|
||||
以便聊天可以继续进行。
|
||||
以便聊天能够继续。
|
||||
|
||||
## 工作原理
|
||||
|
||||
1. 较早的对话轮次会被总结为一条压缩条目。
|
||||
2. 该摘要会保存在会话转录中。
|
||||
2. 摘要会保存在会话转录中。
|
||||
3. 最近的消息会保持原样。
|
||||
|
||||
当 OpenClaw 将历史拆分为压缩分块时,它会让 assistant 工具
|
||||
调用与其匹配的 `toolResult` 条目保持配对。如果拆分点落在工具块
|
||||
内部,OpenClaw 会移动边界,以便这对条目保持在一起,并保留
|
||||
当前未总结的尾部内容。
|
||||
当 OpenClaw 将历史记录拆分为压缩分块时,它会让智能体工具调用
|
||||
与其对应的 `toolResult` 条目保持配对。如果拆分点落在工具块内部,
|
||||
OpenClaw 会移动边界,以确保这对内容保持在一起,并保留当前尚未摘要的尾部内容。
|
||||
|
||||
完整的对话历史仍会保存在磁盘上。压缩只会改变模型在下一轮
|
||||
看到的内容。
|
||||
完整的对话历史仍会保存在磁盘上。压缩只会改变模型在下一轮中看到的内容。
|
||||
|
||||
## 自动压缩
|
||||
|
||||
自动压缩默认开启。当会话接近上下文
|
||||
限制时,或当模型返回上下文溢出错误时,它就会运行(在这种情况下,
|
||||
OpenClaw 会执行压缩并重试)。典型的溢出特征包括
|
||||
自动压缩默认开启。当会话接近上下文限制时,或者当模型返回上下文溢出错误时,它就会运行(在这种情况下,OpenClaw 会先压缩再重试)。典型的溢出特征包括
|
||||
`request_too_large`、`context length exceeded`、`input exceeds the maximum
|
||||
number of tokens`、`input token count exceeds the maximum number of input
|
||||
tokens`、`input is too long for the model` 和 `ollama error: context length
|
||||
exceeded`。
|
||||
|
||||
<Info>
|
||||
在压缩之前,OpenClaw 会自动提醒智能体将重要
|
||||
备注保存到 [memory](/concepts/memory) 文件中。这样可以防止上下文丢失。
|
||||
在压缩之前,OpenClaw 会自动提醒智能体将重要笔记保存到 [memory](/zh-CN/concepts/memory) 文件中。这样可以防止上下文丢失。
|
||||
</Info>
|
||||
|
||||
使用你的 `openclaw.json` 中的 `agents.defaults.compaction` 设置来配置压缩行为(模式、目标 token 数等)。
|
||||
压缩摘要默认会保留不透明标识符(`identifierPolicy: "strict"`)。你可以使用 `identifierPolicy: "off"` 覆盖此行为,或者使用 `identifierPolicy: "custom"` 和 `identifierInstructions` 提供自定义文本。
|
||||
|
||||
你也可以通过 `agents.defaults.compaction.model` 为压缩摘要指定不同的模型。当你的主模型是本地模型或小模型,而你希望由能力更强的模型生成压缩摘要时,这会很有用。该覆盖项接受任意 `provider/model-id` 字符串:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"compaction": {
|
||||
"model": "openrouter/anthropic/claude-sonnet-4-6"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这同样适用于本地模型,例如专门用于摘要的第二个 Ollama 模型,或经过微调的压缩专用模型:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"compaction": {
|
||||
"model": "ollama/llama3.1:8b"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果未设置,压缩会使用该智能体的主模型。
|
||||
|
||||
## 可插拔压缩提供商
|
||||
|
||||
插件可以通过插件 API 上的 `registerCompactionProvider()` 注册自定义压缩提供商。当某个提供商已注册并配置后,OpenClaw 会将摘要生成委托给它,而不是使用内置的 LLM 流程。
|
||||
|
||||
要使用已注册的提供商,请在你的配置中设置提供商 id:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"compaction": {
|
||||
"provider": "my-provider"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
设置 `provider` 会自动强制使用 `mode: "safeguard"`。提供商会收到与内置路径相同的压缩指令和标识符保留策略,并且在提供商输出后,OpenClaw 仍会保留最近轮次和拆分轮次的后缀上下文。如果提供商失败或返回空结果,OpenClaw 会回退到内置 LLM 摘要生成。
|
||||
|
||||
## 自动压缩(默认开启)
|
||||
|
||||
当会话接近或超出模型的上下文窗口时,OpenClaw 会触发自动压缩,并可能使用压缩后的上下文重试原始请求。
|
||||
|
||||
你会看到:
|
||||
|
||||
- 在详细模式下显示 `🧹 Auto-compaction complete`
|
||||
- `/status` 显示 `🧹 Compactions: <count>`
|
||||
|
||||
在压缩之前,OpenClaw 可以运行一次**静默 memory 刷新**轮次,以将持久笔记存储到磁盘。详情和配置请参阅 [Memory](/zh-CN/concepts/memory)。
|
||||
|
||||
## 手动压缩
|
||||
|
||||
在任意聊天中输入 `/compact` 即可强制执行一次压缩。你还可以添加说明来引导
|
||||
摘要内容:
|
||||
在任意聊天中输入 `/compact` 即可强制执行一次压缩。你还可以添加说明来引导摘要:
|
||||
|
||||
```
|
||||
/compact Focus on the API design decisions
|
||||
```
|
||||
|
||||
## 使用其他模型
|
||||
## 使用不同的模型
|
||||
|
||||
默认情况下,压缩使用你的智能体主模型。你也可以使用能力更强的模型来获得更好的摘要:
|
||||
默认情况下,压缩使用你的智能体主模型。你可以使用能力更强的模型来获得更好的摘要:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -75,8 +133,7 @@ exceeded`。
|
||||
|
||||
## 压缩开始通知
|
||||
|
||||
默认情况下,压缩会静默执行。若要在压缩
|
||||
开始时显示简短通知,请启用 `notifyUser`:
|
||||
默认情况下,压缩会静默运行。若要在压缩开始时显示简短通知,请启用 `notifyUser`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -90,39 +147,33 @@ exceeded`。
|
||||
}
|
||||
```
|
||||
|
||||
启用后,用户会在每次压缩开始时看到一条简短消息(例如,“正在压缩
|
||||
上下文...”)。
|
||||
启用后,用户会在每次压缩开始时看到一条简短消息(例如,“正在压缩上下文...”)。
|
||||
|
||||
## 压缩与修剪
|
||||
|
||||
| | 压缩 | 修剪 |
|
||||
| ---------------- | ---------------------------- | -------------------------------- |
|
||||
| **它的作用** | 总结较早的对话 | 裁剪旧的工具结果 |
|
||||
| **是否保存?** | 是(保存在会话转录中) | 否(仅在内存中,每次请求单独处理) |
|
||||
| **作用** | 总结较早的对话内容 | 裁剪旧的工具结果 |
|
||||
| **会保存吗?** | 会(保存在会话转录中) | 不会(仅在内存中、按每次请求) |
|
||||
| **范围** | 整个对话 | 仅工具结果 |
|
||||
|
||||
[Session pruning](/concepts/session-pruning) 是一种更轻量的补充方式,
|
||||
可在不总结的情况下裁剪工具输出。
|
||||
[Session pruning](/zh-CN/concepts/session-pruning) 是一种更轻量的补充方式,它会在不生成摘要的情况下裁剪工具输出。
|
||||
|
||||
## 故障排除
|
||||
|
||||
**压缩过于频繁?** 模型的上下文窗口可能较小,或者工具
|
||||
输出可能较大。可以尝试启用
|
||||
[Session pruning](/concepts/session-pruning)。
|
||||
**压缩太频繁?** 模型的上下文窗口可能较小,或者工具输出可能较大。尝试启用
|
||||
[session pruning](/zh-CN/concepts/session-pruning)。
|
||||
|
||||
**压缩后感觉上下文过时?** 使用 `/compact Focus on <topic>` 来
|
||||
引导摘要,或启用 [memory flush](/concepts/memory),以便备注
|
||||
能够保留下来。
|
||||
**压缩后感觉上下文不够新鲜?** 使用 `/compact Focus on <topic>` 来引导摘要,或者启用 [memory flush](/zh-CN/concepts/memory),以便笔记得以保留。
|
||||
|
||||
**需要一个全新的开始?** `/new` 会启动一个全新的会话,而不会执行压缩。
|
||||
**需要一个全新的开始?** `/new` 会启动一个新的会话,而不会进行压缩。
|
||||
|
||||
有关高级配置(预留 token、标识符保留、自定义
|
||||
上下文引擎、OpenAI 服务端压缩),请参阅
|
||||
[Session Management Deep Dive](/reference/session-management-compaction)。
|
||||
有关高级配置(预留 token、标识符保留、自定义上下文引擎、OpenAI 服务端压缩),请参阅
|
||||
[Session Management Deep Dive](/zh-CN/reference/session-management-compaction)。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Session](/concepts/session) — 会话管理与生命周期
|
||||
- [Session Pruning](/concepts/session-pruning) — 裁剪工具结果
|
||||
- [Context](/concepts/context) — 如何为智能体轮次构建上下文
|
||||
- [Hooks](/automation/hooks) — 压缩生命周期 hooks(before_compaction、after_compaction)
|
||||
- [Session](/zh-CN/concepts/session) — 会话管理与生命周期
|
||||
- [Session Pruning](/zh-CN/concepts/session-pruning) — 裁剪工具结果
|
||||
- [Context](/zh-CN/concepts/context) — 如何为智能体轮次构建上下文
|
||||
- [Hooks](/zh-CN/automation/hooks) — 压缩生命周期钩子(before_compaction、after_compaction)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,15 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要调试 session id、transcript JSONL 或 sessions.json 字段
|
||||
- 你正在修改自动压缩行为,或添加“压缩前”清理逻辑
|
||||
- 你想实现 memory flush 或静默 system turn
|
||||
summary: 深入解析:会话存储 + transcript、生命周期,以及(自动)压缩内部机制
|
||||
- 你需要调试会话 id、转录 JSONL 或 sessions.json 字段
|
||||
- 你正在更改自动压缩行为,或添加“压缩前”整理逻辑
|
||||
- 你想要实现 memory flush 或静默系统轮次
|
||||
summary: 深入解析:会话存储 + 转录、生命周期,以及(自动)压缩内部机制
|
||||
title: 会话管理深入解析
|
||||
x-i18n:
|
||||
generated_at: "2026-04-06T12:45:16Z"
|
||||
generated_at: "2026-04-07T17:57:46Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: e379d624dd7808d3af25ed011079268ce6a9da64bb3f301598884ad4c46ab091
|
||||
source_hash: cb1a4048646486693db8943a9e9c6c5bcb205f0ed532b34842de3d0346077454
|
||||
source_path: reference/session-management-compaction.md
|
||||
workflow: 15
|
||||
---
|
||||
@ -19,14 +19,14 @@ x-i18n:
|
||||
本文档解释 OpenClaw 如何端到端管理会话:
|
||||
|
||||
- **会话路由**(入站消息如何映射到 `sessionKey`)
|
||||
- **会话存储**(`sessions.json`)及其跟踪内容
|
||||
- **Transcript 持久化**(`*.jsonl`)及其结构
|
||||
- **Transcript 清理**(运行前针对特定提供商的修正)
|
||||
- **上下文限制**(上下文窗口与已跟踪 token 的区别)
|
||||
- **压缩**(手动 + 自动压缩)以及应在何处挂接压缩前工作
|
||||
- **静默清理**(例如不应产生用户可见输出的 memory 写入)
|
||||
- **会话存储**(`sessions.json`)及其跟踪的内容
|
||||
- **转录持久化**(`*.jsonl`)及其结构
|
||||
- **转录清理**(运行前按提供商进行的特定修正)
|
||||
- **上下文限制**(上下文窗口与已跟踪 token)
|
||||
- **压缩**(手动 + 自动压缩)以及在哪里挂接压缩前逻辑
|
||||
- **静默整理**(例如不应产生用户可见输出的 memory 写入)
|
||||
|
||||
如果你想先看更高层级的概览,请从以下内容开始:
|
||||
如果你想先看更高层的概览,请从以下内容开始:
|
||||
|
||||
- [/concepts/session](/zh-CN/concepts/session)
|
||||
- [/concepts/compaction](/zh-CN/concepts/compaction)
|
||||
@ -37,12 +37,12 @@ x-i18n:
|
||||
|
||||
---
|
||||
|
||||
## 单一事实来源:Gateway 网关
|
||||
## 事实来源:Gateway 网关
|
||||
|
||||
OpenClaw 的设计围绕单个**Gateway 网关 进程**展开,由它持有会话状态。
|
||||
OpenClaw 围绕一个拥有会话状态的单一 **Gateway 网关进程** 进行设计。
|
||||
|
||||
- UI(macOS 应用、网页 Control UI、TUI)应向 Gateway 网关 查询会话列表和 token 计数。
|
||||
- 在远程模式下,会话文件位于远程主机上;“查看你本地 Mac 上的文件”并不能反映 Gateway 网关 实际使用的内容。
|
||||
- UI(macOS 应用、网页 Control UI、TUI)应向 Gateway 网关查询会话列表和 token 计数。
|
||||
- 在远程模式下,会话文件位于远程主机上;“检查你本地 Mac 上的文件”不会反映 Gateway 网关实际使用的内容。
|
||||
|
||||
---
|
||||
|
||||
@ -51,24 +51,24 @@ OpenClaw 的设计围绕单个**Gateway 网关 进程**展开,由它持有会
|
||||
OpenClaw 以两层方式持久化会话:
|
||||
|
||||
1. **会话存储(`sessions.json`)**
|
||||
- 键 / 值映射:`sessionKey -> SessionEntry`
|
||||
- 体积小、可变、安全可编辑(或删除条目)
|
||||
- 跟踪会话元数据(当前 session id、最近活动时间、开关、token 计数器等)
|
||||
- 键/值映射:`sessionKey -> SessionEntry`
|
||||
- 小型、可变、可安全编辑(或删除条目)
|
||||
- 跟踪会话元数据(当前会话 id、最近活动时间、开关、token 计数器等)
|
||||
|
||||
2. **Transcript(`<sessionId>.jsonl`)**
|
||||
- 追加写入的 transcript,带树结构(条目具有 `id` + `parentId`)
|
||||
2. **转录(`<sessionId>.jsonl`)**
|
||||
- 具有树结构的仅追加转录(条目包含 `id` + `parentId`)
|
||||
- 存储实际对话 + 工具调用 + 压缩摘要
|
||||
- 用于为后续轮次重建模型上下文
|
||||
|
||||
---
|
||||
|
||||
## 磁盘上的位置
|
||||
## 磁盘位置
|
||||
|
||||
每个智能体在 Gateway 网关 主机上的位置:
|
||||
对于 Gateway 网关主机上的每个智能体:
|
||||
|
||||
- 存储:`~/.openclaw/agents/<agentId>/sessions/sessions.json`
|
||||
- Transcripts:`~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl`
|
||||
- Telegram 话题会话:`.../<sessionId>-topic-<threadId>.jsonl`
|
||||
- 转录:`~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl`
|
||||
- Telegram 主题会话:`.../<sessionId>-topic-<threadId>.jsonl`
|
||||
|
||||
OpenClaw 通过 `src/config/sessions.ts` 解析这些路径。
|
||||
|
||||
@ -76,23 +76,23 @@ OpenClaw 通过 `src/config/sessions.ts` 解析这些路径。
|
||||
|
||||
## 存储维护和磁盘控制
|
||||
|
||||
会话持久化为 `sessions.json` 和 transcript 工件提供了自动维护控制(`session.maintenance`):
|
||||
会话持久化为 `sessions.json` 和转录产物提供自动维护控制(`session.maintenance`):
|
||||
|
||||
- `mode`:`warn`(默认)或 `enforce`
|
||||
- `pruneAfter`:陈旧条目的保留期限截止值(默认 `30d`)
|
||||
- `maxEntries`:`sessions.json` 中条目上限(默认 `500`)
|
||||
- `pruneAfter`:过期条目的陈旧时间阈值(默认 `30d`)
|
||||
- `maxEntries`:`sessions.json` 中的条目上限(默认 `500`)
|
||||
- `rotateBytes`:当 `sessions.json` 过大时进行轮转(默认 `10mb`)
|
||||
- `resetArchiveRetention`:`*.reset.<timestamp>` transcript 归档的保留期(默认与 `pruneAfter` 相同;`false` 表示禁用清理)
|
||||
- `maxDiskBytes`:可选的 sessions 目录预算
|
||||
- `resetArchiveRetention`:`*.reset.<timestamp>` 转录归档的保留期(默认:与 `pruneAfter` 相同;`false` 表示禁用清理)
|
||||
- `maxDiskBytes`:可选的 sessions 目录容量预算
|
||||
- `highWaterBytes`:清理后的可选目标值(默认是 `maxDiskBytes` 的 `80%`)
|
||||
|
||||
磁盘预算清理的执行顺序(`mode: "enforce"`):
|
||||
|
||||
1. 先移除最旧的归档或孤立 transcript 工件。
|
||||
2. 如果仍高于目标值,则逐出最旧的会话条目及其 transcript 文件。
|
||||
3. 持续执行,直到占用量小于或等于 `highWaterBytes`。
|
||||
1. 先移除最旧的已归档或孤立转录产物。
|
||||
2. 如果仍高于目标,则驱逐最旧的会话条目及其转录文件。
|
||||
3. 持续执行,直到使用量小于或等于 `highWaterBytes`。
|
||||
|
||||
在 `mode: "warn"` 下,OpenClaw 会报告潜在的逐出项,但不会修改存储 / 文件。
|
||||
在 `mode: "warn"` 下,OpenClaw 会报告可能的驱逐操作,但不会修改存储/文件。
|
||||
|
||||
按需运行维护:
|
||||
|
||||
@ -103,57 +103,57 @@ openclaw sessions cleanup --enforce
|
||||
|
||||
---
|
||||
|
||||
## Cron 会话和运行日志
|
||||
## 定时任务会话和运行日志
|
||||
|
||||
隔离的 cron 运行也会创建会话条目 / transcript,并且它们有专门的保留控制:
|
||||
隔离的 cron 运行也会创建会话条目/转录,并且它们有专用的保留控制:
|
||||
|
||||
- `cron.sessionRetention`(默认 `24h`)会从会话存储中清理旧的隔离 cron 运行会话(`false` 表示禁用)。
|
||||
- `cron.runLog.maxBytes` + `cron.runLog.keepLines` 会裁剪 `~/.openclaw/cron/runs/<jobId>.jsonl` 文件(默认:`2_000_000` 字节和 `2000` 行)。
|
||||
- `cron.runLog.maxBytes` + `cron.runLog.keepLines` 会清理 `~/.openclaw/cron/runs/<jobId>.jsonl` 文件(默认值:`2_000_000` 字节和 `2000` 行)。
|
||||
|
||||
---
|
||||
|
||||
## 会话键(`sessionKey`)
|
||||
|
||||
`sessionKey` 用于标识你所在的_哪个会话桶_(路由 + 隔离)。
|
||||
`sessionKey` 用于标识你处于哪个 _对话桶_ 中(路由 + 隔离)。
|
||||
|
||||
常见模式:
|
||||
|
||||
- 主 / 直接聊天(每个智能体):`agent:<agentId>:<mainKey>`(默认 `main`)
|
||||
- 主/直接聊天(每个智能体):`agent:<agentId>:<mainKey>`(默认 `main`)
|
||||
- 群组:`agent:<agentId>:<channel>:group:<id>`
|
||||
- 房间 / 渠道(Discord / Slack):`agent:<agentId>:<channel>:channel:<id>` 或 `...:room:<id>`
|
||||
- 房间/渠道(Discord/Slack):`agent:<agentId>:<channel>:channel:<id>` 或 `...:room:<id>`
|
||||
- Cron:`cron:<job.id>`
|
||||
- Webhook:`hook:<uuid>`(除非被覆盖)
|
||||
|
||||
规范规则记录在 [/concepts/session](/zh-CN/concepts/session)。
|
||||
规范规则记录于 [/concepts/session](/zh-CN/concepts/session)。
|
||||
|
||||
---
|
||||
|
||||
## 会话 id(`sessionId`)
|
||||
|
||||
每个 `sessionKey` 都会指向当前的 `sessionId`(用于延续对话的 transcript 文件)。
|
||||
每个 `sessionKey` 都指向当前的 `sessionId`(继续该对话的转录文件)。
|
||||
|
||||
经验规则:
|
||||
|
||||
- **重置**(`/new`、`/reset`)会为该 `sessionKey` 创建新的 `sessionId`。
|
||||
- **每日重置**(默认是 Gateway 网关 主机本地时间凌晨 4:00)会在越过重置边界后的下一条消息时创建新的 `sessionId`。
|
||||
- **空闲过期**(`session.reset.idleMinutes` 或旧版 `session.idleMinutes`)会在消息于空闲窗口之后到达时创建新的 `sessionId`。如果同时配置了 daily 和 idle,以先过期者为准。
|
||||
- **线程父级分叉保护**(`session.parentForkMaxTokens`,默认 `100000`)会在父会话已经过大时跳过父 transcript 分叉;新线程会从头开始。设置为 `0` 可禁用。
|
||||
- **每日重置**(默认是 Gateway 网关主机本地时间凌晨 4:00)会在越过重置边界后的下一条消息时创建新的 `sessionId`。
|
||||
- **空闲过期**(`session.reset.idleMinutes` 或旧版 `session.idleMinutes`)会在消息于空闲窗口之后到达时创建新的 `sessionId`。当每日重置和空闲过期同时配置时,以先到期者为准。
|
||||
- **线程父级分叉保护**(`session.parentForkMaxTokens`,默认 `100000`)会在父会话已经过大时跳过父转录分叉;新线程将从全新状态开始。设为 `0` 可禁用。
|
||||
|
||||
实现细节:这一决策发生在 `src/auto-reply/reply/session.ts` 中的 `initSessionState()`。
|
||||
实现细节:该决策发生在 `src/auto-reply/reply/session.ts` 中的 `initSessionState()`。
|
||||
|
||||
---
|
||||
|
||||
## 会话存储结构(`sessions.json`)
|
||||
|
||||
存储的值类型是 `src/config/sessions.ts` 中的 `SessionEntry`。
|
||||
存储的值类型是在 `src/config/sessions.ts` 中定义的 `SessionEntry`。
|
||||
|
||||
关键字段(非完整列表):
|
||||
|
||||
- `sessionId`:当前 transcript id(除非设置了 `sessionFile`,否则文件名从这里派生)
|
||||
- `sessionId`:当前转录 id(除非设置了 `sessionFile`,否则文件名从这里派生)
|
||||
- `updatedAt`:最近活动时间戳
|
||||
- `sessionFile`:可选的显式 transcript 路径覆盖
|
||||
- `sessionFile`:可选的显式转录路径覆盖
|
||||
- `chatType`:`direct | group | room`(帮助 UI 和发送策略)
|
||||
- `provider`、`subject`、`room`、`space`、`displayName`:用于群组 / 渠道标签的元数据
|
||||
- `provider`、`subject`、`room`、`space`、`displayName`:用于群组/渠道标签的元数据
|
||||
- 开关:
|
||||
- `thinkingLevel`、`verboseLevel`、`reasoningLevel`、`elevatedLevel`
|
||||
- `sendPolicy`(按会话覆盖)
|
||||
@ -161,69 +161,72 @@ openclaw sessions cleanup --enforce
|
||||
- `providerOverride`、`modelOverride`、`authProfileOverride`
|
||||
- Token 计数器(尽力而为 / 取决于提供商):
|
||||
- `inputTokens`、`outputTokens`、`totalTokens`、`contextTokens`
|
||||
- `compactionCount`:该会话键完成自动压缩的次数
|
||||
- `memoryFlushAt`:最近一次压缩前 memory flush 的时间戳
|
||||
- `memoryFlushCompactionCount`:最近一次 flush 运行时的压缩计数
|
||||
- `compactionCount`:此会话键已完成自动压缩的次数
|
||||
- `memoryFlushAt`:上次压缩前 memory flush 的时间戳
|
||||
- `memoryFlushCompactionCount`:上次 flush 运行时的压缩计数
|
||||
|
||||
这个存储可以安全编辑,但 Gateway 网关 才是权威:随着会话运行,它可能会重写或重新填充条目。
|
||||
该存储可安全编辑,但 Gateway 网关才是权威来源:会话运行时,它可能会重写或重新填充条目。
|
||||
|
||||
---
|
||||
|
||||
## Transcript 结构(`*.jsonl`)
|
||||
## 转录结构(`*.jsonl`)
|
||||
|
||||
Transcripts 由 `@mariozechner/pi-coding-agent` 的 `SessionManager` 管理。
|
||||
转录由 `@mariozechner/pi-coding-agent` 的 `SessionManager` 管理。
|
||||
|
||||
该文件采用 JSONL 格式:
|
||||
该文件为 JSONL:
|
||||
|
||||
- 第一行:会话头(`type: "session"`,包含 `id`、`cwd`、`timestamp`、可选的 `parentSession`)
|
||||
- 后续内容:带 `id` + `parentId` 的会话条目(树结构)
|
||||
- 然后:带有 `id` + `parentId` 的会话条目(树)
|
||||
|
||||
值得注意的条目类型:
|
||||
|
||||
- `message`:用户 / 助手 / `toolResult` 消息
|
||||
- `custom_message`:由扩展注入的、_会_进入模型上下文的消息(可对 UI 隐藏)
|
||||
- `custom`:_不会_进入模型上下文的扩展状态
|
||||
- `compaction`:持久化的压缩摘要,带 `firstKeptEntryId` 和 `tokensBefore`
|
||||
- `message`:用户/助手/`toolResult` 消息
|
||||
- `custom_message`:由扩展注入、且 _会_ 进入模型上下文的消息(可在 UI 中隐藏)
|
||||
- `custom`:_不会_ 进入模型上下文的扩展状态
|
||||
- `compaction`:持久化的压缩摘要,带有 `firstKeptEntryId` 和 `tokensBefore`
|
||||
- `branch_summary`:在导航树分支时持久化的摘要
|
||||
|
||||
OpenClaw 有意**不会**“修正” transcripts;Gateway 网关 使用 `SessionManager` 来读写它们。
|
||||
OpenClaw 有意 **不会** “修正”转录;Gateway 网关使用 `SessionManager` 读写它们。
|
||||
|
||||
---
|
||||
|
||||
## 上下文窗口与已跟踪 token
|
||||
|
||||
有两个不同的概念很重要:
|
||||
有两个不同的概念需要关注:
|
||||
|
||||
1. **模型上下文窗口**:每个模型的硬性上限(模型可见的 token)
|
||||
2. **会话存储计数器**:写入 `sessions.json` 的滚动统计值(用于 `/status` 和仪表盘)
|
||||
1. **模型上下文窗口**:每个模型的硬上限(模型可见的 token)
|
||||
2. **会话存储计数器**:写入 `sessions.json` 的滚动统计(用于 `/status` 和仪表盘)
|
||||
|
||||
如果你要调优限制:
|
||||
如果你在调整限制:
|
||||
|
||||
- 上下文窗口来自模型目录(并且可通过配置覆盖)。
|
||||
- 存储中的 `contextTokens` 是运行时估算 / 报告值;不要把它当作严格保证。
|
||||
- 上下文窗口来自模型目录(也可通过配置覆盖)。
|
||||
- 存储中的 `contextTokens` 是运行时估算/报告值;不要把它当作严格保证。
|
||||
|
||||
更多信息见 [/token-use](/zh-CN/reference/token-use)。
|
||||
更多信息请参见 [/token-use](/zh-CN/reference/token-use)。
|
||||
|
||||
---
|
||||
|
||||
## 压缩:它是什么
|
||||
|
||||
压缩会将较早的对话总结为 transcript 中一个持久化的 `compaction` 条目,并保留最近的消息不变。
|
||||
压缩会把较早的对话总结为转录中一个持久化的 `compaction` 条目,并保留最近的消息不变。
|
||||
|
||||
压缩之后,后续轮次会看到:
|
||||
压缩后,后续轮次将看到:
|
||||
|
||||
- 压缩摘要
|
||||
- `firstKeptEntryId` 之后的消息
|
||||
|
||||
压缩是**持久化的**(不同于会话裁剪)。参见 [/concepts/session-pruning](/zh-CN/concepts/session-pruning)。
|
||||
|
||||
## 压缩分块边界和工具配对
|
||||
## 压缩分块边界与工具配对
|
||||
|
||||
当 OpenClaw 将较长 transcript 拆分为压缩分块时,它会让助手工具调用与其匹配的 `toolResult` 条目保持配对。
|
||||
当 OpenClaw 将长转录拆分为压缩分块时,它会保持
|
||||
助手工具调用与其对应的 `toolResult` 条目配对。
|
||||
|
||||
- 如果按 token 占比分割的边界落在工具调用和其结果之间,OpenClaw 会将边界移动到助手工具调用消息,而不是把这一对拆开。
|
||||
- 如果尾部的工具结果块原本会让分块超过目标大小,OpenClaw 会保留该待处理工具块,并保持未总结的尾部不变。
|
||||
- 已中止 / 出错的工具调用块不会让待处理分割一直保持打开状态。
|
||||
- 如果 token 份额切分点落在工具调用与其结果之间,OpenClaw
|
||||
会将边界移动到助手工具调用消息处,而不是拆开这一对。
|
||||
- 如果尾部的工具结果块本会让分块超出目标,
|
||||
OpenClaw 会保留这个待处理的工具块,并保持未摘要的尾部完整。
|
||||
- 已中止/报错的工具调用块不会让待处理切分保持开启。
|
||||
|
||||
---
|
||||
|
||||
@ -235,17 +238,17 @@ OpenClaw 有意**不会**“修正” transcripts;Gateway 网关 使用 `Sessi
|
||||
(`request_too_large`、`context length exceeded`、`input exceeds the maximum
|
||||
number of tokens`、`input token count exceeds the maximum number of input
|
||||
tokens`、`input is too long for the model`、`ollama error: context length
|
||||
exceeded`,以及类似的提供商格式变体)→ 压缩 → 重试。
|
||||
2. **阈值维护**:在一次成功轮次之后,当:
|
||||
exceeded`,以及类似的提供商风格变体)→ 压缩 → 重试。
|
||||
2. **阈值维护**:在成功完成一轮后,当:
|
||||
|
||||
`contextTokens > contextWindow - reserveTokens`
|
||||
|
||||
其中:
|
||||
|
||||
- `contextWindow` 是模型的上下文窗口
|
||||
- `reserveTokens` 是为提示词 + 下一次模型输出保留的余量
|
||||
- `reserveTokens` 是为提示词 + 下一次模型输出预留的余量
|
||||
|
||||
这些是 Pi 运行时语义(OpenClaw 会消费这些事件,但何时压缩由 Pi 决定)。
|
||||
这些都是 Pi 运行时语义(OpenClaw 会消费这些事件,但何时压缩由 Pi 决定)。
|
||||
|
||||
---
|
||||
|
||||
@ -265,85 +268,101 @@ Pi 的压缩设置位于 Pi settings 中:
|
||||
|
||||
OpenClaw 还会为嵌入式运行强制执行一个安全下限:
|
||||
|
||||
- 如果 `compaction.reserveTokens < reserveTokensFloor`,OpenClaw 会提升它。
|
||||
- 默认下限是 `20000` token。
|
||||
- 如果 `compaction.reserveTokens < reserveTokensFloor`,OpenClaw 会将其提升。
|
||||
- 默认下限为 `20000` token。
|
||||
- 设置 `agents.defaults.compaction.reserveTokensFloor: 0` 可禁用该下限。
|
||||
- 如果它本来就更高,OpenClaw 不会改动。
|
||||
- 如果它已经更高,OpenClaw 不会改动。
|
||||
|
||||
原因:在压缩变得不可避免之前,为多轮“清理”操作(例如 memory 写入)保留足够的余量。
|
||||
原因:为多轮“整理”操作(如 memory 写入)预留足够余量,避免压缩变得不可避免之前就没有空间。
|
||||
|
||||
实现:`src/agents/pi-settings.ts` 中的 `ensurePiCompactionReserveTokens()`
|
||||
(由 `src/agents/pi-embedded-runner.ts` 调用)。
|
||||
|
||||
---
|
||||
|
||||
## 可插拔压缩提供商
|
||||
|
||||
插件可以通过插件 API 上的 `registerCompactionProvider()` 注册压缩提供商。当 `agents.defaults.compaction.provider` 设置为已注册提供商 id 时,safeguard 扩展会将摘要生成委托给该提供商,而不是使用内置的 `summarizeInStages` 流水线。
|
||||
|
||||
- `provider`:已注册压缩提供商插件的 id。不设置时使用默认 LLM 摘要。
|
||||
- 设置 `provider` 会强制使用 `mode: "safeguard"`。
|
||||
- 提供商会接收与内置路径相同的压缩说明和标识符保留策略。
|
||||
- 在提供商输出后,safeguard 仍会保留最近轮次和拆分轮次的后缀上下文。
|
||||
- 如果提供商失败或返回空结果,OpenClaw 会自动回退到内置 LLM 摘要。
|
||||
- 中止/超时信号会被重新抛出(不会被吞掉),以遵守调用方取消。
|
||||
|
||||
来源:`src/plugins/compaction-provider.ts`、`src/agents/pi-hooks/compaction-safeguard.ts`。
|
||||
|
||||
---
|
||||
|
||||
## 用户可见界面
|
||||
|
||||
你可以通过以下方式观察压缩和会话状态:
|
||||
|
||||
- `/status`(在任意聊天会话中)
|
||||
- `/status`(在任何聊天会话中)
|
||||
- `openclaw status`(CLI)
|
||||
- `openclaw sessions` / `sessions --json`
|
||||
- 详细模式:`🧹 Auto-compaction complete` + 压缩计数
|
||||
|
||||
---
|
||||
|
||||
## 静默清理(`NO_REPLY`)
|
||||
## 静默整理(`NO_REPLY`)
|
||||
|
||||
OpenClaw 支持“静默”轮次,用于用户不应看到中间输出的后台任务。
|
||||
OpenClaw 支持用于后台任务的“静默”轮次,用户不应看到其中间输出。
|
||||
|
||||
约定:
|
||||
|
||||
- 助手以精确的静默 token `NO_REPLY` /
|
||||
`no_reply` 开始其输出,以表示“不要向用户发送回复”。
|
||||
- OpenClaw 会在发送层剥离 / 抑制它。
|
||||
- 对精确静默 token 的抑制不区分大小写,因此当整个负载仅为该静默 token 时,`NO_REPLY` 和
|
||||
`no_reply` 都算。
|
||||
- 这仅用于真正的后台 / 不投递轮次;它不是普通可执行用户请求的快捷方式。
|
||||
`no_reply` 开始输出,以表示“不要向用户发送回复”。
|
||||
- OpenClaw 会在发送层中剥离/抑制它。
|
||||
- 精确静默 token 抑制不区分大小写,因此当整个载荷只是该静默 token 时,`NO_REPLY` 和
|
||||
`no_reply` 都算数。
|
||||
- 这仅用于真正的后台/不发送轮次;它不是普通可执行用户请求的捷径。
|
||||
|
||||
自 `2026.1.10` 起,OpenClaw 在部分分块以 `NO_REPLY` 开头时,也会抑制**草稿 / 输入中流式传输**,这样静默操作就不会在轮次中途泄露部分输出。
|
||||
从 `2026.1.10` 起,如果部分分块以 `NO_REPLY` 开头,
|
||||
OpenClaw 还会抑制 **草稿/输入中流式传输**,这样静默操作就不会在轮次中途泄露部分输出。
|
||||
|
||||
---
|
||||
|
||||
## 压缩前 “memory flush”(已实现)
|
||||
|
||||
目标:在自动压缩发生之前,运行一次静默的智能体轮次,将持久状态写入磁盘(例如智能体工作区中的 `memory/YYYY-MM-DD.md`),这样压缩就无法抹掉关键上下文。
|
||||
目标:在自动压缩发生之前,运行一次静默的 agentic 轮次,将持久状态写入磁盘(例如智能体工作区中的 `memory/YYYY-MM-DD.md`),这样压缩就无法抹掉关键上下文。
|
||||
|
||||
OpenClaw 使用**阈值前 flush** 方法:
|
||||
|
||||
1. 监控会话上下文使用量。
|
||||
2. 当它越过一个“软阈值”(低于 Pi 的压缩阈值)时,向智能体运行一个静默的
|
||||
“立即写入 memory” 指令。
|
||||
3. 使用精确的静默 token `NO_REPLY` / `no_reply`,这样用户就
|
||||
看不到任何内容。
|
||||
2. 当它越过“软阈值”(低于 Pi 的压缩阈值)时,向智能体运行一个静默的
|
||||
“现在写入 memory” 指令。
|
||||
3. 使用精确的静默 token `NO_REPLY` / `no_reply`,这样用户看不到
|
||||
任何内容。
|
||||
|
||||
配置(`agents.defaults.compaction.memoryFlush`):
|
||||
|
||||
- `enabled`(默认:`true`)
|
||||
- `softThresholdTokens`(默认:`4000`)
|
||||
- `prompt`(用于 flush 轮次的用户消息)
|
||||
- `systemPrompt`(附加到 flush 轮次的额外系统提示词)
|
||||
- `systemPrompt`(附加到 flush 轮次中的额外系统提示词)
|
||||
|
||||
说明:
|
||||
|
||||
- 默认 prompt / system prompt 包含 `NO_REPLY` 提示,以抑制
|
||||
- 默认 prompt/system prompt 包含 `NO_REPLY` 提示,用于抑制
|
||||
发送。
|
||||
- 每个压缩周期只运行一次 flush(记录在 `sessions.json` 中)。
|
||||
- Flush 仅对嵌入式 Pi 会话运行(CLI 后端会跳过)。
|
||||
- 当会话工作区为只读时会跳过 flush(`workspaceAccess: "ro"` 或 `"none"`)。
|
||||
- 关于工作区文件布局和写入模式,请参见 [Memory](/zh-CN/concepts/memory)。
|
||||
- 每个压缩周期只运行一次 flush(在 `sessions.json` 中跟踪)。
|
||||
- flush 仅对嵌入式 Pi 会话运行(CLI 后端会跳过)。
|
||||
- 当会话工作区为只读时(`workspaceAccess: "ro"` 或 `"none"`),会跳过 flush。
|
||||
- 有关工作区文件布局和写入模式,请参见 [Memory](/zh-CN/concepts/memory)。
|
||||
|
||||
Pi 也会在扩展 API 中暴露一个 `session_before_compact` hook,但 OpenClaw 的
|
||||
flush 逻辑目前位于 Gateway 网关 侧。
|
||||
flush 逻辑目前位于 Gateway 网关侧。
|
||||
|
||||
---
|
||||
|
||||
## 故障排除清单
|
||||
|
||||
- 会话键不对?从 [/concepts/session](/zh-CN/concepts/session) 开始,并在 `/status` 中确认 `sessionKey`。
|
||||
- 存储与 transcript 不匹配?确认 Gateway 网关 主机,以及 `openclaw status` 中的存储路径。
|
||||
- 压缩刷屏?检查:
|
||||
- 模型上下文窗口(是否太小)
|
||||
- 会话键不对?从 [/concepts/session](/zh-CN/concepts/session) 开始,并确认 `/status` 中的 `sessionKey`。
|
||||
- 存储与转录不匹配?确认 Gateway 网关主机以及 `openclaw status` 提供的存储路径。
|
||||
- 压缩过于频繁?检查:
|
||||
- 模型上下文窗口(过小)
|
||||
- 压缩设置(对于模型窗口来说,`reserveTokens` 过高会导致更早压缩)
|
||||
- `toolResult` 膨胀:启用 / 调整会话裁剪
|
||||
- 静默轮次泄露了输出?确认回复以 `NO_REPLY` 开头(大小写不敏感的精确 token),并且你使用的是包含流式抑制修复的构建版本。
|
||||
- 工具结果膨胀:启用/调整会话裁剪
|
||||
- 静默轮次有泄露?确认回复以 `NO_REPLY` 开头(不区分大小写的精确 token),并且你使用的是包含流式抑制修复的构建版本。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user