📎 配套脚本附件正文未内嵌 · 共 2 个 · 点开可在线查看
📚 另需公共库(正文未重复内嵌,点名字直接看):_bootstrap.py、_config.py
📂 查看全部 761 个脚本附件 →
⚠️ 脚本内含明文凭据(与本页正文一致),请勿在公网环境直接运行。
排障

专题十七 · OpenAI 插件升级后 schema 补丁丢失

1.0.3 有补丁、1.0.4 无补丁 → qwen 不可用 / Base model not found;全版本重打补丁。

专题十七 · OpenAI 插件升级后 Qwen「不可用」与配置页 schema 报错

症状:Agent 配置页模型标「不可用」;右侧红框堆栈落在 get_ai_model_schema / get_customizable_model_schema;plugin_daemon 日志出现 Base model qwen3.6-27b not found;GET /workspaces/current/models/model-types/llm 的 data 变空或模型不再 active。

根因:OpenAI 兼容插件从旧版本(如 1.0.3)升级到新版本(如 1.0.4 / 1.0.5)后,专题一的 schema 补丁只留在旧目录,运行时加载的是未打补丁的新目录。

根治:Dify 默认会每天定时自动升级插件。不改自动升级策略,补丁永远会被下一次升级冲掉 → 已把 model 类的自动升级关闭,并把 langgenius/openai 加进排除名单(§5,2026-09-24 起生效)。

环境:192.168.110.207 Dify plugin_daemon 卷 langgenius/openai-*@*/models/llm/llm.py

HTML:docs/html_cursor/Dify_专题十七_OpenAI插件升级后schema补丁丢失_cursor.html


1. 现象对照

你看到的实际含义
模型旁橙标「不可用」插件无法为该自定义模型派生 schema
配置页红框 + get_ai_model_schema控制台请求模型 schema 时插件抛错
工具「未授权」同时出现多半是连带 UI 状态;OpenAPI auth_type=none 本身常显示未授权,主因仍是模型 schema
「之前好好的,突然坏了」常见于插件静默升级 / 重装,旧补丁目录还在但已不加载
「修好过,过几天又坏」自动升级又装了一个新版本目录——说明 §4 的补丁只是治了标,没做 §5 的根治

2026-08-31 实录(作业7 自愈 Agent 配置页)

2026-10-13 复查(同一台机器,补丁已跟上,策略已固定)


2. 原理(为什么会「突然」)

text
Dify 控制台 / Agent 配置页
  → plugin_daemon 按「当前启用的 openai 包版本」加载 llm.py
  → get_customizable_model_schema(qwen3.6-27b)
  → 按 OpenAI 预定义基座名查找
  → 找不到 → 抛 Base model … not found(未打补丁时)
  → 模型列表为空 / 标不可用 / 配置页 500 式红框

专题一补丁的作用:找不到基座时 clone 一个 chat 模板 schema(context_size=64000),模型即可 list / active。

插件升级后目录变成:

text
.../cwd/langgenius/
  openai-1.0.3@旧hash/models/llm/llm.py   ← 有补丁(但不再被用)
  openai-1.0.4@新hash/models/llm/llm.py   ← 无补丁(运行时用这个)

旧脚本若用 ls … | head -1,可能永远只打到 1.0.3,误报 already patched。

2.1 「自动」是怎么发生的:每日定时检查任务

不是 plugin_daemon 启动时做的,而是 dify-api 里的 Celery 定时任务:

text
dify-api  celery task
  tasks/process_tenant_plugin_autoupgrade_check_task.py
    → 按 category 读 tenant_plugin_auto_upgrade_strategies(6 行)
    → 到 marketplace 拉这些插件的 manifest(结果缓存进 Redis,TTL 1h)
    → 比对「已安装版本 vs 最新版本」
    → 满足策略的 → 排一个升级任务 → plugin_daemon 下载新版本
    → 卷里多出一个 openai-<新版本>@<新hash>/ 目录(旧的不会删)
    → 运行时只加载新目录 → 补丁落空 → 模型「不可用」

关键点:

事实含义
升级是按 category 分组做的(tool / model / extension / agent-strategy / datasource / trigger)openai 属于 model 类,只需治这一行
每个 category 一行策略,UNIQUE(tenant_id, category)不要新增行,只 UPDATE category='model' 那一行
有 upgrade_time_of_day(当天第几秒)到点才跑,所以「某天早上来就坏了」很典型
旧版本目录不会被清掉所以现场会看到多个 openai-*@* 并存,判断时别只看第一个

3. 快速判定(2 分钟)

在 207:

bash
# 0) 【先看这个】自动升级策略 —— 决定「补丁会不会被下一次升级冲掉」
docker exec docker-db_postgres-1 psql -U postgres -d dify -c \
  "select category, strategy_setting, upgrade_mode, exclude_plugins::text,
          to_char(updated_at,'YYYY-MM-DD HH24:MI') as updated
     from tenant_plugin_auto_upgrade_strategies order by category;"

# 1) 有哪些 openai 版本目录
docker exec docker-plugin_daemon-1 sh -c \
  'ls -d /app/storage/cwd/langgenius/openai-*@*/models/llm/llm.py'

# 2) 哪份已有专题一标记
docker exec docker-plugin_daemon-1 sh -c \
  'grep -l "Fallback for custom / non-OpenAI base models" \
   /app/storage/cwd/langgenius/openai-*@*/models/llm/llm.py 2>/dev/null'

# 3) 近期是否仍在报 Base model
docker logs --since 10m docker-plugin_daemon-1 2>&1 | grep -E 'Base model|qwen3.6' | tail

一条命令看全三块(推荐):

bash
python scripts_cursor/Dify_专题十七_OpenAI插件升级后schema补丁丢失/专题十七_01_查看插件自动升级策略.py
判定结论
存在多个 openai-*,且最新版 没有 Fallback 标记就是本专题 → 走 §4 修复
最新版已有标记,但 LLM 列表仍空再查凭据 / 专题十;或重启 plugin_daemon 未生效
只有模型错选(如真选了不存在的 qwen1.5-72b)且列表里 qwen3.6-27b 仍 active改回 qwen3.6-27b 即可,不必重打补丁
model 行 strategy_setting 不是 disabled补丁迟早被冲掉 → 补做 §5 的根治
model 行已是 disabled + 排除含 langgenius/openai策略已到位,这次多半是手动装新版没补丁 → 走 §4

4. 修复步骤(推荐脚本)

顺序很重要:先做 §5 的根治(关掉自动升级),再做本节的重打补丁。

反过来的话,补丁可能当天夜里就被下一次自动升级又冲掉,白干。

4.1 一键:给所有 openai 版本打补丁 + 重启 + 恢复作业7(可选)

bash
# Windows 项目根(先同步)
python scripts_cursor/00_部署_workbuddy到207.py

# 批量补丁 + 重启 plugin_daemon + 恢复自愈 Agent 模型/工具
python scripts_cursor/作业7_故障自愈工作流/作业7_07_修复模型不可用与工具授权.py

或只跑专题一「修改后」脚本(已改为 遍历所有版本):

bash
python scripts_cursor/Dify_专题一_集成Qwen3.6-27B/专题一_04_改llm_schema_修改后.py

4.2 手工(对照)

  1. 对 每一个 openai-*@*/models/llm/llm.py:若无 Fallback for custom / non-OpenAI base models,按专题一替换 get_customizable_model_schema(实现见 scripts_cursor/_plugin_util.py → patch_llm_schema)。
  2. cd /dify/dify-main/docker && docker compose restart plugin_daemon
  3. 等约 10~15 秒后验收。

4.3 验收

bash
# LLM 列表应含 active 的 qwen3.6-27b(用控制台登录后的 API,或跑专题一_03)
python scripts_cursor/Dify_专题一_集成Qwen3.6-27B/专题一_03_验证vLLM与LLM列表.py

期望:

浏览器请 强制刷新(Ctrl+F5)。


5. 根治:把 openai 插件钉住(关掉自动更新)★ 当前生产做法

§4 是治标:坏了就重打一遍。只要插件被自动升级,这个循环就会重来一次。 §5 是治本:让 model 类不再自动升级,补丁就没有被冲掉的机会。

现场状态:2026-09-24 05:41 起已生效(model 行 disabled + 排除 langgenius/openai)。

5.1 落点在哪:tenant_plugin_auto_upgrade_strategies

「关掉 OpenAI 插件的自动更新」这件事,没有单独的配置文件,它就存在 Dify 的库里:

字段:

字段取值含义
categorytool / model / extension / agent-strategy / datasource / trigger六大类插件,openai 属于 model
strategy_settingdisabled / fix_only / latestdisabled=完全不自动升级;fix_only=只跟随安全修复;latest=跟最新版
upgrade_modeall / partial / exclude用哪种方式圈定「不升级哪些」
exclude_pluginsJSON 数组upgrade_mode=exclude 时的排除名单(插件 id,如 langgenius/openai)
include_pluginsJSON 数组upgrade_mode=partial 时的白名单
upgrade_time_of_day整数(当天第几秒)每日定时检查的时点。10800 = 03:00

枚举定义在 dify-api 的 /app/api/models/account.py: TenantPluginAutoUpgradeCategory / TenantPluginAutoUpgradeStrategySetting / TenantPluginAutoUpgradeMode。

当前 207 的实测值(2026-10-13 复核):

categorystrategy_settingupgrade_modeexclude_pluginsupdated_at
toolfix_onlyexclude[]2026-08-17 07:50
modeldisabledexclude["langgenius/openai"]2026-09-24 05:41
extensionfix_onlyexclude[]2026-08-17 07:50
agent-strategyfix_onlyexclude[]2026-08-17 07:50
datasourcefix_onlyexclude[]2026-08-17 07:50
triggerfix_onlyexclude[]2026-08-17 07:50

其余 5 行仍是出厂默认(2026-08-17 建,之后没动过)——只有 model 这一行被人为改过, updated_at 和其它 5 行不一样,这就是「那天改的东西」的痕迹。

为什么同时要 disabled 和 exclude(双保险):

(比如为了别的 model 插件),openai 仍在排除名单里,不会被顺手升掉。

5.2 三种改法

方式 A · 控制台(最推荐,日常就用它)

打开 Dify 控制台 → 插件 → 右上角 设置(自动升级)→ 把策略切到「关闭 / 不自动升级」, 并在「按插件配置」里把 OpenAI 加进排除列表。保存后回 §5.3 复核库里的值是否一致。

若你的版本界面上找不到这一入口,不用纠结——方式 B / C 改的是同一张表,效果完全一样。

方式 B · 用 Dify 自己的 API(不用登录数据库、不用手写 SQL)

bash
# 查看当前策略
GET  /console/api/workspaces/current/plugin/auto-upgrade/fetch
# 改策略(关掉)
POST /console/api/workspaces/current/plugin/auto-upgrade/change
# 只维护排除名单
POST /console/api/workspaces/current/plugin/auto-upgrade/exclude

(需要先 POST /console/api/login 拿 cookie + X-CSRF-Token,与专题一/四的脚本同一套。)

方式 C · 直接改库(最快,脚本已备好)

bash
# 1) 打印现状 + 备份 + 生成 SQL(dry-run,不写库)
python scripts_cursor/Dify_专题十七_OpenAI插件升级后schema补丁丢失/专题十七_02_关闭OpenAI插件自动升级.py

# 2) 确认无误后真正写库
python scripts_cursor/Dify_专题十七_OpenAI插件升级后schema补丁丢失/专题十七_02_关闭OpenAI插件自动升级.py --apply

脚本实际执行的 SQL 只有一句:

sql
update tenant_plugin_auto_upgrade_strategies
   set strategy_setting = 'disabled',
       upgrade_mode     = 'exclude',
       exclude_plugins  = '["langgenius/openai"]'::json,
       updated_at       = now()
 where category = 'model';

只动 category='model' 一行,其余 5 行不动。执行前会把现值备份成 /opt/workbuddy/data/plugin_autoupgrade_backup_<时间戳>.json,回滚就是把三个字段写回去。

5.3 验收

bash
docker exec docker-db_postgres-1 psql -U postgres -d dify -c \
  "select category, strategy_setting, upgrade_mode, exclude_plugins::text,
          to_char(updated_at,'YYYY-MM-DD HH24:MI') as updated
     from tenant_plugin_auto_upgrade_strategies where category='model';"

期望:

再加一条「等一个升级周期后复查」:隔天看卷里有没有新的 openai-<版本>@<hash> 目录冒出来—— 没有新目录 = 策略真的生效了。

5.4 代价与注意(一定要知道)

项说明
以后不会自动拿到新版openai 插件的安全修复 / 新模型支持,需要手动升
手动升级后必须重打补丁装完新版 → 立刻跑 专题一_04(遍历所有版本)→ 刷新模型列表 → 看 LLM 是否 active
别把 6 行都关掉只关 model 类。tool / extension 等保持 fix_only 是合理的(只跟随安全修复)
这是「本机生产环境的策略」换环境 / 重装 Dify 后,这张表会回到默认值,需要重新设置一次
与 §4 的关系两者不冲突:§5 防新坑,§4 修已经踩的坑。建议先 §5 再 §4,顺序反了会白修

6. 2026-10-13 实测:1.0.5 现状与「哪些补丁还需要」

钉住策略生效后手动升到 1.0.5,复查发现上游自己把 chat.py 那一处补好了。

一条命令看全:

bash
python scripts_cursor/Dify_专题十七_OpenAI插件升级后schema补丁丢失/专题十七_01_查看插件自动升级策略.py

实测结果:

版本目录llm.py 专题一补丁chat.py 专题四补丁chat.py 上游原生实现
openai-1.0.3@cc37544…✅ 有✅ 有(_ensure_system_first)—
openai-1.0.4@3b49ff9…✅ 有❌ 没有(函数被重构掉了)—
openai-1.0.5@5158331…(运行时)✅ 有❌ 不需要✅ _single_leading_system

1.0.5 的 chat.py 里,上游写的正是专题四要做的事:

python
def _single_leading_system(messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
    # Qwen accepts only one system message, and it must be the first message.
    chunks: list[str] = []
    rest: list[dict[str, Any]] = []
    for item in messages:
        if item.get("role") in ("system", "developer"):
            ...
    if not chunks:
        return rest
    return [{"role": "system", "content": "\n\n".join(chunks)}, *rest]

结论:

补丁1.0.5 上还要不要原因
专题一 llm.py 的 schema Fallback要qwen3.6-27b 是自定义基座名,上游不认识,还得自己 clone schema
专题四 chat.py 的多 system 合并不要上游已内置 _single_leading_system,功能等价

所以本专题日常真正要盯的,就只剩 llm.py 那一份。


7. 相关代码与附件

文件作用
scripts_cursor/Dify_专题十七_OpenAI插件升级后schema补丁丢失/专题十七_01_查看插件自动升级策略.py一条命令看全:策略 6 行 + 已装插件 + 各版本目录补丁命中(只读)
scripts_cursor/Dify_专题十七_OpenAI插件升级后schema补丁丢失/专题十七_02_关闭OpenAI插件自动升级.py§5 根治:备份现值 → 关掉 model 类自动升级 + 排除 openai(默认 dry-run,加 --apply 才写库)
scripts_cursor/_plugin_util.pypatch_llm_schema、找最新 / 全部插件路径
scripts_cursor/Dify_专题一_集成Qwen3.6-27B/专题一_04_改llm_schema_修改后.py正式补丁入口(遍历所有版本)
scripts_cursor/作业7_故障自愈工作流/作业7_07_修复模型不可用与工具授权.py本故障应急:补丁 + 重启 + 恢复作业7 Agent

备份:补丁脚本会写 llm.py.bak_qwenfix / bak_qwenfix104; 策略脚本会写 /opt/workbuddy/data/plugin_autoupgrade_backup_<时间戳>.json。


8. 和相邻专题的分工

专题何时看
专题一首次接入 Qwen、补丁原理与函数正文
专题四多条 system 导致 400;1.0.5 上已由上游内置,通常不用再打
专题十列表空但 不是「新版本未打补丁」时的其它原因
专题八from __future__ 顺序导致 SyntaxError
本专题十七「以前正常、插件升级后突然不可用」+ 自动升级策略的根治

9. 排错速表

现象处理
跑专题一_04 显示 already patched,但仍报 Base model查是否只 patch 了旧版本;改用全版本脚本或 作业7_07
修好了,过几天又坏十有八九是自动升级又装了一版 → 先照 §3 第 0 步看策略,再走 §5
关掉自动升级后,想升版本怎么办手动升 → 立刻跑 专题一_04 → 刷新模型列表 → 看 LLM 是否 active
补丁后 LLM 仍空等重启完成;核对凭据 qwen3.6-27b;看 docker logs plugin_daemon
仅工具「未授权」且模型已 activeOpenAPI 点授权选「无」;一般可调
配置页仍缓存旧错误Ctrl+F5;必要时清站点数据后再开 Agent
Agent 对话报 400 System message must be at the beginning先确认插件是不是 1.0.5:是 → 上游已内置合并逻辑,多半是别的原因(看专题四);不是 → 需要打 chat.py 补丁