Cron & HEARTBEAT
从“等你说话”到“主动巡逻”——让 Agent 真正 7×24 运转
1. 从 Cron 到 Heartbeat:自主巡检的范式跃迁
定时任务 vs 心跳巡检:你的 Agent 该怎么“醒”
很多人搭第一个 AI Agent 都会选择日报 Agent:每天定时触发,搜索热门新闻,推送到微信 / 飞书。 看起来很好用,但是这里面有个认知误区……
这个 case 做的是 Cron,不是 Heartbeat Cron ≠ Heartbeat
Cron Task = 定时闹钟:到点就响,无条件执行。 Heartbeat = 自主巡检:醒来先看清单,判断后再决定做什么。 一个是“机械执行”,一个是“带脑子巡逻”。
1.1 Heartbeat 执行流程全景
- 定时触发 every: 30m,固定间隔唤醒。
- activeHours 过滤 非活跃时段直接跳过,省 Token。
- 上下文加载 SOUL.md + MEMORY + Session 完整注入。
- 静默拦截 HEARTBEAT_OK 被 Gateway 丢弃,用户零感知。 暂时无法在飞书文档外展示此内容
1.2 静默机制:HEARTBEAT_OK 的拦截逻辑
核心概念:Agent 回复 HEARTBEAT_OK = “一切正常,不用打扰用户”。
- HEARTBEAT_OK 出现在回复的开头或结尾 → 识别为静默信号。
- 剥离后剩余内容 ≤ 300 字符(ackMaxChars)→ 整条消息被丢弃。
- HEARTBEAT_OK 出现在回复中间 → 不做特殊处理。
- 告警消息:不包含 HEARTBEAT_OK,直接输出告警文本。
- 普通对话中出现 HEARTBEAT_OK → 自动剥离并记录日志。
看个例子: [图片]
1.3 Cron vs Heartbeat:核心区别
Cron Task(定时任务)
触发后:无条件执行预设动作 每次都有输出,可用独立 Session
上下文:隔离执行,无记忆 独立 Session 无对话历史
类比:闹钟,7:00 响就是 7:00 响
Heartbeat(心跳巡检)
触发后:先读检查清单,评估后决策 无事发生时静默(HEARTBEAT_OK)
上下文:携带完整 SOUL + MEMORY 默认在主 Session 中运行
类比:保安巡逻,每半小时转一圈,没事不打扰
两个关键差异:1. “有没有决策能力”,2. “能不能静默”。 Cron 不管三七二十一都会推消息,Heartbeat 没大事汇报就闭嘴。
调试技巧:手动唤醒
问题:心跳默认每 30 分钟触发一次,调试时不可能每次都等半小时。 解决方案:直接在飞书中用自然语言让 Agent 执行巡检。
请立刻执行一次心跳巡检
现在跑一遍你的巡检清单
检查一下 HEARTBEAT.md 里的所有检查项,告诉我结果
注意区别:自然语言触发是对话式执行,Agent 可能在当前对话中回复结果,与真正定时心跳有差异(后者走 Gateway 静默拦截)。调试阶段够用,验证静默行为时需等自然心跳周期触发。
AI check AI:你的 Agent 现在有什么“定时能力”?
在飞书中发送: [图片] [图片]
- Cron 还是 Heartbeat?场景选型与组合策略 五个问题帮你做决定。
选型决策树:五个问题定方案
- Q1-Q2 → Cron 精确时间、需要隔离的任务。
- Q3 → Heartbeat 同频率检查可合并,节省成本。
- Q4-Q5 → Cron 一次性提醒或需指定模型。
- 默认 → Heartbeat 大多数监控类任务最终落到 Heartbeat。 暂时无法在飞书文档外展示此内容
一句话记住:心跳看状态,Cron 干活 Heartbeat 擅长“看” Cron 擅长“做” 收件箱有没有紧急邮件? 每天 7:00 生成晨间简报 日历上 2 小时内有没有会议? 每周五 17:00 生成周报 服务器磁盘是不是快满了? 20 分钟后提醒我开会 共同特征:检查状态 → 判断 → 静默或告警 共同特征:在指定时间执行具体任务
成本差距:5 个 Cron VS 5 个任务 1 个 Heartbeat 5x
Token 成本差距 5 次 方案 A: 5 个 Cron job 每次 5 份 Token 消耗 1 次 方案 B: 1 个 HEARTBEAT.md 每次 1 份 Token 消耗 场景:5 个每 30 分钟检查的监控任务(邮件、日历、磁盘、任务、Git)。
- 方案 A:创建 5 个 Cron Job → 每次触发 5 次 Agent turn → 5 份 Token 消耗。
- 方案 B:写入 1 个 HEARTBEAT.md → 每次触发 1 次 Agent turn → 1 份 Token 消耗。 结论:同频率监控任务,合并到 Heartbeat 比拆成多个 Cron 便宜。
Cron vs Heartbeat 完整对比矩阵 维度 Cron Heartbeat 触发方式 精确时间 / cron 表达式 / –at 固定间隔 Session 通常是独立 Session 默认主 Session 上下文 独立 Session 无对话历史 携带完整 Agent 上下文 静默能力 无(每次都有输出) 有(HEARTBEAT_OK 被拦截) 模型选择 可为每个 Job 指定不同模型 统一使用心跳配置的模型 适用场景 报告生成、数据抓取、定时提醒 状态监控、异常检测、例行巡检 成本特征 每个 Job 独立计费 多项检查合并为一次调用 Cron 灵活但贵,Heartbeat 省钱但粗——根据场景选择。
四种典型组合模式 模式1:纯 Cron 每天 9:00 发周报、20 分钟后提醒开会 时间精确、一次性任务 模式2:纯 Heartbeat 每 30 分钟检查邮件 + 日历 + 服务器 多项监控合并、成本最优 模式3:Cron 干活 + Heartbeat 巡检 Cron 7:00 抓数据写文件 Heartbeat 8:00 检查文件是否生成 模式4:Cron 启动 + Heartbeat 持续监控 Cron 触发一个长任务 Heartbeat 持续检查任务是否完成 适合耗时较长的工作流
社区实践:什么情况下 Heartbeat 不合适?
- “每周一 9:00 发周报”——需要精确时间,用 Cron。
- “17 分钟后提醒我”——一次性提醒,用 Cron –at。
- 重型任务(代码库分析、长文本生成)——会阻塞主 Session。
- 需要用高阶模型(Opus)处理——用 Cron 指定 –model。
- 心跳间隔太短(5 分钟)检查一天只变两次的日历——浪费 Token。
适合 Heartbeat 的信号:同频率、轻量级、需要判断、正常情况应该静默。
- HEARTBEAT.md 设计方法与社区案例 写好心跳清单:社区案例与避坑指南。
HEARTBEAT.md 的定位:心跳清单,不是任务手册 官方定义:小而稳定、每 30 分钟安全注入一次的检查清单。 文件为空(只有标题没有内容)→ OpenClaw 自动跳过心跳,节省 API 调用 文件不存在 → 心跳仍会运行,模型自行决定做什么(不推荐) 核心原则:Keep it Tiny —— 精简才是正义 每次心跳都会把 HEARTBEAT.md 注入 Prompt,内容越长 → Token 消耗越大 官方建议:控制在 200 tokens 以内。社区常见错误就是把清单写成几百行的任务手册。
社区案例 社区案例一:VPS 运维巡检(最简模式) 原始代码
HEARTBEAT.md
- VPS disk: run
df -hand alert if any partition is above 85%. - VPS memory: run
free -hand alert if used is above 90%. - Inbox: scan for urgent emails and draft replies when clearly needed.
- Calendar: check next 2 hours and remind me 15 min before events.
- If nothing needs attention reply HEARTBEAT_OK. 中文翻译
心跳巡检清单
- 磁盘:执行 df -h, 任何分区超过 85% 则告警
- 内存:执行 free -h, 使用率超过 90% 则告警
- 收件箱:扫描紧急邮件, 必要时起草回复
- 日历:检查未来 2 小时日程, 提前 15 分钟提醒
- 以上均无异常, 回复 HEARTBEAT_OK 来源:LumaDock 社区教程。特点:每条一行,阈值明确。关键:最后一行停止条件必须有。
社区案例二:轮转心跳(多任务调度模式) 原始代码
HEARTBEAT.md
Cadence-Based Checks
Read heartbeat-state.json.
Run whichever check is most overdue.
Cadences:
- Email: every 30 min (9AM-9PM)
- Calendar: every 2h (8AM-10PM)
- Tasks: every 30 min (anytime)
- Git: every 24h (anytime)
- System: every 24h (3 AM only)
Process:
- Load timestamps from state file
- Find most overdue check
- Run that check
- Update timestamp
- Report or HEARTBEAT_OK 中文翻译
心跳巡检清单
基于节奏的轮转检查
读取状态文件, 执行最过期的那项检查。
各任务频率:
- 邮件:每 30 分钟(9 点-21 点)
- 日历:每 2 小时(8 点-22 点)
- 任务:每 30 分钟(全天)
- Git:每 24 小时(全天)
- 系统:每 24 小时(仅凌晨 3 点)
执行流程:
- 从状态文件加载上次时间
- 计算哪项最过期
- 执行该项检查
- 更新时间戳
- 有事报告,没事静默 来源:digitalknk。特点:每次只跑最过期一项。适合任务 5+ 的场景。
官方推荐:结构化 tasks: block(自动调度) 原始代码 tasks:
-
name: inbox-triage interval: 30m prompt: “Check for urgent unread emails and flag anything time sensitive.”
-
name: calendar-scan interval: 2h prompt: “Check for upcoming meetings that need prep or follow-up.”
Additional instructions
-
Keep alerts short.
-
If nothing needs attention after all due tasks, reply HEARTBEAT_OK. 中文翻译 任务列表:
-
名称:邮件分诊 间隔:30 分钟 指令:“检查紧急未读邮件,标记时间敏感的内容”
-
名称:日历扫描 间隔:2 小时 指令:“检查即将到来的会议,是否需要准备或跟进”
补充指令
- 告警保持简短
- 所有到期任务均无异常,回复 HEARTBEAT_OK OpenClaw 自动解析 tasks: block,只有到期任务注入心跳 Prompt。 没有任务到期 → 整次心跳被跳过(reason=no-tasks-due)。
openclaw.json 心跳配置项全景 配置项 默认值 说明 every “30m” 心跳间隔,“0m” = 禁用 target “none” 消息投递目标,“last” = 最近联系的渠道 activeHours.start / end 无 活跃时段窗口(本地时区) model 继承默认 心跳专用模型(可用便宜模型降本) lightContext false true = 只加载 HEARTBEAT.md,不加载完整上下文 isolatedSession false true = 每次心跳用独立 Session(省 Token,但无对话历史) directPolicy “allow” DM 投递策略,“block” = 禁止私聊推送 includeReasoning false true = 额外发送推理过程消息 日常三件套:every(多久跑一次)+ target(消息发到哪)+ activeHours(几点到几点活跃)。其余为进阶配置。
检查项编写四步法:条件 → 判断 → 动作 → 静默
- 条件:什么时段执行?(时段窗口)
- 判断:检查什么?判断标准是什么?(明确、可验证)
- 动作:异常时做什么?(具体的告警文本或执行操作)
- 静默:正常时怎么处理?(回复 HEARTBEAT_OK,不多说一个字)
模板示例: 在 HH:MM-HH:MM 时段内执行此项检查 检查 [目标] 是否满足 [条件] 如果不满足:[具体动作] 如果满足:回复 HEARTBEAT_OK
反模式警示:心跳的两种“翻车姿势” “狼来了”模式
症状 每次心跳都推送消息,用户被轰炸后直接忽略
原因 检查项写得太模糊,Agent 总能找到点什么说
修复 判断条件必须可量化(“>85%” 而非“磁盘快满了”) Token 焚烧炉模式
症状 每月 Token 费用暴增
原因 HEARTBEAT.md 写了一整页,注入频率太高
修复 精简清单( < 200 tokens)+ 合理间隔(30-45min)
社区翻车实录:1 分钟心跳的教训 案例来源:Medium 用户 @C.Dalrymple 的 OpenClaw 实战日志。
场景:用户将心跳设为 1 分钟以快速测试 X/Twitter 监控功能。 WhatsApp 消息疑似刷屏,Agent 不断回显 SOUL.md 内容和错误信息。 更严重:Agent 在尝试发帖时,暴露了用户的手机号码。 对话历史被大量心跳消息淹没,正常交互无法进行。
用户总结: OpenClaw 需要明确的指令和防护栏,光告诉它“做什么”不够,还必须告诉它“不做什么” 这正是 SOUL.md Boundaries 层的意义所在
HEARTBEAT.md 四条黄金法则 法则1:精简至上 控制在 200 tokens 以内,每条检查项一两行 清单不是论文 法则2:阈值明确 用可量化的判断条件 “>85%”、“文件不存在”、“缺少标记” 法则3:必须有停止条件 最后一行写明“以上均无异常时,回复 HEARTBEAT_OK” 没有这行 = “狼来了” 法则4:设定时段窗口 每个检查项标注适用时段“08:00-09:00” 避免凌晨 3 点推送“今日日报未生成”
小结
- 心跳清单不是任务手册 检查项四步法:条件 → 判断 → 动作 → 静默。三种写法:自由文本 / 轮转调度 / tasks: block。
- 配置三件套 every + target + activeHours,日常最常用的三个参数。
- 四条黄金法则 精简、阈值明确、有停止条件、设时段窗口——避免“狼来了”和 Token 焚烧炉。
- 实战:Cron + Heartbeat 打造高质量日报 每天早上 7 点,让 Agent 帮你读完全网资讯。
为什么一次抓取不够?
- 单次搜索覆盖面有限,容易遗漏重要信息 质量问题
- 所有逻辑塞在一次执行中,Token 消耗大且不可控 成本问题
- 新方案:拆分为“两轮抓取 + 一次巡检”的组合架构 解决方案
Cron 负责干活(抓数据、写文件),Heartbeat 负责巡检(检查质量、异常告警)
三阶段组合架构总览
- 07:00 第一轮抓取 Cron + 独立 Session,三领域广覆盖。
- 07:30 第二轮补充 读取第一轮结果,定向补充薄弱领域。
- 08:00 心跳巡检 检查日报是否完整,异常才推送。
设计要点:Cron 用独立 Session,Heartbeat 用主 Session。
Step 1:确认当前状态
飞书对话: 帮我检查一下当前的 Heartbeat 配置状态:
- 读取 openclaw.json 中 heartbeat 相关配置
- 读取当前 HEARTBEAT.md 的内容
- 列出 memory/ 目录下现有的文件
- 确认当前的时区设置
确认要点:
- heartbeat 已启用
- every / target / activeHours 三件套配置
- 巡检清单
- 每日记录
- 时区正确
Step 2:注册第一轮 Cron 任务(07:00 三领域抓取) [图片]
Step 3:注册第二轮 Cron 任务(07:30 定向补充) [图片] [图片] Step 4:编写 HEARTBEAT.md 巡检清单 [图片]
对应设计:
- 时段窗口 黄金法则 4:08:00-09:00。
- 明确判断条件 黄金法则 2:文件存在 / 缺失 / 包含标记。
- 三种结果分支 告警 / 提醒 / 静默。
- 停止条件 黄金法则 3。
Step 5:配置心跳参数三件套 [图片] [图片]
Step 6:手动触发验证
第一轮抓取 [图片] 第二轮抓取 [图片] [图片]
Step 7:巡检三种场景 场景 状态 预期结果 场景 A 日报缺失 收到「⚠ 今日资讯日报未生成」 场景 B 日报半完成 收到「资讯日报第二轮采集尚未完成」 场景 C 日报完整 期望静默 [图片] [图片]
注意:对话式触发下如果 Agent 会回复检查结果(如“日报完整,无异常”)——这是正常的。 真正的静默验证:观察 Dashboard 心跳日志,或等下一个自然心跳周期,确认飞书无新消息。
小结
- 组合架构 Cron 负责干活(两轮抓取),Heartbeat 负责巡检(质量检查)。
- 两轮抓取策略 第一轮广覆盖,第二轮定向补充薄弱领域。
- 三分支设计 HEARTBEAT.md 的三分支:完整 → 静默、缺失 → 告警、半完成 → 提醒。
- 总结 知识点 一句话总结 Cron vs Heartbeat Cron = 定时闹钟,Heartbeat = 带脑子的巡逻保安 选型决策树 五个问题定方案:精确时间?隔离?可合并?一次性?特殊模型? 成本口诀 同频率监控合并到 Heartbeat,Token 成本降 5 倍 静默机制 HEARTBEAT_OK 被 Gateway 拦截,用户零打扰 四条黄金法则 精简、阈值明确、有停止条件、设时段窗口 组合架构 Cron 干活 + Heartbeat 巡检 = 高质量自动化 机制 > 规则 规则只是期望,心跳才是执行保障