心跳(Gateway)

心跳还是 Cron? 怎么选请看 Cron vs Heartbeat

心跳在主会话中运行周期性的 Agent 对话轮次,让模型在有需要关注的事情时主动告诉你,同时避免刷屏。

故障排除:/automation/troubleshooting

新手快速上手

  1. 保持心跳默认开启(默认 30m,Anthropic OAuth/setup-token 时为 1h),或设置你想要的频率。
  2. 在 Agent 工作区创建一个简短的 HEARTBEAT.md 清单(可选但推荐)。
  3. 决定心跳消息发往哪里(target: "none" 是默认值;设 target: "last" 发送到最近联系过的渠道)。
  4. 可选:启用心跳推理投递以增加透明度。
  5. 可选:如果心跳运行只需要 HEARTBEAT.md,可使用轻量级引导上下文。
  6. 可选:限制心跳只在活跃时段(本地时间)运行。

示例配置:

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        target: "last", // 显式投递到最近联系渠道(默认是 "none")
        directPolicy: "allow", // 默认:允许直发/私聊目标;设 "block" 可抑制
        lightContext: true, // 可选:引导文件中只保留 HEARTBEAT.md
        // activeHours: { start: "08:00", end: "24:00" },
        // includeReasoning: true, // 可选:同时发送单独的 Reasoning: 消息
      },
    },
  },
}

默认值

  • 间隔:30m(Anthropic OAuth/setup-token 认证模式检测到时为 1h)。通过 agents.defaults.heartbeat.every 或按 Agent 的 agents.list[].heartbeat.every 设置;用 0m 禁用。
  • 提示正文(可通过 agents.defaults.heartbeat.prompt 配置): Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.
  • 心跳提示原样作为用户消息发送。系统提示中包含一个”Heartbeat”部分,运行会被标记为内部心跳。
  • 活跃时段(heartbeat.activeHours)按配置的时区检查。在窗口外的心跳跳过,等下一个窗口内的 tick 正常运行。

心跳提示的用途

默认提示故意写得比较宽泛:

  • 后台任务:“Consider outstanding tasks” 促使 Agent 检查后续跟进(收件箱、日历、提醒、排队的工作),浮出紧急事项。
  • 人类问候:“Checkup sometimes on your human during day time” 偶尔发一条轻量的”有什么需要帮忙的吗?“,但会利用你配置的本地时区避免夜间打扰(见 /concepts/timezone)。

如果你想让心跳做非常具体的事(比如”检查 Gmail PubSub 统计”或”验证 Gateway 健康”),把 agents.defaults.heartbeat.prompt(或 agents.list[].heartbeat.prompt)设为自定义正文(原样发送)。

响应约定

  • 没什么需要关注的,回复 HEARTBEAT_OK
  • 心跳运行期间,当 HEARTBEAT_OK 出现在回复的开头或结尾时,OpenClaw 将其视为确认。token 会被去除,如果剩余内容 ackMaxChars(默认 300),整个回复会被丢弃。
  • 如果 HEARTBEAT_OK 出现在回复中间,不做特殊处理。
  • 对于告警,不要包含 HEARTBEAT_OK;只返回告警文本。

心跳之外,消息开头/结尾出现的 HEARTBEAT_OK 会被去除并记录日志;只有 HEARTBEAT_OK 的消息会被丢弃。

配置

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m", // 默认:30m(0m 禁用)
        model: "anthropic/claude-opus-4-6",
        includeReasoning: false, // 默认:false(可用时投递单独的 Reasoning: 消息)
        lightContext: false, // 默认:false;true 时引导文件只保留 HEARTBEAT.md
        target: "last", // 默认:none | 选项:last | none | <频道 id>(核心或插件,如 "bluebubbles")
        to: "+15551234567", // 可选的频道级覆盖
        accountId: "ops-bot", // 可选的多账户频道 id
        prompt: "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.",
        ackMaxChars: 300, // HEARTBEAT_OK 后允许的最大字符数
      },
    },
  },
}

作用域与优先级

  • agents.defaults.heartbeat 设置全局心跳行为。
  • agents.list[].heartbeat 在其上合并;如果任何 Agent 有 heartbeat 块,只有那些 Agent 会运行心跳。
  • channels.defaults.heartbeat 设置所有频道的可见性默认值。
  • channels.<channel>.heartbeat 覆盖频道默认值。
  • channels.<channel>.accounts.<id>.heartbeat(多账户频道)覆盖频道级设置。

按 Agent 的心跳

如果任何 agents.list[] 条目包含 heartbeat 块,只有那些 Agent 运行心跳。按 Agent 的块会在 agents.defaults.heartbeat 之上合并(这样你可以设一次共享默认值,然后按 Agent 覆盖)。

示例:两个 Agent,只有第二个运行心跳。

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        target: "last", // 显式投递到最近联系渠道(默认是 "none")
      },
    },
    list: [
      { id: "main", default: true },
      {
        id: "ops",
        heartbeat: {
          every: "1h",
          target: "whatsapp",
          to: "+15551234567",
          prompt: "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.",
        },
      },
    ],
  },
}

活跃时段示例

限制心跳只在特定时区的工作时段运行:

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        target: "last", // 显式投递到最近联系渠道(默认是 "none")
        activeHours: {
          start: "09:00",
          end: "22:00",
          timezone: "America/New_York", // 可选;未设置时用 userTimezone,否则用主机时区
        },
      },
    },
  },
}

在此窗口外(上午 9 点前或晚上 10 点后东部时间),心跳会被跳过。窗口内的下一个 tick 正常运行。

24/7 配置

想让心跳全天运行,用以下任一方式:

  • 完全省略 activeHours(不限制时间窗口;这是默认行为)。
  • 设全天窗口:activeHours: { start: "00:00", end: "24:00" }

不要把 startend 设成同一时间(比如 08:0008:00)。这会被视为零宽窗口,心跳永远跳过。

多账户示例

accountId 指定多账户频道(如 Telegram)中的特定账户:

{
  agents: {
    list: [
      {
        id: "ops",
        heartbeat: {
          every: "1h",
          target: "telegram",
          to: "12345678:topic:42", // 可选:路由到特定的话题/线程
          accountId: "ops-bot",
        },
      },
    ],
  },
  channels: {
    telegram: {
      accounts: {
        "ops-bot": { botToken: "YOUR_TELEGRAM_BOT_TOKEN" },
      },
    },
  },
}

字段说明

  • every:心跳间隔(时长字符串;默认单位为分钟)。
  • model:心跳运行的可选模型覆盖(provider/model)。
  • includeReasoning:启用时,同时投递单独的 Reasoning: 消息(与 /reasoning on 格式相同)。
  • lightContext:为 true 时,心跳运行使用轻量级引导上下文,工作区引导文件只保留 HEARTBEAT.md
  • session:心跳运行的可选会话键。
    • main(默认):Agent 主会话。
    • 显式会话键(从 openclaw sessions --json会话 CLI 复制)。
    • 会话键格式:见 SessionsGroups
  • target
    • last:投递到最近使用的外部频道。
    • 显式频道:whatsapp / telegram / discord / googlechat / slack / msteams / signal / imessage
    • none(默认):运行心跳但对外投递。
  • directPolicy:直发/私聊投递行为控制:
    • allow(默认):允许直发/私聊心跳投递。
    • block:抑制直发/私聊投递(reason=dm-blocked)。
  • to:可选的接收者覆盖(频道特定 id,如 WhatsApp 的 E.164 格式或 Telegram chat id)。Telegram 话题/线程用 <chatId>:topic:<messageThreadId>
  • accountId:多账户频道的可选账户 id。target: "last" 时,如果解析出的最近频道支持账户,则使用该账户 id;否则忽略。如果账户 id 与解析出的频道的配置不匹配,投递会被跳过。
  • prompt:覆盖默认提示正文(不做合并)。
  • ackMaxCharsHEARTBEAT_OK 后投递前允许的最大字符数。
  • suppressToolErrorWarnings:为 true 时,心跳运行期间抑制工具错误警告 payload。
  • activeHours:限制心跳运行的时间窗口。对象包含 start(HH:MM,包含;用 00:00 表示一天开始)、end(HH:MM 不包含;允许 24:00 表示一天结束)和可选的 timezone
    • 省略或 "user":使用 agents.defaults.userTimezone(如果设置),否则回退到主机系统时区。
    • "local":始终使用主机系统时区。
    • 任何 IANA 标识符(如 America/New_York):直接使用;无效时回退到上述 "user" 行为。
    • startend 不能相等(相等视为零宽窗口,始终在窗口外)。
    • 活跃窗口外的心跳会被跳过,直到下一个窗口内的 tick。

投递行为

  • 心跳默认在 Agent 的主会话中运行(agent:<id>:<mainKey>),或在 session.scope = "global" 时为 global。设 session 可覆盖到特定的频道会话(Discord/WhatsApp 等)。
  • session 只影响运行上下文;投递由 targetto 控制。
  • 要投递到特定频道/接收者,设 target + totarget: "last" 时,使用该会话的最近外部频道。
  • 心跳投递默认允许直发/私聊目标。设 directPolicy: "block" 可抑制直发目标的发送,同时心跳对话轮次仍然运行。
  • 主队列繁忙时,心跳跳过并稍后重试。
  • 如果 target 解析不到外部目的地,运行仍然进行但不发送出站消息。
  • 仅心跳的回复不会保持会话活跃;上次的 updatedAt 会被恢复,空闲过期行为正常。

可见性控制

默认情况下,HEARTBEAT_OK 确认会被抑制,而告警内容会被投递。你可以按频道或按账户调整:

channels:
  defaults:
    heartbeat:
      showOk: false # 隐藏 HEARTBEAT_OK(默认)
      showAlerts: true # 显示告警消息(默认)
      useIndicator: true # 发出指示器事件(默认)
  telegram:
    heartbeat:
      showOk: true # 在 Telegram 上显示 OK 确认
  whatsapp:
    accounts:
      work:
        heartbeat:
          showAlerts: false # 该账户抑制告警投递

优先级:按账户 → 按频道 → 频道默认值 → 内置默认值。

各标志的作用

  • showOk:模型返回仅 OK 回复时,发送 HEARTBEAT_OK 确认。
  • showAlerts:模型返回非 OK 回复时,发送告警内容。
  • useIndicator:为 UI 状态展示发出指示器事件。

如果三个都为 false,OpenClaw 完全跳过心跳运行(不调用模型)。

按频道 vs 按账户示例

channels:
  defaults:
    heartbeat:
      showOk: false
      showAlerts: true
      useIndicator: true
  slack:
    heartbeat:
      showOk: true # 所有 Slack 账户
    accounts:
      ops:
        heartbeat:
          showAlerts: false # 仅 ops 账户抑制告警
  telegram:
    heartbeat:
      showOk: true

常用模式

目标配置
默认行为(静默 OK,告警开启)(无需配置)
完全静默(无消息,无指示器)channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: false }
仅指示器(无消息)channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: true }
仅在某个频道显示 OKchannels.telegram.heartbeat: { showOk: true }

HEARTBEAT.md(可选)

如果工作区中存在 HEARTBEAT.md 文件,默认提示会告诉 Agent 去读它。把它想成你的”心跳清单”:简短、稳定,适合每 30 分钟加载一次。

如果 HEARTBEAT.md 存在但实际上是空的(只有空行和 markdown 标题如 # Heading),OpenClaw 会跳过心跳运行以节省 API 调用。如果文件不存在,心跳仍然运行,由模型决定做什么。

保持精简(简短清单或提醒),避免提示膨胀。

示例 HEARTBEAT.md

# Heartbeat checklist

- Quick scan: anything urgent in inboxes?
- If it's daytime, do a lightweight check-in if nothing else is pending.
- If a task is blocked, write down _what is missing_ and ask Peter next time.

Agent 能更新 HEARTBEAT.md 吗?

能——如果你让它更新的话。

HEARTBEAT.md 就是 Agent 工作区中的一个普通文件,你可以在普通聊天中告诉 Agent:

  • “更新 HEARTBEAT.md,加一个每日日历检查。”
  • “重写 HEARTBEAT.md,让它更短,聚焦在收件箱跟进。”

如果你想让这件事自动发生,也可以在心跳提示中加一行显式指令:“If the checklist becomes stale, update HEARTBEAT.md with a better one.”

安全提示:不要在 HEARTBEAT.md 中放密钥(API 密钥、电话号码、私有 token)——它会成为提示上下文的一部分。

手动唤醒(按需)

你可以入队一个系统事件并触发即时心跳:

openclaw system event --text "Check for urgent follow-ups" --mode now

如果多个 Agent 配置了 heartbeat,手动唤醒会立即运行每个 Agent 的心跳。

--mode next-heartbeat 等待下一个计划的 tick。

推理投递(可选)

默认情况下,心跳只投递最终”回答” payload。

如果你想要透明度,启用:

  • agents.defaults.heartbeat.includeReasoning: true

启用后,心跳也会投递一条以 Reasoning: 为前缀的单独消息(与 /reasoning on 格式相同)。当 Agent 管理多个会话/代码库时,这对了解它为什么决定联系你很有用——但也可能泄露比你想要的更多内部细节。建议在群聊中保持关闭。

成本意识

心跳运行完整的 Agent 对话轮次。间隔越短,消耗的 token 越多。保持 HEARTBEAT.md 精简,需要时考虑用更便宜的 model 或设 target: "none"(只做内部状态更新)。