会话管理系统

📚 学习路径:本文档是架构文档的第 7 部分。建议按顺序阅读:

前言

会话管理是 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

沙箱环境

独立存储

访问控制

需求 说明 实现方式
隐私保护 不同用户的消息互不可见 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 沙箱隔离

代码位置src/agents/sandbox.ts

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 会话解析 ⭐⭐⭐⭐

七、下一步

恭喜你完成了会话管理系统的学习!接下来建议:


通过理解会话管理的工作原理,你已经掌握了 OpenClaw 的对话状态管理!

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐