08 · Session 与心跳:时间如何进入 Agent
解释 OpenClaw 的 Session、Heartbeat、Cron、Webhooks 与 Tasks:谁负责上下文,谁负责定时,谁只做台账。
前面几章已经说明了 Agent 的空间结构:Workspace 放人格和工作文件,Gateway 接消息,Session 承载当前上下文。
这一章补上时间结构。
OpenClaw 不是一个永远摊开的聊天窗口。它把对话分成可重置的 Session,用 Heartbeat 周期性唤醒主会话,用 Cron 精确调度后台任务,用 Webhooks 接外部事件,再用 Tasks 记录那些脱离主对话运行的工作。理解这几层,你才知道什么时候让 Agent “记住”,什么时候让它“清空”,什么时候让它“到点办事”,什么时候只需要一条审计记录。
这一篇只解决一个判断:Session 管上下文,Heartbeat 管周期醒来,Cron 管精确调度,Webhook 管外部事件,Task 只做后台台账。
1. 先把五个词分清楚
这五个词容易混在一起:
| 概念 | 更像什么 | 负责什么 | 不负责什么 |
|---|---|---|---|
Session | 对话桶 | 决定消息进入哪段上下文 | 不保存长期记忆 |
Heartbeat | 周期巡检 | 定期唤醒主会话,让 Agent 自查 | 不保证精确到秒 |
Cron | 闹钟 / 排班表 | 精确时间、一次性提醒、后台任务 | 不理解业务本身 |
Webhook | 外部门铃 | 接收外部系统主动打来的事件 | 不主动轮询外部系统 |
Task | 后台台账 | 记录 detached work 的状态 | 不负责定时触发 |
flowchart LR
User["用户消息"] --> Session["Session<br/>上下文桶"]
Heartbeat["Heartbeat<br/>周期醒来"] --> Session
Cron["Cron<br/>精确调度"] --> Run["Agent run"]
Webhook["Webhook<br/>外部事件"] --> Run
Run --> Task["Task ledger<br/>后台台账"]
Session --> Run
style Session fill:#dbeafe,stroke:#3b82f6,stroke-width:2px
style Heartbeat fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
style Cron fill:#dcfce7,stroke:#22c55e,stroke-width:2px
style Webhook fill:#dcfce7,stroke:#22c55e,stroke-width:2px
style Task fill:#f3f4f6,stroke:#6b7280,stroke-width:2px
一句话:
- 你问 Agent,它进入某个
sessionKey。 - 到了 Heartbeat 时间,Gateway 让主会话自己检查一次。
- 到了 Cron 时间,Gateway 按 job 运行任务。
- 外部系统有事件,就通过 Webhook 唤醒或启动 isolated run。
- 后台 run 发生后,Task ledger 记录它有没有成功。
2. Session 是路由结果,不是聊天窗口 UI
OpenClaw 官方把 conversations 组织成 sessions。每条消息会根据来源进入一个 session。
默认行为可以这样看:
- Direct messages 默认共享一个 DM session,多用户时要检查
dmScope。 - Group chats 按 group 隔离,群里谁能触发要看 group policy。
- Rooms / channels 按 room 或 channel 隔离,thread/topic 会影响 session key。
- Cron jobs 每次运行使用 fresh session,
main、isolated、current要分清。 - Webhooks 按 hook 隔离,除非配置覆盖;不要让外部随意选择 session。
这里有两个核心 ID:
sessionKey是路由桶,决定“这条消息属于哪段对话”。sessionId是当前 transcript 文件,reset 后会换一个新的sessionId。
常见 key 形态:
常见例子包括 agent:main:main、agent:ops:whatsapp:group:120363403215116621、agent:ops:slack:channel:C1234567890、cron:morning-brief 和 hook:uuid。
状态由 Gateway 持有。UI、TUI、Web 控制台都应该问 Gateway,不应该自己猜本地文件。
官方给出的磁盘位置是:
~/.openclaw/agents/agentId/sessions/sessions.json 和 ~/.openclaw/agents/agentId/sessions/sessionId.jsonl。
sessions.json 是小型 mutable store,记录当前 sessionKey -> SessionEntry。sessionId.jsonl 是 append-only transcript,保存真实消息、工具调用、工具结果、compaction summary 等内容。
3. Reset 换的是当前 Session,不是记忆
Session 会复用,直到触发 reset。
官方生命周期规则:
- Daily reset 默认开启,在 Gateway host 的本地时间凌晨 4 点之后创建新 session。
- Idle reset 是可选项,通过
session.reset.idleMinutes设置。 - 手动 reset 通过聊天里的
/new或/reset触发。 /new model还可以顺带切换模型。- Daily reset 和 idle reset 同时存在时,先到期的规则生效。
- 使用 provider-owned CLI session 的活跃会话,不会被 implicit daily default 直接切断;需要
/reset或显式配置session.reset。
这句话很关键:reset 创建新的 sessionId,不等于删除 memory,也不等于删除旧 transcript。
所以不要把 reset 理解成“失忆”。更准确地说,它是给同一个 sessionKey 换一份新的当前 transcript。长期偏好、人物设定、重要事实应该在 Workspace memory 或文件里,Session 只负责当前对话上下文。
Reset 是“换当前稿纸”,不是“烧掉档案柜”。真正要长期保存的东西,应落到 memory 或 workspace 文件里。
4. DM isolation 是安全边界
OpenClaw 默认所有 DM 共享一个 session。这个设计适合单用户私人 Agent,因为连续性最好:你从不同时间点私信它,它都在同一段上下文里。
但只要多个人能私信同一个 Agent,默认 main 就有隐私风险。
官方建议多用户场景启用 DM isolation:
{
"session": {
"dmScope": "per-channel-peer"
}
}四种模式:
dmScope | 隔离粒度 | 适合场景 |
|---|---|---|
main | 所有 DM 共享一个 session | 单用户私人 Agent |
per-peer | 按发送者隔离 | 同一人跨渠道连续性重要 |
per-channel-peer | 按渠道 + 发送者隔离 | 多用户 shared inbox 的默认选择 |
per-account-channel-peer | 按账号 + 渠道 + 发送者隔离 | 多账号网关、多 bot 场景 |
如果同一个人会从多个渠道联系你,可以用 session.identityLinks 显式关联身份。改完之后用 openclaw security audit 检查配置。
判断标准很简单:
- 只有你一个人用,
main可以接受。 - 两个人以上能 DM,默认改
per-channel-peer。 - 多 bot、多账号、多租户,考虑
per-account-channel-peer。 - 跨渠道连续性是产品需求时,再显式配置
identityLinks。
5. Heartbeat 是周期性主会话 turn
Heartbeat 不是服务器健康探针。它是 Gateway 周期性发起的一次 Agent turn,让模型在主会话上下文里检查有没有事情需要提醒你。
官方默认值:
- 默认 interval 是
30m。 - Anthropic OAuth/token,包括 Claude CLI reuse,默认是
1h。 - 关闭 heartbeat 用
every: "0m"。 - 默认 delivery target 是
none。
最小配置示例:
{
"agents": {
"defaults": {
"heartbeat": {
"every": "30m",
"target": "last",
"lightContext": true,
"isolatedSession": true
}
}
}
}字段含义:
every控制心跳间隔,先用默认值,不要为了“主动”盲目缩短。target控制投递目标,默认none;要通知最近渠道才用last。lightContext控制是否轻量上下文,常驻巡检建议开启。isolatedSession控制是否 fresh session,避免心跳携带完整主对话历史。activeHours控制运行时间窗口,防止半夜打扰和无意义调用。model控制心跳专用模型,简单巡检可用便宜模型。includeReasoning控制是否投递 Reasoning,群聊里要谨慎,避免泄漏思考内容。
这里要注意一个反直觉点:isolatedSession: true 并不改变投递路由。它只是让心跳运行时不要带完整主对话历史;结果仍然可以按主 session 的 last route 发送。
Heartbeat 的核心不是“服务器还活着吗”,而是“Agent 到点醒来,看有没有值得提醒你的事”。
6. HEARTBEAT.md 要短
如果 workspace 里有 HEARTBEAT.md,默认 heartbeat prompt 会要求 Agent 读取它。它适合放小而稳定的检查清单。
示例:
# Heartbeat checklist
- Scan inbox for urgent follow-ups.
- Check calendar items in the next 2 hours.
- If nothing needs attention, reply HEARTBEAT_OK.官方还有几个细节:
HEARTBEAT.md缺失时,heartbeat 仍然可以运行,由模型判断要做什么。- 文件只有空行和 Markdown 标题时,会跳过本次心跳,原因是
empty-heartbeat-file。 - 不要把密钥、token、手机号、私密凭据写进
HEARTBEAT.md,它会进入 prompt context。 - 如果清单变长,优先拆成
tasks:block 或改用 Cron,不要把 heartbeat 变成万能脚本。
tasks: block 适合把多个周期检查放在同一个 heartbeat 文件里:
tasks:
- name: inbox-triage
interval: 30m
prompt: "Check for urgent unread emails."
- name: calendar-scan
interval: 2h
prompt: "Check upcoming meetings."
# Additional instructions
- Keep alerts short.
- If nothing needs attention, reply HEARTBEAT_OK.OpenClaw 会只把到期任务放进本次 heartbeat prompt。没有任务到期时,会跳过模型调用,原因是 no-tasks-due。任务上次运行时间写在 session state 的 heartbeatTaskState 里,正常重启后仍可延续。
7. HEARTBEAT_OK 是投递协议
Heartbeat 的回复有一个约定:
- 没有事情需要提醒时,回复
HEARTBEAT_OK。 - Heartbeat run 中,
HEARTBEAT_OK出现在开头或结尾会被当作 ack。 - 剩余内容不超过
ackMaxChars时,OpenClaw 会丢弃这条回复,不打扰用户。 - 有告警时,不要带
HEARTBEAT_OK,只返回告警文本。 - 普通聊天里误发单独的
HEARTBEAT_OK也会被丢弃。
这就是为什么 heartbeat 可以高频运行但不制造消息噪音。
配置可见性时,把三件事分开:
showOk控制是否显示 OK ack,多数情况下关闭。showAlerts控制是否显示非 OK 告警,需要提醒时开启。useIndicator控制是否给 UI 状态面板发 indicator,需要可见状态时开启。
如果三者都为 false,OpenClaw 会直接跳过 heartbeat run,不产生模型调用。
8. Cron 是 Gateway scheduler
Cron 是 OpenClaw 的精确调度机制。它运行在 Gateway 里,不运行在模型里。
官方关键事实:
- Job 存在
~/.openclaw/cron/jobs.json,Gateway 重启不会丢失已有 job。 - 所有 Cron execution 都会创建 background task 记录,Cron 跑过什么,可以回头查。
- 一次性
atjob 默认成功后自动删除,它更像提醒,不是长期任务。 - Cron 可投递到 channel、webhook 或静默,调度和通知是两件事。
- Cron 可指定 Agent、模型、thinking、工具范围,所以调度任务可以有独立运行姿态。
三种 schedule:
at:一次性时间点,例如20m、ISO 8601 时间。every:固定间隔,例如每 2 小时跑一次。cron:日历式排班,例如每天 7 点、每周一 6 点。
时区规则要写准:
at无时区时按 UTC 处理;需要本地时间就显式写清。cron无时区时使用 Gateway host timezone;关键任务建议带--tz。- top-of-hour recurring 默认最多 stagger 5 分钟;要整点用
--exact或schedule.staggerMs = 0。
旧稿里的时区判断过粗。at 和 cron 的无时区行为不同。
9. Cron 的四种 Session 目标
Cron 不只有 main 和 isolated。
| 目标 | 上下文边界 | 适合任务 |
|---|---|---|
main | 进入下一次 heartbeat turn | reminders、system events |
isolated | 在 cron:jobId dedicated session 运行 | 报告、后台杂务、重分析 |
current | 创建 job 时绑定当前 session | 需要当前上下文的重复工作 |
session:name | 使用持久命名 session | 连续积累上下文的流程 |
示例:一次性提醒进入主会话。
openclaw cron add \
--name "Calendar check" \
--at "20m" \
--session main \
--system-event "Next heartbeat: check calendar." \
--wake now示例:每天早上固定时间跑 isolated 简报。
openclaw cron add \
--name "Morning brief" \
--cron "0 7 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Summarize overnight updates." \
--announce \
--channel slack \
--to "channel:C1234567890"示例:每周深度分析,指定模型和 thinking。
openclaw cron add \
--name "Deep analysis" \
--cron "0 6 * * 1" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Weekly deep analysis of project progress." \
--model "opus" \
--thinking high \
--announcemain 的本质是 enqueue system event,并可选择 wake now 或 next-heartbeat。isolated 的本质是专门起一个 cron:jobId agent turn,每次 fresh session,不污染主对话历史。
10. Delivery 不是由 Agent 自己兜底
Cron 的 delivery mode 有三种:
announce把 summary 投递到目标 channel,isolated job 默认是 announce。webhook把完成事件 POST 到 URL,由外部系统接收完成事件。none内部保留,不投递;不等于交给 Agent 自己外发。
对于 cron-owned isolated jobs,runner 负责最终投递路径。Agent 应返回 plain-text summary,由 runner 决定投递、webhook 或静默。--no-deliver 只是保持内部,不代表把外发责任交还给 Agent。
如果 isolated run 返回 silent token,例如 NO_REPLY 或 no_reply,OpenClaw 会抑制 direct outbound delivery,也会抑制 fallback queued summary。结果就是:这次 Cron 不会往聊天里发消息。
排障顺序:
openclaw status
openclaw gateway status
openclaw cron status
openclaw cron list
openclaw cron runs --id job-id --limit 20
openclaw system heartbeat last
openclaw logs --follow
openclaw doctor11. Webhook 是外部事件入口
Cron 是“到点触发”。Webhook 是“外部系统有事就通知 OpenClaw”。
Gateway 可以暴露 HTTP webhook endpoints:
{
"hooks": {
"enabled": true,
"token": "shared-secret",
"path": "/hooks"
}
}常见 endpoint:
POST /hooks/wake:enqueue system event 到 main session。POST /hooks/agent:运行 isolated agent turn。POST /hooks/name:mapped hook,通过配置把自定义 payload 转成 wake 或 agent action。
安全规则必须硬记:
- 请求要带
Authorization: Bearer token,也支持x-openclaw-token。 - Query-string token 会被拒绝。
- Hook endpoint 应放在 loopback、tailnet 或可信反向代理后面。
- 使用专用 hook token,不复用 Gateway auth token。
hooks.path不能用根路径/。- 用
hooks.allowedAgentIds限制可显式路由的 Agent。 - 不要轻易开放 caller-selected session key;需要时配合 allowed prefix。
Webhook 是执行入口,不是普通网页回调。公网暴露前先确认 token、反向代理、allowed agents 和 session key 约束都已收紧。
12. Internal hooks 不是 Webhooks
OpenClaw 还有内部 Hooks。它们不是外部 HTTP endpoint,而是在 Gateway 内部事件发生时运行的小脚本。
典型事件:
command:new:用户发出/new。command:reset:用户发出/reset。command:stop:用户发出/stop。session:compact:before:compaction 前。session:compact:after:compaction 后。session:patch:session 属性修改。agent:bootstrap:workspace bootstrap 注入前。gateway:startup:channel 启动且 hooks 加载后。message:received:任意渠道收到入站消息。message:transcribed:音频转录后。message:preprocessed:媒体和链接理解后。message:sent:出站消息送达后。
常见用途:
/new或/reset时保存 session-memory。- 记录命令审计日志。
- Gateway 启动时运行
BOOT.md。 - Bootstrap 前注入额外 workspace 文件。
如果你要拦截 tool call、reply dispatch、subagent delivery、plugin install 等更深的生命周期,应看 Plugin hooks,而不是内部 Hooks。
13. Tasks 是台账,不是调度器
Background Tasks 记录 detached work。它不决定什么时候运行;Cron、Sub-agent、ACP、CLI agent commands 才会产生运行。
会创建 Task 的来源:
- ACP background runs 会创建 Task;Heartbeat turns 不会。
- Subagent spawns 会创建 Task;normal interactive chat turns 不会。
- 所有 Cron executions,包括 main-session 和 isolated,都会创建 Task;direct slash command responses 不会。
- CLI operations that run through Gateway 会创建 Task。
- Agent media jobs 会创建 Task。
Task 生命周期:
Task 生命周期从 queued 到 running,最后进入 succeeded、failed、timed_out、cancelled 或 lost。
Completion 是 push-driven。Detached work 完成后,可以直接通知目标 channel,也可以 wake requester session 或 heartbeat。不要把它设计成 Agent 每隔几秒 polling 状态;那通常是错误形状。
检查命令:
openclaw tasks list
openclaw tasks show task-id
openclaw tasks cancel task-id
openclaw tasks audit
openclaw tasks maintenance --applyTerminal task records 默认保留 7 天后自动清理。
14. 怎么选机制
按需求选,不按名字选:
| 需求 | 机制 | 为什么 |
|---|---|---|
| 每天 9 点准时发报告 | Cron | 时间点明确 |
| 20 分钟后提醒我 | Cron --at | 一次性提醒 |
| 每 30 分钟顺手看 inbox、calendar、notifications | Heartbeat | 周期醒来,自查是否需要提醒 |
| 每次工具调用前做安全拦截 | Plugin hooks 或 tool policy | 拦截点在工具生命周期 |
/reset 时保存一份摘要到 memory | internal hook | 事件来自 Gateway 内部 |
| GitHub PR 创建后立刻 review | Webhook | 外部系统主动通知 |
| 重分析很重,不想污染主对话 | Cron isolated 或 sub-agent | fresh session,隔离上下文 |
| 只想知道后台跑过什么 | Tasks | Task 是 ledger,不是 scheduler |
一个稳妥默认:
- 私人 Agent:
Session: main,Heartbeat 可用30m或1h,target用none或last,Cron 只放明确时间点的提醒。 - 多用户 Agent:
Session: per-channel-peer,Heartbeat 配activeHours + target none,Cron 用isolated + explicit delivery。 - 运营 / 监控 Agent:
Session: per-account-channel-peer,Heartbeat 用 task block +lightContext,Cron 做 precise jobs + model/tool restrictions,外部事件优先 Webhook。
15. 常见误解
误解一:Heartbeat 越频繁越好。
不对。Heartbeat 是 full agent turn,会消耗 token。官方建议控制成本:isolatedSession: true、lightContext: true、更便宜的 model、小型 HEARTBEAT.md、必要时 target: "none"。
误解二:Cron 和 Heartbeat 都是定时任务,所以随便选。
不对。Heartbeat 适合上下文相关的周期检查;Cron 适合精确时间、一次性提醒、独立后台任务。
误解三:Reset 会删记忆。
不对。Reset 换当前 session transcript;memory 和旧 transcript 仍在。长期事实要写进 memory 或 workspace 文件。
误解四:Webhook endpoint 放公网就行。
不对。Webhook 是执行入口,应该放在 loopback、tailnet 或可信反代后面,并使用专用 token 和 agent allowlist。
误解五:Task 可以当成任务调度器。
不对。Task 是 ledger。它记录 detached work 的状态,不负责定时。
16. 给 Agent 的实践任务
把这组要求发给 OpenClaw Agent,让它检查自己的时间系统:
- 运行
openclaw status和openclaw sessions --json,说明当前 session store 路径、最近活动、dmScope。 - 检查
session.reset配置,说明 daily reset、idle reset、manual reset 的实际边界。 - 读取
HEARTBEAT.md;如果不存在、为空、过长或含敏感信息,请指出。 - 检查
agents.defaults.heartbeat和agents.list[].heartbeat,说明every、target、activeHours、lightContext、isolatedSession是否合理。 - 运行
openclaw cron status、openclaw cron list、openclaw cron runs,列出所有 job 的 schedule、timezone、session target、delivery mode、agentId、model override。 - 检查是否存在多用户 DM 但仍使用
mainsession 的风险。 - 检查
openclaw tasks list和openclaw tasks audit,说明后台任务是否有failed、timed_out、lost。 - 给出最小修改建议,不要直接改配置。
17. 本章自检
读完这一章,你应该能回答:
sessionKey和sessionId的区别是什么?mainDM scope 为什么只适合单用户?/new、/reset、daily reset、idle reset 分别什么时候换 session?- Heartbeat 为什么不是服务器健康探针?
HEARTBEAT_OK为什么能避免消息噪音?- Cron 的
at和cron无时区时分别怎么处理? - Cron
main和isolated的上下文边界有什么不同? - Webhook 和 internal hook 的边界是什么?
- 为什么 Tasks 是 ledger,不是 scheduler?
过关标准:能用一句话说清“OpenClaw 用 Session 管上下文,用 Heartbeat 做周期自查,用 Cron 做精确调度,用 Webhook 接外部事件,用 Tasks 留后台台账”。
18. 接下来去哪
09 · Channel 与安全
继续看外部入口、DM 配对、群组门控、工具策略、沙箱和 Gateway 暴露面。
07 · 多 Agent 协作
回到上一篇,理解多个 Agent 如何拆任务、共享上下文和避免互相污染。
官方教程:自动化
对照官方配置继续看 heartbeat、cron、webhook、task 和 hooks。