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:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user