专题十六:新 Agent 配置页 Internal Server Error(OpenAPI 工具被当成 builtin)
本文解决什么:对话验收通过,但一打开新 Agent 配置页 就弹出红色
Internal Server Error。不是:CPU / GPU 资源不足、vLLM 挂了、模拟 API 挂了。
环境:
192.168.110.207Dify 1.16.1;作业 1「运维巡检 Agent」挂了 OpenAPI 工具getServerStatus。HTML:
docs/html_cursor/Dify_专题十六_新Agent配置页InternalServerError_cursor.html关联:作业 1 工具调用 Agent;专题七/八(插件容器);专题十一(不要点发布)。
运行环境:业务脚本均在 207 固定目录
/opt/workbuddy执行,Python 为/usr/bin/python3。 Windows 开发机仅保留_probe_*调试脚本;同步命令:python scripts_cursor/完整代码约定/00_部署_workbuddy到207.py。
目录
- 现象与误判
- 第一部分 原因(理论与调用链)
- 第二部分 详细操作步骤
- 第三部分 配置修改方式
- 第四部分 CPU 与 GPU:为什么不是资源问题
- 第五部分 完整程序与补丁
- 第六部分 验收与回滚
- 第七部分 对本系统的建议
现象与误判
| 你看到的 | 实际含义 |
|---|---|
| 问「帮我看看 gpu-server-01 的状态」能调工具、能答对 | 运行时链路正常 |
打开 配置 页,右上角红条 Internal Server Error(可能连续两条) | 配置页拉工具凭据失败 |
| 预览区空白 / 刷新图标旁也有红叹号 | 同一接口 500,前端 toast |
容易误判成资源不足,因为红条文案太泛。对照:
| 若真是资源问题 | 本专题 |
|---|---|
| 对话超时、Connection error、空泡、全体变慢 | 对话 正常、延迟约数秒 |
116 nvidia-smi 顶满 / vLLM OOM | vLLM /v1/models 正常 |
| 207 CPU 打满、8777 无响应 | /health 与 /server/status 正常 |
本环境实测:对话 HTTP 200,messages.status=normal;配置页接口对 OpenAPI UUID 返回 500。
本环境 ID:
| 项 | 值 |
|---|---|
| Agent | 运维巡检 Agent |
| agent_id | 01a0189c-7d7e-742f-83d1-74c5c16878da |
| OpenAPI provider 名 | server_status |
tool_api_providers.id | 021a4445-098d-4821-81fe-ff0ebc660ecc |
第一部分 原因(理论与调用链)
1.1 运行时 vs 配置页,走的不是同一条路
【对话 · 运行时 · 正常】
用户发问
→ docker-api-1 POST /agent/<id>/chat-messages
→ 快照 tools.dify_tools[]
provider_type = "api"
provider_id = 021a4445-... (tool_api_providers 表 UUID)
→ ToolManager.get_api_provider_controller(tenant_id, UUID)
→ GET http://192.168.110.207:8777/server/status?...
→ 第二次 LLM 格式化回答
【配置页 · 会 500】
浏览器打开「配置」
→ 前端按「内置插件」去拉凭据
→ GET /console/api/workspaces/current/tool-provider/builtin/<provider_id>/credential/info
这里的 <provider_id> 被填成了上面那个 UUID
→ ToolManager.get_builtin_provider(UUID, tenant_id)
→ plugin_daemon:PluginNotFoundError: plugin not found
→ 接口 HTTP 500
→ 页面 toast「Internal Server Error」Dify 1.16 新 Agent 的 Composer 工具候选列表只枚举 builtin 插件(audio / code / time / webscraper),不包含 工作区 OpenAPI 自定义工具。快照里却合法地挂了 provider_type=api 的工具。配置页仍用 builtin 路由去解释 provider_id,UUID 不可能是插件名。
1.2 日志原文(修复前)
Exception on /console/api/workspaces/current/tool-provider/builtin/021a4445-098d-4821-81fe-ff0ebc660ecc/credential/info [GET]
core.plugin.impl.exc.PluginNotFoundError: plugin not found对照:真正的 builtin 工具(如 time)同一接口是 HTTP 200。
1.3 为什么不能改快照里的 UUID
运行时 get_api_provider_controller 必须用 UUID。若把 provider_id 改回名称 server_status,对话会报:
invalid input syntax for type uuid: "server_status"因此:快照保持 UUID(保证对话);API 对「builtin 路由遇到非插件」做兜底(保证配置页)。不要为消红条去改作业 1 的工具挂载方式。
1.4 容器内改的是哪一个文件
| 项 | 值 |
|---|---|
| 容器 | docker-api-1(镜像 langgenius/dify-api:1.16.1) |
| 文件 | /app/api/services/tools/builtin_tools_manage_service.py |
| 函数 | get_builtin_tool_provider_credential_info |
| 路由 | GET /workspaces/current/tool-provider/builtin/<path:provider>/credential/info |
不要改 list_builtin_tool_provider_tools 里同名的 get_builtin_provider 调用(曾误打过,会搞乱工具列表)。应用脚本会先从镜像恢复原文件,再只替换 credential_info 这一处。
第二部分 详细操作步骤
顺序:定位 → 打补丁 → 验收 → 硬刷新浏览器。
步骤速查
| 步 | 目标 | 通过 | 误判排除 |
|---|---|---|---|
| 0 | 非资源问题 | vLLM/模拟 API 正常 | 不是 GPU/OOM |
| 1 | 复现+日志 | 见 builtin 误调 UUID | 对话能过≠配置页能过 |
| 2 | 打 API 容器补丁 | patch 脚本 PASS | 勿改快照 UUID |
| 3 | 硬刷新浏览器 | 配置页无红条 | 补丁随容器重建丢失→§3.3 |
与 作业 1 / 作业 5 / 作业 7 的 OpenAPI 工具 Agent 同类问题;对话验收通过仍可能配置页 500。
步骤 0 · 确认不是资源问题(30 秒)
在 207 上:
curl -s -m 10 -H 'Authorization: Bearer 123456' http://116.62.10.183:8000/v1/models
curl -s 'http://127.0.0.1:8777/health'
curl -s 'http://127.0.0.1:8777/server/status?server_name=gpu-server-01'期望:有 qwen3.6-27b;health ok;JSON 含 45%。
步骤 1 · 复现与定位
仓库根目录(Windows 用 dify_api.py SSH):
/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/专题十六_01_复现与定位.py完整程序:/opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/专题十六_01_复现与定位.py
运行/引用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/专题十六_01_复现与定位.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题十六 · 步骤 1:复现并定位「打开 Agent 配置页 Internal Server Error」。
对照三项:
1) 对话仍能调 OpenAPI 工具(streaming 200)
2) 配置页接口 builtin/<UUID>/credential/info 是否 500
3) API 日志是否 PluginNotFoundError
"""
from __future__ import annotations
import sys
import _bootstrap # noqa: F401
import _config as C
from dify_api import Dify, pp
def main() -> int:
d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
try:
d.login()
uuid = C.SERVER_STATUS_PROVIDER_ID
print("provider UUID", uuid)
r_api = d.get(
"/workspaces/current/tool-provider/api/get?provider=%s" % C.SERVER_STATUS_PROVIDER
)
pp("1) OpenAPI provider 详情", r_api, limit=400)
r_bad = d.get(
"/workspaces/current/tool-provider/builtin/%s/credential/info" % uuid
)
pp("2) 配置页误打的 builtin credential/info", r_bad, limit=500)
r_ok = d.get("/workspaces/current/tool-provider/builtin/time/credential/info")
pp("3) 真正的 builtin(time)对照", r_ok, limit=300)
r_chat = d.post(
"/agent/%s/chat-messages" % C.HOMEWORK1_AGENT_ID,
body={
"inputs": {},
"query": C.HOMEWORK1_PROBE_QUERY,
"response_mode": "streaming",
"files": [],
"conversation_id": "",
},
extra="-m 120 --max-time 120",
t=150,
)
text = r_chat.get("text") or ""
print("\n4) 对话 HTTP", r_chat.get("code"), "getServerStatus" in text, "45%" in text)
out, _ = d.sh(
"docker logs %s --tail 40 2>&1 | grep -iE 'PluginNotFound|credential/info' | tail -10"
% C.DIFY_API_CTR
)
print("\n5) api 日志片段:\n", out or "(无匹配,可能已打补丁)")
code = r_bad.get("code")
if code == "500":
print("\n[定位完成] 配置页接口 500 = 本专题场景。下一步跑作业1_06。")
return 0
if code == "200":
print("\n[已修复] credential/info 已是 200,配置页应不再红条。请 Ctrl+F5。")
return 0
print("\n[异常] 预期 500 或 200,实际 HTTP", code)
return 1
finally:
d.close()
if __name__ == "__main__":
sys.exit(main())解读:
| 接口 | 修复前 | 修复后 |
|---|---|---|
.../tool-provider/api/get?provider=server_status | 200 | 200 |
.../builtin/<UUID>/credential/info | 500 | 200 空凭据 |
.../builtin/time/credential/info | 200 | 200 |
| 对话 streaming | 200,含 getServerStatus | 仍 200 |
207 上看日志:
bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十六_新Agent配置页InternalServerError/专题十六_02_查日志与补丁.sh完整脚本:scripts_bash_cursor/Dify_专题十六_新Agent配置页InternalServerError/专题十六_02_查日志与补丁.sh
运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十六_新Agent配置页InternalServerError/专题十六_02_查日志与补丁.sh
#!/usr/bin/env bash
# 专题十六 · 在 207 上确认配置页误打的 builtin 接口
set -euo pipefail
UUID="${1:-021a4445-098d-4821-81fe-ff0ebc660ecc}"
echo "=== docker-api-1 最近 PluginNotFound ==="
docker logs docker-api-1 --tail 80 2>&1 | grep -iE "PluginNotFound|credential/info" | tail -15 || true
echo
echo "=== 容器内文件是否已有兜底 ==="
docker exec docker-api-1 grep -n "skip builtin credential/info for non-plugin provider" \
/app/api/services/tools/builtin_tools_manage_service.py || echo "(尚未打补丁)"步骤 2 · 应用补丁(完整程序)
/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/作业1_06_修复配置页InternalServerError.py脚本会:
- 读取
docker-api-1镜像,把builtin_tools_manage_service.py恢复成官方原文件(避免历史误打)。 - 只替换
get_builtin_tool_provider_credential_info函数开头:找不到插件时返回空凭据。 docker restart docker-api-1,等待控制台可访问。- 再 GET 那条 builtin UUID 接口,期望 200。
完整程序:/opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/作业1_06_修复配置页InternalServerError.py
运行/引用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/作业1_06_修复配置页InternalServerError.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""作业 1 · 修复打开 Agent 配置页 Internal Server Error(精确打到 credential/info)。"""
from __future__ import annotations
import sys
import _bootstrap # noqa: F401
import _config as C
from dify_api import Dify
REMOTE = "/app/api/services/tools/builtin_tools_manage_service.py"
OLD = ''' def get_builtin_tool_provider_credential_info(
tenant_id: str,
provider: str,
session: Session,
user: Account | None = None,
include_credential_ids: list[str] | None = None,
) -> ToolProviderCredentialInfoApiEntity:
"""
get builtin tool provider credential info
"""
provider_controller = ToolManager.get_builtin_provider(provider, tenant_id)
'''
NEW = ''' def get_builtin_tool_provider_credential_info(
tenant_id: str,
provider: str,
session: Session,
user: Account | None = None,
include_credential_ids: list[str] | None = None,
) -> ToolProviderCredentialInfoApiEntity:
"""
get builtin tool provider credential info
"""
try:
provider_controller = ToolManager.get_builtin_provider(provider, tenant_id)
except Exception as exc:
err = str(exc).lower()
if type(exc).__name__ in (
"PluginNotFoundError",
"ToolProviderNotFoundError",
) or "plugin not found" in err:
logger.warning(
"skip builtin credential/info for non-plugin provider %s: %s",
provider,
exc,
)
return ToolProviderCredentialInfoApiEntity(
supported_credential_types=[],
is_oauth_custom_client_enabled=False,
credentials=[],
)
raise
'''
def main() -> int:
d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
try:
d.login()
img, _ = d.sh(
"docker inspect %s --format '{{.Config.Image}}'" % C.DIFY_API_CTR
)
image = img.strip()
print("image", image)
# 从镜像恢复原文件(上次误改了 list_builtin_tool_provider_tools)
d.sh(
"docker run --rm --entrypoint cat %s %s > /tmp/builtin_tools_orig.py"
% (image, REMOTE)
)
orig, _ = d.sh("wc -l /tmp/builtin_tools_orig.py; grep -c get_builtin_tool_provider_credential_info /tmp/builtin_tools_orig.py")
print("orig", orig)
d.sh("docker cp /tmp/builtin_tools_orig.py %s:%s" % (C.DIFY_API_CTR, REMOTE))
content, _ = d.sh("docker exec %s cat %s" % (C.DIFY_API_CTR, REMOTE))
if OLD not in content:
print("恢复后仍找不到精确插入点")
print("has func", "get_builtin_tool_provider_credential_info" in content)
return 1
if "skip builtin credential/info for non-plugin provider" in content.split("get_builtin_tool_provider_credential_info", 1)[-1][:800]:
print("目标函数已有补丁")
else:
patched = content.replace(OLD, NEW, 1)
tmp = "/tmp/builtin_tools_patched.py"
with d.sftp.open(tmp, "w") as f:
f.write(patched)
d.sh("docker cp %s %s:%s" % (tmp, C.DIFY_API_CTR, REMOTE))
print("已精确写入 credential_info 补丁")
d.sh("docker restart %s" % C.DIFY_API_CTR)
print("等待 api 起来...")
d.sh(
"for i in 1 2 3 4 5 6 7 8 9 10; do "
"curl -sf -o /dev/null -m 3 http://127.0.0.1/console/api/setup || true; sleep 2; done"
)
d.login()
path = (
"/workspaces/current/tool-provider/builtin/%s/credential/info"
% C.SERVER_STATUS_PROVIDER_ID
)
r = d.get(path)
print("GET", path, "HTTP", r.get("code"))
print((r.get("text") or "")[:400])
ok_time = d.get("/workspaces/current/tool-provider/builtin/time/credential/info")
print("time still", ok_time.get("code"))
if r.get("code") != "200":
return 1
print("[PASS] 刷新浏览器打开运维巡检 Agent 配置页,红条应消失。")
return 0
finally:
d.close()
if __name__ == "__main__":
sys.exit(main())不要手改 800 行文件里第一处 get_builtin_provider——必须用脚本里那段带函数签名的精确替换。
步骤 3 · 浏览器
- Ctrl+F5 强制刷新(旧 500 会被浏览器缓存成红条)。
- 打开
http://192.168.110.207→ 运维巡检 Agent → 配置。 - 红条应消失;再新开对话问 gpu-server-01,工具调用仍在。
第三部分 配置修改方式
3.1 要改的:Dify API 容器内 Python(不是 Agent 快照)
| 改什么 | 改不改 | 原因 |
|---|---|---|
Agent 快照 tools.dify_tools | 不改 | UUID 是运行时必需 |
| OpenAPI Schema / 8777 | 不改 | 与配置页 500 无关 |
builtin_tools_manage_service.py 的 credential_info | 改 | 配置页误打 builtin |
| 工作区「集成 → 工具」 | 不用删工具 | 删了对话会挂 |
3.2 函数级修改对照
改动对比(get_builtin_tool_provider_credential_info)
| 项 | 修改前 | 修改后 |
|---|---|---|
get_builtin_provider | 直接调用,插件不存在就抛错 | try/except |
| 找不到插件时 | HTTP 500 + 前端红条 | 返回空凭据 JSON,HTTP 200 |
| 真正的 builtin(如 time) | 正常 | 行为不变 |
修改前
完整补丁:patches_cursor/Dify_专题十六_新Agent配置页InternalServerError/配置页InternalServerError_credential_info_修改前.py
运行/引用:见 patches_cursor/Dify_专题十六_新Agent配置页InternalServerError/配置页InternalServerError_credential_info_修改前.py
# -*- coding: utf-8 -*-
"""配置页 Internal Server Error · 修改前(摘自 Dify 1.16.1
docker-api-1:/app/api/services/tools/builtin_tools_manage_service.py
函数 get_builtin_tool_provider_credential_info)。
本文件是「要替换的那段函数头部」的完整对照,不是整个 800+ 行服务文件。
应用请用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/作业1_06_修复配置页InternalServerError.py
"""
from __future__ import annotations
from sqlalchemy.orm import Session
from core.tools.entities.api_entities import ToolProviderCredentialInfoApiEntity
from core.tools.tool_manager import ToolManager
from models.account import Account
class BuiltinToolManageService:
@staticmethod
def get_builtin_tool_provider_credential_info(
tenant_id: str,
provider: str,
session: Session,
user: Account | None = None,
include_credential_ids: list[str] | None = None,
) -> ToolProviderCredentialInfoApiEntity:
"""
get builtin tool provider credential info
"""
provider_controller = ToolManager.get_builtin_provider(provider, tenant_id)
supported_credential_types = provider_controller.get_supported_credential_types()
credentials = BuiltinToolManageService.get_builtin_tool_provider_credentials(
tenant_id,
provider,
session=session,
user=user,
include_credential_ids=include_credential_ids,
)
credential_info = ToolProviderCredentialInfoApiEntity(
supported_credential_types=supported_credential_types,
is_oauth_custom_client_enabled=BuiltinToolManageService.is_oauth_custom_client_enabled(tenant_id, provider),
credentials=credentials,
)
return credential_info修改后
完整补丁:patches_cursor/Dify_专题十六_新Agent配置页InternalServerError/配置页InternalServerError_credential_info_修改后.py
运行/引用:见 patches_cursor/Dify_专题十六_新Agent配置页InternalServerError/配置页InternalServerError_credential_info_修改后.py
# -*- coding: utf-8 -*-
"""配置页 Internal Server Error · 修改后(摘自 Dify 1.16.1
docker-api-1:/app/api/services/tools/builtin_tools_manage_service.py
函数 get_builtin_tool_provider_credential_info)。
相对修改前只多了 try/except:插件不存在时返回空凭据 JSON,HTTP 200。
应用请用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/作业1_06_修复配置页InternalServerError.py
"""
from __future__ import annotations
import logging
from sqlalchemy.orm import Session
from core.tools.entities.api_entities import ToolProviderCredentialInfoApiEntity
from core.tools.tool_manager import ToolManager
from models.account import Account
logger = logging.getLogger(__name__)
class BuiltinToolManageService:
@staticmethod
def get_builtin_tool_provider_credential_info(
tenant_id: str,
provider: str,
session: Session,
user: Account | None = None,
include_credential_ids: list[str] | None = None,
) -> ToolProviderCredentialInfoApiEntity:
"""
get builtin tool provider credential info
"""
try:
provider_controller = ToolManager.get_builtin_provider(provider, tenant_id)
except Exception as exc:
err = str(exc).lower()
if type(exc).__name__ in (
"PluginNotFoundError",
"ToolProviderNotFoundError",
) or "plugin not found" in err:
logger.warning(
"skip builtin credential/info for non-plugin provider %s: %s",
provider,
exc,
)
return ToolProviderCredentialInfoApiEntity(
supported_credential_types=[],
is_oauth_custom_client_enabled=False,
credentials=[],
)
raise
supported_credential_types = provider_controller.get_supported_credential_types()
credentials = BuiltinToolManageService.get_builtin_tool_provider_credentials(
tenant_id,
provider,
session=session,
user=user,
include_credential_ids=include_credential_ids,
)
credential_info = ToolProviderCredentialInfoApiEntity(
supported_credential_types=supported_credential_types,
is_oauth_custom_client_enabled=BuiltinToolManageService.is_oauth_custom_client_enabled(tenant_id, provider),
credentials=credentials,
)
return credential_info兜底返回体(与真正 builtin 空凭据结构一致):
{
"supported_credential_types": [],
"is_oauth_custom_client_enabled": false,
"credentials": []
}真正的 builtin(time)仍走原来的 get_builtin_provider,不受 except 影响。
3.3 补丁会丢的情况
| 操作 | 补丁 |
|---|---|
只 docker restart docker-api-1 | 还在(写在容器可写层) |
docker compose up -d --force-recreate / 换镜像 | 丢失,再跑作业1_06 |
| 升级 Dify 小版本 | 核对函数是否还在,再打 |
⚠️ 上面这张表是「直接改容器」的老办法。 现在已改成 override 挂载(见 3.4),补丁不再随容器重建而丢。
3.4 让补丁不再丢:用 docker-compose.override.yaml 挂载(当前生产做法)
问题:docker compose up -d --force-recreate、升级 Dify、或者 207 断电重启后 docker compose up -d,只要容器被重建,改在容器可写层里的 builtin_tools_manage_service.py 就回到原版,红条重现——而且往往是「重启完一阵子才发现」。
做法:把打过补丁的文件放到宿主机一个固定目录,用 compose 的 override 文件只读挂载覆盖容器内那个文件。
目录(宿主机):
/dify/dify-main/docker/
├── docker-compose.yaml # 官方原文件,不动
├── docker-compose.override.yaml # 新增:只做一件事 —— 挂补丁
└── volumes/
└── patches/
└── builtin_tools_manage_service.py # 打过补丁的完整文件docker-compose.override.yaml 全文:
# 修 Internal Server Error:用只读挂载覆盖 api 容器里的那个文件
# 这样容器重建 / 换镜像 / compose up -d 都不会把补丁冲掉
services:
api:
volumes:
- ./volumes/patches/builtin_tools_manage_service.py:/app/api/services/tools/builtin_tools_manage_service.py:ro生效:
cd /dify/dify-main/docker
docker compose up -d api # override 会被自动合并,无需 -f 指定
docker exec docker-api-1 sh -lc \
'ls -la /app/api/services/tools/builtin_tools_manage_service.py && grep -c PluginNotFoundError /app/api/services/tools/builtin_tools_manage_service.py'为什么这么做:
| 好处 | 说明 |
|---|---|
| 抗重建 | up -d / --force-recreate / 换镜像后仍在(挂载优先于镜像内容) |
| 可版本化 | 补丁文件本身就是「真相」,和 Dify 源码分离,升级时对比方便 |
| 只读 | :ro,容器里误改不了,避免「补丁漂移」 |
| 不留调试残留 | 不用 docker cp / docker exec 手改,重启即生效且可追溯 |
注意两点:
override是自动合并的,不要再写-f docker-compose.override.yaml;写了会与默认合并一次、可能重复。- 升级 Dify 后要确认函数签名还对得上:新版本如果改了
builtin_tools_manage_service.py的结构,旧补丁文件会直接覆盖掉官方改动。做法是先docker run起一个新版容器把原文件捞出来 diff,再决定补丁怎么合。
小提示:线上那个
docker-compose.override.yaml的注释是乱码(当年用非 UTF-8 编码写入,中文变成了?),配置本身不受影响;上面贴的是带正确注释的等价版本,需要时直接覆盖即可。
断电重启后的完整恢复顺序见 207 服务入口与断电重启恢复。
第四部分 CPU 与 GPU:为什么不是资源问题
本专题故障发生在 207 的 Dify API 进程(Python 查插件失败),与算力配额无关。下面把「真资源问题」和「本专题」分开写,避免以后有 GPU 时对错号。
4.1 CPU 侧(207,当前生产)
| 组件 | 本专题关系 | 真 CPU 不足时长什么样 |
|---|---|---|
FastAPI :8777 | 配置页 不调用 它 | curl /health 超时、对话 observation 空 |
| Xinference bge-m3 / rerank | 本 Agent 未绑知识库 | 命中测试 >10s、知识库 Agent 变慢 |
docker-api-1 | 只是查插件元数据,CPU 可忽略 | 全控制台卡死、容器 Restarting |
| 配置页 500 | 代码路径抛 PluginNotFoundError | 不会表现为 nvidia-smi 或 load average |
不要因为配置页红条去加 207 的 CPU、关 Rerank、或重启 Xinference。
4.2 GPU 侧(116 vLLM,当前 + 未来)
| 组件 | 本专题关系 | 真 GPU 不足时长什么样 |
|---|---|---|
| Qwen3.6-27B 工具调用 | 对话已成功,说明 GPU 够用 | CUDA OOM、vLLM 进程退出、/v1/models 超时 |
--max-num-seqs 8 排队 | 配置页 不走 生成 | 全员对话变慢,命中测试仍快 |
| 未来把 Embedding/Rerank 迁 GPU | 与本红条 无关 | 见专题十三 3.2 |
配置页打开时 不会 向 116 发 chat/completions。所以:
- 现在只有 CPU 机做 Dify、GPU 机只跑 vLLM:红条仍是 API 路由问题。
- 以后 207 也有 GPU、或 Xinference 上 GPU:按专题十三迁检索即可,不必为这个红条改 GPU 参数。
4.3 何时才该查资源
同时满足才查 CPU/GPU:对话失败或极慢 并且 nvidia-smi / docker stats 异常。只打开配置页报错 → 走本专题步骤 1~2。
第五部分 完整程序与补丁
| 文件 | 用途 |
|---|---|
/opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/专题十六_01_复现与定位.py | 对照 api / builtin / 对话 |
scripts_bash_cursor/Dify_专题十六_新Agent配置页InternalServerError/专题十六_02_查日志与补丁.sh | 207 上看日志与是否已打补丁 |
/opt/workbuddy/scripts_cursor/Dify_专题十六_新Agent配置页InternalServerError/作业1_06_修复配置页InternalServerError.py | 恢复原文件 + 精确打补丁 + 重启 + 验收 |
patches_cursor/Dify_专题十六_新Agent配置页InternalServerError/配置页InternalServerError_credential_info_修改前.py | 函数对照 · 修改前 |
patches_cursor/Dify_专题十六_新Agent配置页InternalServerError/配置页InternalServerError_credential_info_修改后.py | 函数对照 · 修改后 |
换环境:只改 _config.py 的 SERVER_STATUS_PROVIDER_ID、HOMEWORK1_AGENT_ID、DIFY_API_CTR。
第六部分 验收与回滚
6.1 验收清单
- [ ]
专题十六_01中 builtin UUID 的 credential/info 为 HTTP 200 - [ ]
builtin/time/credential/info仍为 200 - [ ] Ctrl+F5 后配置页 无 Internal Server Error 红条
- [ ] 新开对话问 gpu-server-01,仍调用
getServerStatus - [ ]
作业1_05_对话验收.py仍[PASS]
6.2 回滚
从镜像恢复官方文件(作业1_06 开头已在做;单独回滚):
IMG=$(docker inspect docker-api-1 --format '{{.Config.Image}}')
docker run --rm --entrypoint cat "$IMG" \
/app/api/services/tools/builtin_tools_manage_service.py \
> /tmp/builtin_tools_orig.py
docker cp /tmp/builtin_tools_orig.py docker-api-1:/app/api/services/tools/builtin_tools_manage_service.py
docker restart docker-api-1回滚后配置页红条会回来,对话不受影响。
第七部分 对本系统的建议
- 挂 OpenAPI 工具用脚本写快照时,默认把本专题补丁纳入 Dify 重建清单(与专题四 system 合并、Langfuse UUID 补丁同类:都在容器内,重建即丢)。
- 不要用 UI「工具」页反复删加来消红条,除非确认 Composer 已能列出 API 工具;乱点发布会冲掉 max_tokens(专题十一)。
- Dify 升级后先跑
专题十六_01:若官方已修 Composer,credential/info 不再对 UUID 打 builtin,可不再打本补丁。 - 培训口径:红条 ≠ 模型挂了。先看对话,再看
docker-api-1是否PluginNotFoundError。
*专题十六 · 207 实战:作业 1 配置页红条。补丁已在本环境验证 HTTP 200。*