问题:在 /admin/llm/api 页面修改 AI 提供商配置后,配置没有立即生效,AI 依然使用旧的提供商工作 根本原因: - LLM Provider 配置在程序启动时加载到内存 (llm.State) - 管理后台修改配置时,只更新了数据库,内存配置未更新 - AI 继续使用内存中的旧配置 解决方案: 1. 为 llm.State 添加动态更新方法 (UpdateProvider/AddProvider/RemoveProvider) 2. 在 AI Service 中暴露配置更新接口,支持运行时重新加载 3. 在配置保存后自动触发内存配置重新加载 4. 创建新的 LLM Client 使新配置立即生效 关键特性: - 线程安全:使用 sync.RWMutex 保护并发访问 - 容错处理:重新加载失败不影响数据库更新 - 无需重启:配置修改后立即生效 - 完整测试:添加单元测试验证功能 修改文件: - internal/llm/state.go: 添加配置更新方法 - internal/ai/service.go: 添加配置重新加载接口 - internal/llmadmin/admin_llm_routes.go: 配置更新时触发重新加载 - internal/web/web.go: 传递 AI Service 到路由 - main.go: 连接组件 - internal/llm/state_test.go: 新增单元测试 - internal/web/map_tile_proxy_routes_test.go: 修复测试 测试: - ✅ 所有现有测试通过 - ✅ 新增测试覆盖核心功能 - ✅ 项目成功编译 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.0 KiB
4.0 KiB
LLM Provider 配置热更新修复
问题描述
在 /admin/llm/api 页面修改 AI 提供商配置后,配置没有立即生效,AI 依然使用旧的提供商在工作。
根本原因
- LLM Provider 配置在程序启动时加载到内存 (
llm.State) - 通过管理后台修改配置时,只更新了数据库,内存中的配置没有更新
- AI 继续使用内存中的旧配置工作
解决方案
1. 为 llm.State 添加动态更新方法
在 internal/llm/state.go 中添加了三个新方法:
UpdateProvider(config ProviderConfig) error- 更新现有 provider 的配置AddProvider(config ProviderConfig) error- 添加新的 providerRemoveProvider(name string) error- 删除 provider
这些方法会:
- 更新内存中的配置
- 重新创建 LLM Client(使用新的 API Key、BaseURL 等)
- 管理 active provider 的切换
2. 在 AI Service 中暴露配置更新接口
在 internal/ai/service.go 中添加了:
func (s *Service) ReloadLLMProvider(config interface{}) error
func (s *Service) AddLLMProvider(config interface{}) error
func (s *Service) RemoveLLMProvider(name string) error
这些方法接受 interface{} 类型(来自 HTTP handler 的 map),转换为 llm.ProviderConfig,然后调用 llm.State 的相应方法。
3. 在管理路由中触发配置重新加载
修改了 internal/llmadmin/admin_llm_routes.go:
- 添加了
LLMProviderReloader接口 RegisterRoutes接受aiService LLMProviderReloader参数handleCreateLLMProvider、handleUpdateLLMProvider、handleDeleteLLMProvider在数据库操作成功后,调用aiService的相应方法更新内存配置
4. 连接所有组件
修改了:
internal/web/web.go- 添加LLMProviderReloader接口,并在路由注册时传递aiServicemain.go- 将aiService传递给 web router
关键特性
线程安全
所有 llm.State 的更新操作都使用 sync.RWMutex 保护,确保并发安全。
容错处理
如果配置重新加载失败(例如 AI Service 未启用),不会导致请求失败。数据库已经更新,只会返回一个警告信息。
Active Provider 管理
- 更新 provider 为 active 时,自动切换到该 provider
- 删除当前 active provider 时,自动切换到第一个可用的 provider
- 不允许删除最后一个 provider
测试
创建了 internal/llm/state_test.go,包含以下测试:
TestUpdateProvider- 验证配置更新功能TestAddProvider- 验证添加新 providerTestRemoveProvider- 验证删除 provider
所有测试都通过 ✅
使用效果
修复后,在 /admin/llm/api 页面修改 AI 提供商配置时:
- 配置保存到数据库
- 立即更新内存中的配置
- 创建新的 LLM Client
- 无需重启服务,配置立即生效
影响范围
修改的文件
internal/llm/state.go- 添加配置更新方法internal/ai/service.go- 添加配置重新加载接口internal/llmadmin/admin_llm_routes.go- 在配置更新时触发重新加载internal/web/web.go- 传递 AI Service 到路由main.go- 连接组件
新增的文件
internal/llm/state_test.go- 单元测试
兼容性
- 完全向后兼容
- 如果 AI Service 未启用(
aiService == nil),配置更新仍然正常工作,只是不会触发重新加载 - 不影响现有功能
类似功能参考
该实现参考了项目中已有的 ToolRouter 和 TopicRouter 的配置热更新机制,它们通过 ConfigStore 接口在每次使用时从数据库重新加载配置。
不同之处在于:
- ToolRouter/TopicRouter: 每次使用时从 DB 读取(配置小,读取频率低)
- LLM Provider: 在配置更新时主动重新加载(Client 创建有开销,不适合频繁创建)
未来改进建议
- 添加配置验证:在更新前验证 API Key、BaseURL 是否可用
- 添加配置变更日志:记录谁在何时修改了配置
- 支持配置回滚:保存历史版本,出问题时可以快速回滚