背景

当 AI 助手声称"会提醒你"时,程序员的第一反应通常是:这东西靠谱吗?

本文基于使用 Hermes Agent 设置剧集提醒的实际经历,深入解析其 Cron 调度系统的技术实现、可靠性边界及适用场景。

需求场景: 追踪剧集更新,共 8 集,每周固定时间发布。

要求:

  • 官方发布后延迟提醒(等资源上线)
  • 每周固定时间推送
  • 通过 Telegram 接收通知

技术挑战:

  • 跨月度持续运行
  • 处理系统重启/崩溃恢复
  • 分钟级时间精度

架构概览

核心组件

┌─────────────────────────────────────────────────────────────┐
│                    Hermes Agent System                       │
│                                                              │
│  ┌──────────────┐    ┌──────────────┐    ┌─────────────┐  │
│  │   Cron Tool  │───▶│  Scheduler   │───▶│   Runner    │  │
│  │  (API 接口)  │    │  (定时检查)   │    │ (隔离执行)  │  │
│  └──────────────┘    └──────────────┘    └─────────────┘  │
│                                                              │
│  Storage: ~/.hermes/cron/jobs.json                          │
│  Output: ~/.hermes/cron/output/{job_id}/{timestamp}.md      │
└─────────────────────────────────────────────────────────────┘

Hermes 采用 Gateway Scheduler 模式,与消息平台深度集成,支持多平台投递。


存储机制详解

1. 任务持久化

文件位置: ~/.hermes/cron/jobs.json

关键特性: 原子写入 (Atomic Write)

def atomic_write(filepath, data):
    """确保写入操作要么完全成功,要么完全不写入"""
    fd, temp_path = tempfile.mkstemp(
        dir=os.path.dirname(filepath), suffix='.tmp'
    )
    try:
        with os.fdopen(fd, 'w') as f:
            json.dump(data, f)
            f.flush()
            os.fsync(f.fileno())  # 强制同步到磁盘
        os.rename(temp_path, filepath)  # 原子替换
    except Exception:
        os.unlink(temp_path)
        raise

保证: 即使系统崩溃,也不会出现半写文件或 JSON 损坏。

2. 实际任务数据结构

{
  "id": "e804371d723e",
  "name": "剧集提醒 S5E1-E2",
  "prompt": "提醒:新一集已发布...",
  "schedule": {
    "kind": "cron",
    "expr": "0 8 9 4 *"
  },
  "repeat": { "times": null, "completed": 0 },
  "enabled": true,
  "state": "scheduled",
  "next_run_at": "2026-04-09T08:00:00+08:00",
  "deliver": "telegram"
}

关键字段解析:

  • schedule.expr: 标准 Cron 表达式
  • state: 当前状态(scheduled/running/paused)
  • repeat.times: null: 无限重复
  • deliver: 投递目标

调度系统实现

Cron 表达式

示例:0 8 9 4 *

│ │ │ │ │
│ │ │ │ └─── 星期 (0-7, * = 每天)
│ │ │ └───── 月份 (1-12)
│ │ └─────── 日期 (1-31)
│ └───────── 小时 (0-23)
└─────────── 分钟 (0-59)

调度精度

格式精度适用场景
相对延迟 30m分钟级一次性任务
间隔 every 2h分钟级周期性检查
Cron 0 8 * * *分钟级定时提醒
ISO 时间戳秒级精确任务

注意: Hermes 是分钟级精度,不保证秒级准时。


执行环境:Fresh Agent Session

隔离性设计

每个任务在完全独立的会话中运行:

  • 独立上下文 - 任务之间互不干扰
  • 独立工具集 - 静态工具列表,可控
  • 防循环 - 禁止 Cron 会话创建新 Cron
  • 资源控制 - 独立的 token 预算

执行流程

Scheduler 检查 jobs.json
        │
        ▼
触发时间到达?
        │
        ├── Yes ──▶ 创建 Fresh Session
        │                │
        │                ▼
        │           执行提示词
        │                │
        │                ▼
        │           投递结果 (Telegram/Discord等)
        │                │
        │                ▼
        │           更新状态 & 计算下次执行时间
        │
        └── No ───▶ 继续等待

可靠性分析

1. 数据持久化

场景行为可靠性
系统崩溃jobs.json 已原子写入
Gateway 重启从文件恢复
磁盘损坏无副本机制

建议: 定期备份 ~/.hermes/cron/jobs.json

2. 执行可靠性

故障场景处理方式结果
执行超时 (>300s)标记失败,下次重试可能延迟
AI 服务不可用自动切换 Provider有容错
投递失败记录错误可能丢失
系统关机错过执行窗口无法恢复

关键限制: 如果系统关机或 Gateway 停止,错过的任务不会补执行。

3. 时间精度

  • 设计精度: 分钟级
  • 实际观察: 通常在整点 ±30 秒内触发
  • 适用: 提醒、报告(允许延迟)
  • 不适用: 金融交易、医疗警报(需秒级精度)

与其他系统对比

特性Hermes CronLinux CronGitHub Actions
存储JSON 文件crontabGitHub 云端
AI 能力内置需脚本需配置
消息投递多平台需实现有限
可靠性单机系统级企业级
适用场景个人 AI 助手系统任务CI/CD

实践建议

1. 确保 Gateway 持续运行

# 安装为系统服务(开机自启)
hermes gateway install

# 检查状态
hermes gateway status

2. 监控任务状态

# 查看所有任务
hermes cron list

# 查看执行历史
ls ~/.hermes/cron/output/{job_id}/

3. 关键任务的双重保险

对于重要提醒,建议同时使用系统 Cron:

# 主提醒 (Hermes)
hermes cron create "0 8 * * *" "提醒内容"

# 备份提醒 (系统 Cron)
echo "0 8 * * * /usr/local/bin/notify-send '提醒'" | crontab

安全性设计

1. 提示词扫描

创建任务时检查危险模式:

  • SSH 连接尝试
  • 凭证泄露
  • 不可见 Unicode 字符

2. 沙箱执行

  • 限制文件系统访问路径
  • 限制网络访问白名单
  • 超时控制(默认 300 秒)

结论:可信度评估

剧集提醒场景

维度评分说明
可靠性4/5允许几分钟延迟
持久化5/5JSON 文件本地存储
恢复能力4/5重启后自动恢复
精度3/5分钟级足够

结论: 完全适合此场景。

不推荐场景

  • 金融交易: 需要秒级精度和事务保证
  • 医疗警报: 生命安全相关
  • 高频任务: 每秒执行多次

技术规格速查

属性
存储格式JSON
存储位置~/.hermes/cron/jobs.json
写入方式原子写入
调度精度分钟级
执行超时300 秒
Provider 容错自动切换
递归 Cron禁止

参考

  • 旧 GitHub Pages 已发布页面内容迁回 source post。