生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~250,000 tokens,输出 ~18,000 tokens(本章合计)
会话不是静态的数据容器——它有创建、活跃、过期和重置的完整生命周期。OpenClaw 通过灵活的重置策略控制会话的新旧交替,并提供运行时修补(Patch)机制让用户和 Agent 可以动态调整会话属性。本节将分析会话生命周期管理的核心源码。
5.3.1 创建与初始化:首条消息触发会话创建
OpenClaw 的会话采用懒创建(Lazy Creation)策略:不存在预先创建会话的步骤,而是在第一条消息到达时自动创建。src/auto-reply/reply/session.ts 中的 initSessionState() 函数是会话初始化的核心入口。
// src/auto-reply/reply/session.ts
export async function initSessionState(params: {
ctx: MsgContext;
cfg: OpenClawConfig;
commandAuthorized: boolean;
}): Promise<SessionInitResult> {
const { ctx, cfg } = params;
const sessionCfg = cfg.session;
// 1. 加载会话存储
const storePath = resolveStorePath(sessionCfg?.store, { agentId });
const sessionStore: Record<string, SessionEntry> = loadSessionStore(storePath);
// 2. 解析会话键
sessionKey = resolveSessionKey(sessionScope, sessionCtxForState, mainKey);
const entry = sessionStore[sessionKey];
// 3. 判断是否为新会话
const freshEntry = entry
? evaluateSessionFreshness({ updatedAt: entry.updatedAt, now, policy: resetPolicy }).fresh
: false;
if (!isNewSession && freshEntry) {
// 复用已有会话
sessionId = entry.sessionId;
systemSent = entry.systemSent ?? false;
} else {
// 创建新会话
sessionId = crypto.randomUUID();
isNewSession = true;
systemSent = false;
}
// ...
}
这个流程的关键在于第 3 步的"新鲜度"判断:如果会话键在存储中不存在(entry 为 undefined),freshEntry 为 false,会话自动创建;如果存在但已过期(不再"新鲜"),同样创建新会话。
当会话被标记为新会话时,系统会重置一系列状态:
这确保新会话从一个干净的状态开始,不会继承旧会话的 Token 统计和压缩状态。
重置触发器(Reset Triggers)
用户可以通过发送特定命令(如 /new 或 /reset)手动触发会话重置。这些命令被称为重置触发器:
注意触发器匹配是大小写不敏感的(用户输入 /NEW 也能匹配),并且支持在重置命令后附加消息(如 /new 帮我写个邮件),此时会话重置后这条附加消息会作为新会话的第一条消息。
5.3.2 重置策略:每日重置(Daily Reset)与空闲重置(Idle Reset)
除了手动重置,OpenClaw 还支持两种自动重置策略。src/config/sessions/reset.ts 定义了相关类型和逻辑。
每日重置(Daily Reset)
每日重置是默认策略。它的语义是:如果会话的最后更新时间早于今天的重置时间点,则会话被视为过期。
举例:假设重置时间为凌晨 4 点:
现在是 2 月 18 日上午 10 点 → 重置时间线是 2 月 18 日 04:00
现在是 2 月 18 日凌晨 2 点 → 重置时间线是 2 月 17 日 04:00(因为还没过今天的 4 点)
任何在重置时间线之前最后更新的会话都被视为过期。
空闲重置(Idle Reset)
空闲重置基于会话的最后活跃时间。如果会话在指定分钟数内没有新消息,则视为过期。
evaluateSessionFreshness() 是判断会话是否过期的核心函数:
一个关键设计:两种过期条件可以同时生效。即使处于 daily 模式,如果同时配置了 idleMinutes,那么空闲超时也会触发过期。这意味着可以设置"每天凌晨 4 点重置,但如果空闲超过 2 小时也重置"这样的组合策略。
5.3.3 按类型/通道覆盖重置策略
不同类型的会话可能需要不同的重置策略。例如,DM 对话可能适合每日重置,而群组中的线程会话可能更适合短时间空闲后重置。OpenClaw 通过 resetByType 和 resetByChannel 提供了细粒度的覆盖机制。
resolveSessionResetType() 根据会话键和消息属性将会话分为三类:
resolveSessionResetPolicy() 按以下优先级解析重置策略:
以下配置示例展示了这种层次化的覆盖机制:
在这个配置下:
线程会话:3 小时无活动后重置(由 resetByType.thread 覆盖)
Discord 上的所有会话:7 天无活动后重置(由 resetByChannel.discord 覆盖,优先级高于 resetByType)
resolveChannelResetConfig() 负责查找通道特定的覆盖配置:
5.3.4 会话修补(Session Patch):运行时修改会话属性
会话一旦创建,其属性并非一成不变。用户可以通过 sessions.patch 协议方法在运行时修改会话的模型、思考级别、发送策略等属性,而无需重置整个会话。
src/gateway/sessions-patch.ts 中的 applySessionsPatchToStore() 函数实现了这一机制:
会话修补支持以下属性:
思考级别(low/medium/high/xhigh)
执行宿主(sandbox/gateway/node)
执行安全级别(deny/allowlist/full)
每个字段都有严格的校验逻辑。以模型覆盖为例:
修补机制的一个重要特性是设置为 null 表示清除覆盖(恢复默认值),而 undefined(即 patch 中不包含该字段)表示不修改。这遵循了 JSON Patch 中常见的语义约定。
Gateway 的 sessions.reset 方法提供了服务端的完整重置能力:
重置时会保留个性化覆盖(如模型选择、思考级别),但清除对话状态(生成新的 session ID、重置 Token 计数)。这样用户在 /reset 后不需要重新配置偏好设置。
OpenClaw 的会话生命周期管理有以下核心特点:
懒创建:会话在第一条消息到达时自动创建,无需预先初始化
双重过期机制:每日重置(按固定时间点)和空闲重置(按不活跃时长)可以同时生效,取 OR 关系
层次化覆盖:resetByChannel > resetByType > reset,允许针对不同通道和会话类型设置不同策略
手动触发器:/new 和 /reset 命令提供即时重置能力,支持大小写不敏感匹配和附加消息
运行时修补:sessions.patch 允许动态修改会话属性,而 sessions.reset 在重置时保留用户偏好
在下一节中,我们将分析 OpenClaw 如何在 LLM 调用前裁剪过长的上下文,以在有限的上下文窗口内保持对话质量。