很多人以为开源 AI Agent 已经够热闹了,但如果你真正上手跑过几个项目,会发现一个尴尬的现状:绝大多数 Agent 本质上还是一个“聊天机器人”。输入一段话,它回一段话,只不过回复质量比普通搜索引擎好一点。真正能在无人值守状态下干活,并且把结果主动送到你手上的 Agent,反而是少数。
这里的差距,往往不在“模型聪明不聪明”,而在两个非常工程化的能力:定时任务调度和结果推送。
OpenClaw 这类开源 Agent 项目之所以值得关注,不是因为它多了一个对话框皮肤,而是因为它把“触发—执行—通知”这条自动化链路做成了可配置、可扩展的系统。本文不打算只讲概念,而是直接把定时任务和推送这套组合拆开,从配置到代码,从验证到排错,给你一条能跑通的路。
读完这篇文章,你会得到三个明确收益:第一,搞清楚 OpenClaw 这类开源 Agent 的工作流模型,明白定时任务和推送放在哪个位置;第二,拿到一套能在本地跑起来的定时任务配置和推送脚本;第三,知道生产环境里哪些坑最容易踩,以及怎么提前避开。
1. 这篇文章真正要解决的问题
先说一个真实场景。假设你想让 AI 每天早上帮你整理昨天的行业资讯,九点准时发到手机。如果只是打开 Agent 对话框,你需要每天早上手动输入:“帮我整理昨天的资讯,生成摘要,发给我”。一次两次可以,连续一个月你就会放弃。
这就是典型的“能回答问题,但扛不住长期任务”的 Agent。它的能力边界在于:缺少时间维度的自动化,缺少主动触达用户的手段。
定时任务解决的是“什么时候干活”。推送解决的是“干活结果怎么让用户知道”。两者单独拆开都不复杂,但组合在一起,Agent 才从“被动响应”变成“主动服务”。这也是 OpenClaw 这类项目在架构设计上真正花心思的地方。
更实际地说,这篇文章适合下面几类读者:
- 想用开源 AI Agent 搭个人自动化工作流的开发者;
- 后端或运维工程师,想把 Agent 接进现有监控、巡检、日报体系的;
- 对 Cron、Webhook、IM 机器人有基础认知,但还没串起来的人。
如果你只想看 Agent 怎么聊天,这篇文章对你帮助有限。但如果你想让 Agent 替你在固定时间执行巡检、抓取、备份、摘要生成,然后把结果推送到你的手机,这篇文章就是为这个目标写的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. OpenClaw 核心概念与适用场景
2.1 OpenClaw 是什么
OpenClaw 是一个开源的 AI Agent 项目,核心思路是提供一个可以自托管的智能体框架,让你用自己的配置、自己的工具、自己的模型来跑自动化任务。
这里要特别说明一点:这类开源 Agent 项目的迭代速度极快,社区分支和命名也可能频繁调整。文章写到的技术思路和配置范式,是基于开源社区同类项目的主流做法,具体字段名和命令可能随版本变化。实操时,以你自己 clone 的官方仓库 README 和配置文件模板为准,本文重点帮你建立可迁移的理解,而不是让你死记某几个命令。
OpenClaw 这类项目通常具备几个关键特征:
- 支持自然语言定义任务,底层会调用模型进行规划与工具调用;
- 提供插件或动作(Action)机制,可以执行 Shell 命令、请求 HTTP 接口、读写文件、查询数据库;
- 支持定时触发、外部事件触发以及消息推送;
- 可以由用户完全掌控运行环境和数据。
2.2 核心工作流:Trigger → Plan → Execute → Deliver
理解 OpenClaw 的定时任务与推送,不需要背源码,只需要抓住一条主线:
| 环节 | 作用 | 对应本文内容 |
|---|---|---|
| Trigger | 决定任务什么时候启动 | Cron 定时表达式、Webhook 外部触发 |
| Plan | Agent 根据任务描述拆解步骤 | Prompt 与任务配置 |
| Execute | 执行具体工具操作 | 脚本、HTTP 请求、命令 |
| Deliver | 把结果发送给用户 | 推送通知、Webhook 回调 |
传统开发里,这四个环节往往要写四套代码。而 OpenClaw 的思路是:把 Trigger 和 Deliver 做成底层能力,你只需要告诉它“每天九点干什么”“完成后往哪里通知”,剩下的由框架调度。
这也是为什么我建议你把注意力放在任务描述和配置本身,而不是急着去改框架源码。
2.3 定时任务与推送的适用边界
适合用 OpenClaw 定时任务+推送解决的场景:
- 定时资讯摘要、舆情监控;
- 周期性巡检接口或网站可用性;
- 定时生成日报、周报;
- 定时同步数据、备份文件;
- 定时调用第三方 API 并推送结果。
不适合的场景也要说清楚:
- 对实时性要求极高、需要毫秒级响应的任务,不要依赖 Agent 定时调度;
- 涉及生产数据库写入的关键操作,建议先人工审核流程;
- 需要复杂分布式协调的任务,用专业调度系统更合适。
OpenClaw 的定位是“轻量、自主、可配置”,它擅长替代重复性的人肉操作,而不是替代整个分布式任务调度平台。
3. 环境准备与基础部署
在配置定时任务之前,先把运行环境准备好。本文以自托管方式演示,不依赖云端托管服务。
3.1 前置条件
建议准备以下环境:
- 操作系统:Linux 或 macOS,Windows 需要借助 Docker;
- 运行环境:Node.js 18+ 或 Python 3.10+,具体看项目分支要求;
- 容器工具:Docker 与 Docker Compose,便于隔离依赖;
- 版本管理:Git,用于克隆项目;
- 数据库:大多数开源 Agent 项目会用 SQLite 或 PostgreSQL 保存任务历史,SQLite 够用时可不必额外装 PostgreSQL。
版本细节以你 clone 的仓库实际要求为准,不建议在一开始就纠结“最新版本号”,先跑通最小链路。
3.2 克隆与安装
bash复制git clone https://github.com/你的目标仓库地址/openclaw.git
cd openclaw
# 安装 Node 依赖(如果项目是 Node 技术栈)
npm install
# 如果是 Python 技术栈,则创建虚拟环境
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
如果是 Docker 方式,官方一般会提供 docker-compose.yml:
bash复制docker compose up -d
docker compose logs -f
启动后,项目通常会提供一个本地管理界面或命令行入口。先确认服务健康,再做配置。
3.3 基础配置文件
大部分开源 Agent 会把配置集中在 .env 或 config.yaml。一个典型的 .env 包含这些信息:
properties复制# .env
AGENT_NAME=my-agent
# 模型相关配置,按你的模型服务商填写
MODEL_PROVIDER=openai-compatible
MODEL_API_KEY=sk-xxxx
MODEL_BASE_URL=https://你的模型服务地址
# 存储
DATABASE_PATH=./data/claw.db
# 时区
TZ=Asia/Shanghai
配置完成后,启动项目,先用一个简单任务验证 Agent 能正常响应。不要一上来就配定时任务,否则你会分不清是调度问题还是 Agent 本身的问题。
4. 定时任务配置:从 Cron 表达式到 Agent 调度
4.1 理解 Cron 表达式
Cron 是 Linux 世界里最经典的任务调度语法,也是 OpenClaw 这类项目普遍支持的定时触发方式。一个标准 Cron 表达式由五个字段组成:
code复制分 时 日 月 周
例如:
text复制0 9 * * *
表示每天 09:00 执行。
text复制*/30 * * * *
表示每 30 分钟执行一次。
text复制0 18 * * 5
表示每周五 18:00 执行。
有些实现支持六段或七段,会额外包含秒或年份,但核心逻辑一致。要注意的是:Cron 表达式的时区由运行环境决定。如果你的服务器时区是 UTC,那么“每天九点”实际上是北京时间下午五点。生产环境务必显式设置时区。
4.2 在 OpenClaw 中定义一个定时任务
在 OpenClaw 这类框架里,定时任务通常以任务文件或配置块的形式存在。下面是一个典型的 YAML 示例,定义了一个每天上午九点执行的资讯摘要任务:
yaml复制# config/tasks/daily_digest.yaml
name: daily_digest
description: 每天生成一次技术资讯摘要
trigger:
type: cron
expression: "0 9 * * *"
timezone: "Asia/Shanghai"
task:
prompt: |
请访问我配置的资讯源,筛选出与人工智能、开源项目相关的信息,
整理成 5 条以内的中文摘要,并说明每一条为什么值得关注。
actions:
- http_get
- summarize
delivery:
type: webhook
url: "https://你的推送地址"
format: markdown
这段配置的实际字段名可能因项目而异,但三个核心部分不会变:trigger 定义什么时候执行,task 定义做什么,delivery 定义结果送到哪里。
4.3 常见定时任务的表达式参考
| 场景 | Cron 表达式 | 说明 |
|---|---|---|
| 每天 08:30 | 30 8 * * * |
适合日报类任务 |
| 每两小时 | 0 */2 * * * |
适合周期巡检 |
| 每周一 10:00 | 0 10 * * 1 |
适合周报 |
| 每月 1 日 00:30 | 30 0 1 * * |
适合月度汇总 |
| 工作日每 5 分钟 | */5 * * * 1-5 |
适合高频监控 |
配置定时任务最容易犯的错,是把“我希望执行”和“表达式让我执行”搞混。配完之后,先看下一次触发时间是否符合预期,而不是干等。
5. 推送通知配置:从 Webhook 到 IM 机器人
5.1 为什么推送是刚需
定时任务跑完之后,结果不能只在服务器日志里躺着。真正让定时任务产生价值的,是把结果主动送到用户眼前。
推送方式按可操作性从高到低排序:
text复制Webhook 回调 > IM 机器人(Server酱/钉钉/企业微信)> Telegram Bot > SMTP 邮件
Webhook 是最通用的方式。本质上就是向一个 URL 发送 HTTP POST 请求,携带 JSON 数据。任何支持 Webhook 的服务都可以接入。
5.2 用 Python 写一个通用推送函数
先不管 OpenClaw 怎么集成,你完全可以先用一段脚本验证推送链路是否畅通。下面这个例子用 Python 发送 Markdown 消息到 Server酱或钉钉机器人。
python复制# notify.py
import requests
import json
def send_webhook(url: str, title: str, content: str, token: str = None) -> dict:
"""
通用 Webhook 推送:
- Server酱: 调用方传入完整 send 地址
- 钉钉/企业微信: 直接在 url 中拼好 access_token
"""
payload = {
"title": title,
"content": content,
"msgtype": "markdown"
}
if token:
payload["token"] = token
resp = requests.post(url, json=payload, timeout=10)
resp.raise_for_status()
return resp.json()
if __name__ == "__main__":
# 示例:推送到 Server酱
send_webhook(
url="https://你的server酱推送地址",
title="任务执行成功",
content="## 巡检结果\n一切正常"
)
这段代码的好处是简单,你只需要把 url 换成自己的推送地址,就能先验证网络、权限和消息格式。
5.3 各类推送渠道对比
| 渠道 | 优点 | 限制 | 适合场景 |
|---|---|---|---|
| Server酱 | 个人部署简单,微信能收到 | 免费版有频率限制 | 个人通知 |
| 钉钉自定义机器人 | 免费,支持 Markdown,配置快 | 需要公网可访问的 Webhook,有机器人安全设置 | 团队工作通知 |
| 企业微信机器人 | 能直达企业内部成员 | 仅企业内部可用 | 企业巡检与告警 |
| Telegram Bot | 全球可访问、接口灵活 | 需要额外搭建网络通道 | 海外服务器或开发者偏好场景 |
| SMTP 邮件 | 没有第三方依赖 | 邮件易进垃圾箱、配置繁琐 | 正式日报 |
选择哪个渠道,最重要的是考虑你能否稳定收到,而不是追求渠道多。
5.4 在 OpenClaw 中接入推送
从 OpenClaw 的角度看,推送通常被抽象为 Action 或 Delivery Plugin。你只需要在任务配置里引用它,而不需要每次手写 HTTP 请求。
yaml复制delivery:
type: plugin
name: server_chan
config:
send_key: "${SERVER_CHAN_KEY}"
message_template: |
{{.task_name}} 执行完成
用时: {{.duration}}
状态: {{.status}}
详情: {{.summary}}
这里使用 ${SERVER_CHAN_KEY} 而不是硬编码,是为了避免密钥泄露到仓库里。推送密钥、API Key 必须放在环境变量或密钥管理服务中。
6. 完整示例:定时巡检 + 推送结果
现在把定时任务和推送串成一个完整的例子。场景是:每天早上 08:30,检查一个网站是否可访问、证书是否快过期,并把结果推送到 Server酱。
这个例子分成两个部分:OpenClaw 任务配置和实际巡检脚本。你可以先把巡检脚本单独跑通,再交给 Agent 调度。
6.1 巡检脚本
python复制# tasks/health_check.py
import ssl
import socket
import datetime
import requests
def check_http(url: str, timeout: int = 10) -> tuple[bool, float]:
start = datetime.datetime.now()
try:
resp = requests.get(url, timeout=timeout)
ok = resp.status_code < 400
return ok, (datetime.datetime.now() - start).total_seconds()
except Exception as e:
return False, 0.0
def check_cert_expire(hostname: str, port: int = 443) -> datetime.date:
ctx = ssl.create_default_context()
with socket.create_connection((hostname, port), timeout=10) as sock:
with ctx.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
return datetime.datetime.strptime(cert["notAfter"], "%b %d %H:%M:%S %Y GMT").date()
def main():
target = "https://example.com"
hostname = "example.com"
ok, cost = check_http(target)
expire_date = check_cert_expire(hostname)
left_days = (expire_date - datetime.date.today()).days
lines = [
f"## 巡检结果: {target}",
f"- HTTP 状态: {'正常' if ok else '异常'}",
f"- 响应耗时: {cost:.2f}s",
f"- 证书过期时间: {expire_date}",
f"- 证书剩余天数: {left_days} 天",
]
print("\n".join(lines))
# 将结果写入临时文件,供 Agent 或推送模块读取
with open("/tmp/health_report.md", "w", encoding="utf-8") as f:
f.write("\n".join(lines))
if __name__ == "__main__":
main()
这个脚本不依赖 OpenClaw 也能跑,这是有意的设计。把复杂逻辑放在普通脚本里,让 Agent 负责调度和编排,能让整个系统更容易测试和排错。
6.2 OpenClaw 任务配置
yaml复制# config/tasks/health_check.yaml
name: health_check_daily
trigger:
type: cron
expression: "30 8 * * *"
timezone: "Asia/Shanghai"
task:
prompt: |
执行健康巡检脚本,读取生成的报告文件,如果状态异常,说明具体情况。
actions:
- name: run_script
command: "python3 tasks/health_check.py"
delivery:
type: plugin
name: server_chan
config:
send_key: "${SERVER_CHAN_KEY}"
message_template: |
{{ .task_name }} 巡检完成
结果如下:
{{ include "/tmp/health_report.md" }}
这种设计的好处是职责清晰:定时触发交给 Cron,执行逻辑交给脚本,结果格式化交给推送模板。任何一环出问题,都可以单独测试。
6.3 手动触发验证
配置完成后,先用项目提供的 CLI 或接口手动触发一次,确认链路通畅:
bash复制# 假设项目提供了命令行触发入口
openclaw task run health_check_daily
如果项目没有命令行入口,可以把 Cron 表达式临时改为每两分钟执行一次,观察日志是否打印执行记录,同时检查推送是否收到。
7. 运行结果与效果验证
7.1 如何判断任务成功
一次定时任务是否成功,不能只凭“脚本退出码是 0”来判断。至少要检查三个层面:
- 框架日志里是否记录了任务进入执行阶段;
- 任务脚本是否真的产生了预期产物(报告文件、数据库写入);
- 推送目标是否收到了符合格式要求的消息。
text复制[2025-06-10 08:30:00] INFO Task health_check_daily started
[2025-06-10 08:30:02] INFO Action run_script executed, exit_code=0
[2025-06-10 08:30:02] INFO Report file size = 214 bytes
[2025-06-10 08:30:02] INFO Delivery server_chan success
看到类似日志,才说明定时任务真正闭环。
7.2 预期推送效果
如果你用 Server酱,手机上收到的消息应该包含:
text复制health_check_daily 巡检完成
- HTTP 状态: 正常
- 响应耗时: 0.23s
- 证书过期时间: 2026-01-01
- 证书剩余天数: 205 天
如果推送只收到标题,没有正文,优先检查消息模板内容和变量是否解析成功。
7.3 失败时的第一排查动作
任务失败时不要乱猜。第一步看日志,第二步看脚本单独执行能否成功,第三步看推送 URL 是否可达。
记住一个原则:先证明环节独立可用,再放进调度系统里。千万别在 Agent 任务里调试一个本身就没跑通的脚本。
8. 常见问题与排查方法
下面是定时任务与推送场景里出现频率最高的几个问题。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 任务到点没执行 | Cron 表达式时区不对 | 查看框架日志中最近触发时间,对比当前时间 | 在配置中显式设置 timezone: Asia/Shanghai |
| 任务执行了但推送没收到 | Webhook URL 配置错误或密钥失效 | 用 curl 单独 POST 测试推送地址 | 重新生成 Webhook 或检查密钥环境变量 |
| 每天同一时间执行两次 | 时间戳记录被重复初始化,或存在多个进程同时调度 | 检查是否同时跑了两套调度进程 | 使用分布式锁,或保证只有主节点触发 |
| 推送消息内容为空 | 模板变量名和实际输出字段不一致 | 打印完整变量上下文 | 比对官方模板字段命名 |
| 推送频率过高被限流 | 任务 Crontab 设置太密 | 查看服务商限流文档 | 降低频率,或聚合多条消息后一次推送 |
| 脚本报编码错误 | 服务器默认编码不是 UTF-8 | 检查日志中的 UnicodeEncodeError | 在脚本头部添加 # -*- coding: utf-8 -*- 并设置环境变量 PYTHONIOENCODING=utf-8 |
只要定时任务用于生产环境,就一定会遇到重复、漏执行、通知丢失这几类问题。提前设计对幂等和手动补跑的处理方式,比事后补救便宜得多。
9. 最佳实践与工程建议
9.1 任务设计要保证幂等
同一个定时任务,因为网络抖动或重启,完全可能被执行两次。你的脚本必须能接受重复执行。比如巡检脚本重复跑没关系,但“插入数据库记录”的任务就需要先查重,或使用唯一约束。
9.2 统一时区
服务器、数据库、Cron 表达式、日志时间戳最好全部统一为 Asia/Shanghai,否则排查问题时非常痛苦。这个规则听起来简单,实际项目里至少一半的“任务没按时跑”是因为时区不一致。
9.3 推送要做失败重试与降级
推送失败是常态,不是异常。建议采用“指数退避”策略:失败后等待 1 秒、5 秒、30 秒再重试,最多三次。如果多次失败,至少要把失败记录写入日志文件。
python复制# retry_example.py
import time
import requests
def push_with_retry(url, payload, max_retries=3):
for attempt in range(max_retries):
try:
resp = requests.post(url, json=payload, timeout=10)
resp.raise_for_status()
return True
except Exception as e:
wait = (2 ** attempt) * 5 # 5s, 10s, 20s
print(f"push failed: {e}, retry in {wait}s")
time.sleep(wait)
return False
9.4 密钥与敏感信息管理
推送 Webhook 地址本身就是一种凭据,泄露以后别人可以向你的手机发垃圾消息。所有密钥都应该通过环境变量或 Kubernetes Secret 注入,不能硬编码到配置文件里。定期更换 Server酱或钉钉机器人的 Webhook 地址,也是个好习惯。
9.5 运行日志与审计
给每个定时任务打上稳定 ID,日志中记录任务名、触发时间、执行耗时、产物大小、推送状态。这样不仅能定位问题,还能为后续优化任务频率提供依据。
9.6 安全边界
不要给 Agent 配置过高的文件系统权限和数据库权限。定时任务如果涉及删除文件、修改数据,务必让脚本先打印将要执行的操作,或者要求确认后真正执行。Agent 的自主性提高以后,权限收敛比模型能力更重要。
10. 后续学习方向
这篇文章的核心,是帮你把“定时触发”和“结果推送”接入开源 Agent 工作流。一旦这条路跑通,你可以继续深入四个方向:
- 工具扩展:研究 OpenClaw 的 Action 机制,把公司内部 API 封装成 Agent 可以调用的工具;
- 多任务编排:让一个任务执行完后自动触发另一个任务,形成简单的工作流链;
- 记忆与状态管理:定时任务积累了历史结果后,如何用向量数据库让 Agent 记住过去的状态,下次对比分析;
- 异常自愈:Agent 执行脚本失败后,尝试自动重跑、更换方案、或者把失败信息推送给人类处理。
OpenClaw 这类项目的价值不在于某个模型跑分多高,而在于它让 AI 从一个需要你反复输入的对话窗口,变成真正能定时、定点、主动汇报的自动化节点。如果你手里正好有日报、巡检、监控整理这类重复劳动,不妨按本文的路径搭一个最小闭环。先把一个简单任务跑通,再逐步扩大自动化范围,这条路比一开始就设计宏大的多 Agent 系统要稳得多。
