
把OpenClaw从“装好”推到“能用好”中间往往就是一份透着血泪的配置文件。上一篇文章带大家完成了安装部署这篇我把配置这一关彻底讲透主配置的结构怎么组织、任务调度怎么写才抗造、通知通道怎么接能确保不漏报、安全项怎么设不给自己挖坑以及那些光看报错很难猜透的隐蔽问题。不管你是刚装好OpenClaw想跑通第一个任务还是已经跑了几周准备把配置从“能跑”优化成“放心挂机”这篇文章都值得按顺序读完。我见过不少人在装好OpenClaw之后把示例配置拿来就改改一步跑一次报错就注释掉。任务少的时候还能糊弄等到了几十个任务、多通道通知全接上之后那份配置基本就是一团打满补丁的意大利面。OpenClaw的配置体系其实没有那么复杂核心就围绕“实例信息、任务编排、通道推送、安全校验”四块难点在于搞清楚每个字段背后的行为逻辑而不是语法本身。1. 拿到OpenClaw之后先把这份主配置读懂1.1 配置文件在哪、由哪几块组成OpenClaw安装完成后会在当前用户目录下生成一个.openclaw目录。Linux环境下是~/.openclaw/Windows环境下是C:\Users\你的用户名\.openclaw\。主配置文件名固定为openclaw.yaml它负责整个OpenClaw实例的运行参数另外还有一个secrets.yaml专门用来存放密钥类敏感信息后面我会专门讲这两个文件的分工这里先记住一个原则凡是token、密码、API密钥一律不许直接写进openclaw.yaml。打开openclaw.yaml你会看到典型的四段式布局instance: name: home-server timezone: Asia/Shanghai data_dir: ~/.openclaw/data scheduler: polls_per_minute: 60 jitter: true history_days: 30 tasks: - name: example_task trigger: type: cron expr: 0 9 * * * command: type: shell script: echo hello channels: [default_email] channels: - name: default_email type: smtp ...这四个根节点分别对应instance描述OpenClaw自己scheduler描述调度器的运行行为tasks是你真正要跑的任务列表channels是任务执行结果的输出去向。初次上手最需要改的是instance和第一个tasks其余字段保持默认即可。1.2 先改这几个实例级参数instance里的字段很多人直接跳过等到出问题才回头补。其中timezone是最容易被忽略的OpenClaw的cron表达式默认走的是系统时区但如果你的服务器是UTC而人生活在中国标准时间那么0 9 * * *就会在下午五点触发而不是早上九点。为了避免这种错乱我建议不管服务器是什么时区都在instance.timezone里显式写上你的业务时区。data_dir决定任务状态、历史记录、缓存数据的落盘位置。默认放在~/.openclaw/data如果/分区空间吃紧建议把它挪到大容量磁盘配置成绝对路径即可。polls_per_minute表示调度器每分钟轮询一次任务列表的次数默认60就够用不用调大。除非你的任务时间精度要求到秒级否则调高只会增加无谓的系统开销。还有一点改完instance段后需要重启OpenClaw服务才能生效它不在热加载范围内。后面要讲的热加载只覆盖tasks和channels段。1.3 环境变量与密钥文件的边界secrets.yaml的职责只有一个保存不该进代码仓库的敏感值。# secrets.yaml smtp_password: your-smtp-password webhook_signing_key: xxxxxxxx api_keys: data_api: sk-xxxxxx引用方式是在openclaw.yaml里通过${secrets.smtp_password}这类模板语法取值。OpenClaw启动时会把secrets.yaml的内容加载进内存之后所有任务运行时都只从内存读取不会在日志里打印具体值。如果你不想用文件保存OpenClaw也支持直接从环境变量取比如${env:MY_TOKEN}。我个人的混合方案是openclaw.yaml里不出现任何真实密钥只引用secrets.yaml或环境变量secrets.yaml用完后设置文件权限为600并且加入.gitignore。这样即使配置文件被迫分享出去泄露的也只是引用名不是真实值。2. 任务调度配置从“能跑”到“靠谱”2.1 定时、周期、一次性三种触发方式的使用场景OpenClaw的任务触发方式在tasks[].trigger.type里定义共三种cron、interval和once。cron适合固定在某个时间点执行的任务比如每天早上九点生成报表- name: daily_report trigger: type: cron expr: 0 9 * * *interval适合固定间隔执行的任务比如每五分钟拉取一次接口数据- name: data_puller trigger: type: interval every: 5mevery字段的单位支持s、m、h、d如果你写every: 60而不是every: 60sOpenClaw默认按秒解析新手经常在这里栽跟头。once则用于只跑一次的一次性任务比如迁移后清理临时文件。它通常在openclaw run手动触发时使用不需要写在常驻配置里。三种方式里最容易出错的是cron的表达式解析。OpenClaw使用标准的五段式cron分 时 日 月 周不是某些工具采用的六段式。周字段如果是0在多数实现里表示周日但部分实现里7也表示周日。为了保险我建议周日一律写成0避开实现差异。2.2 超时与重试最容易被低估的字段很多人的第一个任务只有三行名字、触发表达式、命令。看起来能跑但实际上缺了两个关键字段timeout和retry。先看timeout。OpenClaw默认不限制任务执行时长听起来很美好实测下来很坑某个网络请求如果一直不返回任务就永远占着执行槽位后续任务被阻塞调度器状态越来越乱。我的一贯做法是给每个任务都显式设置超时即使最简单的shell命令也设置timeout: 60s。内部脚本如果设计得当60秒绝对够用如果超时了那说明脚本本身有问题没必要让它无限挂下去。再看retry。OpenClaw的重试策略默认关闭即任务失败后直接进入失败通道不会再次执行。对于数据拉取这类网络任务瞬时抖动很常见我建议设置2到3次重试。注意重试间隔不是固定值OpenClaw使用指数退避策略默认从10秒开始每次翻倍最大到5分钟。这个设计比较科学避免任务失败时所有任务同时重试形成风暴。- name: data_puller trigger: type: interval every: 5m command: type: python entry: puller_main.py timeout: 90s retry: times: 3 on_timeout: false这里有个细节on_timeout默认是true即超时也算失败并参与重试。我建议在对外部系统的请求任务里把它设为false因为超时往往说明目标系统已经过载立刻重试大概率还会超时不如直接放弃等下一个周期再处理。2.3 任务依赖与并发上限当一个任务需要等另一个任务跑完之后才能执行就需要用到depends_on。比如先拉取数据再生成报表再推送通知三者之间存在先后关系。- name: pull_data ... - name: gen_report depends_on: - task: pull_data status: success ...status表示上游任务必须达到的状态可选success、finished、any。success要求必须成功finished只要跑完就行不区分成败any是前两者的并集几乎用不到。我推荐使用success让失败的任务直接阻断下游避免生成一份基于残缺数据的报表。并发方面OpenClaw默认是串行执行任务即同一时刻只有一个任务在运行。如果你的任务里有耗时长的处理又不希望它阻塞后面的定时任务可以给任务打上execution_group标签- name: heavy_job execution_group: background ...同一个组里的任务串行执行不同组的任务可以并行。在四核以下的机器上我建议最多开两个组再多并行会明显拉高负载反而拖慢所有任务。3. 通知与联动通道配置3.1 多通道输出不是越多越好是要分场景任务执行完结果总得让人知道。OpenClaw的channels节点就是干这个的。支持的类型常见有smtp邮件、webhook通用HTTP回调、local写入本地日志/通知文件。多配几个通道本身没有错但如果你把每个通道都挂在所有任务上那等于没有通知——因为真正重要的消息会被淹没在无关消息里。我的做法是按消息级别分流通道名称类型用途critical_emailsmtp只在任务失败时发邮件alert_webhookwebhook任务失败或重试耗尽时推送到群机器人archive_loglocal所有任务结果统一写日志归档这样的好处是日常噪声只落在日志通道真正需要人工介入的情况只通过critical_email和alert_webhook触达。OpenClaw支持在任务的notify字段里指定触发条件和通道而不是简单的channels列表。3.2 Webhook 通道的完整配置一个典型Webhook通道长这样- name: alert_webhook type: webhook endpoint: https://your-domain.example/callback method: POST headers: Content-Type: application/json X-Signing-Key: ${secrets.webhook_signing_key} body_template: | { task: {{ task.name }}, status: {{ task.status }}, message: {{ task.stderr | default() }} }body_template是OpenClaw通道配置里最有用的字段。它支持{{ }}模板语法把任务名称、状态、输出信息填充进去按接收端要求的格式组装payload。注意headers里的密钥值必须从secrets.yaml引用不要明文写。还需要注意一个网络层面问题如果OpenClaw部署在内网Webhook目标又在公网你必须确保网络策略允许这个出站请求。这类问题最容易在OpenClaw日志里表现为connection timeout或503但原因其实在网络边界不在OpenClaw本身。3.3 任务里怎么精确指定通知模板任务节点上的notify允许你按执行状态分别定义通知逻辑- name: daily_report ... notify: on_failure: channels: [critical_email] retry_exhausted: true on_success: channels: [archive_log]retry_exhausted: true的意思是“重试全部耗尽后最终失败”时触发通知。这个字段很多人漏掉如果你的任务设置了3次重试而只配置了on_failureOpenClaw默认在第一次失败时就会通知而不是重试耗尽后才通知。你会发现收了一封“失败”邮件任务却在第二次重试里成功了属于典型的狼来了。加上retry_exhausted: true才能保证通知是一条真正需要处理的失败消息。关于on_success通知建议设置得保守一点。数据拉取这类高频任务每次成功都发邮件纯粹是浪费精力归档到本地日志就好。只有对“一天只跑一次且没有结果就无法推进”的关键任务才值得在成功时推送一个确认消息。4. 安全与校验让配置变更不再胆战心惊4.1 内置校验命令发布前必跑的一步OpenClaw提供了三条和配置相关的命令组合起来可以覆盖绝大部分问题openclaw config validate openclaw config test --task daily_report openclaw config dry-run --task daily_reportconfig validate做静态检查解析YAML并检查字段类型、必填项、依赖关系是否成环。它不一定能发现所有问题但能把语法问题和明显的结构问题挡在发布之前。config test会不真正执行脚本只验证命令类型、入口文件、任务依赖能否正确解析。dry-run则是完整执行一遍任务流程但把外部副作用如发送邮件、发起HTTP请求替换成模拟执行输出日志告诉你“这一步会请求谁”、“那一步会写入什么”。我个人的上线流程是这样的改完配置先validate再做一次test最后跑一次dry-run确认无误后才动生产配置。这三步都很快最慢的也就几秒钟。4.2 密钥脱敏与文件权限OpenClaw默认在每个任务的日志里记录命令入口和输出摘要。如果你的脚本里出现curl -H Authorization: Bearer xxxx ...日志记录的是命令模板本身真实密钥不会落盘。但要注意如果你的脚本把密钥打印到标准输出那它就会进日志文件。secrets.yaml的权限Linux下执行chmod 600 ~/.openclaw/secrets.yaml确保只有当前用户能读写。Windows下则要确保该文件不被同步到云盘或纳入版本控制。我见过最离谱的事故就是有人把整个.openclaw目录打包分享出去里面躺着真实的数据库密码结果自然是灾难性的。4.3 热加载的边界什么改了要重启OpenClaw支持openclaw reload命令平滑加载新配置但这个热加载有边界tasks和channels的改动热加载生效运行中的任务不受影响新任务在下个调度周期按新配置执行。instance和scheduler的改动必须重启服务才生效。插件代码的改动必须重启服务因为Python模块加载到内存后不会自动重新加载。记住这一点能帮你省掉不少排查时间。比如你把polls_per_minute从60改成120然后reload了一番发现没有任何变化不是配置没生效而是它根本不在热加载范围内。直接重启服务再确认openclaw status里的配置指纹变了没。5. 一个完整的配置示例每日数据汇总任务5.1 从需求拆解到配置落地光讲零散字段不好理解我直接给一个实际场景的完整配置。假设需求是每天凌晨2点拉取某业务接口的昨日数据做一次本地汇总计算然后把汇总表推送到工作群里如果失败就发一封紧急邮件。拆解一下需要三个阶段定时触发器cron表达式0 2 * * *。主任务拉取数据、执行汇总。通知通道一个Webhook用于工作群推送一个STMP用于失败邮件。配置落地如下instance: name: ops-worker timezone: Asia/Shanghai data_dir: /data/openclaw channels: - name: work_webhook type: webhook endpoint: https://your-domain.example/webhook method: POST headers: Content-Type: application/json body_template: | { task: {{ task.name }}, status: {{ task.status }}, time: {{ task.started_at }}, summary: {{ task.stdout | default() | truncate(500) }} } - name: alert_email type: smtp host: smtp.example.com port: 465 username: openclawexample.com password: ${secrets.smtp_password} from: openclawexample.com to: [opsexample.com] subject_template: [OpenClaw] 任务失败: {{ task.name }} tasks: - name: daily_data_report trigger: type: cron expr: 0 2 * * * command: type: python entry: daily_report.py args: [--date, {{ now | date_delta(days1) | format_date(%Y-%m-%d) }}] timeout: 300s retry: times: 2 on_timeout: false notify: on_failure: channels: [alert_email] retry_exhausted: true on_success: channels: [work_webhook]这个例子里有一个实用的模板语法{{ now | date_delta(days1) | format_date(%Y-%m-%d) }}。它把当前时间减一天再格式化成YYYY-MM-DD直接作为daily_report.py的参数传进去。这样任务拿到的就是“昨日”这个语义不需要在Python脚本里再处理时区偏移。5.2 分阶段验证先本地手动跑再挂定时新配置上线我强烈建议先不要直接挂定时。做法是openclaw run daily_data_reportrun命令会忽略trigger配置立刻执行一次任务。我每次新写任务都先这样手动跑一遍确认脚本逻辑无误、通道推送正常然后再收回定时调度。如果你跳过这一步直接等定时触发遇到问题就只能在凌晨蹲日志体验很糟糕。手动跑通之后再执行openclaw reload openclaw statusstatus会列出正在生效的任务名、下次触发时间、最近执行结果。确认daily_data_report下次触发时间是次日凌晨2点就算完成部署了。5.3 后续还能怎么扩展这个配置模板的可扩展性很好。比如你希望“拉数据”和“汇总计算”分开成两个任务只需把daily_report.py拆成两个脚本然后加一个depends_on关系。再比如你希望每周一发一份周报可以新加一个任务cron表达式写成0 9 * * 1复用同一个Webhook通道。有一点经验值得多说通道配置一旦稳定就不要轻易改动。Webhook回调方的密钥轮换、SMTP密码更换都要在低峰期操作并且改完必须跑一次config test。因为这类配置的错误不是马上能发现的很可能到了真正需要推送时才静默失败那才是真正头疼的时刻。6. 高频踩坑这些配置错误我见过太多6.1 cron 时区与时间语义的错位时区问题是OpenClaw配置里最常见的坑。前面说了要在instance.timezone里显式设置但这还不够如果你的脚本里用了datetime.now()它读的是系统时区不一定与你设置的OpenClaw时区一致。我处理这个问题的办法是在脚本里不依赖系统时区而是显式使用OpenClaw传入的--date参数或者从环境变量OPENCLAW_TZ读取时区值。这样无论把OpenClaw迁移到哪个服务器上业务时间语义都不会变。另外注意节假日和夏令时问题。cron表达式的0 2 * * *在夏令时切换的当天可能会被跳过或重复触发。国内无所谓但如果你的任务目标在欧洲或北美业务线建议在业务侧做幂等设计同一数据被计算两次结果应该一致。6.2 YAML缩进、锚点与特殊字符YAML的缩进错误几乎每个接触过的人都被坑过一次。OpenClaw的配置解析器对缩进敏感tasks列表下的每个- name:必须保持同样的缩进层级。这个错误在validate阶段基本都能被发现但有一种错误很难发现字段拼写正确、缩进正确但层级错了。比如tasks: - name: demo command: type: shell这里type: shell被接到了command的同级而不是command的子字段。validate可能不会报错因为从YAML结构上看它是合法的但command会变成一个空对象任务类型解析失败。怎么避免写完配置后一定跑config test缺了这条光看YAML很难揪出来。还有一个技巧用YAML锚点复用配置。多个任务如果共享同样的retry和timeout配置可以这样写defaults: defaults timeout: 60s retry: times: 2 tasks: - name: task_a : *defaults command: ... - name: task_b : *defaults command: ...: *defaults会在解析时展开默认值。这样后续要统一调整超时只需改一处非常实用。6.3 路径分隔符与转义跨平台迁移OpenClaw配置时路径是最易踩的雷。在Linux的shell任务里可以直接写/data/scripts/run.sh但如果在Windows的cmd环境下写同样的路径会直接失败。OpenClaw没有自动做路径分隔符转换不同平台如实照用。我的建议是任务脚本路径尽量以相对路径定位到入口文件而不是写绝对路径然后在instance.data_dir中指定工作目录- name: task_with_script command: type: shell script: scripts/run.sh workdir: ~/.openclaw/data这样跨平台迁移时只需改instance.data_dir任务配置不用动。还有一种路径相关的问题脚本里包含空格。YAML里的字符串含空格不需要引号包裹但如果路径本身以#或:开头就建议用单引号包起来避免被YAML误解为注释或键值分隔。6.4 版本升级引起的兼容问题OpenClaw版本升级后配置报错的概率其实不低。我在升级之后固定做三件事先看openclaw changelog里的Breaking Changes再跑config validate最后用openclaw run手动触发几个关键任务做回归。常见的兼容性问题包括旧配置里的某字段在新版本里改名、某个通道类型被合并、模板语法的过滤器名发生变化。这类问题在validate阶段大多能暴露出来但有些是运行期才报错的所以才需要手动回归。如果你长期维护OpenClaw配置建议在本地留一份“升级前备份”升级后对比openclaw status --verbose输出的配置指纹。这个指纹是配置内容的哈希值只要指纹变了说明实际生效配置已经和磁盘上的文件一致了。6.5 任务日志被反复清理的错觉最后说一个不算报错但很影响排查的坑history_days字段控制历史记录保留时长。如果你设了7天那七天后你去查一个“突然不推送”的任务日志发现已经是空的了——不是任务没执行而是执行记录被清理了。排查低频任务的问题时我建议临场先把history_days调大到30定位完再调回来。如果你有集中式日志系统也可以在系统的channels下挂一个local通道做永久归档每个任务都写一份task.stdout到指定文件这样即使在数据丢失后也有原始依据可用。这些都是我在大量配置实践中踩出来的经验。OpenClaw的配置不难难的是理解每个字段背后的行为边界。按照这套流程走下来你把任务挂上定时之后基本就可以安心等到下一次通知推送了。