支持全局配置保存后立即应用到运行时

- 新增 Robot.apply_runtime_config 统一刷新邮件发送器、管理员列表与 LLM 运行时缓存\n- 新增 LLMRegistry.invalidate_cache 主动清理目录与 legacy 配置缓存\n- 后台保存全局配置与 LLM 目录后立即应用运行时配置,减少重启依赖
This commit is contained in:
liuwei
2026-04-29 17:27:21 +08:00
parent 28dc9da852
commit b53206d0d1
3 changed files with 60 additions and 2 deletions

View File

@@ -13,6 +13,7 @@ import json
import yaml
import toml
from utils.markdown_to_image import get_md2img_health_snapshot, warmup_md2img_browser_sync
from utils.ai.llm_registry import LLMRegistry
# 创建系统信息蓝图
system_bp = Blueprint('system', __name__)
@@ -479,8 +480,13 @@ def update_system_config():
if getattr(server, "robot", None) and getattr(server.robot, "config", None):
server.robot.config.reload()
# 保存 YAML 后立刻把运行时依赖对象同步一遍,避免必须重启进程才能读到新值。
server.robot.apply_runtime_config(reload_catalog=True)
else:
# 即便当前没有可用 robot 实例,也尽量把 LLM 路由缓存清掉,避免后续请求短时间内读旧值。
LLMRegistry.invalidate_cache()
return jsonify({"success": True, "message": "全局配置已保存"})
return jsonify({"success": True, "message": "全局配置已保存并应用到运行时"})
except Exception as e:
logger.error(f"保存系统配置失败: {e}")
return jsonify({"success": False, "message": str(e)}), 500
@@ -606,8 +612,12 @@ def update_system_llm_config():
if getattr(server, "robot", None) and getattr(server.robot, "config", None):
server.robot.config.reload()
# LLM 目录保存到 MySQL 后,需要主动失效运行时缓存,保证插件下一次调用直接走新目录。
server.robot.apply_runtime_config(reload_catalog=True)
else:
LLMRegistry.invalidate_cache()
return jsonify({"success": True, "message": "全局 LLM 配置已保存"})
return jsonify({"success": True, "message": "全局 LLM 配置已保存并应用到运行时"})
except Exception as e:
logger.error(f"保存全局 LLM 配置失败: {e}")
return jsonify({"success": False, "message": str(e)}), 500

View File

@@ -30,6 +30,7 @@ from utils.robot_cmd.robot_command import GroupBotManager, Feature, PermissionSt
from utils.wechat.contact_manager import ContactManager
from utils.wechat.member_monitor import ChatroomMemberMonitor
from utils.wechat.message_to_db import MessageStorage
from utils.ai.llm_registry import LLMRegistry
from wechat_ipad import WechatAPIClient
from wechat_ipad.models.message import WxMessage, MessageType
@@ -144,6 +145,38 @@ class Robot:
GroupBotManager.admin_list = self.config.wx_config.get("admin", [])
self.recent_msg_ids = deque(maxlen=20)
def apply_runtime_config(self, reload_catalog: bool = False) -> None:
"""把最新全局配置应用到当前运行中的关键对象。
说明:
1. `self.config.reload()` 只会刷新 Config 实例中的字段,不会自动更新启动时已构造的依赖对象;
2. 这里集中处理“保存配置后希望立刻生效”的轻量刷新动作,避免为大多数改动走整进程重启;
3. 该方法刻意不去重建 DB 连接、微信登录态、插件实例,尽量把影响范围控制在可热刷的配置项。
"""
# 邮件发送器在初始化时会拷贝 SMTP 参数,因此这里需要按最新配置重建一份实例。
self.email_sender = EmailSender(
smtp_server=self.config.email.get("smtp_server", "smtp.163.com"),
smtp_port=self.config.email.get("smtp_port", 465),
sender_email=self.config.email.get("sender_email", "bovine_liu@163.com"),
sender_password=self.config.email.get("sender_password", "LTS9BhmX9XhS36QS")
)
# 管理员列表走 GroupBotManager 的类级缓存;只 reload Config 不会自动回写到这里。
GroupBotManager.admin_list = self.config.wx_config.get("admin", [])
# system_context 中保存的是 config 对象引用reload 后插件读取到的是最新字段。
# 但 LLMRegistry 自己还有一层短 TTL 缓存,因此保存全局 LLM 配置后需要显式清掉。
if reload_catalog:
self.llm_catalog_db.bootstrap_from_legacy_llm(self.config.llm)
LLMRegistry.invalidate_cache()
self.LOG.info(
"运行时配置已应用: "
f"admin_count={len(GroupBotManager.admin_list)}, "
f"email_sender={'ready' if self.email_sender else 'missing'}, "
f"llm_cache_reloaded={reload_catalog}"
)
def _cleanup_migrated_system_jobs(self):
"""清理已经迁移到插件层的历史系统任务键。"""
migrated_keys = [

View File

@@ -24,6 +24,21 @@ class LLMRegistry:
"legacy_llm": {},
}
@classmethod
def invalidate_cache(cls) -> None:
"""主动清空运行时缓存。
说明:
1. 后台修改全局 YAML 或 MySQL 中的 LLM 目录后,旧缓存可能还在 3 秒有效期内;
2. 对于“保存后立刻生效”的后台体验,主动失效比等待 TTL 自然过期更直接;
3. 这里只清缓存,不做任何 IO下一次 resolve/get_catalog 时会自动重新装载最新配置。
"""
cls._cache = {
"cache_until": 0.0,
"catalog": {},
"legacy_llm": {},
}
@classmethod
def get_root_config_path(cls) -> Path:
return Path(__file__).resolve().parents[2] / "config.yaml"