背景
当 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 Cron | Linux Cron | GitHub Actions |
|---|---|---|---|
| 存储 | JSON 文件 | crontab | GitHub 云端 |
| 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/5 | JSON 文件本地存储 |
| 恢复能力 | 4/5 | 重启后自动恢复 |
| 精度 | 3/5 | 分钟级足够 |
结论: 完全适合此场景。
不推荐场景
- 金融交易: 需要秒级精度和事务保证
- 医疗警报: 生命安全相关
- 高频任务: 每秒执行多次
技术规格速查
| 属性 | 值 |
|---|---|
| 存储格式 | JSON |
| 存储位置 | ~/.hermes/cron/jobs.json |
| 写入方式 | 原子写入 |
| 调度精度 | 分钟级 |
| 执行超时 | 300 秒 |
| Provider 容错 | 自动切换 |
| 递归 Cron | 禁止 |
参考
- 旧 GitHub Pages 已发布页面内容迁回 source post。