AI 编程教程中文版
从原理到实战

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,mainisolatedcurrent 要分清。
  • Webhooks 按 hook 隔离,除非配置覆盖;不要让外部随意选择 session。

这里有两个核心 ID:

  • sessionKey 是路由桶,决定“这条消息属于哪段对话”。
  • sessionId 是当前 transcript 文件,reset 后会换一个新的 sessionId

常见 key 形态:

常见例子包括 agent:main:mainagent:ops:whatsapp:group:120363403215116621agent:ops:slack:channel:C1234567890cron:morning-briefhook:uuid

状态由 Gateway 持有。UI、TUI、Web 控制台都应该问 Gateway,不应该自己猜本地文件。

官方给出的磁盘位置是:

~/.openclaw/agents/agentId/sessions/sessions.json~/.openclaw/agents/agentId/sessions/sessionId.jsonl

sessions.json 是小型 mutable store,记录当前 sessionKey -> SessionEntrysessionId.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 跑过什么,可以回头查。
  • 一次性 at job 默认成功后自动删除,它更像提醒,不是长期任务。
  • 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 分钟;要整点用 --exactschedule.staggerMs = 0

旧稿里的时区判断过粗。atcron 的无时区行为不同。

9. Cron 的四种 Session 目标

Cron 不只有 main 和 isolated。

目标上下文边界适合任务
main进入下一次 heartbeat turnreminders、system events
isolatedcron: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 \
  --announce

main 的本质是 enqueue system event,并可选择 wake nownext-heartbeatisolated 的本质是专门起一个 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_REPLYno_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 doctor

11. 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 生命周期从 queuedrunning,最后进入 succeededfailedtimed_outcancelledlost

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 --apply

Terminal task records 默认保留 7 天后自动清理。

14. 怎么选机制

按需求选,不按名字选:

需求机制为什么
每天 9 点准时发报告Cron时间点明确
20 分钟后提醒我Cron --at一次性提醒
每 30 分钟顺手看 inbox、calendar、notificationsHeartbeat周期醒来,自查是否需要提醒
每次工具调用前做安全拦截Plugin hooks 或 tool policy拦截点在工具生命周期
/reset 时保存一份摘要到 memoryinternal hook事件来自 Gateway 内部
GitHub PR 创建后立刻 reviewWebhook外部系统主动通知
重分析很重,不想污染主对话Cron isolated 或 sub-agentfresh session,隔离上下文
只想知道后台跑过什么TasksTask 是 ledger,不是 scheduler

一个稳妥默认:

  • 私人 Agent:Session: main,Heartbeat 可用 30m1htargetnonelast,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: truelightContext: 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,让它检查自己的时间系统:

  1. 运行 openclaw statusopenclaw sessions --json,说明当前 session store 路径、最近活动、dmScope
  2. 检查 session.reset 配置,说明 daily reset、idle reset、manual reset 的实际边界。
  3. 读取 HEARTBEAT.md;如果不存在、为空、过长或含敏感信息,请指出。
  4. 检查 agents.defaults.heartbeatagents.list[].heartbeat,说明 everytargetactiveHourslightContextisolatedSession 是否合理。
  5. 运行 openclaw cron statusopenclaw cron listopenclaw cron runs,列出所有 job 的 schedule、timezone、session target、delivery mode、agentId、model override。
  6. 检查是否存在多用户 DM 但仍使用 main session 的风险。
  7. 检查 openclaw tasks listopenclaw tasks audit,说明后台任务是否有 failedtimed_outlost
  8. 给出最小修改建议,不要直接改配置。

17. 本章自检

读完这一章,你应该能回答:

  1. sessionKeysessionId 的区别是什么?
  2. main DM scope 为什么只适合单用户?
  3. /new/reset、daily reset、idle reset 分别什么时候换 session?
  4. Heartbeat 为什么不是服务器健康探针?
  5. HEARTBEAT_OK 为什么能避免消息噪音?
  6. Cron 的 atcron 无时区时分别怎么处理?
  7. Cron mainisolated 的上下文边界有什么不同?
  8. Webhook 和 internal hook 的边界是什么?
  9. 为什么 Tasks 是 ledger,不是 scheduler?

过关标准:能用一句话说清“OpenClaw 用 Session 管上下文,用 Heartbeat 做周期自查,用 Cron 做精确调度,用 Webhook 接外部事件,用 Tasks 留后台台账”。

18. 接下来去哪

19. 官方资料

本页目录