OpenClaw 心跳与自动化调度:Cron、Trigger 与 Heartbeat 的协同机制 原创
引言:自动化不止是”定时跑一下”
用 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 就不再是一个”定时器”,而是一个真正具备节奏感、实时性且成本可控的自动化中枢。