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

大模型运行成功但 Dify 仍不可用

七层排查:网络、默认模型、插件 schema。步骤未改,代码块已换成完整程序。

Dify_专题五_大模型运行成功但Dify仍不可用_cursor.md

这是基于原文生成的 Cursor 版文档。

原文件未改动;本版只做三件事:统一阅读入口、修正已审出的明显问题、补充更适合快速排障的提示。

Cursor 版修订说明

阅读提示

运行环境:业务脚本均在 207 固定目录 /opt/workbuddy 执行,Python 为 /usr/bin/python3。 Windows 开发机仅保留 _probe_* 调试脚本;同步命令:python scripts_cursor/完整代码约定/00_部署_workbuddy到207.py。


原文主体(已纳入 Cursor 版纠错)

专题五:大模型"运行成功"了,但 Dify 里还是不行——系统性排查

阅读导航(何时打开 · 报错往哪查)

本文是单点修复/排障专题,配合《安装配置手册》使用;下文实战步骤与代码全部保留,此处只做索引。

何时打开说明
vLLM curl 通,Dify 仍不可用按 7 层总图 从外到内,不要跳层
不知道先查哪§十一 落地清单顺序
层典型现象章节
1容器在但 /v1 不通§三
2Dify→116 网络§四
3凭据/Base 错§五
4不兼容/列表空§六 + 专题一/十
7400 system§九 + 专题四

典型场景:vLLM 容器已跑、日志显示 Application startup complete,你在聊天里发了句"大模型运行成功了 这里还是不行"。

这说明模型端看起来正常,但 Dify 到模型之间的链路仍有某个环节没通。

本文给出从"模型端"到"Dify 问答"的 7 层排查路径,每一层都附带可直接执行的命令/代码,直到定位并解决。


一、场景描述

关键认知:运行成功只是容器和模型加载成功,不等于 Dify 能正确地把请求交给它。


二、排查总图(7 层,从外到内)

text
模型端是否真可用?
    └─ 是 → Dify 服务器到模型端网络通吗?
              └─ 是 → Dify 模型供应商凭据配对了吗?
                        └─ 是 → 模型 schema 兼容吗?(不兼容/选不到)
                                  └─ 是 → 默认 LLM 指向 qwen3.6-27b 了吗?
                                            └─ 是 → plugin_daemon 加载 patch 了吗?
                                                      └─ 是 → 问答时 system 消息格式正确吗?
                                                                └─ 是 → 通。

每一层都可能让"模型运行成功"的表象破裂。下面逐层展开。


三、第 1 层:模型端真的可用吗?(区分"启动"与"可服务")

不要只看 docker logs 里的启动成功,要做三次 curl。

3.1 列出模型

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_01.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_01.sh

bash
#!/usr/bin/env bash
set -euo pipefail

curl -s http://116.62.10.183:8000/v1/models \
  -H "Authorization: Bearer 123456" | head

必须返回模型名 qwen3.6-27b:

json
{
  "object": "list",
  "data": [
    {"id": "qwen3.6-27b", "object": "model"}
  ]
}

如果这里为空,说明 --served-model-name 没配对或模型没加载完。

3.2 最简单的一次对话

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_02.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_02.sh

bash
#!/usr/bin/env bash
set -euo pipefail

curl -s -X POST http://116.62.10.183:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer 123456" \
  -d '{
    "model": "qwen3.6-27b",
    "messages": [{"role": "system", "content": "你是一个助手"},{"role": "user", "content": "你好"}],
    "max_tokens": 128
  }'

期望:返回 choices[0].message.content,无 400/500。

3.3 带工具的最小验证(确认 parser 正确)

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_03.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_03.sh

bash
#!/usr/bin/env bash
set -euo pipefail

curl -s -X POST http://116.62.10.183:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer 123456" \
  -d '{
    "model": "qwen3.6-27b",
    "messages": [{"role": "user", "content": "上海今天天气怎么样"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "查询天气",
        "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
      }
    }],
    "tool_choice": "auto"
  }'

期望:返回里有 tool_calls,且 name 为 get_weather。若此处报错,优先检查 --tool-call-parser qwen3_xml(专题四 C 类)。


四、第 2 层:Dify 服务器到模型端的网络是否可达?

vLLM 在 116.62.10.183:8000,Dify 在 192.168.110.207,必须能从 207 连到 116:8000。

在 Dify 服务器上执行:

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_04.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_04.sh

bash
#!/usr/bin/env bash
set -euo pipefail

curl -s -m 10 http://116.62.10.183:8000/v1/models \
  -H "Authorization: Bearer 123456" | head

如果超时/连接失败:

之前保存凭据时如果报 Connection error / no available node,多半就是这里没通。


五、第 3 层:Dify 模型供应商凭据是否配对?

在 Dify「设置 → 模型供应商 → OpenAI-API-compatible」里,添加/编辑自定义模型时核对:

字段正确值常见错误
API Base URLhttp://116.62.10.183:8000/v1忘写 /v1;写成 /v1/(多斜杠也可能通,但最好一致)
API Key123456vLLM 未启用鉴权时可任意填,但 Dify 要求非空
自定义模型名qwen3.6-27b必须与 vLLM --served-model-name 完全一致
模型类型LLM误选成 Text Embedding / Rerank

保存时会触发 Dify 的连通性校验:它会用上面这些信息去 /v1/models 拉模型列表,拉不到就保存失败。


六、第 4 层:模型 schema 是否兼容(选不到 / 显示"不兼容")

现象:凭据保存成功,但前端模型列表里 qwen3.6-27b 显示"不兼容",或创建 Agent 时选不到。

根因:OpenAI 插件 models/llm/llm.py 的 get_customizable_model_schema 只认预定义 OpenAI 基座模型(如 gpt-4),自定义名 qwen3.6-27b 找不到,于是抛出 Base model qwen3.6-27b not found,前端据此标为不兼容。

解决:patch llm.py(文件在 plugin_daemon 容器挂载目录,路径类似):

text
/dify/dify-main/docker/volumes/plugin_daemon/cwd/langgenius/openai-1.0.3@<hash>/models/llm/llm.py

把 get_customizable_model_schema 改成:找不到基座时,clone 一个 chat 能力的预定义 schema,并允许凭据里的 model_properties 覆盖 context_size / max_tokens。

完整补丁:patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_01.py

运行/引用:见 patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_01.py

python
def get_customizable_model_schema(
        self, model: str, credentials: dict
    ) -> AIModelEntity:
        schema = {item.model: item for item in self.predefined_models()}.get(
            _base_model(model)
        )
        if schema is None:
            # Fallback for custom / non-OpenAI base models served via an
            # OpenAI-compatible endpoint (e.g. Qwen, DeepSeek, local vLLM):
            # clone a chat-capable predefined schema so the model is listable
            # and can be set as the default model.
            template = next(
                (m for m in self.predefined_models()
                 if m.model_properties.get("mode") == "chat"),
                None,
            )
            if template is None:
                template = self.predefined_models()[0]
            props = dict(template.model_properties)
            mp = (credentials or {}).get("model_properties") or {}
            try:
                if "context_size" in mp:
                    props["context_size"] = int(mp["context_size"])
                if "max_tokens" in mp:
                    props["max_tokens"] = int(mp["max_tokens"])
            except (ValueError, TypeError):
                pass
            schema = template.model_copy(deep=True, update={"model_properties": props})
        return schema.model_copy(
            deep=True,
            update={
                "model": model,
                "label": I18nObject(zh_hans=model, en_us=model),
                "fetch_from": FetchFrom.CUSTOMIZABLE_MODEL,
            },
        )

改完重启:

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_05.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_05.sh

bash
#!/usr/bin/env bash
set -euo pipefail

cd /dify/dify-main/docker && docker compose restart plugin_daemon

然后回到模型供应商页,重新保存凭据,qwen3.6-27b 应该变为可选/兼容。


七、第 5 层:默认 LLM 是否切到了 qwen3.6-27b?

现象:模型可选,但新建应用时默认仍是 gpt-5.6 之类的旧模型,导致问答时报 The model gpt-5.6 does not exist。

7.1 先看当前默认模型

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_06.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_06.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker exec docker-db_postgres-1 psql -U postgres -d dify -c \
  "SELECT model_type, provider_name, model_name FROM tenant_default_models;"

期望看到:

text
   model_type   |          provider_name           | model_name
----------------+----------------------------------+-------------
 llm            | langgenius/openai/openai         | qwen3.6-27b
 text-embedding | langgenius/xinference/xinference | bge-m3

7.2 如果 llm 还是 gpt-5.6,改成 qwen3.6-27b

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_07.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_07.sh

bash
#!/usr/bin/env bash
set -euo pipefail

# 获取当前登录用户对应的 tenant_id
TENANT_ID=$(docker exec docker-db_postgres-1 psql -U postgres -d dify -tc \
  "SELECT id FROM tenants WHERE email='38205036@qq.com'" | xargs)

# 把 llm 默认模型改成 qwen3.6-27b
docker exec docker-db_postgres-1 psql -U postgres -d dify -c \
  "UPDATE tenant_default_models
   SET provider_name='langgenius/openai/openai', model_name='qwen3.6-27b'
   WHERE tenant_id='$TENANT_ID' AND model_type='llm';"

7.3 重启 Dify 相关容器

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_08.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_08.sh

bash
#!/usr/bin/env bash
set -euo pipefail

cd /dify/dify-main/docker && docker compose restart api worker plugin_daemon

新建应用时默认 LLM 就会是 qwen3.6-27b。


八、第 6 层:plugin_daemon 是否加载了 patch?

现象:明明改了 llm.py 或 chat.py,但问题照旧,像没改一样。

根因:OpenAI 插件在 plugin_daemon 容器内被 Python 导入后缓存,必须重启容器才能加载新文件; 或者 patch 写到了 from __future__ import annotations 之前,触发 SyntaxError,导致整个 openai 插件加载失败。

8.1 检查 plugin_daemon 是否健康

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_09.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_09.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker ps --filter name=plugin_daemon --format '{{.Names}} {{.Status}}'
# 应显示 docker-plugin_daemon-1 Up ...

8.2 检查插件加载日志有无 Python 报错

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_10.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_10.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker logs docker-plugin_daemon-1 2>&1 | grep -iE 'error|syntax|traceback|openai' | tail -20

如果看到 SyntaxError: from __future__ imports must occur at the beginning,说明 chat.py 里的函数被写到了 from __future__ 之前,需要上移。

8.3 改完任何 patch 都要重启

完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_11.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_11.sh

bash
#!/usr/bin/env bash
set -euo pipefail

cd /dify/dify-main/docker && docker compose restart plugin_daemon
# 等 5-10 秒
sleep 8
docker ps --filter name=plugin_daemon --format '{{.Names}} {{.Status}}'

九、第 7 层:问答时 system 消息格式是否正确?

现象:前面全通了,但只要一发消息就报 400 System message must be at the beginning。

根因与解决:Qwen3 的 chat template 只接受一条 system 消息且在最前,而 Dify Agent 会把知识库助手提示 + Agent 工具提示 + 空 system + 配置 + 环境变量多条 system 堆在最前面。需要在 chat.py 里把它们合并成一条。

文件路径同 llm.py,只是改 models/llm/chat.py。在 from __future__ import annotations 之后加入/替换:

完整程序:/opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_01.py

运行/引用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_01.py

python
def _ensure_system_first(messages: list[PromptMessage]) -> list[PromptMessage]:
    """Qwen3/vLLM chat templates accept ONLY one system message, at the start.

    Dify (esp. Agent apps) stacks several system/developer prompts: KB assistant
    prompt + agent tool prompt + an empty system + config manifest... Merging them
    into a single system message (joined by blank lines, empties dropped) keeps it
    at the front; every other message keeps its original relative order.
    """
    system_parts: list[str] = []
    rest: list[PromptMessage] = []
    for m in messages:
        if isinstance(m, (SystemPromptMessage, DeveloperPromptMessage)):
            text = _text_content(m)
            if text.strip():
                system_parts.append(text)
        else:
            rest.append(m)
    if system_parts:
        rest.insert(0, SystemPromptMessage(content="\n\n".join(system_parts)))
    return rest

调用处:在 client.chat.completions.create 里把 prompt_messages 包一层:

完整程序:/opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_02.py

运行/引用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_02.py

python
    response = client.chat.completions.create(
        model=model,
        messages=cast(Any, [message(item) for item in _ensure_system_first(prompt_messages)]),
        stream=stream,
        ...
    )

改完重启 plugin_daemon,然后重新提问验证。详细抓日志、直连复现的方法见 Dify_专题四_Agent问答报错.md。


十、常见"假成功"陷阱速查

现象你以为的问题真正原因
docker logs 显示 startup complete模型可用还要 curl /v1/models 和 /v1/chat/completions 验证
模型在 116 本机 curl 通网络没问题Dify 在 207,要从 207 curl 116:8000 才算通
Dify 凭据保存成功模型配好了还要看是否显示"不兼容"、默认模型是否指向 qwen
改了 chat.py 但还报错改错了多半是没重启 plugin_daemon,或插件加载失败
普通聊天助手能用,Agent 不行Agent 配置错是 Agent 塞了多条 system,必须合并
第一次问答正常,重启后不行了模型挂了vLLM 容器可能 Exited,或者 Xinference 里的 bge-m3 实例掉了

十一、落地清单(按顺序排查)


十二、关联文档


十三、实战记录(本次部署真实遇到的情况)

本专题的引子就是那张截图:"大模型运行成功了 这里还是不行"。按统一维度拆解真实经过。

现象:docker logs vllm-qwen3.6-27b 显示 Application startup complete,但 Dify 里发消息仍报 System message must be at the beginning。

定位(按 7 层逐层查):

改了什么(真正卡在第 6+7 层):早期给 chat.py 打的"置顶 system"补丁只排序没合并,且一度因函数写在 from __future__ import annotations 之前触发 SyntaxError,导致整个 openai 插件没真正加载(保存凭据时还报过 no available node)。修复:

  1. 把 _ensure_system_first 重写为"合并"逻辑;
  2. 把新增函数移到 from __future__ 之后;
  3. 备份 chat.py.bak_systemfix / llm.py.bak_qwenfix。

怎么重启服务: 完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_12.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_12.sh

bash
#!/usr/bin/env bash
set -euo pipefail

cd /dify/dify-main/docker && docker compose restart plugin_daemon
# 若改过 default model 也要重启:
docker compose restart api worker plugin_daemon

怎么看日志: 完整脚本:scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_13.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_13.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker logs docker-plugin_daemon-1 2>&1 | grep -iE 'error|syntax|traceback|openai' | tail -20
# 应无 SyntaxError / Traceback,能看到 openai 插件正常 register

怎么判断正常:用 Agent API streaming 实测发一条问题,无 event: error 且能正常返回知识库答案(详见专题四 2.6)。

对照专题四:本专题的"假成功"在第 6 节有速查表,这次根因就是其中"模型在 116 本机通、但插件没加载 patch"那一行。

一句话对照:专题五前面是"7 层排查法",本节是"用户截图那个场景被按这 7 层一步步定位到第 7 层并修好"的真实经过。


本专题 Python 程序一览

| 文件 | 用途 | |---|---|| 专题五_01_验证vLLM三层.py | 专题五 · 步骤 1:验证 vLLM 三层(列模型 / 单轮对话 / 工具调用)。 | | 专题五_02_验证207到vLLM网络.py | 专题五 · 步骤 2:从 Dify 服务器验证到 vLLM 的网络可达性。 | | 专题五_03_查默认LLM模型.py | 专题五 · 步骤 3:查询 tenant_default_models 当前默认 LLM。 | | 专题五_04_改默认LLM为Qwen_修改后.py | 专题五 · 步骤 4 · 修改后:把 tenant 默认 LLM 改为 qwen3.6-27b 并重启 api/worker/plugin。 | | 专题五_05_检查plugin_daemon健康.py | 专题五 · 步骤 5:检查 plugin_daemon 容器状态与 Python 加载错误。 | | 专题五_06_应用llm_schema补丁_修改后.py | 专题五 · 步骤 6 · 修改后:patch llm.py get_customizable_model_schema(自定义模型可选)。 | | 专题五_07_应用chat合并system补丁_修改后.py | 专题五 · 步骤 7 · 修改后:patch chat.py 合并多条 system(同专题四步骤 4)。 |

专题五_01_验证vLLM三层.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_01_验证vLLM三层.py

完整补丁:patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_02.py

运行/引用:见 patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_02.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题五 · 步骤 1:验证 vLLM 三层(列模型 / 单轮对话 / 工具调用)。"""
from __future__ import annotations

import json
import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def curl_json(d: Dify, cmd: str, label: str) -> None:
    out, err = d.sh(cmd, t=120)
    print("\n=== %s ===" % label)
    print((out or err)[:1500])


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        auth = "-H 'Authorization: Bearer %s'" % C.VLLM_KEY
        curl_json(
            d,
            "curl -s %s/v1/models %s | head -c 800" % (C.VLLM_URL, auth),
            "3.1 GET /v1/models",
        )
        chat_body = {
            "model": C.LLM_MODEL,
            "messages": [
                {"role": "system", "content": "你是一个助手"},
                {"role": "user", "content": "你好"},
            ],
            "max_tokens": 128,
        }
        remote = "/tmp/vllm_chat_smoke.json"
        with d.sftp.open(remote, "w") as f:
            f.write(json.dumps(chat_body, ensure_ascii=False))
        curl_json(
            d,
            "curl -s -X POST %s/v1/chat/completions -H 'Content-Type: application/json' %s -d @%s"
            % (C.VLLM_URL, auth, remote),
            "3.2 POST /v1/chat/completions",
        )
        tool_body = {
            "model": C.LLM_MODEL,
            "messages": [{"role": "user", "content": "上海今天天气怎么样"}],
            "tools": [{
                "type": "function",
                "function": {
                    "name": "get_weather",
                    "description": "查询天气",
                    "parameters": {
                        "type": "object",
                        "properties": {"city": {"type": "string"}},
                        "required": ["city"],
                    },
                },
            }],
            "tool_choice": "auto",
        }
        remote2 = "/tmp/vllm_tool_smoke.json"
        with d.sftp.open(remote2, "w") as f:
            f.write(json.dumps(tool_body, ensure_ascii=False))
        curl_json(
            d,
            "curl -s -X POST %s/v1/chat/completions -H 'Content-Type: application/json' %s -d @%s"
            % (C.VLLM_URL, auth, remote2),
            "3.3 POST /v1/chat/completions(带 tools)",
        )
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题五_02_验证207到vLLM网络.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_02_验证207到vLLM网络.py

完整补丁:patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_03.py

运行/引用:见 patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_03.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题五 · 步骤 2:从 Dify 服务器验证到 vLLM 的网络可达性。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        cmd = (
            "curl -s -m 10 %s/v1/models -H 'Authorization: Bearer %s' | head -c 800"
            % (C.VLLM_URL, C.VLLM_KEY)
        )
        out, err = d.sh(cmd, t=30)
        text = out or err
        print(text)
        if C.LLM_MODEL in text:
            print("\n[OK] 从 Dify 服务器可达 vLLM,且列出 %s" % C.LLM_MODEL)
            return 0
        print("\n[FAIL] 未在响应中看到 %s" % C.LLM_MODEL)
        return 1
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题五_03_查默认LLM模型.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_03_查默认LLM模型.py

完整补丁:patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_04.py

运行/引用:见 patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_04.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题五 · 步骤 3:查询 tenant_default_models 当前默认 LLM。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        sql = (
            "docker exec %s psql -U postgres -d dify -c "
            "\"SELECT model_type, provider_name, model_name FROM tenant_default_models;\"" % C.PG_CONTAINER
        )
        out, err = d.sh(sql)
        print(out or err)
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题五_04_改默认LLM为Qwen_修改后.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_04_改默认LLM为Qwen_修改后.py

完整补丁:patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_05.py

运行/引用:见 patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_05.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题五 · 步骤 4 · 修改后:把 tenant 默认 LLM 改为 qwen3.6-27b 并重启 api/worker/plugin。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        tenant_sql = (
            "docker exec %s psql -U postgres -d dify -tc "
            "\"SELECT id FROM tenants WHERE email='%s'\"" % (C.PG_CONTAINER, C.DIFY_EMAIL)
        )
        out, err = d.sh(tenant_sql)
        tenant_id = out.strip()
        if not tenant_id:
            print("未找到 tenant:", err)
            return 1
        print("tenant_id:", tenant_id)
        upd = (
            "docker exec %s psql -U postgres -d dify -c "
            "\"UPDATE tenant_default_models SET provider_name='%s', model_name='%s' "
            "WHERE tenant_id='%s' AND model_type='llm';\"" % (
                C.PG_CONTAINER, C.OPENAI_PROVIDER, C.LLM_MODEL, tenant_id
            )
        )
        out2, err2 = d.sh(upd)
        print(out2 or err2)
        out3, err3 = d.sh(
            "cd %s && docker compose restart api worker plugin_daemon" % C.DIFY_DOCKER_DIR,
            t=180,
        )
        print(out3 or err3)
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题五_05_检查plugin_daemon健康.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_05_检查plugin_daemon健康.py

完整补丁:patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_06.py

运行/引用:见 patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_06.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题五 · 步骤 5:检查 plugin_daemon 容器状态与 Python 加载错误。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        out1, _ = d.sh(
            "docker ps --filter name=plugin_daemon --format '{{.Names}} {{.Status}}'"
        )
        print("=== plugin_daemon 状态 ===")
        print(out1.strip())
        out2, _ = d.sh(
            "docker logs %s 2>&1 | grep -iE 'error|syntax|traceback|openai' | tail -20"
            % C.PLUGIN_CONTAINER
        )
        print("\n=== 最近 plugin 相关日志 ===")
        print(out2.strip() or "(无匹配行,通常表示 OK)")
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题五_06_应用llm_schema补丁_修改后.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_06_应用llm_schema补丁_修改后.py

完整补丁:patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_07.py

运行/引用:见 patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_07.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题五 · 步骤 6 · 修改后:patch llm.py get_customizable_model_schema(自定义模型可选)。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
import _plugin_patch as P
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        llm_path = P.find_plugin_file(d, "llm.py")
        print("llm.py:", llm_path)
        content = P.read_remote_file(d, llm_path)
        new_content = P.replace_method(
            content, "get_customizable_model_schema", P.GET_CUSTOMIZABLE_MODEL_SCHEMA
        )
        P.deploy_plugin_file(d, llm_path, new_content)
        print("已应用 llm.py schema 补丁并重启 plugin_daemon")
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题五_07_应用chat合并system补丁_修改后.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_07_应用chat合并system补丁_修改后.py

完整补丁:patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_08.py

运行/引用:见 patches_cursor/Dify_专题五_大模型运行成功但Dify仍不可用/专题五_内联_08.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题五 · 步骤 7 · 修改后:patch chat.py 合并多条 system(同专题四步骤 4)。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _plugin_patch as P
from dify_api import Dify

import _config as C  # noqa: F401


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        chat_path = P.find_plugin_file(d, "chat.py")
        content = P.read_remote_file(d, chat_path)
        new_content = P.replace_function(content, "_ensure_system_first", P.ENSURE_SYSTEM_FIRST)
        P.deploy_plugin_file(d, chat_path, new_content)
        print("已应用 chat.py 合并 system 补丁")
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())