Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • OpenClaw

  • Hermes-Agent

    • Hermes Agent 概述
    • Hermes Agent 实战 01|架构总览:用一个 Agent 管一整个机房
    • Hermes Agent 实战 02|多 Profile 与超管模型:一个 Agent 安全地管十几台机器
    • Hermes Agent 实战 03|Gateway 运维:systemd、裸进程,和一个 Telegram token 撞车
    • Hermes Agent 实战 04|模型路由实战:config 全解、thinking 注入与 401/503 源码级根因
    • Hermes Agent 实战 05|技能工程:写、去重、pin,与每周自我审计
    • Hermes Agent 实战 06|让 Agent 自己上班:cron 驱动的无人值守巡检
      • 1. Hermes 的定时任务长什么样
      • 2. 无人值守 ≠ 交互式:四条会翻车的差异
        • 2.1 没有人能点「批准」
        • 2.2 「最终回复」不会自己送达
        • 2.3 模型会「假装发了」
        • 2.4 静默失败最致命
      • 3. 一个真实任务的完整形态
      • 4. 幂等与只读:两条底线
      • 5. 可复现 checklist
      • 6. 完整 jobs.json 条目(含字段陷阱)
        • 6.1 危险命令拦截:为什么 cron 里 python3 -c '...' 必失败
        • 6.2 心跳消息必须包含的内容
      • 7. Agent 可直接解析的元数据块
    • Hermes Agent 实战 07|数据库实战:可直接抄走的 SQL Server 巡检脚本
    • Hermes Agent 实战 08|量化交易助手:持仓盈亏、网格减仓,与「没开单」的真相
    • Hermes Agent 实战 09|接入 OpenWebUI:把每个 Profile 暴露成一个「模型」
    • Hermes Agent 实战 10|升级不翻车,与给上游提 PR:一个被冲掉三次的修复
    • Hermes Agent 实战 11|踩坑合集:当「手动 rm」从来不是真正的修复
    • Hermes Agent 实战 12|工具链外延:用 AI 运维 AI,与这个系列的诞生
    • Hermes Agent 实战 13|旗舰篇:让 Agent 从零部署并灾难恢复一个 7 节点生产集群
  • Claude-Code

  • AI-Agent
  • Hermes-Agent
Carry の Blog
2026-06-22
目录

Hermes Agent 实战 06|让 Agent 自己上班:cron 驱动的无人值守巡检原创

# 让 Agent 自己上班:cron 驱动的无人值守巡检

系列第 06 篇。前面的 agent 都是「我问、它答」。这篇讲怎么让它没人盯着也自己干活:每天凌晨巡检数据库、每周对比多机指标、定时清理过期索引,干完主动发报告给我。无人值守和交互式是两套完全不同的工程——这篇讲清楚区别在哪、怎么不翻车。

# 1. Hermes 的定时任务长什么样

每个 Profile 有自己的 cron 定义,本质是一份 jobs.json,里面每个任务 = 一条 cron 表达式 + 一段给 agent 的 prompt:

// ~/.hermes/profiles/<name>/cron/jobs.json (示意)
{
  "jobs": [
    {
      "id": "dba-daily-inspect",
      "schedule": "0 1 * * *",          // 每天 01:00(主机时钟 +08:00)
      "prompt": "运行 collect_slow_sql 脚本,巡检最近24小时慢SQL,发日报",
      "deliver": "telegram"
    }
  ]
}
1
2
3
4
5
6
7
8
9
10
11
# 改完 jobs.json 必须重启对应网关(cron 由网关进程调度)
systemctl --user restart hermes-gateway-<name>.service
# 查当前在跑的 cron
hermes cron list
1
2
3
4

我真实在跑的几个:每天凌晨的 DBA 慢 SQL 巡检、每周的多机指标对比广播、定期的过期索引清理(manage_stale_indices.sh)、每周一的技能审计(上一篇)。

# 2. 无人值守 ≠ 交互式:四条会翻车的差异

这是这篇的核心。交互式能跑通的东西,搬到 cron 上经常静默失败。我用一堆失败换来这四条:

# 2.1 没有人能点「批准」

cron 触发时没有用户在场。于是任何需要审批的危险操作——内联的 python3 -c、bash -c、execute_code——会被安全防护直接拦掉,任务卡死。

对策:把要跑的逻辑写成已提交的脚本文件,cron 里只 python3 xxx.py / bash xxx.sh。脚本是受信的,内联命令不是。

如果你确实想允许内联 cron 命令,得在 config.yaml 设 approvals.cron_mode: approve——但这会削弱所有 cron 的安全性,我选择不开。

# 2.2 「最终回复」不会自己送达

交互式里 agent 的最后一段话你直接就看到了。但 cron 任务如果 deliver: local、或这个 Profile 压根没接 IM 平台,agent 的「最终响应」哪儿也去不了。

对策:送达逻辑焊死在脚本里(脚本自己调 IM API 发出去),不要指望 agent 的最终回复就是送达。

# 2.3 模型会「假装发了」

我让 agent 在 cron 里 curl 一个通知,它跳过了——因为把命令回显出来,对模型来说感觉就像已经做了。

对策:同上,凡是「必须发生」的副作用(发通知、写文件),别留给模型自由发挥,写进脚本。

# 2.4 静默失败最致命

无人值守最大的风险不是报错,而是悄无声息地死掉——你以为它在跑,其实三周前就挂了。

对策:每次都发一条心跳,哪怕一切正常。让「群里没消息」本身成为告警:

✅ superdba skill-audit clean(curated 9)      ← clean 也发
⚠️ slow-sql: 3 条值得关注,详情见附件               ← 有事更发
1
2

这样「沉默 == 任务死了」是可检测的。沉默绝不能是默认的「正常」。

# 3. 一个真实任务的完整形态

把上面四条落到一个真实的「每日慢 SQL 巡检」上,它长这样:

  1. 触发:cron 0 1 * * *,prompt 一句话「运行巡检脚本」。
  2. 执行:agent 跑一个已提交的 collect_slow_sql 脚本(绕过审批拦截),脚本只读地查 DMV、导出慢 SQL(注意防截断,见下一篇)。
  3. 判断:脚本/agent 区分「真问题」和「正常空闲」——比如交易机器人 24 小时没开单,是在等信号,不是故障;数据库某些 idle 等待是正常的,不是瓶颈(详见第 07 篇的「误读 idle wait」战例)。
  4. 送达:脚本自己把日报发到 Telegram,clean 也发心跳。
  5. 只读:巡检绝不自动改库。要改的东西,列进报告等人确认。

第 3 点特别重要:无人值守的 agent 最容易犯的错是「把正常当异常」或「把异常当正常」——半夜把你吵醒去看一个根本不存在的问题,比不报警还糟。

# 4. 幂等与只读:两条底线

  • 只读:巡检、审计、报告类任务一律不写生产。真要做变更类定时任务(如清理过期索引),单独评估、加防护、可回滚。
  • 幂等:任务重复触发(systemd 重启、补跑)不应造成二次伤害。报告类天然幂等;变更类要自己保证「跑两次 == 跑一次」。

# 5. 可复现 checklist

把一个交互式流程改造成无人值守,过一遍:

  1. 逻辑落成提交过的脚本文件,cron 只负责调它——绕开审批拦截。
  2. 送达写进脚本,不依赖 agent 的最终回复。
  3. 每次发心跳(clean 也发),让静默成为可检测的告警。
  4. 区分真问题 vs 正常态,宁可漏报也别狼来了。
  5. 只读 + 幂等;变更类任务单独加防护。
  6. 改 jobs.json 后重启对应网关;用 hermes cron list 确认在跑。

# 6. 完整 jobs.json 条目(含字段陷阱)

挂在 cron 上的「每日慢 SQL 巡检」长这样(去掉无关字段):

{
  "id": "dba-daily-inspect",
  "schedule": "0 1 * * *",
  "prompt": "运行 collect_slow_sql 脚本,巡检最近24小时慢SQL,发日报。不要内联 python3 -c。",
  "deliver": "telegram",
  "tools": ["execute_command"],
  "timeout_sec": 300
}
1
2
3
4
5
6
7
8

三个看着不起眼但少了会爆的字段:

  • deliver: telegram — 没有它,agent 回复只写到 state.db,根本不到你手机。
  • tools: ["execute_command"] — 把可用工具收敛到最小集合。cron 上下文里给 40+ 工具纯属作死。
  • timeout_sec: 300 — 没有它,agent 会拿满 max_iterations=90 轮,把 cron 进程拖到天荒地老。

# 6.1 危险命令拦截:为什么 cron 里 python3 -c '...' 必失败

Hermes 的「危险命令防护」是命令前缀+正则匹配,命中即拒:

危险模式 拦截理由
python3 -c '...' / python -c 单行注入,agent 经常塞随机字符串
bash -c '...' 同上
execute_code {...} 工具调用 不留审计痕迹
eval / exec 同上
rm -rf / / mkfs / dd if= 破坏性
curl ... \| bash 远程代码执行

绕过的正确办法:把命令写成脚本提交到仓库,cron 只调文件路径。错误的办法(看到群里有人这么干):给 Profile 加一个白名单 unsafe-commands,绕过防护——这等于把整个防护体系卸了。

# 6.2 心跳消息必须包含的内容

「永远发心跳」不只是发一句话,格式要可解析——否则群消息海里抓不到:

✅ superdba daily-inspect | 09-22 01:00 CST | clean | curated=9 | ms=2,341
⚠️ superdba daily-inspect | 09-22 01:00 CST | missing=3 extra=1 | ms=3,102
1
2

四个字段都要有:profile / task-id / 时间戳带时区 / 状态枚举(clean|warn|err) / 耗时。这样以后写监控脚本用 grep + awk 就能从 Telegram 历史捞出所有心跳,自动算「任务挂了」。


# 7. Agent 可直接解析的元数据块

{
  "_meta": {
    "doc_version": "2025-01-15",
    "article_id": "hermes-06-autonomous-cron",
    "profile_context": "any",
    "executable_examples": true,
    "dependencies": ["hermes-cli", "systemd-user"],
    "estimated_setup_time": "45min"
  },
  "quick_start": {
    "add_cron_job": "edit ~/.hermes/profiles/<name>/cron/jobs.json",
    "restart_gateway": "systemctl --user restart hermes-gateway-<name>.service",
    "list_jobs": "hermes cron list",
    "test_job": "hermes cron run <job-id> --dry-run"
  },
  "job_template": {
    "id": "daily-inspect",
    "schedule": "0 1 * * *",
    "prompt": "运行 scripts/daily_inspect.py,发送报告",
    "deliver": "local",
    "tools": ["execute_command"],
    "timeout_sec": 300,
    "retry": {"max": 3, "backoff": "exponential"}
  },
  "safety_rules": [
    "cron job 必须使用已提交的脚本文件,禁止内联命令",
    "scripts/ 目录必须存在且可执行",
    "所有输出必须包含心跳标记,方便监控",
    "超时设置必须 <= 300 秒,防止无限运行"
  ],
  "verification": {
    "jobs_json_exists": "test -f ~/.hermes/profiles/<name>/cron/jobs.json",
    "json_valid": "jq empty ~/.hermes/profiles/<name>/cron/jobs.json 2>/dev/null",
    "gateway_running": "systemctl --user is-active hermes-gateway-<name>.service",
    "job_count": "jq '.jobs | length' ~/.hermes/profiles/<name>/cron/jobs.json"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

AI Agent 使用指南:

  • 当用户说"我要加一个定时任务" → 使用 job_template 模板,然后执行 quick_start.restart_gateway
  • 当用户说"检查 cron 配置" → 依次执行 verification.jobs_json_exists、verification.json_valid、verification.gateway_running
  • 当用户说"测试任务但不真跑" → 执行 hermes cron run <job-id> --dry-run
  • 当 cron job 跑不动 → 先检查 safety_rules 是否违反(特别是禁止内联命令)

下一篇是这套自动化的最佳实战场——数据库。讲几个真实战例:一个被拖了几个月、最后因数据量增长放大 42 倍变成 P0 的「已知 bug」;一个吃掉 230GB 的 LOB 黑洞;以及 AI 把正常空闲等待误读成性能瓶颈的教训。

#AI Agent#Hermes#cron#自动化#运维
上次更新: 6/21/2026

← Hermes Agent 实战 05|技能工程:写、去重、pin,与每周自我审计 Hermes Agent 实战 07|数据库实战:可直接抄走的 SQL Server 巡检脚本→

最近更新
01
Hermes Agent 实战 13|旗舰篇:让 Agent 从零部署并灾难恢复一个 7 节点生产集群 原创
06-22
02
Hermes Agent 实战 12|工具链外延:用 AI 运维 AI,与这个系列的诞生 原创
06-22
03
Hermes Agent 实战 11|踩坑合集:当「手动 rm」从来不是真正的修复 原创
06-22
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式