前言
在多频道、多用户的 AI 网关场景中,会话管理是最核心的基础能力之一。OpenClaw 采用基于 JSONL 的持久化方案,配合树形消息结构,实现了会话分支、历史回溯和自动压缩等高级功能。本文将从底层存储到上层策略,全面解析 OpenClaw 的会话管理机制。
会话存储位置
每个 Agent 的会话数据独立存储在各自的目录下:
~/.openclaw/agents/<agentId>/sessions/
├── telegram_123456.jsonl
├── discord_789012.jsonl
├── whatsapp_345678.jsonl
└── web_dashboard.jsonl
文件名格式为 <channel>_<userId>.jsonl,每个文件对应一个用户在一个频道上的完整对话历史。这种设计让不同频道、不同用户的会话自然隔离,避免数据串扰。
JSONL 存储格式
OpenClaw 使用 JSONL(JSON Lines)格式存储每一条消息,每行一个 JSON 对象:
{"id":"msg_001","parentId":null,"role":"user","content":"你好","timestamp":1710000000,"channel":"telegram"}
{"id":"msg_002","parentId":"msg_001","role":"assistant","content":"你好!有什么可以帮你的吗?","timestamp":1710000001,"channel":"telegram"}
{"id":"msg_003","parentId":"msg_002","role":"user","content":"帮我翻译一段英文","timestamp":1710000010,"channel":"telegram"}
核心字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string | 消息唯一标识,自动生成 |
parentId |
string/null | 父消息 ID,根消息为 null |
role |
string | 角色:user、assistant、system |
content |
string | 消息文本内容 |
timestamp |
number | Unix 时间戳 |
channel |
string | 来源频道 |
metadata |
object | 可选,附加元数据(如媒体信息) |
选择 JSONL 而非数据库有几个关键优势:文件追加写入性能极高;无需外部依赖;易于备份和迁移;人类可直接阅读和调试。
树形会话结构
OpenClaw 会话管理最独特的设计是树形结构。通过 id 和 parentId 字段,消息之间构成父子关系,而非简单的线性列表。
为什么要用树形结构?
在实际使用中,用户常常需要"回到某个节点重新对话"。例如:
msg_001: 帮我写一封邮件
├── msg_002: [助手写了正式版邮件]
│ └── msg_003: 再简短一些 → msg_004: [助手修改]
└── msg_005: 用轻松的语气写 → msg_006: [助手写了轻松版]
当用户从 msg_001 分叉出 msg_005 时,OpenClaw 会以 msg_001 为新的分支起点,构建一条独立的上下文路径。模型看到的对话历史是 msg_001 → msg_005,而不会混入 msg_002、msg_003 的内容。
在 Dashboard 中使用分支
在 Web Dashboard 中,你可以直观地看到会话的树形结构。点击任意历史消息的"从此处分支"按钮,即可创建新的对话分支。每个分支独立维护上下文,互不干扰。
上下文构建策略
当 OpenClaw 需要调用模型 API 时,会从当前消息节点沿 parentId 链向上回溯,收集祖先消息作为上下文。这个过程受以下配置控制:
{
"sessions": {
"maxHistoryMessages": 50,
"maxHistoryTokens": 8000
}
}
回溯过程会在以下条件之一满足时停止:
- 达到
maxHistoryMessages条消息上限 - 累计 token 数超过
maxHistoryTokens - 到达树的根节点
自动压缩机制
当对话超长,即将超出模型的上下文窗口时,OpenClaw 会自动触发压缩(compaction)。压缩策略通过配置控制:
{
"sessions": {
"autoCompaction": true,
"compactionStrategy": "summary"
}
}
summary 策略(默认)
OpenClaw 会将较早的对话历史发送给模型,请求生成一段摘要。这段摘要会作为一条 system 角色的消息插入上下文开头,替代原始的历史消息。这样既保留了关键信息,又大幅减少了 token 消耗。
摘要消息的格式如下:
{"id":"compact_001","parentId":null,"role":"system","content":"[会话摘要] 用户之前询问了关于Python异步编程的问题,讨论了asyncio的基本用法和常见陷阱...","timestamp":1710001000,"metadata":{"type":"compaction","originalCount":35}}
truncate 策略
简单截断,直接丢弃最早的消息,仅保留最近的 N 条。这种策略不会产生额外的模型调用,但可能丢失重要上下文。适合对成本敏感且对话连贯性要求不高的场景。
按频道类型差异化配置
不同频道的使用模式差异很大——私聊通常是长对话,群聊则是碎片化的短交互。OpenClaw 支持按频道类型覆盖会话配置:
{
"sessions": {
"maxHistoryMessages": 50,
"channelOverrides": {
"dm": {
"maxHistoryMessages": 100,
"maxHistoryTokens": 16000
},
"group": {
"maxHistoryMessages": 20,
"maxHistoryTokens": 4000
}
}
}
}
在上面的配置中,私聊(dm)保留更长的历史以维持连贯对话,群聊(group)则限制较短以降低成本和减少无关消息干扰。
会话数据维护
手动清理
# 清除某个用户的会话
openclaw session clear --agent default --session telegram_123456
# 清除某个 Agent 的全部会话
openclaw session clear --agent myagent --all
# 导出会话为 JSON(方便分析)
openclaw session export --session telegram_123456 --format json > history.json
自动清理
你可以配置会话文件的自动清理策略:
{
"sessions": {
"retention": {
"maxAge": "30d",
"maxSize": "100mb"
}
}
}
超过 30 天或总大小超过 100MB 的旧会话数据会在 OpenClaw 启动时被自动归档。
多设备同步
由于会话数据存储在文件系统中,多实例部署时需要注意同步问题。推荐方案:
- 单机部署:无需额外配置,文件天然一致
- 多机部署:使用共享存储(如 NFS)挂载
~/.openclaw/agents/目录,或切换到 Redis 存储后端
总结
OpenClaw 的会话管理系统以 JSONL 文件为基础,通过 id/parentId 构建树形结构,支持会话分支和灵活的上下文回溯。自动压缩机制确保长对话不会超出模型限制,按频道类型的差异化配置则让资源分配更加合理。理解这些机制后,你可以根据实际使用场景精细调整会话参数,在对话质量和成本之间取得平衡。