OpenClaw 心跳与自动化调度:Cron、Trigger 与 Heartbeat 的协同机制 原创

温馨提示:
本文最后更新于 2026-09-15,已超过 0 天没有更新。 若文章内的图片失效(无法正常加载),请留言反馈或直接 联系我

引言:自动化不止是”定时跑一下”

用 OpenClaw 一段时间后,很多人会陷入一个误区:自动化 = 写个 cron 定时任务。但真正生产级的自动化调度,从来不是单一路径。你的 Agent 需要”定期巡逻”、需要”准点执行”、还需要”事件一到就响应”——这三种诉求本质不同,用单一机制硬扛,要么空转烧钱,要么错过时机。

OpenClaw 原生提供了三条调度通道:Heartbeat(心跳)Cron(定时任务)Trigger(触发器)。它们不是三选一的替代品,而是可以互相咬合的齿轮。本文用完整的 JSON 配置,把这套协同机制讲透,并给出可直接落地的运维监控实战案例。

(本文面向已有 OpenClaw 使用经验的开发者,假设你熟悉 agent 会话、workspace、config 文件的基础结构。)

一、三种调度机制概览

先给三者一个清晰定位,避免后面混淆。

机制 驱动方式 本质 典型场景
Heartbeat 时间轮询(带自适应) “每隔一段时间醒来看看” 批量巡检、状态汇总、空闲期清扫
Cron 严格时间表 “到点必须做” 日报、备份、准点告警、固定频率任务
Trigger 事件驱动 “当某件事发生就立刻动” 监控进程输出、条件变化、日志关键字命中

一句话记忆:Heartbeat 管”多久一次”,Cron 管”几点几分”,Trigger 管”发生了什么”。三者的调度精度与资源成本也成反比——Heartbeat 最便宜但延迟最高,Trigger 延迟最低但需要常驻监听。

┌────────────────────────────────────────────────────────┐
│                    OpenClaw 调度体系                     │
│                                                        │
│   Heartbeat (轮询)   Cron (定时)     Trigger (事件)      │
│   ┌──────────┐    ┌──────────┐    ┌──────────┐        │
│   │ 醒来→看清单│    │ 到点→执行 │    │ 事件→响应 │        │
│   │ 批量巡检   │    │ 固定动作  │    │ 条件触发  │        │
│   └────┬─────┘    └────┬─────┘    └────┬─────┘        │
│        └───────────────┼───────────────┘              │
│                        ▼                             │
│                 Delivery 投递层                       │
│            announce / webhook / none                 │
│            current / isolated / main                 │
└────────────────────────────────────────────────────────┘

二、Heartbeat:让 Agent”定期醒来”

2.1 定位与轮询间隔

Heartbeat 是最低成本的”巡逻机制”。它由 Gateway 按固定间隔注入一次心跳轮询,Agent 醒来后读取 HEARTBEAT.md(检查清单),决定”这次要不要干活,还是安静跳过”。关键设计点:心跳不是每轮都要消耗推理,它更像一个”唤醒铃”,真正做不做由清单决定。

轮询间隔在配置里用 heartbeatIntervalSeconds 控制:

{
  "heartbeat": {
    "intervalSeconds": 300,
    "checklist": "HEARTBEAT.md",
    "silentOnNoWork": true,
    "model": "volcengine-coding/deepseek-v4-flash"
  }
}

间隔选多少?默认 5 分钟(300s)是一个稳妥起点。想更快响应调小,但要注意 token 消耗会线性上升;想省钱调大,但会牺牲实时性。这个权衡在第七节展开。

2.2 HEARTBEAT.md 检查清单设计

HEARTBEAT.md 是心跳的核心,它决定了”空转”还是”干活”。好的清单应该:短、可判断、可跳过。每一条都是一个”是否需要行动”的布尔判断,而不是一段开放式的任务描述。

# HEARTBEAT.md - 心跳检查清单

## 必须项(每轮检查,命中才动作)
1. 磁盘占用 > 85%? → 触发清理脚本
2. 是否有 pending 的后台子代理/长任务? → 检查状态并汇总
3. MEMORY.md 是否有需要归档的过期条目? → 精简压缩

## 定时项(配合 Cron 做二次确认)
4. 今天是周几?是否到了周备份日? → 交棒给 Cron

## 静默规则
- 以上全部为"否" → 回复 HEARTBEAT_OK,不发送任何消息

2.3 静默规则:不空转、不刷屏

心跳最容易犯的错是”每次都汇报”。设想每 5 分钟收到一条”一切正常”,一天就是 288 条垃圾消息。正确的做法是引入静默(silent)规则:只有清单命中时才说话,否则回 HEARTBEAT_OK。这由 silentOnNoWork 和清单里的判断逻辑共同保证。

真正需要用户看到的,才走投递;不需要的,留在内部。这也是第七节 Delivery 要解决的问题。

2.4 心跳期间可做的主动工作

心跳的空档不是浪费——它是执行批量、低优先级、主动工作的黄金时段:

  • 整理记忆:压缩 MEMORY.md、归档过期日志(文本 > 大脑)
  • 巡检项目:检查 workspace 里的待办、失败的重试任务
  • 健康检查:拉取日志、检查端口、核对配置文件
  • 清扫:删除临时文件、清理废弃子代理会话

这类工作”晚几分钟做也行”,非常适合心跳的低优先级轮询。

三、Cron:到点必须做

3.1 四种 schedule 类型

Cron 是精确调度器,OpenClaw 的 schedule 字段支持四种类型:

类型 语义 示例
at 指定时刻执行一次/重复 每天 03:00 备份
every 固定间隔循环 每 15 分钟检查一次
cron 标准 cron 表达式 0 8 * * 1-5 工作日 8 点
stream 连续流式(常搭配 Trigger) 持续监听进程输出

完整配置示例:

{
  "cron": [
    {
      "name": "daily-backup",
      "schedule": { "type": "cron", "expression": "0 3 * * *" },
      "sessionTarget": "main",
      "delivery": { "mode": "announce", "channel": "webchat" },
      "task": "执行数据库备份并上传到异地存储"
    },
    {
      "name": "every-15m-health",
      "schedule": { "type": "every", "intervalMinutes": 15 },
      "sessionTarget": "isolated",
      "delivery": { "mode": "none" },
      "task": "检查核心服务端口存活,异常才告警"
    }
  ]
}

3.2 sessionTarget:在哪个会话里执行

这是最容易踩坑的地方。sessionTarget 决定 Cron 任务在哪种会话上下文中运行:

  • main:主会话,有完整长期记忆(MEMORY.md),适合需要全局上下文的任务,但会占用主会话、成本更高。
  • isolated:隔离会话,干净上下文,互不污染,适合可独立完成的任务,成本低、并发安全。
  • current:当前活跃会话,适合用户在场时的临时任务。

经验法则:需要记忆的任务用 main,纯粹执行的用 isolated。健康检查这类无状态任务,永远选 isolated。

四、Trigger:事件一到就响应

4.1 stream 模式监控进程输出

Trigger 是三者里唯一的事件驱动机制。stream 调度类型配合 Trigger,可以持续监听某个进程的 stdout/stderr,一旦出现匹配就触发动作。这对”日志告警””错误捕获”类场景是杀手锏。

{
  "trigger": {
    "name": "app-crash-detector",
    "stream": {
      "command": "tail -f /var/log/myapp/error.log",
      "match": "FATAL|CRITICAL|OutOfMemory"
    },
    "once": false,
    "dedupeWindowSeconds": 300,
    "delivery": { "mode": "webhook", "url": "https://alert.example.com/hook" },
    "task": "分析日志上下文,输出根因分析报告"
  }
}

4.2 条件脚本与状态去重

除了文本匹配,Trigger 还支持条件脚本——一个返回布尔值的脚本,返回 true 才触发。这让触发逻辑可以复杂到”不仅仅是匹配关键字”:

#!/bin/bash
# /opt/triggers/disk-full.sh
# 返回 0 触发,1 不触发
THRESHOLD=90
USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
[ "$USAGE" -ge "$THRESHOLD" ] && exit 0 || exit 1

状态去重(dedupe)是关键防抖手段。磁盘告警可能每分钟触发一次,如果没有 dedupeWindowSeconds: 300,5 分钟就能刷出 5 条告警。加个去重窗口,让同一事件在窗口期内只响应一次,配合”恢复时再上报一次”就能形成干净的”故障-恢复”闭环。

4.3 once:一次性触发

"once": true 让 Trigger 只响应第一次命中,之后自动停用。这适合”启动后首次就绪通知””部署完成后的一次性确认”等场景,避免重复投递。

五、三者协同:一个体系三种节奏

真正高效的做法,是让三者各司其职、互相接力:

                    ┌─────────────────────────┐
   Heartbeat(轮询)  │  批量巡检 + 状态汇总     │  ← 低优先级、可跳过
                    └────────────┬────────────┘
                                 │ 发现"该做定时活了"
                                 ▼
                    ┌─────────────────────────┐
   Cron(定时)       │  精确定时 + 固定动作     │  ← 准点、必须做
                    └────────────┬────────────┘
                                 │ 启动后进入长监听
                                 ▼
                    ┌─────────────────────────┐
   Trigger(事件)    │  异常响应 + 事件驱动     │  ← 实时、低延迟
                    └─────────────────────────┘
  • Heartbeat 做批量检查:每 5 分钟醒来,扫一遍状态,发现磁盘告急就把”清理任务”交给 Cron。
  • Cron 做精确定时:凌晨 3 点执行备份,工作日 8 点生成日报,准点无误。
  • Trigger 做事件响应:错误日志一出现 FATAL,立刻触发分析告警,不等下一次轮询。

三者组合,既覆盖了”周期”维度,也覆盖了”时刻”和”事件”维度,几乎没有调度盲区。

六、Pacing:自适应动态节奏

固定间隔的问题在于:系统繁忙时你可能希望检查更勤,空闲时又不想空烧。Pacing 机制解决了这个矛盾——用 min/max 间隔把轮询限定在一个区间,再用 next_check 自适应调整。

{
  "heartbeat": {
    "pacing": {
      "minIntervalSeconds": 60,
      "maxIntervalSeconds": 900,
      "adaptive": true
    }
  }
}

自适应逻辑通常这样设计:

  • 活跃时收紧:检测到 pending 任务、异常状态、用户在线 → next_check 缩短到 min 附近,快速响应。
  • 安静时退避:一切正常、深夜空闲 → next_check 拉长到 max,省 token。

这让心跳从”死板定时器”变成”智能节流器”——资源在真正需要时投入,平时自动休眠。

七、Delivery:结果怎么送达

调度机制负责”什么时候干”,Delivery 负责”结果给谁看、以什么方式”。

7.1 三种模式

模式 行为 适用
announce 主动推送消息到指定渠道 需要人看到的告警、日报
webhook POST 到外部 URL 对接企业微信、钉钉、自建系统
none 只执行,不投递 内部巡检、静默任务
{
  "delivery": {
    "mode": "announce",
    "channel": "webchat",
    "target": "main"
  }
}

7.2 current vs isolated vs main

投递目标同样要选会话:current 投给当前活跃会话(用户在场最合适),isolated 投给独立会话(适合并行、不影响主会话),main 投进主会话(带长期记忆,适合需要上下文沉淀的汇报)。

成本意识:投递到 main 会占用主会话 token 且可能打断对话流;能用 isolated 就别用 main。静默巡检用 none,只在异常时手动升级为 announce,是最省钱的组合。

八、实战案例:一套完整的运维监控体系

把前面所有机制串起来,构建一个”服务器 + 服务 + 安全”的全栈监控体系:

{
  "heartbeat": {
    "intervalSeconds": 300,
    "pacing": { "minIntervalSeconds": 60, "maxIntervalSeconds": 900, "adaptive": true },
    "checklist": "HEARTBEAT.md",
    "silentOnNoWork": true,
    "model": "volcengine-coding/deepseek-v4-flash"
  },
  "cron": [
    {
      "name": "nightly-backup",
      "schedule": { "type": "cron", "expression": "0 3 * * *" },
      "sessionTarget": "isolated",
      "delivery": { "mode": "webhook", "url": "https://alert.example.com/backup-done" },
      "task": "备份 MySQL + WordPress 上传异地,成功/失败各上报一次"
    },
    {
      "name": "weekday-report",
      "schedule": { "type": "cron", "expression": "0 8 * * 1-5" },
      "sessionTarget": "main",
      "delivery": { "mode": "announce", "channel": "webchat" },
      "task": "汇总昨日流量、错误日志、备份状态生成运维日报"
    }
  ],
  "trigger": [
    {
      "name": "fatal-error",
      "stream": { "command": "tail -f /var/log/myapp/error.log", "match": "FATAL|CRITICAL" },
      "once": false,
      "dedupeWindowSeconds": 300,
      "delivery": { "mode": "webhook", "url": "https://alert.example.com/oncall" },
      "task": "抓取日志上下文,分析根因并给出修复建议"
    },
    {
      "name": "disk-full-once",
      "stream": { "command": "/opt/triggers/disk-full.sh" },
      "once": true,
      "delivery": { "mode": "announce", "channel": "webchat" },
      "task": "磁盘超限,执行清理并汇报释放空间"
    }
  ]
}

这个体系的运行逻辑:心跳每 5 分钟(自适应 60-900s)静默巡检,一切正常不打扰任何人;磁盘一旦超限,条件脚本命中触发一次性清理并公告;凌晨 3 点 Cron 备份走 webhook 上报;工作日 8 点日报走 main 会话沉淀到记忆;FATAL 错误由 Trigger 秒级响应直达 oncall。**低成本、高实时、无死角**。

九、成本优化:频率、模型与路由

9.1 心跳频率 vs token 消耗

token 消耗与心跳频率近似线性相关。每 5 分钟一次 = 每天 288 次心跳;每 30 分钟一次 = 48 次。哪怕每次心跳只花几百 token,量级差距也很可观。能用 Pacing 退避到 max 就别钉死在 min。同时,silentOnNoWork 的静默跳过能省掉大量”空转推理”。

9.2 轻量模型跑心跳

心跳这种”判断要不要干活”的低难度任务,完全不必用旗舰模型。给 heartbeat 指定一个轻量、便宜的模型,把贵模型留给真正复杂的 Cron 分析和 Trigger 根因判断:

{
  "heartbeat": { "model": "volcengine-coding/deepseek-v4-flash" },
  "cron":      { "model": "your-heavy-reasoning-model" },
  "trigger":   { "model": "your-heavy-reasoning-model" }
}

9.3 模型路由策略

总结一套实用的路由策略:

  • Heartbeat → 轻量快模型(判断清单、跳过快)。
  • Cron 固定动作 → 中端模型(有明确步骤的执行)。
  • Trigger 根因分析 → 强推理模型(异常场景要深度思考)。
  • Delivery 尽量用 none / 聚合,把多次低频结果合并成一次 announce,减少投递成本。

一句话:把贵模型的每一分钱花在真正需要聪明的地方,routine 巡检交给便宜模型。

十、调度机制选型决策表

场景 推荐机制 配置要点
批量巡检 / 状态汇总 Heartbeat intervalSeconds + HEARTBEAT.md 清单 + silentOnNoWork + 轻量模型
准点备份 / 日报 / 告警 Cron at/every/cron 表达式 + sessionTarget 选 isolated/main + delivery 定渠道
日志关键字命中 / 错误捕获 Trigger (stream) match 正则 + dedupeWindowSeconds 去重 + webhook 直达
复杂条件(磁盘/负载阈值) Trigger (条件脚本) 脚本返回 0/1 + once 一次性 + 恢复时再上报
系统活跃/空闲波动 Heartbeat + Pacing min/max 间隔 + adaptive 自适应 + next_check 动态调整
深夜低成本巡检 Pacing 退避 安静时 next_check 拉长到 max + model 换轻量 + delivery=none
秒级实时响应 Trigger stream 常驻监听 + 不等轮询 + 强推理模型分析
完整运维监控 三者协同 Heartbeat 巡检 + Cron 定时 + Trigger 响应 + 分层 Delivery

结语

Heartbeat、Cron、Trigger 不是竞争关系,而是互补的三根支柱。Heartbeat 负责”常态化巡逻”,Cron 负责”关键节点准点执行”,Trigger 负责”突发事件的即时响应”;再用 Pacing 控制节奏、用 Delivery 决定结果去向、用模型路由控制成本。当你能把这套机制咬合成一个整体,你的 OpenClaw 就不再是一个”定时器”,而是一个真正具备节奏感、实时性且成本可控的自动化中枢。