feat: 引入LLM场景路由与后台拓扑管理能力

变更项:

1. 新增 llm.scenes 场景路由层,支持 scene->backend 统一映射,并补充默认场景配置。

2. 扩展 LLMRegistry,新增 scene 解析逻辑;当声明 scene 时强制按场景路由结果生效,保持旧 backend 配置兼容。

3. 扩展后台 /api/system/llm_config 读写能力,支持 scenes 配置保存;新增插件 LLM 依赖扫描与拓扑数据输出。

4. 升级 system_llm 页面:新增场景路由管理区、插件依赖拓扑表,支持可视化查看 插件->scene->backend->provider。

5. 迁移核心插件配置到 scene 模式(保留兼容字段):dify/global_news/game_task/message_summary/ai_auto_response/member_context/douyu。

6. 调整部分插件初始化默认 llm_config,补充 scene 字段,确保后台场景切换可直接生效。
This commit is contained in:
liuwei
2026-04-20 14:36:56 +08:00
parent 09daaf956c
commit 7b6bd19781
14 changed files with 351 additions and 6 deletions

View File

@@ -36,6 +36,12 @@ class LLMRegistry:
llm_config = config.get("llm", {}) or {}
return llm_config if isinstance(llm_config, dict) else {}
@classmethod
def get_default_backend(cls) -> str:
"""读取全局默认后端名称。"""
llm_config = cls.get_llm_config()
return str(llm_config.get("default_backend", "") or "").strip()
@classmethod
def get_backend(cls, backend_name: str) -> Dict[str, Any]:
if not backend_name:
@@ -45,9 +51,68 @@ class LLMRegistry:
backend = backends.get(backend_name, {}) or {}
return dict(backend) if isinstance(backend, dict) else {}
@classmethod
def get_scenes(cls) -> Dict[str, str]:
"""读取 llm.scenes 场景路由配置,返回 scene->backend 的映射。"""
llm_config = cls.get_llm_config()
raw_scenes = llm_config.get("scenes", {}) or {}
if not isinstance(raw_scenes, dict):
return {}
normalized: Dict[str, str] = {}
for raw_scene, raw_backend in raw_scenes.items():
scene_name = str(raw_scene or "").strip()
backend_name = str(raw_backend or "").strip()
if not scene_name or not backend_name:
continue
normalized[scene_name] = backend_name
return normalized
@classmethod
def get_scene_backend_name(cls, scene_name: str) -> str:
"""根据场景名解析后端名;若场景不存在则自动回退 default_backend。"""
name = str(scene_name or "").strip()
if not name:
return cls.get_default_backend()
scenes = cls.get_scenes()
backend_name = str(scenes.get(name, "") or "").strip()
if backend_name:
return backend_name
return cls.get_default_backend()
@classmethod
def resolve_by_scene(cls, scene_name: str) -> Dict[str, Any]:
"""按场景解析最终后端配置,并附带 scene 字段用于链路追踪。"""
backend_name = cls.get_scene_backend_name(scene_name)
backend = cls.get_backend(backend_name)
if backend_name:
backend["backend"] = backend_name
if scene_name:
backend["scene"] = str(scene_name).strip()
return backend
@classmethod
def resolve(cls, local_config: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
local = dict(local_config or {})
# 兼容说明:
# 1. 新链路优先支持 scene 字段,便于“业务场景 -> 后端”集中路由;
# 2. 若未配置 scene再按旧逻辑读取 backend保持历史插件零改动可运行。
scene_name = (
local.get("scene")
or local.get("scene_name")
or local.get("scene_ref")
or ""
)
scene_name = str(scene_name).strip()
if scene_name:
merged = cls.resolve_by_scene(scene_name)
merged.update(local)
# 约定:只要声明了 scene就以 scene 路由结果为准。
# 这样后台切换 scene 绑定时,无需改插件配置即可全局生效。
merged["backend"] = cls.get_scene_backend_name(scene_name)
merged["scene"] = scene_name
return merged
backend_name = (
local.get("backend")
or local.get("backend_name")
@@ -61,4 +126,3 @@ class LLMRegistry:
merged.update(local)
merged["backend"] = backend_name
return merged