第 7 章 · 会话管理
每个模型都有"上下文窗口"——它能同时看到的最大信息量。就像人的短期记忆一样,超过容量就会"忘事"。OpenClaw 的会话管理系统,就是让 Agent 在有限记忆中保持连贯性的"记忆术"。
本章你将学到:
- 理解会话的完整生命周期——从创建到重置到清理
- 掌握上下文窗口管理策略——压缩、剪裁、手动控制
- 学会会话调试和状态恢复的实用技巧
7.1 上下文:模型"看到"的一切
在理解会话管理之前,你需要先理解"上下文"(Context)这个概念。
"上下文"就是 OpenClaw 发送给模型的所有内容。它由三部分组成:
┌───────────────────────────────────────────────┐
│ 系统提示词 │
│ ├── 工具列表 + 工具 Schema(JSON 定义) │
│ ├── 技能列表(名称 + 描述) │
│ ├── 工作空间位置 │
│ ├── 时间信息(UTC + 用户本地时间) │
│ ├── 运行时元信息(主机/OS/模型/思考模式) │
│ └── 注入的工作空间文件(Project Context) │
├───────────────────────────────────────────────┤
│ 对话历史 │
│ ├── 用户消息 + 助手消息 │
│ ├── 工具调用 + 工具结果 │
│ └── 附件(图片/音频/文件) │
├───────────────────────────────────────────────┤
│ 压缩摘要(如果有的话) │
└───────────────────────────────────────────────┘
关键区别:上下文 ≠ 记忆。上下文是"模型当前看到的",记忆是"存在磁盘上的"。上下文满了,OpenClaw 会压缩(Compaction);但压缩后的摘要仍然占上下文空间。真正的"释放"只有重置会话(/new)才能做到。
7.1.1 上下文检查命令
OpenClaw 提供了几条命令让你随时检查上下文使用情况:
/status → 快速查看"上下文有多满"
/context list → 查看注入的工作空间文件及大小
/context detail → 更详细的上下文分解(含工具 Schema 大小)
/usage tokens → 在回复中追加 Token 用量统计
/context list 示例输出:
🧠 Context breakdown
System prompt (run): 38,412 chars (~9,603 tok)
Injected workspace files:
- AGENTS.md: 1,742 chars (~436 tok)
- SOUL.md: 912 chars (~228 tok)
- TOOLS.md: TRUNCATED | raw 54,210 chars → injected 20,962 chars
- IDENTITY.md: 211 chars (~53 tok)
- USER.md: 388 chars (~97 tok)
Skills list: 2,184 chars (~546 tok) (12 skills)
Tool schemas (JSON): 31,988 chars (~7,997 tok)
Session tokens (cached): 14,250 total / ctx=200,000
这个输出告诉你:当前会话的上下文占了约 14K token,总容量 200K。上下文越满,留给对话的空间就越少,也越接近触发自动压缩。
7.2 会话生命周期
7.2.1 会话的创建
OpenClaw 为每个对话场景创建独立的会话。会话用"会话键"(Session Key)来标识:
直接聊天(DM):
agent:<agentId>:<mainKey>
例如:agent:main:main
群聊:
agent:<agentId>:<channel>:group:<id>
例如:agent:main:discord:group:123456
Cron 任务:
cron:<job.id>
Webhook:
hook:<uuid>
Node 会话:
node-<nodeId>
7.2.2 DM 隔离模式(安全配置)
默认情况下,所有 DM 共享同一个"主会话"。这在单用户场景下没问题,但在多用户场景下是安全隐患:
⚠️ 安全警告
如果你的 Agent 可以接收多个用户的 DM,强烈建议启用 DM 隔离。否则 Alice 的私人对话内容可能通过共享的会话泄露给 Bob。
{
session: {
dmScope: "per-channel-peer", // 按通道 + 发送者隔离
},
}
dmScope 的可选值:
| 值 | 行为 | 适用场景 |
|---|---|---|
main |
所有 DM 共享一个会话 | 单用户(默认) |
per-peer |
按发送者隔离 | 多用户、单通道 |
per-channel-peer |
按通道 + 发送者隔离(推荐) | 多用户、多通道 |
per-account-channel-peer |
按账户 + 通道 + 发送者隔离 | 多账户收件箱 |
如果同一个人在多个渠道联系你,可以用 identityLinks 把它们合并到一个会话:
{
session: {
identityLinks: {
alice: ["telegram:123456789", "discord:987654321012345678"],
},
},
}
7.2.3 会话重置
会话不是无限长的。OpenClaw 提供了多种重置策略:
按时间重置(默认):
{
session: {
reset: {
mode: "daily", // 每天 4:00 AM 重置
atHour: 4,
idleMinutes: 120, // 或者空闲 2 小时后重置(两者先到先得)
},
},
}
按类型定制重置:
{
session: {
resetByType: {
thread: { mode: "daily", atHour: 4 },
direct: { mode: "idle", idleMinutes: 240 },
group: { mode: "idle", idleMinutes: 120 },
},
resetByChannel: {
discord: { mode: "idle", idleMinutes: 10080 }, // Discord 群聊 7 天后重置
},
},
}
手动重置:
/new # 开始新会话
/new sonnet # 开始新会话并切换到 Sonnet 模型
/reset # 等同于 /new
重置时,当前的对话历史会被"封存"(不是删除),下次消息到来时创建新的会话 ID。
7.2.4 会话存储维护
长时间运行后,会话数据会越来越大。OpenClaw 内置了维护机制:
{
session: {
maintenance: {
mode: "enforce", // "warn" 只报告不执行
pruneAfter: "30d", // 30 天前的会话自动清理
maxEntries: 500, // 最多保留 500 个会话条目
rotateBytes: "10mb", // sessions.json 文件超过 10MB 时轮转
},
},
}
清理顺序:
- 清理超过
pruneAfter的过期会话 - 限制会话数量不超过
maxEntries - 归档已删除会话的 JSONL 转录文件
- 清理旧的归档文件
# 预览会清理什么
openclaw sessions cleanup --dry-run
# 执行清理
openclaw sessions cleanup --enforce
7.3 上下文压缩(Compaction):长对话的"记忆整理术"
当对话历史接近上下文窗口上限时,OpenClaw 会自动触发压缩——把早期的对话总结成一个摘要,释放空间给新消息。
7.3.1 压缩的工作原理
压缩前:
┌─────────────────────────────────────────────────┐
│ [消息1] [消息2] ... [消息50] [消息51] ... [消息100] │
│ │
│ ↑ 这些会占用大量上下文空间 │
└─────────────────────────────────────────────────┘
压缩后:
┌─────────────────────────────────────────────────┐
│ [压缩摘要:前50条消息的精炼总结] │
│ [消息51] ... [消息100] │
│ │
│ ↑ 摘要只占一小部分空间 │
└─────────────────────────────────────────────────┘
压缩是持久化的——摘要被写入 JSONL 转录文件。未来的请求会使用"压缩摘要 + 最近消息"作为上下文。
7.3.2 自动压缩
默认开启。当会话接近或超过上下文窗口时自动触发。
🧹 Auto-compaction complete
7.3.3 手动压缩
你可以在任何时候手动触发压缩:
/compact # 使用默认策略压缩
/compact 重点关注决策和未解决的问题 # 带自定义指令的压缩
7.3.4 指定压缩模型
如果你用了一个较小的模型做日常对话,可以用更强的模型来做压缩摘要:
{
agents: {
defaults: {
compaction: {
model: "anthropic/claude-sonnet-4-6", // 用 Sonnet 做压缩
},
},
},
}
7.3.5 压缩前的自动记忆刷盘
上一章提到过,OpenClaw 在压缩之前会自动触发记忆刷盘,让 Agent 把重要信息写入磁盘。这个机制确保压缩不会丢失关键信息。
7.3.6 OpenAI 服务端压缩
如果你用的是 OpenAI 的 Responses 模型,OpenClaw 还支持让 OpenAI 服务端做压缩——这是和 OpenClaw 本地压缩并行运行的两道防线。
7.4 会话剪裁(Session Pruning):减少工具结果的体积
剪裁和压缩是两个不同的机制:
| 压缩(Compaction) | 剪裁(Pruning) | |
|---|---|---|
| 作用对象 | 所有消息 | 仅工具结果 |
| 持久性 | 写入 JSONL 转录 | 仅内存中,不写磁盘 |
| 触发方式 | 上下文接近上限 | 按 TTL(时间)触发 |
| 效果 | 生成摘要 | 截断或清除旧工具结果 |
7.4.1 为什么需要剪裁
Agent 在工作中会频繁调用工具——读文件、执行命令、搜索网页。这些工具结果会累积在上下文中,占据大量空间。剪裁专门清理这些"过期的工具结果",释放空间。
7.4.2 TTL 模式
剪裁基于"缓存 TTL"——当上次 Anthropic API 调用超过 TTL 时间后,下次请求时会触发剪裁:
{
agents: {
defaults: {
contextPruning: {
mode: "cache-ttl",
ttl: "5m", // 5 分钟后触发剪裁
},
},
},
}
推荐配置:ttl 应该和模型的 cacheRetention 匹配。如果你用的是 Anthropic 的 cacheRetention: "short"(5 分钟),TTL 设为 5m 最合适。
7.4.3 软剪裁 vs 硬清除
软剪裁(Soft Trim):
保留工具结果的头和尾,中间替换为 "..."
适合:太大的工具输出,你可能还需要部分信息
硬清除(Hard Clear):
整个工具结果替换为 "[Old tool result content cleared]"
适合:已经完全不需要的旧工具结果
{
agents: {
defaults: {
contextPruning: {
mode: "cache-ttl",
softTrimRatio: 0.3, // 超过 30% 的空间被剪裁时触发软剪裁
hardClearRatio: 0.5, // 超过 50% 时触发硬清除
softTrim: {
maxChars: 4000,
headChars: 1500,
tailChars: 1500,
},
},
},
},
}
7.4.4 限制剪裁范围
你可以指定只剪裁特定工具的结果:
{
agents: {
defaults: {
contextPruning: {
mode: "cache-ttl",
tools: {
allow: ["exec", "read"], // 只剪裁这两个工具的结果
deny: ["*image*"], // 永远不剪裁包含图片的结果
},
},
},
},
}
7.4.5 受保护的内容
剪裁不会影响以下内容:
- 用户消息和助手消息(永远不会被修改)
- 最近
keepLastAssistants条助手消息之后的工具结果(默认 3 条) - 包含图片块的工具结果
7.5 流式输出:让回复"实时"显示
没有人愿意盯着空白屏幕等 30 秒才看到回复。OpenClaw 的流式输出(Streaming)让 Agent 的回复逐步显示在聊天中。
7.5.1 两层流式架构
OpenClaw 有两个独立的流式层:
模型输出
└─ text_delta/events
├─ 分块流(Block Streaming)
│ └─ 把文本分成块,逐块发送为独立消息
└─ 预览流(Preview Streaming)
└─ 在 Telegram/Discord/Slack 中实时编辑一条临时消息
分块流:Agent 生成过程中,每积累一定字数就发送一条消息。这样用户可以看到"进度"。
预览流:先发送一条临时消息,然后在生成过程中不断编辑更新这条消息的内容。生成完成后替换为最终回复。
7.5.2 启用分块流
{
agents: {
defaults: {
blockStreamingDefault: "on", // 全局启用
blockStreamingBreak: "text_end", // 遇到句子结尾就发送
blockStreamingChunk: {
minChars: 100, // 最少积累 100 字符再发送
maxChars: 2000, // 最多 2000 字符就发送
breakPreference: "paragraph", // 优先在段落边界分割
},
},
},
}
7.5.3 人类感延迟
分块流可以加入随机延迟,让多段回复更像人类在"打字":
{
agents: {
defaults: {
humanDelay: "natural", // 800-2500ms 的随机延迟
},
},
}
7.5.4 预览流配置
不同通道支持不同的预览模式:
| 通道 | off |
partial |
block |
progress |
|---|---|---|---|---|
| Telegram | 支持 | 支持 | 支持 | 映射为 partial |
| Discord | 支持 | 支持 | 支持 | 映射为 partial |
| Slack | 支持 | 支持 | 支持 | 支持 |
{
channels: {
telegram: {
streaming: "partial", // 实时编辑预览消息
},
discord: {
streaming: "block", // 分块追加预览
},
},
}
⚠️ 注意:分块流和预览流可以同时启用,但如果你为通道启用了分块流(
*.blockStreaming: true),预览流会被跳过(避免重复发送)。
7.6 会话工具:跨会话操作
Agent 可以通过工具操作会话——查看会话列表、获取历史、跨会话发送消息。
7.6.1 会话可见性
{
tools: {
sessions: {
visibility: "tree", // "self" | "tree" | "agent" | "all"
},
},
}
| 值 | 可见范围 |
|---|---|
self |
仅当前会话 |
tree |
当前会话 + 当前会话派生的子 Agent 会话 |
agent |
同一 Agent 的所有会话 |
all |
所有 Agent 的所有会话 |
在沙盒环境中,可见性会被进一步限制为 tree(只能看到自己派生的子 Agent)。
7.6.2 会话工具的使用场景
场景 1:Agent 查看自己最近在做什么
用户:总结一下今天所有的对话
Agent:[调用 sessions_list 查看所有活跃会话]
Agent:你今天和我聊了 3 个话题...
场景 2:Agent 跨会话传递信息
用户:告诉 Discord 群里的人,我改了 API 的端点
Agent:[调用 sessions_send 向 Discord 群会发送消息]
Agent:已经通知了 Discord 群。
场景 3:Agent 派生子任务
用户:帮我同时查一下这三个项目的状态
Agent:[调用 sessions_spawn 派生 3 个子 Agent 并行查询]
Agent:查询完成,三个项目的状态如下...
7.7 发送策略:控制消息投递
你可以基于会话类型限制消息的投递:
{
session: {
sendPolicy: {
rules: [
{ action: "deny", match: { channel: "discord", chatType: "group" } },
{ action: "deny", match: { keyPrefix: "cron:" } },
],
default: "allow",
},
},
}
运行时覆盖(仅限会话所有者):
/send on # 允许当前会话发送消息
/send off # 禁止当前会话发送消息
/send inherit # 继承配置中的规则
7.8 实用调试技巧
7.8.1 查看会话状态
/status → 查看当前会话的模型、上下文使用量、压缩次数
/context list → 查看上下文组成和大小
/compact → 手动压缩,释放空间
/new → 重新开始
/stop → 中止当前运行,清除排队中的后续任务
7.8.2 查看会话列表
# 列出所有会话
openclaw sessions --json
# 只看最近 60 分钟活跃的会话
openclaw sessions --active 60
7.8.3 手动管理会话
# 查看会话存储路径和最近会话
openclaw status
# 清理过期会话(预览)
openclaw sessions cleanup --dry-run
# 清理过期会话(执行)
openclaw sessions cleanup --enforce
7.8.4 Token 用量追踪
/usage tokens → 在每条回复末尾追加 Token 用量
这对于监控成本和优化上下文管理非常有用。
💡 提示:
/usage tokens是实时监控成本的最佳方式。开启后你可以在每条回复中看到精确的 Token 消耗,快速识别哪些对话在"烧钱"。
本章小结
- 上下文是模型"看到"的一切,包括系统提示词、对话历史、工具结果
- 会话按场景隔离(DM、群聊、Cron、Webhook 各有独立键)
- 多用户场景务必设置
dmScope隔离 DM 会话,防止隐私泄露 - 压缩(Compaction)把旧对话总结为摘要,持久化到 JSONL
- 剪裁(Pruning)清除旧的工具结果,只在内存中生效,不写磁盘
- TTL 模式的剪裁与 Prompt Caching 配合使用效果最佳
- 分块流和预览流让用户实时看到 Agent 的回复进度
/status、/context、/compact是会话调试的三件套
下一步
Agent 有了"记忆术"(会话管理),接下来要让它"能做事"——这就是工具体系的范畴。下一章深入实践 OpenClaw 的工具、技能和插件三层扩展体系,让你的 Agent 从"能聊天"进化到"能干活"。