feat: 将LLM配置主存储迁移到MySQL
变更项: 1) 新增 t_llm_config 数据访问层与建表逻辑。 2) Robot 启动时自动初始化并在空库时从 YAML 导入。 3) 后台 system LLM API 改为读写 MySQL。 4) LLMRegistry 改为优先 MySQL 读取并回退 YAML。 5) DashboardServer 挂载 llm_config_db 提供后台访问。
This commit is contained in:
@@ -39,6 +39,43 @@ def _save_system_yaml(config_obj: dict) -> None:
|
||||
yaml.safe_dump(config_obj, f, allow_unicode=True, sort_keys=False)
|
||||
|
||||
|
||||
def _load_llm_config_runtime() -> dict:
|
||||
"""读取运行时 LLM 配置。
|
||||
|
||||
读取优先级:
|
||||
1. 优先从机器人挂载的 MySQL 配置读取(主数据源);
|
||||
2. 若数据库对象不可用或读取异常,回退到 config.yaml(兜底)。
|
||||
"""
|
||||
try:
|
||||
server = current_app.dashboard_server
|
||||
llm_config_db = getattr(server, "llm_config_db", None)
|
||||
if llm_config_db:
|
||||
row = llm_config_db.get_config() or {}
|
||||
if row:
|
||||
return {
|
||||
"default_backend": row.get("default_backend", ""),
|
||||
"backends": row.get("backends", {}) or {},
|
||||
"scenes": row.get("scenes", {}) or {},
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning(f"从 MySQL 读取 LLM 配置失败,回退 YAML: {e}")
|
||||
|
||||
config_obj = _load_system_yaml()
|
||||
llm_config = config_obj.get("llm", {}) or {}
|
||||
return llm_config if isinstance(llm_config, dict) else {}
|
||||
|
||||
|
||||
def _save_llm_config_runtime(llm_config: dict) -> None:
|
||||
"""保存运行时 LLM 配置到主数据源(MySQL)。"""
|
||||
server = current_app.dashboard_server
|
||||
llm_config_db = getattr(server, "llm_config_db", None)
|
||||
if not llm_config_db:
|
||||
raise RuntimeError("llm_config_db 未初始化,无法保存 LLM 配置到 MySQL")
|
||||
ok = llm_config_db.save_config(llm_config or {}, source="admin")
|
||||
if not ok:
|
||||
raise RuntimeError("保存 LLM 配置到 MySQL 失败")
|
||||
|
||||
|
||||
def _plugins_root_path() -> str:
|
||||
"""返回插件根目录绝对路径。"""
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'plugins'))
|
||||
@@ -105,8 +142,7 @@ def _scan_plugin_llm_usage() -> list:
|
||||
|
||||
def _build_llm_topology() -> dict:
|
||||
"""构建 LLM 拓扑视图(供后台页面直观展示依赖关系)。"""
|
||||
config_obj = _load_system_yaml()
|
||||
llm_config = config_obj.get("llm", {}) or {}
|
||||
llm_config = _load_llm_config_runtime()
|
||||
scenes = llm_config.get("scenes", {}) or {}
|
||||
backends = llm_config.get("backends", {}) or {}
|
||||
default_backend = str(llm_config.get("default_backend", "") or "").strip()
|
||||
@@ -287,12 +323,11 @@ def get_current_user_info():
|
||||
@login_required
|
||||
def get_system_config_raw():
|
||||
try:
|
||||
server = current_app.dashboard_server
|
||||
config_path = _system_config_path()
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
config_text = f.read()
|
||||
robot_config = getattr(getattr(server, "robot", None), "config", None)
|
||||
llm_config = getattr(robot_config, "llm", {}) if robot_config else {}
|
||||
# 这里展示“运行时有效”的 LLM 后端列表(优先 MySQL),避免与 YAML 展示不一致。
|
||||
llm_config = _load_llm_config_runtime()
|
||||
llm_backends = (llm_config or {}).get("backends", {})
|
||||
return jsonify({
|
||||
"success": True,
|
||||
@@ -333,8 +368,7 @@ def update_system_config():
|
||||
@login_required
|
||||
def get_system_llm_config():
|
||||
try:
|
||||
config_obj = _load_system_yaml()
|
||||
llm_config = config_obj.get("llm", {}) or {}
|
||||
llm_config = _load_llm_config_runtime()
|
||||
backends = llm_config.get("backends", {}) or {}
|
||||
scenes = llm_config.get("scenes", {}) or {}
|
||||
backend_list = []
|
||||
@@ -368,7 +402,8 @@ def get_system_llm_config():
|
||||
"scenes": scene_list,
|
||||
"topology_rows": topology.get("topology_rows", []),
|
||||
"plugin_usages": topology.get("plugin_usages", []),
|
||||
"config_path": _system_config_path(),
|
||||
# 配置来源改为 MySQL;保留 YAML 路径用于排障与一次性导入核对。
|
||||
"config_path": f"mysql:t_llm_config (fallback yaml: {_system_config_path()})",
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
@@ -428,13 +463,12 @@ def update_system_llm_config():
|
||||
return jsonify({"success": False, "message": f"场景 {scene_name} 绑定的后端不存在"}), 400
|
||||
normalized_scenes[scene_name] = backend_name
|
||||
|
||||
config_obj = _load_system_yaml()
|
||||
config_obj["llm"] = {
|
||||
llm_config = {
|
||||
"default_backend": default_backend,
|
||||
"backends": normalized_backends,
|
||||
"scenes": normalized_scenes,
|
||||
}
|
||||
_save_system_yaml(config_obj)
|
||||
_save_llm_config_runtime(llm_config)
|
||||
|
||||
if getattr(server, "robot", None) and getattr(server.robot, "config", None):
|
||||
server.robot.config.reload()
|
||||
|
||||
@@ -51,6 +51,7 @@ class DashboardServer:
|
||||
self.plugin_schedule_db = robot_instance.plugin_schedule_db
|
||||
self.plugin_schedule_manager = robot_instance.plugin_schedule_manager
|
||||
self.group_plugin_config_db = robot_instance.group_plugin_config_db
|
||||
self.llm_config_db = robot_instance.llm_config_db
|
||||
self.group_plugin_config_service = robot_instance.group_plugin_config_service
|
||||
# 获取联系人管理器实例
|
||||
self.contact_manager = robot_instance.contact_manager
|
||||
|
||||
Reference in New Issue
Block a user