ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Hermes 实战 :调度——cron 6:00 无人值守跑日报

Hermes 实战 :调度——cron 6:00 无人值守跑日报 早上 6:00你还在睡觉日报自己跑完了。collect.py 抓完四个源curate.py 调 Hermes 把条目整理成正文render.py 出网页——一条链在一个没人看着的时刻走完执行记录落在磁盘上等你起床再翻。上篇回顾推送有了还差到点自动跑。那会儿跑一次日报要手动敲三下——collect、curate、render 各一条命令。这不叫自动化叫「每天记得按一下」。这篇把「人肉定时」换成 Hermes 自己的调度器用 cron 子命令建一个真实的 job每天 6:00 把管线自动跑完。这篇做两件事用 cron 把 collect→curate→render 串成真实的定时任务把「无人值守」的前提和兜底讲透。前提是 gateway 常驻兜底是跨天去重。这两条恰恰是大多数定时任务教程不讲的部分。手动三步的尽头是无人值守先把这轮要加的东西放进全景图后面每一节都是给图里的一格装细节。调度不是另起炉灶是载体项目走到这的自然演化——手动三步跑顺了下一步就是让它自己跑。hermes cron 全家桶十个子命令先看命令面。hermes cron --help把全部子命令列得很清楚逐字usage: hermes cron [-h] [--accept-hooks] {list,create,add,edit,pause,resume,run,remove,rm,delete,status,runs,history,tick} ... Manage scheduled tasks positional arguments: {list,create,add,edit,pause,resume,run,remove,rm,delete,status,runs,history,tick} list List scheduled jobs create (add) Create a scheduled job edit Edit an existing scheduled job pause Pause a scheduled job resume Resume a paused job run Run a job on the next scheduler tick remove (rm, delete) Remove a scheduled job status Check if cron scheduler is running runs (history) Show durable execution attempts tick Run due jobs once and exit options: -h, --help show this help message and exit --accept-hooks Auto-approve unseen shell hooks without a TTY prompt (equivalent to HERMES_ACCEPT_HOOKS1 / hooks_auto_accept: true).十个子命令usage 里多出来的 add/rm/delete/history 是别名不算单独功能按用途分两组管理 job 本身list/create/edit/pause/resume/remove触发与追溯run/status/runs/tick。顶层那个--accept-hooks是让无人值守时自动批准未见过的 shell 钩子等同HERMES_ACCEPT_HOOKS1后面手动触发时会用到。create 的关键选项hermes cron create --help逐字usage: hermes cron create [-h] [--name NAME] [--deliver DELIVER] [--repeat REPEAT] [--skill SKILLS] [--script SCRIPT] [--no-agent] [--workdir WORKDIR] schedule [prompt] positional arguments: schedule Schedule like 30m, every 2h, or 0 9 * * * prompt Optional self-contained prompt or task instruction options: -h, --help show this help message and exit --name NAME Optional human-friendly job name --deliver DELIVER Delivery target: origin, local, telegram, discord, signal, or platform:chat_id --repeat REPEAT Optional repeat count --skill SKILLS Attach a skill. Repeat to add multiple skills. --script SCRIPT Path to a script under ~/.hermes/scripts/. Default mode: script stdout is injected into the agents prompt each run. With --no-agent: the script IS the job and its stdout is delivered verbatim. .sh/.bash files run via bash, everything else via Python. --no-agent Skip the LLM entirely — run --script on schedule and deliver its stdout directly. Empty stdout silent. Classic watchdog pattern (memory alerts, disk alerts, CI pings). --workdir WORKDIR Absolute path for the job to run from. Injects AGENTS.md / CLAUDE.md / .cursorrules from that directory and uses it as the cwd for terminal/file/code_exec tools. Omit to preserve old behaviour (no project context files).两个位置参数schedule 和 prompt。schedule 支持两种写法——cron 表达式0 9 * * *和自然语言30m、every 2h。后面我用0 6 * * *五段依次是「分 时 日 月 周」代表每天 6:00。几个选项先划重点--script指定 scripts/ 目录下的脚本。默认模式下脚本 stdout 注入 agent 的 prompt--no-agent下脚本本身就是 job。--no-agent完全跳过 LLM按计划跑脚本、把 stdout 直接投递。空输出 静默这是 watchdog 模式。--workdirjob 的运行目录会把该目录的 AGENTS.md / CLAUDE.md / .cursorrules 注入上下文。--deliver输出投递目标默认 local。改 job 用hermes cron edit id选项和 create 基本对齐–schedule / --script / --no-agent / --workdir 都有还多了--agent能把 no-agent 的 job 改回 agent 模式。这串帮助里有几个设计判断后面展开。先落地。把管线接进 cron建一个真实的 job先写调度入口脚本。cron --script 要求脚本路径在 scripts/ 下——Windows 的 Hermes home 是%LOCALAPPDATA%\hermes所以放在%LOCALAPPDATA%\hermes\scripts\run_daily_report.py。逻辑很直接os.chdir 到日报目录按序用 subprocess 跑 collect→curate→renderstdout 输出每步的最后一行作简报。#!/usr/bin/env python3H7 调度入口6:00 无人值守跑「各家 AI 动态日报」管线。 串起 collect → curate → render 三步stdout 输出简报供 cron 投递。 注curate.py 内部已调 hermes chat 汇总此脚本本身不需要 LLM 用 hermes cron --no-agent 挂载脚本即 job、stdout 即投递内容。 importosimportsubprocessimportsys DAILYrD:\CF-AICoding\hermes-lab\daily-reportSTEPS[collect.py,curate.py,render.py]# 顺序即依赖defmain()-int:os.chdir(DAILY)lines[]forstepinSTEPS:psubprocess.run([sys.executable,step],capture_outputTrue,textTrue,encodingutf-8,errorsreplace,)out(p.stdoutor).strip()err(p.stderror).strip()ifp.returncode!0:print(f[fail]{step}rc{p.returncode})iferr:print(err)returnp.returncode# 取该步最后一行输出作简报无输出则如实标注tailout.splitlines()[-1]ifoutelse(no output)lines.append(f[ok]{step}:{tail})print(\n.join(lines))return0if__name____main__:sys.exit(main())一个细节curate.py 内部已经调 hermes chat 汇总所以这个调度脚本本身不需要 LLM。用 --no-agent 挂载脚本即 job、stdout 即投递内容外层不用再起一个 agent 循环。建 job 的命令和输出逐字取自本机$ hermes cron create 0 6 * * * --name daily-report-0600 --script run_daily_report.py --no-agent --workdir D:\CF-AICoding\hermes-lab\daily-report Created job: 21967688cba0 Name: daily-report-0600 Schedule: 0 6 * * * Script: run_daily_report.py Mode: no-agent (script stdout delivered directly) Workdir: D:\CF-AICoding\hermes-lab\daily-report Next run: 2026-08-29T06:00:0008:00 ⚠ Gateway is not running — jobs wont fire automatically. Start it with: hermes gateway install sudo hermes gateway install --system # Linux servers Check status: hermes cron statusjob 建好了id 是 21967688cba0Next run 已经算到次日 6:00。看到这一步你八成以为建好 cron job 就完事——不是。最后三行那个 ⚠ 警告才是这篇最重要的工程事实。无人值守的前提gateway 常驻hermes cron status把话说得很直白逐字解法两条路hermes gateway install把 gateway 装成服务Windows 装成 Scheduled Task登录自启Linux 装成 system 服务或者hermes gateway run前台一直跑着。装成服务才是真正无人值守的前提——前台跑意味着你得留着那个终端。诚实边界本机我没把 gateway 装成服务cron 到 6:00 自动 fire 的那一下我也没真等过。这篇讲的「无人值守自动触发」机制是实打实的——create 的 ⚠ 警告、cron status 的检查都是实跑取证的输出。但自动触发那一刻标「待核实」。我验证的是手动触发路径下一节讲。手动触发与追溯cron run runs 落盘gateway 没跑不等于 job 不能跑。cron 有个专门绕开 gateway 的调试通道cron run id直接触发。$ hermes cron run 21967688cba0 --accept-hooks Triggered job: daily-report-0600 (21967688cba0) Next run: 2026-08-29T06:00:0008:00 Ran now: succeeded.cron runs记录这次执行——durable execution执行记录持久化不是进程内存里过一下就没了0cb54fe76a424dcdb73bacb7bf70f67f completed job21967688cba0 sourcedirect 2026-08-28T21:25:27.71976508:00sourcedirect记录的是我这次手动触发自动触发时这个字段会不一样但本机没真等过 6:00具体值我没取到不瞎写。每一行的执行 ID都能对着 executions.db 追。执行输出落在%LOCALAPPDATA%\hermes\cron\output\job_id\时间戳.md。我这次触发的输出逐字# Cron Job: daily-report-0600 **Job ID:** 21967688cba0 **Run Time:** 2026-08-28 21:25:45 **Mode:** no_agent (script) --- [ok] collect.py: - 跨天去重过滤掉 24 条昨天已报道的标题 [ok] curate.py: 今日无新动态24 条与昨日已报道重复已剔除。日报沿用昨日内容。 [ok] render.py: 已报道档案更新新增 0 条标题 → history.json注意 Mode 是 no_agent (script)——没有 agent 循环纯脚本这是 --no-agent 的直接体现。文件路径带着 job id 和时间戳每次执行一落盘天然可追溯。顺带说明这个 job 的 deliver 是 local输出只落本地文件。系列第 7 篇《多渠道接入》的 push.py 还没接进调度——推送要凭据本机没配标「待核实」。推送跑通的无人值守等凭据配好才算数。重复触发也不会重复跨天去重兜底上面那份输出内行人一眼能看出它有多「安全」。当时 24 条新闻全都报道过了于是 collect 全部滤掉、curate 走了「今日无新动态」守卫、render 归档 0 条。这意味着即使 cron 在无人值守下重复触发、触发时机错了、一天跑了两遍日报也不会产生两份重复内容。跨天去重在这儿成了调度的安全网——系列第 4 篇《记忆系统拆解》做的去重反过来给调度兜底。curate.py 里那个守卫是关键逐字items 为空时不白调 Hermes直接写「今日无新动态」。空输出时 --no-agent 的 stdout 就一句话投递也不会变成垃圾。自动化最怕的不是「跑挂了」是「跑挂了还产出一堆重复的东西」。跨天去重把后一种风险焊死了。job 生命周期pause / resume / tickjob 不是建好就一劳永逸。生命周期命令逐字$ hermes cron pause 21967688cba0 Paused job: daily-report-0600 (21967688cba0) $ hermes cron resume 21967688cba0 Resumed job: daily-report-0600 (21967688cba0) Next run: 2026-08-29T06:00:0008:00resume 之后 Next run 还是 2026-08-29T06:00——暂停不改变下一次运行的时间点。cron tick是「把到期 job 跑一遍就退出」我触发它时没有到期 job它静默返回一个字都不输出。这个行为后面在工程判断里会用到。job 的完整状态画成生命周期图持久化落在%LOCALAPPDATA%\hermes\cron\下jobs.json 存 job 定义executions.db 存执行记录output/ 存每次 stdout。jobs.json 里这个 job 的完整字段逐字节选{id:21967688cba0,name:daily-report-0600,script:run_daily_report.py,no_agent:true,schedule:{kind:cron,expr:0 6 * * *,display:0 6 * * *},repeat:{times:null,completed:1},enabled:true,state:scheduled,next_run_at:2026-08-29T06:00:0008:00,last_run_at:2026-08-28T21:25:45.67534208:00,last_status:ok,deliver:local,workdir:D:\\CF-AICoding\\hermes-lab\\daily-report}enabled / state 是 pause / resume 改的last_run_at / last_status 是我手动触发后更新的。整个 job 就是一份可读的 JSON——调度器重启、机器重启都靠这份文件恢复现场。什么任务值得上调度cron 用起来了该回答一个更本质的问题什么任务值得上调度我的判断三条缺一不可。第一固定时间。日报在每天 6:00时间点是定的。一个「等我有空再跑」的任务不需要 cron。第二确定性流程。collect→curate→render 每一步都是脚本输入输出确定没有需要 agent 临时决策、来回确认的环节。凡是跑一半会卡住问你「要不要继续」的任务都不适合无人值守——没人回答它。第三可离线查结果。执行输出落盘你起床再翻不耽误事。反过来一个「跑完必须立刻有人处理」的任务调度只负责跑不负责唤醒人。对照这三条日报是教科书式的调度对象。顺带说省 token–no-agent 模式下cron 只跑脚本不起 agent 循环。curate.py 内部调 Hermes 汇总那一下才消耗 token外层没有额外 LLM 开销。这是最省的定时跑法——脚本即 jobstdout 即投递内容。还有 watchdog 模式–no-agent 帮助里那句「Empty stdout silent」。意思是脚本输出为空时这次执行就是安静的不产生任何投递。适合「有告警才说话」的任务——磁盘超了才输出一行。结论无人值守上线新问题也跟着来回到开头那个画面。日报现在能自己跑了——job 建好、手动触发验证跑通、执行输出可追溯跨天去重兜底。README 那句「H7 用 Hermes 的 cron 在 6:00 自动跑」的承诺兑现了一半job 在手动触发在6:00 自动那一下等 gateway 装成服务才算数。但无人值守不是把问题消掉了是把问题换了一批。以前你盯着跑现在没人盯——跑挂了谁发现以前 key 在环境变量里现在多了一个常驻的 gateway 进程——凭据面变大了以前手动跑一次花一次钱现在每天自动跑——成本不声不响地累积。这三件就是我下一篇要处理的安全、本地模型、成本运维。跑起来的调度让日报第一次像一个「产品」而不是一个「脚本」。但产品是有运维责任的。下一篇见。最后留个问题如果让你给自己的 agent 配一个定时任务你想让它每天替你做什么查天气、盯服务器告警、把关注的博客打包成早报、还是让它定时清理你的下载目录想看我怎么处理无人值守的安全与运维关注别丢。
返回列表