From ef49588485cf72debb223d67a221df1f165d9e57 Mon Sep 17 00:00:00 2001 From: liuwei Date: Mon, 20 Apr 2026 14:45:03 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4LLM=E6=97=A7?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=85=A5=E5=8F=A3=E5=B9=B6=E7=BB=9F=E4=B8=80?= =?UTF-8?q?scene=E5=8D=95=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 变更项: 1. LLMRegistry 仅保留 scene 入口,删除 backend_name/backend_ref/scene_ref 等兼容解析分支,未声明 scene 时仅保留直连配置。 2. Dify/GlobalNews/GameTask 插件初始化改为仅传 scene,不再拼接 backend/provider/url 等旧兼容字段。 3. 清理插件配置冗余:dify/global_news/game_task/douyu 的 config.toml 删除 backend 字段,统一由 scene 映射后端。 4. 后台 system API 调整为严格模式:插件依赖扫描仅采集 scene;scene 保存时必须绑定有效 backend。 5. 后台页面去除拓扑中的配置Backend冗余列,并新增前端校验,禁止提交空场景或未绑定后端。 --- admin/dashboard/blueprints/system.py | 33 ++++++++++------------- admin/dashboard/templates/system_llm.html | 15 ++++++----- plugins/dify/config.toml | 2 -- plugins/dify/main.py | 12 +-------- plugins/douyu/config.toml | 2 -- plugins/game_task/config.toml | 1 - plugins/game_task/main.py | 13 +-------- plugins/global_news/config.toml | 1 - plugins/global_news/main.py | 8 +----- utils/ai/llm_registry.py | 27 ++++--------------- 10 files changed, 31 insertions(+), 83 deletions(-) diff --git a/admin/dashboard/blueprints/system.py b/admin/dashboard/blueprints/system.py index 39b44f3..dc7edf7 100644 --- a/admin/dashboard/blueprints/system.py +++ b/admin/dashboard/blueprints/system.py @@ -45,11 +45,11 @@ def _plugins_root_path() -> str: def _scan_plugin_llm_usage() -> list: - """扫描各插件 config.toml,提取插件与 LLM 后端/场景的引用关系。 + """扫描各插件 config.toml,提取插件与 LLM 场景的引用关系。 说明: 1. 该扫描仅用于后台可视化,不会改写插件配置; - 2. 兼容两种写法:顶层 section 下直接写 backend/scene,或嵌套在 llm/api/report_api 等节点; + 2. 严格模式只采集 scene:顶层 section 写法,或嵌套在 llm/api/report_api 等节点; 3. 返回结果用于“插件 -> scene -> backend”依赖拓扑展示。 """ plugins_root = _plugins_root_path() @@ -59,17 +59,15 @@ def _scan_plugin_llm_usage() -> list: usages = [] def _collect_refs(plugin_name: str, section_name: str, payload: dict) -> None: - """从单个配置节点收集 backend/scene 引用。""" + """从单个配置节点收集 scene 引用。""" if not isinstance(payload, dict): return - backend_name = str(payload.get("backend") or "").strip() - scene_name = str(payload.get("scene") or payload.get("scene_name") or "").strip() - if not backend_name and not scene_name: + scene_name = str(payload.get("scene") or "").strip() + if not scene_name: return usages.append({ "plugin": plugin_name, "section": section_name, - "backend": backend_name, "scene": scene_name, }) @@ -94,13 +92,13 @@ def _scan_plugin_llm_usage() -> list: for nested_name, nested_value in section_value.items(): if isinstance(nested_value, dict): _collect_refs(item, f"{section_name}.{nested_name}", nested_value) - # 顶层兜底:兼容极少数直接写在根节点的 backend/scene。 + # 顶层兜底:兼容极少数直接写在根节点的 scene。 _collect_refs(item, "__root__", config_obj if isinstance(config_obj, dict) else {}) # 去重:同插件同 section 仅保留一条记录,避免前后兜底重复。 unique = {} for row in usages: - key = f"{row.get('plugin')}::{row.get('section')}::{row.get('scene')}::{row.get('backend')}" + key = f"{row.get('plugin')}::{row.get('section')}::{row.get('scene')}" unique[key] = row return sorted(unique.values(), key=lambda x: (x.get("plugin", ""), x.get("section", ""))) @@ -117,12 +115,8 @@ def _build_llm_topology() -> dict: topology_rows = [] for usage in plugin_usages: scene_name = str(usage.get("scene") or "").strip() - backend_name = str(usage.get("backend") or "").strip() - resolved_backend = backend_name - # 若插件只写了 scene,则由 scenes 路由解析后端。 - if not resolved_backend and scene_name: - resolved_backend = str(scenes.get(scene_name) or "").strip() - # 若既没有 scene 也没有 backend,则兜底 default_backend(仅展示,不改配置)。 + # 严格模式:插件必须声明 scene,后端统一由 scenes 映射解析。 + resolved_backend = str(scenes.get(scene_name) or "").strip() if not resolved_backend: resolved_backend = default_backend @@ -130,10 +124,9 @@ def _build_llm_topology() -> dict: "plugin": usage.get("plugin", ""), "section": usage.get("section", ""), "scene": scene_name, - "backend": backend_name, "resolved_backend": resolved_backend, "provider": str((backends.get(resolved_backend) or {}).get("provider", "") or "").strip(), - "valid_scene": bool((not scene_name) or scene_name in scenes), + "valid_scene": bool(scene_name in scenes), "valid_backend": bool((not resolved_backend) or resolved_backend in backends), }) @@ -428,9 +421,11 @@ def update_system_llm_config(): backend_name = str(raw.get("backend") or "").strip() if not scene_name: continue - if backend_name and backend_name not in normalized_backends: + # 严格模式:每个 scene 必须绑定一个有效 backend,避免“空绑定”导致运行时不确定性。 + if not backend_name: + return jsonify({"success": False, "message": f"场景 {scene_name} 未绑定后端"}), 400 + if backend_name not in normalized_backends: return jsonify({"success": False, "message": f"场景 {scene_name} 绑定的后端不存在"}), 400 - # 允许场景先占位但暂不绑定后端,方便后台分步配置。 normalized_scenes[scene_name] = backend_name config_obj = _load_system_yaml() diff --git a/admin/dashboard/templates/system_llm.html b/admin/dashboard/templates/system_llm.html index 42986c0..0c5638a 100644 --- a/admin/dashboard/templates/system_llm.html +++ b/admin/dashboard/templates/system_llm.html @@ -54,7 +54,7 @@
- + 删除 @@ -172,11 +172,6 @@ - - - -