我最近在搭一个长期跑的自治交易员,底座用的是 Hermes。

需求其实不复杂。我希望它像一个刚入职的交易员助理,每天 24 小时自己学套利、看行情、整理案例、写策略、跑模拟盘、写日记、做复盘。除非碰到开户、动钱、上实盘、放风控这种我必须拍板的事,否则别来烦我。

听上去很合理。真跑起来就出问题了。

它每轮结束都会很乖地说一句:

下一步:继续收集案例,之后搭建模拟交易环境。无需老板决策,继续工作。

然后就没有然后了。

嘴上说继续,人已经下班。

一、问题不在提示词

我一开始也以为是 prompt 写得不够狠,于是加了一堆规则:

  • 必须持续工作

  • 不要停下来等待

  • 只在关键决策时请求老板

  • 没有需要决策的事就继续推进

这些话本身没错,但解决不了问题。

因为现在大多数 Agent 产品的最小交互单位是一个 turn。它跑完这一轮、把回复吐出来,系统就认为这轮结束了,不会自动再发起下一轮。你让它"继续",它在文字里答应你,但没有外部调度器再叫它一次,下一轮就是不会发生。

很多人对 autonomous agent 的误解就在这里。你以为缺的是更强的 prompt,其实缺的是一个会按时叫醒它的 runtime。

二、别人的 Agent 凭什么能跑一整天

差别就一句话:

普通对话:用户发消息 → Agent 工作一轮 → 回复 → 停下 长期自治:调度器到点 → 新建 session → 读状态文件 → 工作一轮 → 写回状态 → 等下次调度

真正的 24 小时工作,不是让一个上下文窗口硬撑一整天,而是把长期任务切成很多个短周期:

每 30 分钟醒一次,读当前状态,挑最高优先级的任务,推进一个明确的工作单元,更新任务队列,写运行日志,然后等下一次 heartbeat。

所以长期工作真正依赖的,是 Gateway、Cron、Heartbeat 和状态文件这四样东西。

三、Hermes 里的四个部件

我最后把整套机制拆成了四层。

1. Gateway:后台闹钟

Hermes 的 cron 任务不是靠当前聊天窗口自己倒计时的。

你执行 hermes cron create ...,本质上只是把任务写进 Hermes 的任务列表。真正负责到点检查、启动任务、新建 session 的,是 Gateway。

如果你看到这样的提示:

Gateway is not running — jobs won't fire automatically. Start it with: hermes gateway install

意思就是:闹钟列表已经写好了,但没有人在后台看表。

所以第一步先把 Gateway 装起来:

hermes gateway install

没有它,cron 任务能 list 出来,但不会自动跑。

2. Cron:按时唤醒 Agent

Cron 负责定义"什么时候叫醒 Agent"。这里有一个很容易踩的坑:

hermes cron create "30m" ...

这一句不是"每 30 分钟运行一次",而是"30 分钟之后运行一次"。你会在列表里看到:

Schedule: once in 30m Repeat: 0/1

这就是个一次性任务。

要循环跑,正确写法是:

hermes cron create "every 30m" ...

或者在聊天里:

/cron add "every 30m" "..."

every 这个词是关键。

3. Heartbeat:醒来之后该干什么

Cron 只负责叫醒 Agent,醒来之后做什么不能靠它临场发挥。

我建议给每个长期任务配一个 HEARTBEAT.md,相当于交接班卡片,写清楚每次被唤醒之后必须做什么:

  1. 读取连续工作规则

  2. 读取当前状态

  3. 读取任务队列

  4. 检查是否存在阻塞

  5. 推进一个实际工作单元

  6. 更新状态文件

  7. 写运行日志

里面有一句话我特别强调:

不要只输出计划。只要没有阻塞,就必须实际推进文件、研究、代码、报告或记录中的至少一项。

这一句是用来防止 Agent 每次醒来都礼貌地说一句"下一步我会继续",然后什么都不做。

4. 状态文件:替代聊天上下文

Hermes 的 cron run 大概率是一个 fresh session,不会继承你当前聊天窗口里的上下文。

如果你在 cron prompt 里写"继续刚才的工作",它根本不知道"刚才"是什么。

所以上下文必须落到文件系统里。我一般至少会建三个:

  • memory/current-state.md:记录当前阶段、主任务、已完成事项

  • memory/task-queue.md:分成 NOW、NEXT、LATER、BLOCKED、DONE 五栏

  • memory/run-state.md:记录最近一次运行类型、完成事项、当前 focus、下一步、是否被阻塞

每次 cron 新建 session,都从这些文件里恢复上下文。

长期自治的关键就在这里:不要让聊天记录承载连续性,要让文件系统承载连续性。

四、一个通用的 Work Heartbeat 模板

写法不复杂,关键是自包含。

你是这个项目的长期工作 Agent。工作目录是 /path/to/project。 这是一次 Work Heartbeat。不要只汇报计划,必须实际推进一个工作单元,除非遇到明确阻塞。

先读取:

  • HEARTBEAT.md

  • config/continuity_policy.md

  • memory/current-state.md

  • memory/task-queue.md

  • memory/run-state.md

然后执行:

  1. 检查是否存在阻塞事项。

  2. 如果没有阻塞,从 memory/task-queue.md 选择最高优先级任务。

  3. 推进一个明确工作单元。

  4. 更新 memory/current-state.md、memory/task-queue.md、memory/run-state.md。

  5. 如有实质进展,在 logs/ 写一条简短运行记录。

本轮回复只需要说明:

  • 完成了什么

  • 更新了哪些文件

  • 下一轮继续什么

  • 是否需要用户决策

注意里面没有"继续刚才"这种话。它每次都靠工作目录和状态文件自己恢复。

五、建议先配三个 Cron

刚上手没必要搞得太复杂。我自己一开始就配了三个:

  1. Work Heartbeat,every 30m,负责日常推进

  2. Short Review,every 12h,负责短周期复盘,避免只是在堆文件

  3. Major Review,every 48h,负责阶段性反思,更新方向和任务队列

如果你的任务只是普通资料整理,甚至可以先只开第一个。等确认它能稳定接力,再加 12 小时和 48 小时的复盘。

六、最小文件结构

任何长期任务,我建议至少保留这几个文件:

HEARTBEAT.md
config/continuity_policy.md
memory/current-state.md
memory/task-queue.md
memory/run-state.md
logs/

每个文件解决的问题分别是:

  • HEARTBEAT.md:每次醒来做什么

  • continuity_policy.md:长期运行规则

  • current-state.md:当前进展

  • task-queue.md:下一步具体做什么

  • run-state.md:上一次运行留下的接力信息

它们其实都在解决同一件事:Agent 可以失去聊天上下文,但不能失去工作上下文。

七、Git 不要当成实时日志

机制跑起来之后,文件会频繁变化。但我不建议让 Agent 每 30 分钟就自动 commit,更不建议自动 push。

Git 是审计账本,不是运行日志。

我自己用的规则是这样:

  • 文件写入:随时

  • 本地 commit:一个明确工作单元结束之后

  • push 到远程:低频,并且确认没有敏感信息

下面这些东西,无论如何都不要提交进 Git:

  • API key

  • cookie、token

  • 密码、私钥

  • 个人身份材料

  • 大体量原始数据

  • 高频变化的数据库文件

让 Agent 自动工作,不等于让它自动把一切推到远程。

八、最后

如果你的 Agent 做完一轮就停,不用急着骂模型。先问自己四个问题:

  1. 后台 Gateway 起了没?

  2. Cron 用的是 once 还是 every?

  3. 每次唤醒的 prompt 是不是自包含?

  4. 有没有状态文件接住上一轮的工作?

四个都对,它才有可能真的 24 小时跑下去。

否则你只是在和一个很听话、但每次说完话就下班的 Agent 聊天。

长期工作真正的秘密,不是让 Agent 一口气跑得更久,而是让它每次醒来都知道自己是谁、在哪、要接着做什么。