技能默认是「你喊它才动」。但很多活的本质是按时发生——每天爬一次数据、每小时跑一次健康检查、每周一发周报。这时候你要的不是「手动触发」,是触发器(Trigger)和定时(Schedule)。
OpenClaw 里这套能力通常落在「自动化(Automation)」机制上:你定义一个任务(prompt/指令)、一个时间规则,它在到点时自己醒来、自己跑、自己收尾。这套机制用熟了,你就是把一堆重复劳动交给时钟,自己只管看结果。
一、两种触发形态
1.1 定时触发( ScheduleType = once / recurring )
- once:只跑一次,在某个具体时刻(
scheduledAt)。适合「明早 9 点发一条提醒」这种一次性任务。 - recurring:按周期反复跑,用调度表达式描述「多久一次、在哪天哪点」。适合日报、巡检、清理。
1.2 条件触发
不是按钟点,而是「某件事发生了就跑」。比如监听文件变化、监听外部事件、监听某个状态达到阈值。这类实现细节因版本而异,具体事件源与配置方式以官方文档当前版本为准。但思路一致:把「判断条件」从你的脑子里搬到系统里,到点或到条件自动执行。
经验法则:能定时的别用条件(定时可预期、好排查、好复盘);定不了时的才用条件(比如「上游一产出就处理」「错误率超 5% 就报警」)。凡是能用时间描述的,优先用时间,因为时间是最容易被人类理解和验证的维度。
二、周期任务怎么配
recurring 任务的核心是调度表达式。OpenClaw 这类系统常用 RRULE(RFC 5545 标准) 描述重复规则。下面用真实可读的例子讲清楚它怎么读、怎么写、有哪些坑。
RRULE 由若干 KEY=VALUE 用 ; 拼成,最关键的几个:
| 字段 | 含义 | 举例 |
|---|---|---|
FREQ | 重复基本单位 | DAILY / HOURLY / WEEKLY / MONTHLY / YEARLY |
INTERVAL | 间隔倍数 | INTERVAL=2 表示「每 2 个 FREQ」 |
BYDAY | 限定星期几 | MO,WE,FR(周一周三周五) |
BYHOUR | 限定小时 | BYHOUR=9 |
BYMINUTE | 限定分钟 | BYMINUTE=0 |
BYMONTHDAY | 限定月内几号 | BYMONTHDAY=1,15 |
BYMONTH | 限定月份 | BYMONTH=1,6,12 |
几个能直接抄的模板
# 每 2 小时跑一次(不分工作日)
FREQ=HOURLY;INTERVAL=2
# 每个工作日的 09:00 跑(周一到周五)
FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;BYHOUR=9;BYMINUTE=0
# 每周一、三、五的 09:00 跑
FREQ=WEEKLY;BYDAY=MO,WE,FR;BYHOUR=9;BYMINUTE=0
# 每月 1 号、15 号、28 号的 09:00 跑
FREQ=MONTHLY;BYMONTHDAY=1,15,28;BYHOUR=9;BYMINUTE=0
# 每年 1 月、6 月、12 月 1 号的 09:00 跑
FREQ=YEARLY;BYMONTH=1,6,12;BYMONTHDAY=1;BYHOUR=9;BYMINUTE=0
读法口诀:先看
FREQ定节奏,再看INTERVAL定倍率,最后看BY*系列把「具体时刻」钉死。缺了BYHOUR/BYMINUTE的周期规则,系统往往不知道在当天的哪一分钟醒,配置会直接被判不合法——所以日/周/月/年级别的周期,小时和分钟必须给。
RRULE 还能表达「边界」
标准 RRULE 还支持 COUNT(总共跑几次就停)、UNTIL(跑到哪个绝对时刻止)、EXDATE(排除某些具体日期)。比如「工作日 9 点跑,但国庆那几天别跑」,就可以在规则外配合排除日期来实现。具体是否支持这些修饰符,以官方文档当前版本为准,但思路是通用的:周期描述「常态」,排除描述「例外」。
三、一次性和周期的配置对照
| 维度 | once | recurring |
|---|---|---|
| 必填 | scheduledAt(具体时刻) | rrule(周期表达式) |
| 适用 | 提醒、单次批处理 | 日报、巡检、清理 |
| 失效后 | 跑完即结束 | 下一周期自动再来 |
| 排查重点 | 时刻是否过期 | 表达式是否合法、时区 |
配置时通常还要给任务一个 name(方便识别)和 prompt(到点执行的具体指令),以及 status(ACTIVE 才真正生效,PAUSED 是暂停)。指令写清楚「醒来后要做什么、产出放哪」,不然它醒了也不知道干啥。
四、生效范围与生命周期
周期任务可以限定生效区间:从 validFrom 开始,到 validUntil 结束。比如「双十一期间每天巡检」,就把区间钉在活动周期内,活动一结束自动停,不用你手动关。这对「阶段性任务」极其省心——你设定一次,系统帮你收尾。
另外,自动化可以绑定工作目录(cwds)——它决定任务醒来时在哪个目录里干活。如果你的技能要读写特定项目的文件,这个目录必须配对,否则跑出来的是空结果或者找不到文件。很多「定时任务跑了但啥也没干」的案子,根因就是 cwds 指错了地方。
五、常见场景清单
- 监控巡检:每小时跑一次健康检查,异常才通知,正常静默。
- 数据备份:每天凌晨把关键目录打包落盘。
- 周期报告:每周一 9 点汇总上周数据出周报。
- 临时提醒:明早 8 点提醒开会(once)。
- 清理任务:每月 1 号清理临时目录过期文件。
这些场景的共同点是「我懒得记、也不该记」。凡是你发现自己每周手动重复同一件事,就该写成一个 recurring 自动化。
这里最容易忽略的一步,是想清楚产出去哪、谁来消费。很多人配定时任务只想着「让它跑」,却没想「它跑完的东西给谁」。结果任务确实每天醒了、确实干了活,但报告躺在一个没人看的目录里,等于白跑。配之前先回答三个问题:产出文件放哪个确定路径?下游是另一个技能自动读,还是人手动收?失败时谁会被通知?把这三个答案写进任务的 prompt,定时任务才真正闭环,而不是只完成「跑」这一个动作。
六、定时任务失效排查
定时任务「没按时醒」是高频投诉。按这个顺序查:
- 状态是不是 ACTIVE:
PAUSED的任务再怎么配也不会跑。先确认开关。 - 时区对不对:你以为是北京时间 9 点,系统是 UTC 9 点,差 8 小时。周期任务尤其要核对时区配置——这是排第一的坑。
- RRULE 是否合法:缺
BYHOUR/BYMINUTE的日级规则、拼错的FREQ值,都会被直接拒。先用上面模板对照。 - scheduledAt 是否已过:once 任务如果设定的时刻已经过去,自然不会再触发。
- 工作目录是否存在:绑定的 cwds 指向的目录要是没了,任务醒了也干不了活。
- 进程/服务在不在:调度依赖后台服务常驻。服务没起来,再对的规则也白搭。具体服务名与管理方式以官方文档当前版本为准。
| 现象 | 优先怀疑 | 第一步动作 |
|---|---|---|
| 一次都没跑 | 状态 PAUSED / 时刻过期 | 查 status 与 scheduledAt |
| 每天错 8 小时 | 时区 | 对照本地时区配置 |
| 配置报错 | RRULE 非法 | 用模板逐一比对字段 |
| 跑了但没产物 | cwds 错 | 核对工作目录路径 |
| 跑一段时间后停 | validUntil 到了 | 查生效区间 |
七、一个排错走查
现象:我配了「每个工作日 9 点出日报」,结果连续三天没收到。走查:
- 查 status:是 ACTIVE,没暂停。
- 查时区:系统默认 UTC,我按北京时间 9 点写的
BYHOUR=9,实际是北京时间 17 点才跑,而我 17 点已经下班没注意 → 改成对应 UTC 的小时,或显式设时区。 - 查 cwds:指向的目录存在,没问题。
- 修正时区后第二天准时收到。
你看,绝大多数「没按时醒」都不是调度引擎坏了,是时区或字段的小错位。把 RRULE 读熟、时区钉死、工作目录配对,剩下的交给时钟。
八、RRULE 实战换算练习
光看模板不够,动手算几个,把读法变成肌肉记忆:
FREQ=DAILY;BYHOUR=23;BYMINUTE=30→ 每天 23:30 跑一次。注意 DAILY 必须给小时分钟,否则不合法。FREQ=WEEKLY;INTERVAL=2;BYDAY=SU;BYHOUR=3;BYMINUTE=0→ 每两周的周日 03:00 跑(双周任务)。FREQ=MONTHLY;BYMONTHDAY=-1;BYHOUR=20;BYMINUTE=0→ 每月最后一天 20:00 跑(负数表示从月末倒数,具体是否支持以官方为准)。FREQ=HOURLY;INTERVAL=6;BYDAY=MO,TU,WE,TH,FR→ 工作时间内每 6 小时跑一次,周末不跑。
练到「看到表达式能在三秒内说出『哪天几点、隔多久』」,你才算真会读 RRULE。排错时这一步能省大量来回。
九、条件触发深入:事件源长什么样
条件触发虽然具体实现随版本变化,但事件源通常有几种形态值得提前想清楚:文件系统事件(某目录出现新文件就处理)、Webhook/外部推送(别人调你一个接口就触发)、内部状态事件(错误率超阈值就报警)。选哪种,取决于「谁先知道该跑了」:如果是外部先知道,用 Webhook;如果是你自己巡检发现,用定时 + 条件判断更稳。别为了用条件而用条件——很多「条件触发」其实用「定时轮询 + 判断」就能优雅实现,还更好排查。
这里有个权衡:条件触发胜在「实时」,但实时意味着你要一直盯着事件源、要处理事件丢失和重复投递;定时轮询胜在「简单可靠」,代价是有一点延迟。对绝大多数内部场景,那几分钟的延迟根本无伤大雅,而少维护一套事件管道省下的心力是实打实的。除非业务真的对延迟零容忍,否则我默认选轮询。
十、定时与钩子、子代理的组合
这三样不是孤立的:一个 recurring 定时任务(第 03 篇)到点醒来,内部可以派子代理并行干活(第 04 篇),干完在 Stop 钩子(第 02 篇)里自动发通知。这就是「组合技」的雏形——时间负责唤醒,子代理负责分摊,钩子负责收尾。理解每一块单独的语义,组合时才不会互相踩。比如定时任务的 cwds 配错,子代理即便派得再对也读不到文件;Stop 钩子若返回非零,整个定时任务会被判失败。组合越深,越要回到「分层排查」的基本功。
十一、新手配定时最易犯的三种错
结合上面所有内容,把最高频的三个坑单独拎出来强调,因为它们占了定时任务工单的绝大部分:
第一种,以为「配了就一定会跑」。实际上 status 是 PAUSED、或 scheduledAt 已经过期、或后台调度服务没起,任何一个条件不满足都不会醒。配完第一件事不是放手,是手动触发一次验证它真能跑。
第二种,时区想当然。人在国内,系统默认 UTC,于是「每天 9 点」实际是下午 5 点。这种错最隐蔽,因为任务确实在跑,只是不在你以为的时间。配完务必核对时区,最好显式声明。
第三种,把指令写得太含糊。prompt 只写「做日报」,技能不知道日报长啥样、放哪、发给谁,醒来也只能干瞪眼。定时任务的指令比手动对话更要写死细节,因为它没有你坐在旁边临场补充。
十二、验证清单:上线前过一遍
- 状态是
ACTIVE吗? - 时区对吗?
BYHOUR/BYMINUTE给了吗? cwds指向的目录存在且可读写吗?- 指令里写清了产出位置和格式吗?
- 手动触发一次,确认真跑出结果了吗?
五条全过,再放手让它自己跑。
定时任务的魅力在于把「记得做」变成「系统做」。写好 RRULE、配对时区和工作目录,剩下的交给时钟——你只需要在它第一次没醒时,按上表把脉。等它稳定跑上一个月,你会惊讶于自己省下了多少本该用来「记得做」的脑容量。
