1. OpenClaw 定时任务为什么总在半夜静默失败
很多人第一次给 OpenClaw 配 Crontab,都会经历同一个剧本:白天手动跑publish-schedule-daily.sh一切正常,日志刷刷地打,文章也发出去了;配成定时任务之后,第二天早上打开后台一看,什么都没发生。没有报错邮件,没有日志新增,crontab -l里那行配置明明还在。
这不是 OpenClaw 的问题,也不是 Crontab 坏了,而是定时任务的运行环境和你的交互式 Shell 环境根本不是一回事。你在终端里敲命令时,PATH、HOME、各种环境变量、当前工作目录都是齐的;Cron 拉起进程时,环境极简,PATH通常只有/usr/bin:/bin,工作目录是当前用户的家目录,bash甚至可能不是你以为的那个bash。OpenClaw 的发布脚本依赖 Node 运行时、依赖工作区路径、依赖 Cookie 文件,这些在 Cron 环境里全部可能找不到。
所以「OpenClaw 定时任务配置详解」这件事,核心不是把 Crontab 那五个星号写对,而是把运行环境、发布脚本、日志监控这三件事串成一条可观测的链路。我试过最省事的做法,是让 Crontab 只负责「在正确的时间调用一个绝对路径的包装脚本」,所有环境准备、路径切换、日志重定向都塞进这个包装脚本里。这样 Crontab 行永远只有一行,排障时只需要看一个文件。
这篇文章面向需要自动化构建与部署的开发者,交付的是可以直接复制的 Crontab 片段、发布脚本模板、日志监控命令,以及任务触发后怎么验证它真的执行成功了。适合谁:已经在本地跑通 OpenClaw 发布流程、想把它变成每天自动运行的人;以及配了定时任务但一直不生效、想搞清楚到底卡在哪一步的人。
下面从 Crontab 表达式讲起,一路走到日志监控和故障排查。每一步都给命令和预期结果,你可以边看边在自己的机器上验证。
2. TaoToken 前置准备:给 OpenClaw 发布脚本接上模型能力
OpenClaw 的发布脚本本身不生成内容,它负责读取当天的文章 JSON、格式化、调用平台接口发布。真正需要模型能力的地方,是内容生成、标题润色、摘要提取这些环节。如果你的 OpenClaw 工作流里包含「定时生成文章再发布」,那发布脚本在跑之前,得先有一个能稳定调用的模型接口。
这里我用 TaoToken 来做模型接入层。它的作用是提供一个统一的 API 入口,让你在脚本里用标准的 OpenAI 兼容格式调用不同模型,不用为每个模型单独改代码。对定时任务来说这点很关键:脚本要无人值守运行,接口地址和鉴权方式必须固定,不能今天换个域名明天换个 Key 格式。
先拿 Key。打开 https://taotoken.net/api-keys ,登录后创建一个 API Key,复制出来。这个 Key 只显示一次,建议直接写进环境变量文件而不是硬编码在脚本里。
Base URL 用https://taotoken.net/api,注意这个地址不带任何查询参数。Model ID 根据你工作流里用的模型填,比如做内容生成常用的是通用对话模型,做代码相关任务可以选 coding 系列。三个要素记牢:Base URL + API Key + Model ID,后面配置文件里会反复用到。
如果你用的是 Claude Code 这类工具做内容润色,TaoToken 也提供了对应的接入方式,文档在 https://taotoken.net/doc 。Cline 的 MCP 配置、Codex 的auth.json配置,思路都一样:把 Base URL 指向 TaoToken,把 Key 填进去,Model ID 选对。
对定时任务场景,我建议把模型配置写成一个独立的环境文件,比如~/.openclaw/.env,内容大致是这样:
# ~/.openclaw/.env export TAOTOKEN_BASE_URL="https://taotoken.net/api" export TAOTOKEN_API_KEY="sk-你的Key" export OPENCLAW_MODEL_ID="你的模型ID" export OPENCLAW_WORKSPACE="$HOME/.openclaw/workspace"然后在包装脚本里source这个文件。这样 Crontab 不需要知道任何模型细节,脚本自己会把环境准备好。为什么不在 Crontab 行里直接写环境变量?因为 Crontab 对环境变量的解析规则和 Shell 不一样,%需要转义,引号处理也容易出问题,写多了必踩坑。
如果你还没有 Coding Plan,长期跑定时任务建议了解一下 https://taotoken.net/coding-plan ,按量或包月的方式对无人值守的自动化任务更友好,不用担心某天额度突然耗尽导致发布中断。
模型对话的调试入口在 https://taotoken.net/models ,配好之后可以先在网页上发一条消息,确认 Key 和模型都通,再去跑脚本。这一步能省掉后面大量「到底是网络问题还是配置问题」的纠结。
3. 可复制配置:Crontab 表达式与发布脚本模板
这一节是全文的核心,给的是能直接抄的配置。先讲 Crontab 表达式,再给包装脚本模板,最后给 OpenClaw 发布脚本本身的调用方式。
Crontab 五个字段的顺序是:分钟、小时、日期、月份、星期。星期里 0 和 7 都代表周日。举几个 OpenClaw 场景常用的:
# 每天 07:00 发布每日文章 0 7 * * * /bin/bash /home/你的用户名/.openclaw/workspace/skills/ai-publisher/scripts/run-publish.sh # 每天 22:00 收集数据指标 0 22 * * * /bin/bash /home/你的用户名/.openclaw/workspace/skills/ai-publisher/scripts/run-fetch.sh # 每周日 22:00 生成周报 0 22 * * 0 /bin/bash /home/你的用户名/.openclaw/workspace/skills/ai-publisher/scripts/run-weekly.sh注意这里调用的不是publish-schedule-daily.sh本身,而是run-publish.sh这个包装脚本。包装脚本的作用是把环境准备好,再调用真正的业务脚本。这是让定时任务稳定的关键设计。
包装脚本模板run-publish.sh:
#!/bin/bash # OpenClaw 定时发布包装脚本 # 位置:~/.openclaw/workspace/skills/ai-publisher/scripts/run-publish.sh set -euo pipefail # 1. 固定 PATH,避免 Cron 环境找不到 node/npm export PATH="/usr/local/bin:/usr/bin:/bin:$HOME/.nvm/versions/node/$(ls $HOME/.nvm/versions/node 2>/dev/null | tail -1)/bin" # 2. 加载模型与环境变量 source "$HOME/.openclaw/.env" # 3. 切换到工作区,避免相对路径失效 cd "$OPENCLAW_WORKSPACE/skills/ai-publisher" # 4. 日志目录与当天日志文件 LOG_DIR="$OPENCLAW_WORKSPACE/skills/ai-publisher/logs" mkdir -p "$LOG_DIR" LOG_FILE="$LOG_DIR/publish-$(date +%Y-%m-%d).log" # 5. 记录开始时间 echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] 定时发布任务启动" >> "$LOG_FILE" # 6. 调用真正的发布脚本,stdout/stderr 全部进日志 if bash scripts/publish-schedule-daily.sh >> "$LOG_FILE" 2>&1; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] 发布任务执行成功" >> "$LOG_FILE" else echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] 发布任务执行失败,退出码 $?" >> "$LOG_FILE" exit 1 fi这个脚本里有几个细节值得说。set -euo pipefail让脚本遇到错误立即退出,不会带着错误状态继续往下跑。PATH里手动拼了 nvm 的 node 路径,因为 Cron 不会加载你的.bashrc,nvm 管理的 node 在 Cron 里默认是找不到的。cd到工作区是因为 OpenClaw 的发布脚本内部用了相对路径读文章 JSON,不切目录会报文件不存在。
如果你用 Cline 的 MCP 方式接入模型,配置片段长这样,放在 Cline 的 MCP 设置里:
{ "mcpServers": { "taotoken": { "command": "npx", "args": ["-y", "@taotoken/mcp-server"], "env": { "TAOTOKEN_BASE_URL": "https://taotoken.net/api", "TAOTOKEN_API_KEY": "sk-你的Key", "TAOTOKEN_MODEL_ID": "你的模型ID" } } } }Codex 的auth.json配置,路径通常在~/.codex/auth.json:
{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key", "model": "你的模型ID" }Claude Code 的配置在~/.claude/settings.json或项目级.claude/settings.json:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key", "ANTHROPIC_MODEL": "你的模型ID" } }三件套永远是 Base URL、Key、Model ID,缺一个都跑不起来。配好之后,把包装脚本加上执行权限:
chmod +x ~/.openclaw/workspace/skills/ai-publisher/scripts/run-publish.sh然后手动跑一次,确认脚本本身没问题,再去配 Crontab。手动跑的命令:
bash ~/.openclaw/workspace/skills/ai-publisher/scripts/run-publish.sh跑完看日志文件有没有生成,内容对不对。这一步过了,Crontab 才有意义。
4. 验证请求:任务触发后怎么确认真的执行成功
配完 Crontab 不代表任务会跑,跑了不代表跑成功。这一节讲怎么验证,从「任务有没有被触发」到「发布有没有真的生效」,一层层往下查。
第一层,确认 Crontab 配置已经生效:
crontab -l输出里应该能看到你加的那几行。如果看不到,说明保存没成功,重新crontab -e编辑。
第二层,确认 Cron 服务在运行。Linux 上:
systemctl status cronmacOS 上 Cron 是 launchd 管理的,用:
sudo launchctl list | grep cron服务没起来的话,任务永远不会触发。
第三层,看日志文件有没有新增。这是最直接的证据:
tail -f ~/.openclaw/workspace/skills/ai-publisher/logs/publish-$(date +%Y-%m-%d).log如果日志文件根本没生成,说明包装脚本没被执行,问题在 Crontab 或 Cron 服务。如果文件生成了但只有「任务启动」没有后续,说明包装脚本执行了但业务脚本卡住或报错,往下看 stderr 内容。
第四层,验证模型接口是否通。在包装脚本的环境里手动发一个请求:
source ~/.openclaw/.env curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "'"$OPENCLAW_MODEL_ID"'", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 10 }'返回里如果有choices字段,说明接口通。如果返回 401,是 Key 问题;如果返回local proxy failed或连接超时,是网络或 Base URL 问题;如果返回里choices是空的,是 Model ID 写错了。
第五层,验证发布结果。日志里出现「发布成功」还不够,去目标平台后台确认文章真的出现了。OpenClaw 的发布脚本通常会在日志里记录平台返回的文章 ID 或 URL,拿这个去核对。
一个完整的成功日志长这样:
[2026-03-13 07:00:01] [INFO] 定时发布任务启动 [2026-03-13 07:00:02] [INFO] 读取文章:ai-originally-so-008.json [2026-03-13 07:00:03] [INFO] 调用模型生成摘要... [2026-03-13 07:00:08] [INFO] 摘要生成完成 [2026-03-13 07:00:09] [INFO] 发布到 CSDN... [2026-03-13 07:00:45] [INFO] CSDN 发布成功,文章 ID: 12345678 [2026-03-13 07:00:46] [INFO] 发布任务执行成功看到最后一行「发布任务执行成功」,才算真的成功。中间任何一步断了,日志会停在那一行,你就知道该查哪里。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
定时任务跑不起来,报错就那么几类。这一节按真实报错信息对照排查,每条都给原因和动作。
401 Unauthorized。日志里出现401或invalid api key,说明 Key 不对或没传。检查~/.openclaw/.env里的TAOTOKEN_API_KEY是不是复制完整了,有没有多余空格。Cron 环境里如果没source这个文件,Key 就是空的,请求自然 401。确认包装脚本里有source "$HOME/.openclaw/.env"这一行。
local proxy failed。这个报错通常出现在请求发不出去的时候,可能是 Base URL 写错,也可能是本机网络策略拦截。先确认TAOTOKEN_BASE_URL是https://taotoken.net/api,没有多余路径。然后用第 4 节的 curl 命令手动测一次,curl 通而脚本不通,说明是脚本环境问题;curl 也不通,说明是网络或地址问题。
reading choices 相关报错。日志里出现cannot read property 'choices' of undefined或类似,说明接口返回的结构和脚本预期的不一样。常见原因是 Model ID 写错,接口返回了错误对象而不是正常的 completion 结构。把 Model ID 换成确认可用的,再跑一次。也有可能是请求体格式不对,比如messages数组为空。
OAuth 相关报错。如果你用的是 Claude Code 或 Codex 这类带 OAuth 流程的工具,报错里出现OAuth token expired或refresh token failed,说明登录态过期了。这类工具需要重新走一次授权,或者改用 API Key 方式接入。用 TaoToken 的 API Key 方式可以绕开 OAuth 的过期问题,对无人值守的定时任务更合适。
任务没触发,日志文件都没生成。按顺序查:crontab -l有没有那行;Cron 服务在不在跑;包装脚本路径是不是绝对路径;脚本有没有执行权限。Crontab 里必须用绝对路径,~在 Crontab 里不一定展开成你的家目录。
任务触发了但立刻退出。看日志里有没有「任务启动」后面直接跟「执行失败」。这种情况多半是set -e在某个命令上触发了退出,比如source的文件不存在、cd的目录不存在。把包装脚本里的set -euo pipefail临时改成set -x调试,能看到每一步执行了什么。
发布成功但内容不对。日志显示成功,但平台上的文章是旧的或空的。检查 OpenClaw 读取的文章 JSON 路径对不对,cd的工作区是不是正确。Cron 的工作目录默认是家目录,不cd的话相对路径全错。
排查的核心思路是:先确认任务被触发,再确认脚本被执行,再确认接口被调用,最后确认结果被写入。四层里哪层断了,问题就在哪层。日志文件是唯一的真相来源,所有输出都往日志里写,不要依赖终端回显。
6. 把定时任务接进你的 OpenClaw 工作流
到这里,Crontab 表达式、包装脚本、日志监控、故障排查都齐了。回到最开始那个问题:为什么手动跑正常、定时跑就失败?因为定时任务的运行环境是「干净」的,你得自己把环境补齐。包装脚本就是干这个的。
如果你还没配模型接入,先去 https://taotoken.net/api-keys 拿一个 Key,把 Base URL、Key、Model ID 三件套写进~/.openclaw/.env。接入文档在 https://taotoken.net/doc ,里面有各工具的详细配置。想先试试模型通不通,去 https://taotoken.net/models 发条消息最快。长期跑自动化任务的话,https://taotoken.net/coding-plan 的额度方式更适合无人值守场景。
配好之后,建议先手动跑三次包装脚本,确认每次都成功,再挂 Crontab。挂上之后盯两天日志,确认触发时间和执行结果都符合预期。稳定之后就可以不用管了,它会每天按时干活,日志留在那里,出问题随时能查。
最后留一个实用习惯:每周备份一次 Crontab 配置,命令是crontab -l > ~/crontab-backup-$(date +%Y%m%d).txt。机器重装或迁移时,这一行能省你半小时。