问题:定时任务和对话互相打架
用 OpenClaw 搭了一套投资情报系统后,我的 Agent 身上挂了 20 多条定时任务(cron)——每天跑数据脚本、更新表格、推送日报。
听起来很美,直到我发现了一个致命问题:
所有 cron 都跑在 main session 里。
这意味着:
- 我跟 Agent 聊天时,cron 触发了要排队等我对话结束
- cron 脚本跑了 3 分钟,这 3 分钟我发消息 Agent 不回
- 多条 cron 同时触发(比如早上 9:00 有 4 条),互相排队阻塞
- 某条 cron 脚本挂了,整个 main session 卡住
简单来说:Agent 变成了一个单线程打工人,既要伺候老板,又要干杂活,谁都不满意。
为什么不一开始就用 Isolated Session?
因为之前试过,踩了一堆坑:
坑 1:GPT 在 isolated session 里会卡死
默认情况下,isolated session 会注入完整的 bootstrap context(SOUL.md、USER.md、MEMORY.md、一堆 skill 扫描),prompt 太大直接导致 LLM request timeout。
坑 2:--light-context 下工具调不动
加了 --light-context 能解决超时,但 GPT 在精简上下文下不会主动调用 message 工具推送消息。任务跑完了,你什么也收不到。
坑 3:内置投递机制不可靠
OpenClaw 有内置的 announce / deliver 机制(cron 跑完后自动把结果投递给你),但实测经常出现 delivered: true 但实际消息没发出的情况。
坑 4:Announce 重试风暴
isolated session 完成后的 announce 回调 main session,如果 main session 正忙(比如在做 context compaction),会重试 4 次,每次 60 秒 timeout。结果 Gateway 卡死需要重启。
所以之前的结论是:isolated 不可靠,全部走 main session。
转机:换一种投递思路
某天我重新想了一下这个问题,发现核心障碍不是 isolated session 本身,而是投递方式选错了。
之前的思路:
cron → isolated session 跑任务 → 内置 announce/deliver 投递结果 ❌
新思路:
cron → isolated session 跑任务 → Agent 自己用 message 工具推送 ✅
关键区别:不依赖 OpenClaw 的内置投递机制,让 Agent 在 prompt 里直接用 message 工具往聊天里发消息。
同时把模型从 GPT 换成 Claude Sonnet(在 light-context 下工具调用更可靠),一举解决了之前的几个坑。
实施方案
第一步:试点验证
不敢一上来就全量迁移。先创建了一条最简单的试点 cron:
openclaw cron add "Cron Trial" \
--cron "*/5 * * * *" \
--session isolated \
--no-deliver \
--light-context \
--timeout 120000 \
--message '这是一条测试消息。用 message 工具推送到飞书私聊。'
关键参数:
--session isolated:不走 main session--no-deliver:关闭内置投递--light-context:减少 prompt 膨胀- prompt 里明确告诉 Agent 用
message工具推送
第二步:连续验证
跑了 3 轮(每 5 分钟一次),全部成功:
| Round | 状态 | 耗时 | 消息送达 |
|---|---|---|---|
| 1 | ✅ ok | 7.2s | ✅ |
| 2 | ✅ ok | 6.0s | ✅ |
| 3 | ✅ ok | 6.3s | ✅ |
而且 main session 正在对话时,worker 也能正常执行和投递,互不干扰。
第三步:分层迁移
不是所有任务都一样复杂。按复杂度分了 5 个 Tier:
| Tier | 说明 | 示例 |
|---|---|---|
| 1 | 纯脚本,无推送 | 数据预拉取、快照 |
| 2 | 脚本 + 数据库/表格更新 | 价格更新、看板生成 |
| 3 | 脚本 + 文字推送 | 财报日历、日报 |
| 4 | 脚本 + 图片推送 | 持仓监控(含信息图) |
| 5 | 复杂链路(脚本+AI分析+图片+推送+归档) | 投研日报、周报 |
从 Tier 1 开始,每个 Tier 验证通过后再迁下一个。
第四步:集中验证技巧
这里有个实用技巧:不要等到正常触发时间才验证。
把 cron 表达式临时改成马上触发的一次性时间:
# 原来是每天 09:20,临时改成今天 15:35
openclaw cron edit <job-id> --cron "35 15 23 3 *"
一个下午就能验证完所有任务。验证通过后再改回正确的 schedule。
完整的 Cron 配置模板
纯脚本任务(Tier 1)
openclaw cron edit <job-id> \
--session isolated \
--no-deliver \
--light-context \
--timeout 120000 \
--message '运行数据脚本:
cd /path/to/workspace && python3 -u scripts/my_script.py 2>&1
成功后回复 HEARTBEAT_OK,失败则简要报告错误。'
脚本 + 表格更新(Tier 2)
openclaw cron edit <job-id> \
--session isolated \
--no-deliver \
--timeout 300000 \
--message '【定时任务】价格更新:
1. 运行: cd /path/to/workspace && python3 -u scripts/update_prices.py 2>&1
2. 读取 data/price_updates.json
3. 逐条用 feishu_bitable_update_record 更新表格
4. 全部完成后回复 HEARTBEAT_OK,失败则简要报告错误。'
脚本 + 推送消息(Tier 3)
openclaw cron edit <job-id> \
--session isolated \
--no-deliver \
--timeout 180000 \
--message '【定时任务】日报推送:
1. 运行: cd /path/to/workspace && python3 -u scripts/generate_report.py 2>&1
2. 读取 data/report.md
3. 用 message 工具推送到飞书 target: user:<your-open-id>
4. 完成后回复 HEARTBEAT_OK'
脚本 + 图片推送(Tier 4)
openclaw cron edit <job-id> \
--session isolated \
--no-deliver \
--timeout 300000 \
--message '【定时任务】监控报告:
1. 运行: cd /path/to/workspace && python3 -u scripts/generate_monitor.py 2>&1
2. 运行: python3 -u scripts/generate_infographic.py 2>&1
3. 读取 data/monitor.json,生成文字摘要
4. 用 message 工具推送文字摘要到飞书 target: user:<your-open-id>
5. 用 message 工具推送信息图(filePath: data/infographic.png, caption: "监控报告")
6. 完成后回复 HEARTBEAT_OK'
迁移前后对比
迁移前:
┌─────────────────────────┐
│ Main Session │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │对话│ │cron│ │cron│ │ ← 全部排队,互相阻塞
│ └────┘ └────┘ └────┘ │
└─────────────────────────┘
迁移后:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Main Session │ │ Isolated #1 │ │ Isolated #2 │
│ 用户对话 │ │ cron 任务 │ │ cron 任务 │ ← 各跑各的
└──────────────┘ └──────────────┘ └──────────────┘
结果
| 指标 | 迁移前 | 迁移后 |
|---|---|---|
| Main session cron 数量 | 18 条 | 0 条 |
| 对话被 cron 打断 | 经常 | 永不 |
| Cron 互相排队阻塞 | 经常 | 不会 |
| 单条 cron 失败影响范围 | 整个 main session | 仅该条 |
| 平均执行耗时 | 与对话竞争 | 6~200 秒独占 |
踩坑清单(帮你避雷)
1. 一定要加 --no-deliver
不加的话,内置投递和 Agent 的 message 工具会重复发送,或者内置投递静默失败。
2. 一定要加 --timeout
isolated session 没有人工干预,如果脚本挂了,没有 timeout 就永远不会结束。建议:
- 简单脚本:120 秒
- 中等复杂:300 秒
- 长任务(数据拉取):1800 秒
3. --light-context 看情况
如果任务只需要 exec + message,加 --light-context 可以减少 token 消耗。但如果需要调用飞书表格等复杂工具,可能需要完整 context(实测 Sonnet 在 light-context 下也能用,但你的 mileage may vary)。
4. Prompt 要写清楚
Isolated session 的 Agent 没有你对话的上下文,也没有 SOUL.md 的人格设定。它只看到你给的 prompt。所以:
- 脚本路径写绝对路径
- 推送 target 写完整
- 成功/失败的处理逻辑写清楚
- 不要假设 Agent “知道"任何上下文
5. --session-key 在 isolated 模式下不生效为持久 session
每次触发都会新建 session。如果你的任务需要跨次记忆(比如"上次跑的结果”),目前 isolated 模式做不到。
6. 用一次性 cron 表达式验证
不要傻等到凌晨 5:30 才知道任务挂了。用 --cron "35 15 23 3 *" 这种一次性表达式集中验证。
7. 回滚只需要一条命令
openclaw cron edit <job-id> --session main
随时可以把某条任务切回 main session。
总结
OpenClaw 的 cron 系统其实很灵活,但默认的 main session + announce 模式在任务多了之后会变成瓶颈。
核心思路:
- 任务跑在 isolated session(不占 main session lane)
- 投递由 Agent 自己完成(用 message 工具,不依赖内置 announce)
- 分层迁移(从简到难,逐步验证)
- 保留回滚能力(一条命令切回 main)
如果你的 OpenClaw 上也挂了不少定时任务,而且开始感觉对话变卡了——试试这个方案。一个下午就能搞定。
实测环境:OpenClaw 2026.3.8-beta.1,Claude Sonnet,21 条 cron 全量迁移。