专题十七 · 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.207Difyplugin_daemon卷langgenius/openai-*@*/models/llm/llm.pyHTML:
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 配置页)
- 运行时插件:
langgenius/openai:1.0.4@3b49ff9… - 旧补丁仍在:
openai-1.0.3@cc3754…/models/llm/llm.py(已含 Fallback) - 新目录未补丁:
openai-1.0.4@…/models/llm/llm.py→ValueError: Base model qwen3.6-27b not found - Agent DB 里模型名仍是
qwen3.6-27b(配置没坏),前端却可能错显成其它「不可用」名
2026-10-13 复查(同一台机器,补丁已跟上,策略已固定)
- 运行时插件:
langgenius/openai:1.0.5@5158331…(又升了一版) - 卷里三个版本目录并存:
1.0.3/1.0.4/1.0.5 - 三份
llm.py都已含 Fallback 补丁 → 模型列表正常,不再「不可用」 chat.py:只有1.0.3有专题四的合并补丁;1.0.5用的是上游原生实现(见 §6)
2. 原理(为什么会「突然」)
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。
插件升级后目录变成:
.../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 定时任务:
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:
# 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一条命令看全三块(推荐):
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(可选)
# Windows 项目根(先同步)
python scripts_cursor/00_部署_workbuddy到207.py
# 批量补丁 + 重启 plugin_daemon + 恢复自愈 Agent 模型/工具
python scripts_cursor/作业7_故障自愈工作流/作业7_07_修复模型不可用与工具授权.py或只跑专题一「修改后」脚本(已改为 遍历所有版本):
python scripts_cursor/Dify_专题一_集成Qwen3.6-27B/专题一_04_改llm_schema_修改后.py4.2 手工(对照)
- 对 每一个
openai-*@*/models/llm/llm.py:若无Fallback for custom / non-OpenAI base models,按专题一替换get_customizable_model_schema(实现见scripts_cursor/_plugin_util.py→patch_llm_schema)。 cd /dify/dify-main/docker && docker compose restart plugin_daemon- 等约 10~15 秒后验收。
4.3 验收
# LLM 列表应含 active 的 qwen3.6-27b(用控制台登录后的 API,或跑专题一_03)
python scripts_cursor/Dify_专题一_集成Qwen3.6-27B/专题一_03_验证vLLM与LLM列表.py期望:
model-types/llm中qwen3.6-27b,status=active- Agent 配置页模型无「不可用」橙标
plugin_daemon新日志不再出现Base model qwen3.6-27b not found
浏览器请 强制刷新(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 的库里:
- 库:
dify(不是dify_plugin) - 表:
tenant_plugin_auto_upgrade_strategies - 唯一键:
(tenant_id, category)—— 一个 category 一行,共 6 行
字段:
| 字段 | 取值 | 含义 |
|---|---|---|
category | tool / model / extension / agent-strategy / datasource / trigger | 六大类插件,openai 属于 model |
strategy_setting | disabled / fix_only / latest | disabled=完全不自动升级;fix_only=只跟随安全修复;latest=跟最新版 |
upgrade_mode | all / partial / exclude | 用哪种方式圈定「不升级哪些」 |
exclude_plugins | JSON 数组 | upgrade_mode=exclude 时的排除名单(插件 id,如 langgenius/openai) |
include_plugins | JSON 数组 | upgrade_mode=partial 时的白名单 |
upgrade_time_of_day | 整数(当天第几秒) | 每日定时检查的时点。10800 = 03:00 |
枚举定义在 dify-api 的 /app/api/models/account.py: TenantPluginAutoUpgradeCategory / TenantPluginAutoUpgradeStrategySetting / TenantPluginAutoUpgradeMode。
当前 207 的实测值(2026-10-13 复核):
| category | strategy_setting | upgrade_mode | exclude_plugins | updated_at |
|---|---|---|---|---|
| tool | fix_only | exclude | [] | 2026-08-17 07:50 |
| model | disabled | exclude | ["langgenius/openai"] | 2026-09-24 05:41 |
| extension | fix_only | exclude | [] | 2026-08-17 07:50 |
| agent-strategy | fix_only | exclude | [] | 2026-08-17 07:50 |
| datasource | fix_only | exclude | [] | 2026-08-17 07:50 |
| trigger | fix_only | exclude | [] | 2026-08-17 07:50 |
其余 5 行仍是出厂默认(2026-08-17 建,之后没动过)——只有 model 这一行被人为改过, updated_at 和其它 5 行不一样,这就是「那天改的东西」的痕迹。
为什么同时要 disabled 和 exclude(双保险):
disabled管当下:model这一类整个不升级;exclude管将来:万一有人把strategy_setting改回fix_only/latest
(比如为了别的 model 插件),openai 仍在排除名单里,不会被顺手升掉。
5.2 三种改法
方式 A · 控制台(最推荐,日常就用它)
打开 Dify 控制台 → 插件 → 右上角 设置(自动升级)→ 把策略切到「关闭 / 不自动升级」, 并在「按插件配置」里把 OpenAI 加进排除列表。保存后回 §5.3 复核库里的值是否一致。
若你的版本界面上找不到这一入口,不用纠结——方式 B / C 改的是同一张表,效果完全一样。
方式 B · 用 Dify 自己的 API(不用登录数据库、不用手写 SQL)
# 查看当前策略
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 · 直接改库(最快,脚本已备好)
# 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 只有一句:
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 验收
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';"期望:
strategy_setting = disabledupgrade_mode = excludeexclude_plugins = ["langgenius/openai"]updated = 刚刚
再加一条「等一个升级周期后复查」:隔天看卷里有没有新的 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 那一处补好了。
一条命令看全:
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 里,上游写的正是专题四要做的事:
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.py | patch_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 |
| 仅工具「未授权」且模型已 active | OpenAPI 点授权选「无」;一般可调 |
| 配置页仍缓存旧错误 | Ctrl+F5;必要时清站点数据后再开 Agent |
Agent 对话报 400 System message must be at the beginning | 先确认插件是不是 1.0.5:是 → 上游已内置合并逻辑,多半是别的原因(看专题四);不是 → 需要打 chat.py 补丁 |