OpenClaw 学习系列之九:会话管理系统
会话管理是 OpenClaw 的核心功能之一,负责管理对话历史、会话状态和上下文隔离。本文档将深入解析会话管理系统的设计、存储结构和生命周期管理。理解会话的概念和作用掌握会话存储结构和格式了解会话生命周期管理理解会话隔离机制✅对话历史:所有用户消息和 AI 回复✅工具调用:工具执行记录和结果✅状态信息:会话元数据和配置✅上下文信息:系统提示词、记忆检索结果等。
会话管理系统
📚 学习路径:本文档是架构文档的第 7 部分。建议按顺序阅读:
- 01. 技术基础 - 了解 TypeScript 技术特性
- 02. 整体框架 - 理解 OpenClaw 架构
- 03. 消息流转 - 掌握消息生命周期
- 04. 设计原理 - 理解反共识设计
- 05. Gateway 深度解析 - 理解控制平面
- 06. Agent 运行机制 - 了解 Agent 如何工作
前言
会话管理是 OpenClaw 的核心功能之一,负责管理对话历史、会话状态和上下文隔离。本文档将深入解析会话管理系统的设计、存储结构和生命周期管理。
通过阅读本文档,你将能够:
- 理解会话的概念和作用
- 掌握会话存储结构和格式
- 了解会话生命周期管理
- 理解会话隔离机制
一、会话概述
1.1 什么是会话?
会话(Session)是指用户与 Agent 之间的一次完整对话交互,包括:
- ✅ 对话历史:所有用户消息和 AI 回复
- ✅ 工具调用:工具执行记录和结果
- ✅ 状态信息:会话元数据和配置
- ✅ 上下文信息:系统提示词、记忆检索结果等
1.2 会话的作用
| 作用 | 说明 | 实现方式 |
|---|---|---|
| 上下文连续性 | 保持对话的上下文连续性 | 存储历史消息 |
| 状态持久化 | 持久化会话状态到磁盘 | JSONL 文件存储 |
| 多轮对话 | 支持多轮对话交互 | 会话标识管理 |
| 个性化记忆 | 记住用户的偏好和历史 | 记忆系统集成 |
1.3 会话类型
| 类型 | 说明 | Session Key 格式 | 特点 |
|---|---|---|---|
| 主会话 | 用户自己的主会话 | agent:main:main |
权限最高,完全信任 |
| 私聊会话 | 其他用户的私聊 | agent:main:channel:dm:peerId |
沙箱隔离,限制工具 |
| 群组会话 | 群聊消息 | agent:main:channel:group:groupId |
沙箱隔离,@ 提及触发 |
| 线程会话 | 支持线程的渠道 | agent:main:channel:thread:threadId |
线程隔离 |
二、会话存储结构
2.1 物理存储路径
~/.openclaw/agents/<agentId>/sessions/
├── session.json # 会话元数据映射
├── <sessionId>.jsonl # 具体对话日志
└── <sessionId>.jsonl # 更多对话日志
说明:
session.json:记录所有 Session 的元数据映射<sessionId>.jsonl:存储具体的对话日志(JSON Lines 格式)
2.2 会话元数据
文件:session.json
{
"sessions": {
"agent:main:main": {
"id": "agent:main:main",
"type": "main",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T12:00:00Z",
"messageCount": 100,
"lastMessageAt": "2024-01-01T12:00:00Z"
},
"agent:main:telegram:default:dm:123456789": {
"id": "agent:main:telegram:default:dm:123456789",
"type": "dm",
"channel": "telegram",
"peerId": "123456789",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T12:00:00Z",
"messageCount": 50,
"lastMessageAt": "2024-01-01T12:00:00Z"
}
}
}
2.3 对话日志格式
文件:<sessionId>.jsonl
JSON Lines 格式,每行一个 JSON 对象:
{"role": "user", "content": "你好", "timestamp": "2024-01-01T12:00:00Z", "id": "msg_1"}
{"role": "assistant", "content": "你好!有什么可以帮助你的?", "timestamp": "2024-01-01T12:00:01Z", "id": "msg_2"}
{"role": "user", "content": "帮我查一下天气", "timestamp": "2024-01-01T12:00:02Z", "id": "msg_3"}
{"role": "tool", "content": "执行命令: weather --city=Beijing", "timestamp": "2024-01-01T12:00:03Z", "id": "msg_4", "toolName": "exec"}
{"role": "tool_result", "content": "北京今天天气:晴,温度 25°C", "timestamp": "2024-01-01T12:00:04Z", "id": "msg_5", "toolCallId": "msg_4"}
{"role": "assistant", "content": "北京今天天气:晴,温度 25°C", "timestamp": "2024-01-01T12:00:05Z", "id": "msg_6"}
消息类型:
| 类型 | 说明 | 字段 |
|---|---|---|
user |
用户消息 | content, timestamp, id |
assistant |
AI 回复 | content, timestamp, id |
tool |
工具调用 | toolName, arguments, timestamp, id |
tool_result |
工具结果 | content, toolCallId, timestamp, id |
2.4 为什么使用 JSONL?
优势:
| 优势 | 说明 |
|---|---|
| 追加友好 | 可以直接追加新消息,无需重写整个文件 |
| 读取高效 | 可以逐行读取,不需要加载整个文件到内存 |
| 压缩友好 | 每行独立,压缩效果好 |
| 易于调试 | 可以用文本编辑器直接查看 |
| 容错性好 | 单行损坏不影响其他行 |
三、会话生命周期管理
3.1 生命周期阶段
| 阶段 | 说明 | 触发条件 |
|---|---|---|
| 创建会话 | 创建新的会话实例 | 首次收到消息 |
| 活跃使用 | 会话正在被使用 | 有活跃的消息交互 |
| 空闲状态 | 会话暂时空闲 | 超过一定时间无新消息 |
| 归档存储 | 会话被归档 | 长时间未使用或消息过多 |
| 删除清理 | 会话被删除 | 用户手动删除或自动清理 |
3.2 会话创建
代码位置:src/agents/session-manager.ts
export async function createSession(
sessionKey: string,
options: SessionOptions,
): Promise<Session> {
// 1. 生成会话 ID
const sessionId = generateSessionId();
// 2. 创建会话文件
const sessionPath = resolveSessionFilePath(sessionId);
await fs.writeFile(sessionPath, '', 'utf-8');
// 3. 更新会话元数据
await updateSessionMetadata(sessionKey, {
id: sessionKey,
type: options.type,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
messageCount: 0,
});
// 4. 返回会话对象
return {
id: sessionKey,
sessionId,
type: options.type,
createdAt: new Date(),
updatedAt: new Date(),
};
}
3.3 消息追加
代码位置:src/agents/session-writer.ts
export async function appendMessage(
sessionKey: string,
message: SessionMessage,
): Promise<void> {
// 1. 解析会话文件路径
const sessionPath = resolveSessionFilePath(sessionKey);
// 2. 追加消息到文件
const line = JSON.stringify(message) + '\n';
await fs.appendFile(sessionPath, line, 'utf-8');
// 3. 更新会话元数据
await updateSessionMetadata(sessionKey, {
updatedAt: new Date().toISOString(),
messageCount: await countMessages(sessionKey),
lastMessageAt: message.timestamp,
});
}
3.4 会话加载
代码位置:src/agents/session-loader.ts
export async function loadSession(
sessionKey: string,
): Promise<Session> {
// 1. 检查会话是否存在
const metadata = await getSessionMetadata(sessionKey);
if (!metadata) {
throw new Error(`Session not found: ${sessionKey}`);
}
// 2. 加载会话历史
const history = await loadSessionHistory(sessionKey);
// 3. 返回会话对象
return {
id: sessionKey,
type: metadata.type,
createdAt: new Date(metadata.createdAt),
updatedAt: new Date(metadata.updatedAt),
history,
};
}
3.5 会话压缩
当会话历史过长时,自动压缩较早的消息。
代码位置:src/agents/session-compactor.ts
export async function compactSession(
sessionKey: string,
options: CompactOptions,
): Promise<CompactResult> {
// 1. 加载会话历史
const history = await loadSessionHistory(sessionKey);
// 2. 确定压缩点
const compactPoint = findCompactPoint(history, options);
// 3. 生成摘要
const summary = await generateSummary(history.slice(0, compactPoint));
// 4. 重写会话文件
const compactedHistory = [
{ role: 'system', content: summary },
...history.slice(compactPoint),
];
await rewriteSessionFile(sessionKey, compactedHistory);
// 5. 更新元数据
await updateSessionMetadata(sessionKey, {
updatedAt: new Date().toISOString(),
messageCount: compactedHistory.length,
});
return {
compacted: true,
originalCount: history.length,
compactedCount: compactedHistory.length,
};
}
压缩策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 保留最近 N 条 | 只保留最近的 N 条消息 | 通用场景 |
| 保留最近 N 天 | 只保留最近 N 天的消息 | 长期会话 |
| 保留重要消息 | 保留包含重要信息的消息 | 重要会话 |
| 生成摘要 | 生成摘要替代早期消息 | 需要保留上下文 |
四、会话隔离机制
4.1 为什么需要会话隔离?
| 需求 | 说明 | 实现方式 |
|---|---|---|
| 隐私保护 | 不同用户的消息互不可见 | Session Key 隔离 |
| 安全隔离 | 限制工具执行权限 | 沙箱环境 |
| 状态独立 | 每个会话独立的状态管理 | 独立存储 |
| 权限控制 | 不同会话有不同的权限 | 访问控制 |
4.2 Session Key 隔离
代码位置:src/routing/session-key.ts
export function buildAgentPeerSessionKey(params: {
agentId: string;
mainKey?: string | undefined;
channel: string;
accountId?: string | null;
peerKind?: "dm" | "group" | "channel" | null;
peerId?: string | null;
}): string {
const parts = [
'agent',
normalizeAgentId(params.agentId),
normalizeMainKey(params.mainKey),
params.channel,
params.accountId || 'default',
params.peerKind || 'dm',
params.peerId || 'unknown',
];
return parts.join(':');
}
Session Key 格式:
agent:<agentId>:<mainKey>:<channel>:<accountId>:<peerKind>:<peerId>
示例:
agent:main:main- 主会话agent:main:telegram:default:dm:123456789- Telegram 私聊agent:main:telegram:group:100123456789- Telegram 群聊
4.3 沙箱隔离
export class Sandbox {
constructor(private config: SandboxConfig) {
// 初始化沙箱环境
}
async exec(command: string, args: string[]): Promise<ExecResult> {
// 1. 验证命令安全性
if (!this.isCommandSafe(command)) {
throw new Error('Command not allowed');
}
// 2. 限制资源使用
const limits = this.config.limits;
const options = {
timeout: limits.timeout,
maxMemory: limits.maxMemory,
};
// 3. 执行命令
const result = await this.runCommand(command, args, options);
return result;
}
private isCommandSafe(command: string): boolean {
// 检查命令是否在白名单中
return ALLOWED_COMMANDS.includes(command);
}
}
沙箱配置:
| 会话类型 | 沙箱级别 | 允许的工具 | 网络访问 |
|---|---|---|---|
| 主会话 | 完全信任 | 所有工具 | 允许 |
| 私聊会话 | 沙箱隔离 | 限制工具 | 禁止 |
| 群组会话 | 沙箱隔离 | 限制工具 | 禁止 |
| 线程会话 | 沙箱隔离 | 限制工具 | 禁止 |
五、会话管理 API
5.1 核心 API
代码位置:src/agents/session-manager.ts
export interface SessionManager {
// 创建会话
createSession(sessionKey: string, options: SessionOptions): Promise<Session>;
// 加载会话
loadSession(sessionKey: string): Promise<Session>;
// 追加消息
appendMessage(sessionKey: string, message: SessionMessage): Promise<void>;
// 压缩会话
compactSession(sessionKey: string, options: CompactOptions): Promise<CompactResult>;
// 删除会话
deleteSession(sessionKey: string): Promise<void>;
// 列出所有会话
listSessions(): Promise<SessionMetadata[]>;
}
5.2 使用示例
// 创建会话
const session = await sessionManager.createSession(
'agent:main:telegram:default:dm:123456789',
{ type: 'dm' }
);
// 追加消息
await sessionManager.appendMessage(
'agent:main:telegram:default:dm:123456789',
{
role: 'user',
content: '你好',
timestamp: new Date().toISOString(),
id: generateId(),
}
);
// 加载会话
const loadedSession = await sessionManager.loadSession(
'agent:main:telegram:default:dm:123456789'
);
// 压缩会话
const result = await sessionManager.compactSession(
'agent:main:telegram:default:dm:123456789',
{ maxMessages: 100 }
);
// 删除会话
await sessionManager.deleteSession(
'agent:main:telegram:default:dm:123456789'
);
六、核心代码文件索引
| 文件路径 | 功能 | 重要性 |
|---|---|---|
| src/agents/session-manager.ts | 会话管理器 | ⭐⭐⭐⭐⭐ |
| src/agents/session-loader.ts | 会话加载 | ⭐⭐⭐⭐⭐ |
| src/agents/session-writer.ts | 会话写入 | ⭐⭐⭐⭐⭐ |
| src/agents/session-compactor.ts | 会话压缩 | ⭐⭐⭐⭐ |
| src/routing/session-key.ts | Session Key 生成 | ⭐⭐⭐⭐⭐ |
| src/config/sessions.ts | 会话配置 | ⭐⭐⭐⭐ |
| src/gateway/sessions-resolve.ts | 会话解析 | ⭐⭐⭐⭐ |
七、下一步
恭喜你完成了会话管理系统的学习!接下来建议:
- 📖 阅读 08. 记忆系统 - 了解长期记忆管理
- 🔄 查看 03. 消息流转 - 理解完整消息流程
- 🛠️ 探索 message_flow/ - 查看详细步骤文档
通过理解会话管理的工作原理,你已经掌握了 OpenClaw 的对话状态管理!
更多推荐




所有评论(0)