改个模型名,两个定时任务静默死了:一次定义与引用的分离事故

排障实录 02:改个模型名,把两个定时任务搞死了

2026-10-20 | 真实故障复盘 | 一个改名引发的连锁反应


一句话结论

改配置的时候,你改的是"定义";但系统里还有一堆地方存的是"引用"。定义改了,引用全断。

我改了一个模型名,一周内两个自动化任务静默失败,直到我截图排查才发现。


一、事故现场

一张控制台截图,顶部一条红色警告:

arduino 复制代码
部分模型无法刷新。请打开"模型"重试。

任务列表里两条红色:

任务 计划 上次运行 状态
RSI素材日收集 每天 23:00 15 小时前 ❌
behavior_loop周检 每周一 09:00 27 小时前 ❌

它们已经连续失败了,但没有任何人收到通知 ------因为这两个任务都设了 delivery: none(静默模式)。


二、捞错误日志

bash 复制代码
# 列出所有自动化任务及其状态
openclaw automations list

关键字段出来了:

json 复制代码
{
  "name": "RSI素材日收集",
  "lastRunStatus": "error",
  "lastRunError": "automation model override 'deepseek-direct/deepseek-v4-flash' \
    rejected by agents.defaults.modelPolicy.allow: \
    deepseek-direct/deepseek-v4-flash is not in [api88/..., blockrun/..., \
    deepseek-direct/deepseek-flash, deepseek-direct/deepseek-v4-pro, ...]"
}

翻译成人话:

  • 任务里写死了模型 deepseek-direct/deepseek-v4-flash
  • 但允许清单里只有 deepseek-direct/deepseek-flash
  • 名字差一截,直接被拒绝执行

三、根因:三天前的一次改名

三天前我把模型名对齐到官方新命名:

diff 复制代码
- "deepseek-v4-flash"   (旧名)
+ "deepseek-flash"      (新名,指向同一个后端)

改的时候我只做了两件事:

  1. 改了 provider 的模型表
  2. 改了全局默认模型

漏了第三件事:检查有哪些任务/会话在硬编码引用旧名。

结果:

  • 2 个自动化任务 → 失败
  • 若干旧会话 → 界面上还显示旧名(但不影响运行,因为旧名 API 仍可调用)

四、修复

不需要重建任务,只需要改任务里的模型覆盖字段:

bash 复制代码
# 方式一:通过工具更新
automations update <jobId> '{"payload":{"model":"deepseek-direct/deepseek-flash"}}'

修复后:

任务 旧模型 新模型 下次运行
RSI素材日收集 deepseek-v4-flash ❌ deepseek-flash ✅ 今晚 23:00
behavior_loop周检 deepseek-v4-flash ❌ deepseek-flash ✅ 下周一 09:00

注意:lastRunStatus 不会自动刷新,要等下次实际运行成功才会变绿。这期间界面上还是红叉,属于正常现象。


五、顺手发现的第二个坑

改任务的时候注意到,behavior_loop周检 的 message 字段是:

erlang 复制代码
峰哥行为层RSI闭环:每周自动扫描 corrections.md → 归集 → 标晋升...

结尾是个省略号------指令被截断了。

任务即使能跑,也会因为指令不完整而跑偏。

这说明:任务的 prompt 本身也会被截断,长指令要检查完整性。


六、第三个坑:白名单失真

排查时顺便看了模型白名单:

bash 复制代码
# 白名单原本 59 条

其中:

  • api88/* 和 blockrun/* 占 55 条
  • 但 api88 的 token 报 401 Invalid token,blockrun 早就在冷却期

一个白名单里 93% 是死条目,等于形同虚设。

更严重的:安全审计报过一条 CRITICAL------

arduino 复制代码
Small models (<=300B params) detected: api88/qwen3.5-35b-a3b
  @ agents.defaults.model.fallbacks (unsafe; sandbox=off; web=[web_search, web_fetch, browser])

一个 35B 小模型,带联网工具,没有沙箱------它如果被 fallback 选中,就是个风险。

修复:白名单从 59 条砍到 4 条,全是实际在用的:

arduino 复制代码
deepseek-direct/deepseek-flash      text+image
deepseek-direct/deepseek-v4-pro     text
deepseek-direct/deepseek-chat       text
deepseek-direct/deepseek-reasoner   text

七、四条可以抄走的经验

  1. 改任何一个"名字",都要全局搜一遍引用。 模型名、插件名、agent 名都一样。
  2. 静默任务失败了不会有人告诉你。 关键任务至少配一个失败告警通道。
  3. 任务 prompt 也会被截断。 长指令要检查结尾完整性。
  4. 白名单不是越多越安全。 一堆失效条目反而掩盖真正的风险。

八、一个更普适的教训

这次故障不是"改错了",而是"改完之后没有验证引用完整性"。

配置系统里,定义(definition)和引用(reference)是分开存储的 。改定义的时候,引用不会自动跟着变,也不会报错------它只会在被使用的那一刻失败。

而如果那个"使用"发生在半夜、发生在静默任务里、发生在没有告警的地方,你就永远不知道它坏了。


所有日志和命令都是真实的,可复现。

相关推荐
知守观1 小时前
从 4 套 PDF 库的混战,聊聊老项目的依赖管理与“静默失败”
java·后端·设计模式
用户072367066601 小时前
基于 JavaAgent 的无侵入 Mock:让联调和链路测试不再等下游
java·后端
小蒜学长1 小时前
基于SpingBoot+Vue的定向越野赛事管理系统的设计与开发(代码+数据库+LW)
java·前端·spring boot·后端·前后端分离·定向越野赛事
海岳云舟1 小时前
spring自带线程池使用不当导致的死锁问题
java·后端
写码跑山的老艾1 小时前
10 张图看懂:一次 MySQL 刷数,为什么压垮了 ES?
后端
姜鱼问生1 小时前
获取的全是 172 开头的假 IP?Nginx 反代后,Flask 怎么才能拿到真实访客 IP?
后端
小蒜学长1 小时前
基于过程性评价的ai助学平台(代码+数据库+LW)
java·spring boot·后端·微信小程序·过程性评价
陈随易1 小时前
副业搞钱点子之 Umami 统计如何赚钱
前端·后端·程序员