Files
Moltbot/docs/zh-CN/concepts/session.md
Josh Palmer a3ec2d0734 Docs: update zh-CN translations and pipeline
What:
- update zh-CN glossary, TM, and translator prompt
- regenerate zh-CN docs and apply targeted fixes
- add zh-CN AGENTS pipeline guidance

Why:
- address terminology/spacing feedback from #6995

Tests:
- pnpm build && pnpm check && pnpm test
2026-02-03 13:23:00 -08:00

167 lines
9.2 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:
- 修改会话处理或存储
summary: 聊天的会话管理规则、键和持久化
title: 会话管理
x-i18n:
generated_at: "2026-02-03T07:47:44Z"
model: claude-opus-4-5
provider: pi
source_hash: 147c8d1a4b6b4864cb16ad942feba80181b6b0e29afa765e7958f8c2483746b5
source_path: concepts/session.md
workflow: 15
---
# 会话管理
OpenClaw 将**每个智能体的一个直接聊天会话**视为主会话。直接聊天折叠为 `agent:<agentId>:<mainKey>`(默认 `main`),而群组/频道聊天获得各自的键。`session.mainKey` 会被遵循。
使用 `session.dmScope` 控制**私信**如何分组:
- `main`(默认):所有私信共享主会话以保持连续性。
- `per-peer`:跨渠道按发送者 ID 隔离。
- `per-channel-peer`:按渠道 + 发送者隔离(推荐用于多用户收件箱)。
- `per-account-channel-peer`:按账户 + 渠道 + 发送者隔离(推荐用于多账户收件箱)。
使用 `session.identityLinks` 将带提供商前缀的对等 ID 映射到规范身份,这样在使用 `per-peer``per-channel-peer``per-account-channel-peer` 时,同一个人可以跨渠道共享私信会话。
## Gateway 网关是唯一数据源
所有会话状态都**由 Gateway 网关拥有**"主" OpenClaw。UI 客户端macOS 应用、WebChat 等)必须向 Gateway 网关查询会话列表和令牌计数,而不是读取本地文件。
- 在**远程模式**下,你关心的会话存储位于远程 Gateway 网关主机上,而不是你的 Mac 上。
- UI 中显示的令牌计数来自 Gateway 网关的存储字段(`inputTokens``outputTokens``totalTokens``contextTokens`)。客户端不会解析 JSONL 对话记录来"修正"总数。
## 状态存储位置
- 在 **Gateway 网关主机**上:
- 存储文件:`~/.openclaw/agents/<agentId>/sessions/sessions.json`(每个智能体)。
- 对话记录:`~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl`Telegram 话题会话使用 `.../<SessionId>-topic-<threadId>.jsonl`)。
- 存储是一个映射 `sessionKey -> { sessionId, updatedAt, ... }`。删除条目是安全的;它们会按需重新创建。
- 群组条目可能包含 `displayName``channel``subject``room``space` 以在 UI 中标记会话。
- 会话条目包含 `origin` 元数据(标签 + 路由提示),以便 UI 可以解释会话的来源。
- OpenClaw **不**读取旧版 Pi/Tau 会话文件夹。
## 会话修剪
默认情况下OpenClaw 在 LLM 调用之前从内存上下文中修剪**旧的工具结果**。
这**不会**重写 JSONL 历史记录。参见 [/concepts/session-pruning](/concepts/session-pruning)。
## 压缩前记忆刷新
当会话接近自动压缩时OpenClaw 可以运行一个**静默记忆刷新**轮次,提醒模型将持久性笔记写入磁盘。这仅在工作区可写时运行。参见[记忆](/concepts/memory)和[压缩](/concepts/compaction)。
## 传输到会话键的映射
- 直接聊天遵循 `session.dmScope`(默认 `main`)。
- `main``agent:<agentId>:<mainKey>`(跨设备/渠道的连续性)。
- 多个电话号码和渠道可以映射到同一个智能体主键;它们作为进入同一个对话的传输通道。
- `per-peer``agent:<agentId>:dm:<peerId>`
- `per-channel-peer``agent:<agentId>:<channel>:dm:<peerId>`
- `per-account-channel-peer``agent:<agentId>:<channel>:<accountId>:dm:<peerId>`accountId 默认为 `default`)。
- 如果 `session.identityLinks` 匹配带提供商前缀的对等 ID例如 `telegram:123`),则规范键替换 `<peerId>`,这样同一个人可以跨渠道共享会话。
- 群组聊天隔离状态:`agent:<agentId>:<channel>:group:<id>`(房间/频道使用 `agent:<agentId>:<channel>:channel:<id>`)。
- Telegram 论坛话题在群组 ID 后附加 `:topic:<threadId>` 以进行隔离。
- 旧版 `group:<id>` 键仍被识别以进行迁移。
- 入站上下文可能仍使用 `group:<id>`;渠道从 `Provider` 推断并规范化为规范的 `agent:<agentId>:<channel>:group:<id>` 形式。
- 其他来源:
- 定时任务:`cron:<job.id>`
- Webhooks`hook:<uuid>`(除非由 hook 显式设置)
- 节点运行:`node-<nodeId>`
## 生命周期
- 重置策略:会话被重用直到过期,过期在下一条入站消息时评估。
- 每日重置:默认为 **Gateway 网关主机本地时间凌晨 4:00**。当会话的最后更新早于最近的每日重置时间时,会话即为过期。
- 空闲重置(可选):`idleMinutes` 添加一个滑动空闲窗口。当同时配置每日和空闲重置时,**先过期者**强制新会话。
- 旧版仅空闲模式:如果你设置了 `session.idleMinutes` 而没有任何 `session.reset`/`resetByType` 配置OpenClaw 会保持仅空闲模式以保持向后兼容。
- 按类型覆盖(可选):`resetByType` 允许你覆盖 `dm``group``thread` 会话的策略thread = Slack/Discord 线程、Telegram 话题、连接器提供的 Matrix 线程)。
- 按渠道覆盖(可选):`resetByChannel` 覆盖渠道的重置策略(适用于该渠道的所有会话类型,优先于 `reset`/`resetByType`)。
- 重置触发器:精确的 `/new``/reset`(加上 `resetTriggers` 中的任何额外项)启动新的会话 ID 并传递消息的其余部分。`/new <model>` 接受模型别名、`provider/model` 或提供商名称(模糊匹配)来设置新会话模型。如果单独发送 `/new``/reset`OpenClaw 会运行一个简短的"问候"轮次来确认重置。
- 手动重置:从存储中删除特定键或删除 JSONL 对话记录;下一条消息会重新创建它们。
- 隔离的定时任务总是每次运行生成新的 `sessionId`(没有空闲重用)。
## 发送策略(可选)
阻止特定会话类型的投递,无需列出单个 ID。
```json5
{
session: {
sendPolicy: {
rules: [
{ action: "deny", match: { channel: "discord", chatType: "group" } },
{ action: "deny", match: { keyPrefix: "cron:" } },
],
default: "allow",
},
},
}
```
运行时覆盖(仅所有者):
- `/send on` → 为此会话允许
- `/send off` → 为此会话拒绝
- `/send inherit` → 清除覆盖并使用配置规则
将这些作为独立消息发送以使其生效。
## 配置(可选重命名示例)
```json5
// ~/.openclaw/openclaw.json
{
session: {
scope: "per-sender", // keep group keys separate
dmScope: "main", // DM continuity (set per-channel-peer/per-account-channel-peer for shared inboxes)
identityLinks: {
alice: ["telegram:123456789", "discord:987654321012345678"],
},
reset: {
// Defaults: mode=daily, atHour=4 (gateway host local time).
// If you also set idleMinutes, whichever expires first wins.
mode: "daily",
atHour: 4,
idleMinutes: 120,
},
resetByType: {
thread: { mode: "daily", atHour: 4 },
dm: { mode: "idle", idleMinutes: 240 },
group: { mode: "idle", idleMinutes: 120 },
},
resetByChannel: {
discord: { mode: "idle", idleMinutes: 10080 },
},
resetTriggers: ["/new", "/reset"],
store: "~/.openclaw/agents/{agentId}/sessions/sessions.json",
mainKey: "main",
},
}
```
## 检查
- `openclaw status` — 显示存储路径和最近的会话。
- `openclaw sessions --json` — 导出每个条目(使用 `--active <minutes>` 过滤)。
- `openclaw gateway call sessions.list --params '{}'` — 从运行中的 Gateway 网关获取会话(使用 `--url`/`--token` 进行远程 Gateway 网关访问)。
- 在聊天中单独发送 `/status` 消息可查看智能体是否可达、会话上下文使用了多少、当前的思考/详细模式开关,以及你的 WhatsApp Web 凭证上次刷新时间(有助于发现重新链接需求)。
- 发送 `/context list``/context detail` 查看系统提示中的内容和注入的工作区文件(以及最大的上下文贡献者)。
- 单独发送 `/stop` 消息可中止当前运行、清除该会话的排队后续操作,并停止从中生成的任何子智能体运行(回复包含已停止的数量)。
- 单独发送 `/compact`(可选指令)消息可总结旧上下文并释放窗口空间。参见 [/concepts/compaction](/concepts/compaction)。
- 可以直接打开 JSONL 对话记录查看完整轮次。
## 提示
- 将主键专用于 1:1 通信;让群组保留各自的键。
- 自动清理时,删除单个键而不是整个存储,以保留其他地方的上下文。
## 会话来源元数据
每个会话条目记录其来源(尽力而为)在 `origin` 中:
- `label`:人类可读标签(从对话标签 + 群组主题/频道解析)
- `provider`:规范化的渠道 ID包括扩展
- `from`/`to`:入站信封中的原始路由 ID
- `accountId`:提供商账户 ID多账户时
- `threadId`:渠道支持时的线程/话题 ID
来源字段为私信、频道和群组填充。如果连接器仅更新投递路由(例如,保持私信主会话新鲜),它仍应提供入站上下文,以便会话保留其解释器元数据。扩展可以通过在入站上下文中发送 `ConversationLabel``GroupSubject``GroupChannel``GroupSpace``SenderName` 并调用 `recordSessionMetaFromInbound`(或将相同上下文传递给 `updateLastRoute`)来实现。