电脑合上盖,AI 还替你干活吗:定时任务的三层怎么选

想让 AI 每天早上替你干一件事,第一反应是写个 cron。真做起来会发现,Claude Code 给了三层可选:会话里的 /loop、本机的定时任务、云端的 Routines。选错层比 prompt 写坏更疼,因为它决定了你的机器能不能合盖、AI 能不能碰到你本地的文件、错过的那一次要不要补。用"素材在哪、多久一次、谁点确认"三个问题定层,再讲讲本机这一层跑了一个月踩出来的几条规矩:无头进程会死、重试必须幂等、成功失败都得有人知道。


我有几件事想让 AI 定时替我做:每天早上把昨天的笔记翻一遍,挑出能写成文章的;每个月初把几家账单拉下来对一遍;提了 PR 之后盯着 CI,红了就去看日志。第一反应都是一样的:写个 cron,到点拉起一个 Claude 进程。

真做起来才发现,“到点拉起”这四个字底下有三种完全不同的做法。Claude Code 现在给了三层:会话里的 /loop、本机的定时任务、云端的 Routines。它们跑在不同的地方,能碰到的东西不一样,机器合上盖之后的行为也不一样。我在本机这一层跑了一个月的每日任务,中间有几次换层的冲动,最后想明白了一件事:选错层比 prompt 写坏更疼。prompt 写坏改一行就好,层选错了要重搭。

三层各是什么

先把三层摆平了看。

会话内的 /loop。你开着一个 Claude Code 会话,敲 /loop 5m 看看 CI 过了没,它就每五分钟替你看一次。它跑在你这台机器上、这个会话里,继承会话的一切:当前目录、已经连上的 MCP、你给过的权限。最短一分钟一次。代价是会话一关它就停,而且再长的循环七天也会自动到期,防的是你忘了它还在跑。

本机定时任务。分两种做法。一种是 Claude Code 桌面版自带的本地定时任务,在应用里建一条,到点起一个新会话,跑完在侧栏里能看回放。另一种是自己动手:macOS 用 launchd,Linux 用 cron,到点执行 claude -p "……" 这种无头模式。两种做法的共同点是都跑在你的机器上,所以它能碰到你本地的任何东西:文件、字体、只在本机配过的工具。共同的代价也一样:机器得醒着。

云端的 Routines。这是今年四月出的,跑在 Anthropic 管理的云上。你在网页或者用 /schedule 命令建一条,指定 prompt、要用的 GitHub 仓库、要接的连接器。每次运行是一个全新的云端会话,把仓库 clone 一份,跑完把改动推到 claude/ 前缀的分支。它不需要你的机器开着,最短一小时一次。触发方式除了定时,还有两种:一个 HTTP 接口可以让你的告警系统直接调它,GitHub 事件比如 PR 打开也能触发它。

三层的关系不是谁比谁高级,而是各管一段。文档里那张对比表我看了很多遍,最后浓缩成三个问题。

第一个问题:素材在哪

这是决定性的一问。

如果这件事要用到的东西在你本机,比如一个不在 GitHub 上的笔记目录、一套只装在本机的字体、一个走本机代理才能访问的服务,那只能选本机这一层。云端的 Routines 每次是 fresh clone,它看得见仓库,看不见你的硬盘。我那个每日任务就卡在这里:素材是本机的知识库和一堆本机才有的渲染工具,所以它只能跑在本机。

反过来,如果这件事的输入全在 GitHub 仓库里,输出是一个 PR,中间要碰的外部系统都有连接器,那云端是更省心的选择。机器合盖、出差、断网都不影响它。文档里举的几个例子全是这个形状:每周扫一遍合并的 PR 找过期的文档、每晚给 issue 打标签、PR 一打开就按你的清单做一遍审查。

如果这件事只跟当前这个会话有关,比如等一次构建、盯一个 PR 的评论,那 /loop 就够了,不值得为它建一条持久的任务。

三个问题定一层:素材在本机就只能本机跑,全在 GitHub 上云端更省心,只跟这个会话有关就用 /loop

第二个问题:机器睡着了怎么办

这个问题平时想不到,出事了才想到。三层的答案完全不同。

/loop 最简单:机器睡了、会话关了,它就不跑了,醒来也不补。它本来就是给”我在场”的场景设计的。

本机定时任务分两种情况。桌面版的本地任务,如果睡过了点,机器醒来时它会补跑一次,只补最近错过的那次,再往前的丢掉。文档特意提醒了一句:一个定在早上九点的任务,可能在晚上十一点才跑,所以 prompt 里最好写上”如果已经过了下午五点,只汇报错过了什么”这种护栏。自己用 launchd 拉的任务行为类似,睡眠期间错过的点会在唤醒后跑一次,多个错过的点合并成一次;但关机期间错过的不补。

云端 Routines 不受你机器的影响。它有自己的问题:每次运行可能比定的时间晚几分钟,这是有意的错峰。

同一个早上九点,机器十点才醒:/loop 干脆不跑,本机任务醒来补一次,云端照常九点跑完

第三个问题:谁点确认

/loop 继承会话的权限设置,你给过的它就有。桌面版的本地任务每条可以单独设权限模式,如果它跑到一半要一个没给过的权限,会停在那里等你点,会话留在侧栏里,你什么时候回来什么时候点。这是一种设计:它宁可停,也不替你做主。

云端 Routines 没有这个选项。它是全自动的,没有权限提示,你在建的时候勾了哪些连接器,它运行时就能用那些连接器的所有工具,包括写操作。而且它做的所有事都以你的身份出现:提交、PR、Slack 消息,署名都是你。所以文档反复强调一句话:把仓库、网络、连接器都缩到这条任务真正需要的范围。默认它会把你账号上所有连接器都勾上,建的时候要手动去掉用不着的。

自己用 claude -p 拉的任务,要跑起来通常得加跳过权限的参数,这一步等于把权限模式定成了”全给”。

本机这一层的几条规矩

三层里我用得最重的是本机这一层,跑了一个月,踩出来几条规矩。它们不限于 Claude,任何”没人盯着的 AI 任务”都用得上。

无头进程会死,入口脚本要带重试claude -p 起来的进程是靠网络活着的,网络抖一下、接口超时一下,它就退出了。我另一条任务早期就这么”假死”过几次:日志里只有一行 start,没有 end,下午才发现。后来入口脚本改成失败等两分钟再来,最多三次,退出码非零就算失败。

重试必须幂等。加了重试立刻遇到新问题:如果第一次是在做完主要工作之后、发通知之前死的,第二次会不会把主要工作再做一遍?比如文章发两篇、账单入两次。解法是每次启动先问”今天做过了吗”:查一个带日期的记号,比如输出目录里有没有今天日期开头的文件。有,就跳过主步骤,只做剩下的收尾。这样重试永远是安全的,最坏情况是收尾做了两遍。

一个任务的三次启动:第一次死在半路,第二次先问"做过了吗"再接着做,第三次误触发直接退出

成功失败都要有人知道。定时任务最怕的不是失败,是悄悄失败两周没人发现。我的做法是跑完发一封邮件:做了什么、哪一步是人工要接手的、还剩多少积压。失败也发,主题前面带个失败标记,正文写清卡在哪一步。云端 Routines 在这一点上有个坑,文档专门标了出来:运行列表里的绿色状态只代表”会话正常启动正常退出”,不代表你 prompt 里的任务成功了。网络被拦、连接器缺工具、任务本身没做完,都得点进去看记录才知道。

发布前要有一道不讲情面的闸。AI 自己审自己不够。凡是会对外产生影响的步骤,比如发布、推送、发消息,前面放一个确定性的检查:构建通过没有、断言过没有。检查不过就不往下走,而且这道闸是脚本写死的,不是 prompt 里的一句叮嘱。叮嘱会被遗忘,脚本不会。

云端那一层的两个反直觉

如果你选了 Routines,有两件事和直觉相反。

一是本机用 claude mcp add 加的 MCP 服务器不会自动带上云。它们存在你机器上,不在你的账号里,Routines 看不见。要么去账号里把它加成连接器,要么把 .mcp.json 提交进仓库让它随 clone 一起过去。

二是通过 HTTP 接口触发时附带的文本,比如一条告警的内容,到了 AI 那边是被包在一个”不可信数据”的标记里的。AI 不会直接把它当指令执行,除非你保存的 prompt 里明确写了”去处理这段文本里描述的告警”。这是防拿到 token 的人往里塞指令,但第一次用会觉得它”没反应”。

收尾

回头看这一个月,我对”定时让 AI 干活”这件事的理解变了。一开始以为难点在 prompt,后来发现 prompt 是最容易改的部分。真正的决定在更前面:这件事的素材在哪,机器睡着了它该怎么办,出了事谁来点确认。这三个问题答完,层就定了;层定了,剩下的都是老问题:重试、幂等、通知、发布前的闸。

这些老问题二十年前就有答案。只不过以前约束的是脚本,现在约束的是一个会自己做决定的东西。

评论