首页 › tutorials › 计划任务让Claude Code无人值守

概述

本教程聚焦 Claude Code 在「Agent 模式与自动化」方向上最前沿的一层——让智能体脱离你的双手,自己按时间表跑任务。你将学会三种无人值守编排方式:无头一次性任务(claude -p)、后台异步任务(background)、定时/计划任务(cron + /loop),并掌握三者组合成完整闭环的工程方法。适用人群:已经熟悉交互式 Claude Code、想把它接入 CI、定时巡检、长周期监控或"挂着自动干活"场景的开发者与平台工程师。

前置条件


第一步:理解三种自动化模式的本质区别

很多人把"自动化"混为一谈,但 Claude Code 里至少有三套完全不同的机制,弄混就会踩坑。先用一张表把它们对齐:

模式 触发方式 是否阻塞 生命周期 典型场景
无头 -p 命令行一次性调用 阻塞,跑完即退 进程级,跑完结束 脚本里跑一次、CI 流水线
后台任务 run_in_background 不阻塞,异步 随会话存活 起开发服务器、长测试、长构建
计划任务 cron 表达式 / /loop 到点排队 会话级或持久化 定时巡检、轮询状态、定时日报

关键认知:计划任务不是系统 crontab,它是会话级的。它活在你的 Claude Code 进程里,只有当 REPL 处于空闲(idle)状态时才会触发——你正在打字、它正忙着回答你时,任务会排队等,不会打断你。这一点决定了后面所有的用法设计。

flowchart LR
    A[自动化需求] --> B{触发时机?}
    B -->|跑一次就走| C[无头 -p 模式]
    B -->|现在开始一直跑| D[后台任务 background]
    B -->|按时间表周期触发| E[计划任务 cron/loop]
    C --> F[脚本/CI]
    D --> G[开发服务器/长进程]
    E --> H[巡检/轮询/日报]
    F & G & H --> I[组合闭环]

记住这张图,下一步我们逐个拆解。

第二步:无头 -p 模式做一次性任务

-p(--print)是最底层的自动化入口:加在任何命令后,Claude 就非交互执行,把结果直接打印到 stdout,然后退出。它本质上是把 Claude 当成一个 Unix 管道里的可执行程序。

基础用法:

# 一次性分析,结果直接输出
claude -p "分析当前目录的 package.json,列出过时的依赖"

# 配合管道,把别的内容喂给它
cat error.log | claude -p "总结这个日志里的三类高频错误"

# 拿到结构化输出,方便后续脚本解析
claude -p "列出 src 下所有未处理的 TODO 注释" \
  --output-format json

--output-format stream-json 是自动化场景的杀手锏。它把 Claude 的思考过程、每一次工具调用、最终结果都按行输出成 JSON 事件流,让你的外部脚本能逐条消费、实时响应:

claude -p "修复 lint 错误并提交" \
  --output-format stream-json \
  --verbose \
| jq -r 'select(.type=="tool_use") | .name'

这条管道能实时打印 Claude 用了哪些工具——等价于给智能体装了一个可观测的探针。

预期结果:终端逐行打印 JSON 事件,脚本可解析;普通 -p 则直接打印纯文本结论。

常见问题: - 进程一直挂着不退? 多半是 Claude 在无头运行时启动了后台 bash 任务(比如 npm run dev)。官方明确:claude -p 退出时会清理它启动的后台任务。如果你手动 & 起了进程,需要自己用 disown 或 nohup 托管。 - stream-json 模式偶尔卡住? 这是社区已知的偶发问题(GitHub issue #53584),重试或加 --input-format 通常可绕过。

第三步:后台任务让 Agent 异步干活

后台任务解决的是"这个命令很慢,但我现在还想继续和 Claude 对话"。在工具调用里用 run_in_background: true,命令就被剥离到守护线程执行,主循环立刻返回,Claude 继续思考。

典型场景:

(对话中)
你:跑一下完整测试套件
Claude: [启动] npm test   ← run_in_background,立刻返回任务 ID
Claude: 测试在后台跑着,我先帮你看别的。跑完会通知我。

(你继续问别的问题,几分钟后)
系统: <task-notification> 后台任务完成
Claude: 测试跑完了,3 个失败,我来看……

几个反直觉但关键的点:

  1. 不需要也不应该写 &。直接由 harness 接管为 detached,跨轮次存活。
  2. 任务结束会"回呼"主 Agent。这就是为什么 Claude 知道"测试跑完了"——后台退出时,主循环被重新唤醒,附带退出状态。这意味着后台任务本身就是一种轻量的事件驱动自动化。
  3. 输出落盘。后台任务的 stdout/stderr 会写到文件,之后用对应工具读取那一份即可,避免巨量日志冲爆上下文。

工程上,后台任务最适合"等待外部状态变化"的活——构建、部署、长测试、慢查询。它和计划任务的区别是:后台任务一次性、长时、异步;计划任务周期性、到点触发。

第四步:计划任务 cron 做定时循环

这是本教程的核心。计划任务让你对 Claude 说"每 30 分钟检查一次部署"、"每天早上 9 点生成日报",Claude 在底层用 cron 工具注册任务,到点自动把对应的 prompt 重新喂给自己。

4.1 怎么创建

最自然的方式是直接用自然语言告诉 Claude:

你:每 30 分钟检查一次生产环境的健康指标,有异常就在这个会话里报告。

Claude 会调用 cron 创建工具,生成一个类似 cron: "*/30 * * * *" 的任务。底层工具签名长这样(你通常不用手写,但理解它有助于调试):

// 周期任务
{
  "cron": "*/30 * * * *",     // 每 30 分钟
  "prompt": "检查生产健康指标,异常时报告",
  "recurring": true           // 周期触发
}

// 一次性任务(提醒/一次性巡检)
{
  "cron": "30 14 28 6 *",     // 6 月 28 日 14:30
  "prompt": "提醒我核对季度数据",
  "recurring": false          // 触发一次即自动删除
}

4.2 cron 表达式速查

五段格式 分 时 日 月 周,本地时区,无需换算:

表达式 含义
*/5 * * * * 每 5 分钟
*/30 * * * * 每 30 分钟
0 * * * * 每小时整点
0 9 * * 1-5 工作日早 9 点
30 14 28 6 * 6 月 28 日 14:30(一次性)

4.3 黄金法则:避开整点

这是新手最容易忽略的一条。所有人写"每早 9 点"都会写 0 9 * * *,所有"每小时"都写 0 * * * *——结果全网用户的任务在同一秒砸向 API,形成人为的流量尖峰。正确做法是主动错峰:

❌ cron: "0 9 * * *"      // 每个人都这么写,撞车
✅ cron: "57 8 * * *"     // 早 8:57,效果一样,避开洪峰
✅ cron: "7 * * * *"      // 每小时第 7 分
✅ cron: "*/30 * * * *"   // 周期任务自带 ±10% 抖动,可接受

只有用户明确点名"9:00 整"时才用 0 9。绝大多数"早上左右"的需求,提前几分钟用户根本无感,却能让任务更稳。这条规则同时对你和整个 Claude 用户群都有利。

预期结果:/ 看任务列表(或让 Claude 列出),能看到注册的任务、下次触发时间;到点时(且 REPL 空闲)自动执行 prompt。

第五步:/loop 做动态自调度

cron 表达式适合"固定周期"——每 30 分钟、每天 9 点。但很多自动化的真实节奏是"看情况":CI 还在跑就 1 分钟看一次,跑完了就歇着。这正是 /loop 解决的问题。

/loop 是一个内置技能,支持两种节奏:

动态模式下,Claude 用一个"唤醒"机制在未来的某个时刻把自己叫醒。这里有一个工程上很重要的细节——prompt cache(提示缓存)的 5 分钟 TTL:

所以选唤醒间隔时的心智模型是:

正在轮询一个 ~8 分钟的 CI?
  ❌ 每 60 秒醒一次 → 8 次缓存都热但白白烧掉
  ✅ 每 270 秒醒两次  → 命中缓存窗口,更省
  ✅ 或干脆 1200s 以上 → 一次性付一次缓存失效,但间隔长总量少

❌ 千万别选 300 秒 → 既付了缓存失效的代价,又没摊薄,最差组合

默认无特殊信号时,1200–1800 秒(20–30 分钟)是合理的"心跳"间隔。Claude 会在唤醒时把同一个 loop prompt 再喂进来,形成持续运转。

第六步:durable 持久化 vs session-only 会话级

计划任务有两种存活范围,选错就是"关了电脑任务就没了"的灾难。

判定原则很简单:

要长期、跨天、机器重启后还要继续 → durable: true
只是这次会话里临时跑跑 → 默认 session-only

注意一个安全护栏:周期任务(recurring: true)最多存活 7 天,到点自动跑最后一次然后删除。这是为了防止"设了忘了"的任务无限消耗。所以如果要做一个真正长期的服务,你需要每 7 天内重新续期一次,或用外部系统 crontab 调度 claude -p 来兜底。

第七步:组合模式——完整的无人值守闭环

真正的无人值守不是单一模式,而是三者接力。下面这个闭环是生产级自动化的标准范式:

sequenceDiagram
    participant C as 计划任务(cron)
    participant A as 主Agent(空闲)
    participant B as 后台任务
    participant E as 外部状态(CI/部署)

    C->>A: 到点触发 prompt「巡检」
    A->>E: 读取状态
    alt 一切正常
        A-->>C: 等待下次触发
    else 发现异常(CI失败)
        A->>B: 派发后台修复任务(run_in_background)
        A-->>C: 不阻塞,等下次巡检
        B->>E: 诊断+修复+提交
        E-->>B: 完成
        B-->>A: task-notification 回呼
        A->>E: 验证修复
    end

这个闭环的精髓:

  1. cron 负责"心跳"——周期性、低成本的检查,不阻塞。
  2. 后台任务负责"重活"——一旦发现要处理的活,派到后台异步干,主循环立刻释放。
  3. task-notification 负责"接力"——后台干完回呼主 Agent,自动进入验证环节,无需人工介入。

三者各司其职,整个系统就具备了"自己发现问题、自己修、自己验证"的能力。


实战案例:无人值守的 CI 健康巡检员

我们用前面所有知识点,搭一个真实可用的项目:每 30 分钟自动检查主干 CI 状态,发现失败就派后台 Agent 诊断并提交修复,每天早 9 点(错峰 8:57)生成日报。

1. 注册周期巡检任务(会话内对 Claude 说)

你:帮我设置一个巡检任务,每 30 分钟检查一次 main 分支的 CI 状态。
    如果 CI 是红的(失败),不要自己卡住——派一个后台 Agent 去诊断根因、
    尝试修复并提交一个修复分支,修完回呼你做验证。任务持久化到磁盘,
    机器重启后也要继续。

Claude 会创建一个 durable 的周期任务:

{
  "cron": "*/30 * * * *",
  "prompt": "检查 main 分支 CI 状态。失败则派后台 Agent 诊断+修复+提交,修完回呼验证。正常则静默。",
  "recurring": true,
  "durable": true
}

2. 注册每日日报(一次性/周期,错峰)

你:再加一个,每天早上 8:57 生成一份「过去 24 小时 CI 失败与修复」日报,
    写到 reports/YYYY-MM-DD.md。持久化。
{ "cron": "57 8 * * *", "prompt": "生成过去 24 小时 CI 日报,写入 reports/今天.md", "recurring": true, "durable": true }

3. 巡检 prompt 内部的执行逻辑(Claude 自动遵循)

当 30 分钟到点、REPL 空闲,巡检 prompt 触发,Claude 大致这样跑:

# 第一步:低成本读状态(不阻塞)
gh run list --branch main --limit 1 --json conclusion,name  \
  | jq -r '.[0].conclusion'
Claude(思考):CI 失败了。我直接修会阻塞巡检循环,应该派到后台。
Claude(动作):[Agent 工具, run_in_background: true]
  目标:拉取失败日志 → 定位根因 → 改代码 → 跑本地测试 → 提交 fix/ci-* 分支
Claude(回复):已派发后台修复任务,本轮巡检结束。

后台 Agent 干完后,<task-notification> 回呼主 Agent,主 Agent 自动拉取修复分支、复跑 CI、确认变绿——全程无人工。

4. 用 /loop 处理"修复中"的动态节奏

如果失败修复需要 10 分钟,而你不想干等下一个 30 分钟巡检,可以临时启动一个动态 loop:

你:/loop 等 CI 修复完成,跑完就停。

Claude 会用动态自调度,在缓存窗口内(≤270s)高频检查,一旦 CI 变绿就停止 loop——比固定 cron 灵敏得多,又不浪费。

5. 运维要点


常见问题与排错

Q:任务到点了怎么没触发? A:九成是 REPL 不空闲。计划任务只在 Claude 空闲(等你输入、没在生成)时触发;你正打字或它正忙着时,任务会排队。确保那个会话窗口是开着的、处于空闲态。会话关了,session-only 任务就没了;durable 任务要等下次会话起来才恢复。

Q:durable 任务机器重启后会怎样? A:下次 Claude 启动时,scheduled_tasks.json 里的任务自动恢复。一次性 durable 任务如果在关机期间错过了触发时间,启动时会补跑(catch-up);周期任务直接按下一个 cron 点继续。

Q:后台任务跑飞了怎么停? A:用任务管理工具按 ID 停止(对应"停止运行中的后台任务"),或直接说"停掉刚才那个修复任务"。后台任务的退出码和状态会回呼主 Agent,你能看到结果。

Q:cron 表达式总是撞整点,API 限流怎么办? A:严格遵循第四步的错峰法则——任何"大概几点"的需求都偏移到非 0/30 分。系统本身对周期任务加了抖动,但你自己写一次性/整点任务时不抖动,必须手动错峰。

Q:stream-json 输出太大,外部脚本扛不住? A:用 jq 按事件类型过滤,只消费你关心的(如只取 tool_use 或最终 result),不要全量解析。

Q:想完全脱离 Claude 会话、做 24x7 服务怎么办? A:会话级计划任务做不到真 7×24(要开着窗口)。真正的常驻服务应该用外部系统 crontab 调度 claude -p,把 Claude 当无头一次性进程来编排,再配合持久化的 scheduled_tasks.json 做会话内的细粒度任务。两层结合才是生产级架构。


延伸阅读

训练营适用性评估

参考来源

  1. Run prompts on a schedule — Claude Code Docs — 官方计划任务文档,涵盖 /loop、cron 工具、durable 持久化与 7 天过期机制
  2. Run Claude Code programmatically (Headless) — 官方无头模式文档,-p、--output-format stream-json 与后台任务退出清理行为
  3. Background Claude — Run Claude Code in the background — 后台运行、计划任务与无头模式的工程化实战指南
  4. How the agent loop works — Claude Code Docs — Agent 执行循环原理,理解后台任务回呼机制的基础
  5. Chapter 3: Scheduled Tasks & Automation Loops — Claude Code Handbook — 三种调度方式的对比与组合编排实践

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入