跳转至

AUTOMATION PATTERN

Cron 任务设计模式

Maturity
L2
Complexity
medium
Reliability
high
Hermes
cron
Version
v1.1.1

When to Use

  • Recurring autonomous jobs
  • Jobs that must never double-fire
  • Jobs needing delivery guarantees

When NOT to Use

  • One-off tasks
  • Jobs needing interactive input
Skill Contract(本模式的模块声明)

版本 v1.1.1 | 分类 conventions | 相关 state-file-pattern · evolution-gate · error-compact-pattern · control-flow-separation

对应 12-Factor Agents Factor 6: Lifecycle APIs 对应 Loop Engineering Step 5: Automations

核心原则

Cron 任务的核心风险不是「跑崩了」,而是「跑偏了但没人发现」

该不该自动化:频率×可逆性遴选(2026-09-07,借鉴 polydao)

不是所有任务都值得做成 cron。先用三条门槛筛,再谈怎么设计。

一个任务值得做成定时自动化的唯一标准:频率高 × 可逆性好

判据 合格线 解释
频率 至少每周重复 跑得够多才能看出模式、积累纠正;一月跑一次的任务看不出规律,自动化不划算
可验证 结果一分钟内能确认 输出必须有快、便宜的校验路径(读一眼、脚本断言、与 ground truth 对比),否则「准不准」永远悬着
可逆 错了成本≈0、可撤销 错了能回滚/丢弃/重跑,不产生不可逆副作用;「错了白花钱」是昂贵教训不是学费

反例:发消息 / 支付 / 发布 / 发邮件这类「一旦发出不可撤回」的动作,三条门槛没过前不配进自动化。这类任务要等成熟后,由确定性 gate 包住再上。

合格示例:竞品跟踪、changelog 监控、线索补全、来源筛选、行情监控、财报抓取。不合格示例(现阶段):自动发推、自动下单、自动发布文章。

判断口诀:频率低→不做;验证不了→不做;不可逆→不做。三条都过才配谈三段式与幂等。 本文剩下的三段式、幂等、防静默失败都是「确定要自动化之后」的工程,这条准则是「要不要自动化」的入口。

三段式结构

每个 Cron 任务遵循三段式:

Pre-flight(起飞前检查) → Execute(执行) → Post-flight(落地报告)

Pre-flight

1. 读取 STATE.md,检查上次运行状态
2. 检查 Idempotency Keys,跳过已处理的批次
3. 检查资源可用性(磁盘/网络/API Key)
4. 如果任何检查失败 → 记录到 STATE.md → 跳过本次运行

Execute

1. 锁定状态(STATE.md status → running)
2. 按步骤执行,每步更新进度
3. 使用确定性代码处理已知路径,LLM 只在决策点介入
4. 失败时按 error-compact-pattern 压缩后写入上下文

Post-flight

1. 更新 STATE.md(status → idle,记录统计)
2. 生成运行报告(成功/失败/跳过)
3. 如果失败率超过阈值 → 通知人类
4. 如果连续失败 N 次 → 自动暂停 Cron

幂等性保障

场景 问题 解法
任务重复触发 同一批数据跑了两遍 Idempotency Keys
部分成功 跑了 50%,下次从哪开始? STATE.md 进度记录
静默失败 报错了但没人看见 失败率阈值+告警
跑偏 输出了错误结果但没报错 Maker/Checker 验证

Idempotency Key 实现

def generate_key(task_id: str, batch: str, date: str) -> str:
    return f"{task_id}/{batch}/{date}"

def should_skip(key: str, state: dict) -> bool:
    return key in state.get("idempotency_keys", [])

防静默失败

核心思路:大声失败比沉默通过好一万倍。

防护层 机制 触发条件
L1 日志记录 任何错误
L2 失败率告警 单次运行失败率 > 20%
L3 自动暂停 连续 3 次运行失败
L4 人类通知 L3 触发后推送到 IM

Hermes 原生 Monitor 模式(2026-08)

上面的三段式是"agent 自查";Hermes 现在提供原生监控模式,从运行时层面解决"跑偏没人发现"——不需要 agent 每 tick 自查,大部分 tick 根本不烧 token。

monitor_script / monitor_url(变化检测)

每个 tick:
  1. 先运行 monitor 脚本(或抓取 URL),对输出做哈希
  2. 哈希与上次相同 → 跳过 agent 运行(0 token,静默 tick)
  3. 哈希变化 → 把 unified diff + 新输出注入 agent prompt,跑一轮 agent
  4. 首个 tick 总是跑 agent(建立基线)
  • 适用:监控网页变化、文件变化、价格/行情变化、外部 API 状态、CI 状态
  • 与三段式的关系:monitor 是 Pre-flight 的自动化升级(变化检测交给运行时),agent 只在变化时执行 Execute
  • 脚本要求:输出必须稳定(无时间戳/随机顺序),否则每 tick 都"看起来变了"

no_agent=True(Watchdog 模式)

脚本即任务:stdout 非空 → 原样投递;stdout 空 → 静默(什么都不发)。适合纯告警/看门狗(磁盘水位、进程存活、API 配额、日志关键词),零 token

链式与上下文(context_from / script / workdir)

能力 用法 场景
context_from=[jobB] job A 最新输出注入 job B 的 prompt 数据流水线(A 采集 → B 处理)
script(agent 模式) 脚本 stdout 注入 prompt 当上下文 数据收集
enabled_toolsets 限制 job 工具集 降 token:只读监控 job 只给 web 工具
attach_to_session 用户可回复该 job 投递并续上下文 交互式任务
workdir 指定目录运行 + 注入 AGENTS.md/CLAUDE.md 项目内 job

选择矩阵

场景 推荐
网页/文件/行情变化检测 monitor_script / monitor_url
纯脚本告警/看门狗 no_agent=True
数据流水线(A→B) context_from 链式
定期内容生成 三段式 + enabled_toolsets
交互式/可追问任务 attach_to_session
项目内定时维护 workdir + 三段式

与成熟度分级配合

级别 Cron 行为
L1 只跑报告,不写外部。失败只记日志不告警
L2 跑报告+草稿,失败推送摘要到 IM
L3 全自动执行,失败自动暂停+通知

模板

# Cron Job: {job-name}

## 调度
- 频率: {cron 表达式}
- 超时: {最大运行时间}
- 重试: {次数和策略}

## 步骤
1. {步骤 1: 描述}
2. {步骤 2: 描述}

## 失败处理
- 可重试: {错误类型}
- 不可重试: {错误类型}
- 人类通知: {通知方式}

## 状态文件
- 路径: reports/{job-name}/STATE.md

真实案例:每日新闻摘要 Cron

以下数据来自 Hermes Agent 7×24 运行环境,已脱敏。

接入前(裸 Cron)

问题:每天 8:30 跑新闻摘要,一周内出现 2 次静默失败(Agent 输出空内容但标记成功)、1 次重复投递(同一内容发了两次)。
根因:无幂等键 → 重跑时不知道哪些批次已处理;无 Post-flight 验证 → 空输出也当成功。

接入后(cron-job-pattern 三段式 + STATE.md)

## STATE.md 快照(运行第 21 天)

### Current Run
- **Last run**: 2026-08-28T08:30:00+08:00
- **Status**: idle
- **Current batch**: 2026-08-28

### Idempotency Keys
- 2026-08-28: news-digest: dispatched ✓
- 2026-08-27: news-digest: dispatched ✓
- 2026-08-26: news-digest: skipped (duplicate trigger, 8:30:02 second fire)

量化结果

指标 接入前(1 周) 接入后(3 周)
静默失败 2 次 0 次
重复投递 1 次 0 次(幂等键拦截)
人工介入 3 次 0 次
Token 浪费(空跑/重复) ~40k ~0

关键改进:幂等键拦截了 8:30:02 的重复触发(Hermes cron 调度偶尔在同分钟内触发两次),Post-flight 验证在 8/22 捕获了一次空输出并自动重试成功。