This is an automated email from the ASF dual-hosted git repository.

gongchao pushed a commit to branch ai-enhance
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git

commit 331adc7b2563f8d419832b683b83fe3ac0e13a3b
Author: tomsun28 <[email protected]>
AuthorDate: Sat Oct 18 17:48:18 2025 +0800

    [chore] refactor ai service
    
    Signed-off-by: tomsun28 <[email protected]>
---
 hertzbeat-ai-agent/pom.xml                         |  16 +-
 .../ai/agent/config/DynamicOpenAiApiKey.java       |  43 +++--
 .../hertzbeat/ai/agent/config/LlmConfig.java       |   8 +-
 .../ai/agent/config/OpenAiYamlConfig.java          |  43 -----
 .../agent/controller/OpenAiConfigController.java   | 160 -----------------
 .../hertzbeat/ai/agent/dao/OpenAiConfigDao.java    |  37 ----
 ...Event.java => AiProviderConfigChangeEvent.java} |   8 +-
 ...enAiConfigDto.java => ModelProviderConfig.java} |  40 +++--
 ...enAiConfigService.java => AiConfigService.java} |  34 +---
 .../ai/agent/service/impl/AiConfigServiceImpl.java | 128 +++++++++++++
 .../service/impl/ConversationServiceImpl.java      |   8 +-
 .../service/impl/OpenAiConfigServiceImpl.java      | 200 ---------------------
 .../common/constants/GeneralConfigTypeEnum.java    |   7 +-
 .../controller/GeneralConfigController.java        |   4 +-
 .../impl/ModelProviderConfigServiceImpl.java       |  59 ++++++
 .../src/main/resources/application-test.yml        |  13 --
 .../src/main/resources/application.yml             |  21 ---
 home/docs/download.md                              |   2 +-
 .../current/download.md                            |   2 +-
 web-app/src/app/pojo/ModelProviderConfig.ts        |  29 +++
 web-app/src/app/service/general-config.service.ts  |   9 +
 web-app/src/app/service/openai-config.service.ts   |  58 ------
 .../shared/components/ai-chat/chat.component.html  |  10 +-
 .../shared/components/ai-chat/chat.component.ts    |  81 +++------
 24 files changed, 337 insertions(+), 683 deletions(-)

diff --git a/hertzbeat-ai-agent/pom.xml b/hertzbeat-ai-agent/pom.xml
index b9d06e59c..9bb22303a 100644
--- a/hertzbeat-ai-agent/pom.xml
+++ b/hertzbeat-ai-agent/pom.xml
@@ -26,7 +26,7 @@
        <artifactId>hertzbeat-ai-agent</artifactId>
        <version>${hertzbeat.version}</version>
        <properties>
-               <spring-ai.version>1.0.1</spring-ai.version>
+               <spring-ai.version>1.0.3</spring-ai.version>
                <java.version>17</java.version>
        </properties>
 
@@ -51,12 +51,22 @@
                </dependency>
                <dependency>
                        <groupId>org.springframework.ai</groupId>
-                       <artifactId>spring-ai-starter-model-openai</artifactId>
+            <artifactId>spring-ai-openai</artifactId>
                </dependency>
+        <dependency>
+            <groupId>org.springframework.ai</groupId>
+            <artifactId>spring-ai-client-chat</artifactId>
+        </dependency>
                <dependency>
                        <groupId>org.apache.hertzbeat</groupId>
                        <artifactId>hertzbeat-common</artifactId>
                </dependency>
+        <!-- common -->
+        <dependency>
+            <groupId>org.apache.hertzbeat</groupId>
+            <artifactId>hertzbeat-base</artifactId>
+            <scope>provided</scope>
+        </dependency>
                <dependency>
                        <groupId>org.apache.hertzbeat</groupId>
                        <artifactId>hertzbeat-alerter</artifactId>
@@ -90,4 +100,4 @@
                </plugins>
        </build>
 
-</project>
\ No newline at end of file
+</project>
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/DynamicOpenAiApiKey.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/DynamicOpenAiApiKey.java
index 2eaa6b912..bad25be51 100644
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/DynamicOpenAiApiKey.java
+++ 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/DynamicOpenAiApiKey.java
@@ -18,40 +18,39 @@
 package org.apache.hertzbeat.ai.agent.config;
 
 import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.ai.agent.pojo.dto.OpenAiConfigDto;
-import org.apache.hertzbeat.ai.agent.service.OpenAiConfigService;
+import org.apache.hertzbeat.ai.agent.pojo.dto.ModelProviderConfig;
+import org.apache.hertzbeat.base.dao.GeneralConfigDao;
+import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
+import org.apache.hertzbeat.common.util.JsonUtil;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.ai.model.ApiKey;
 import org.springframework.stereotype.Component;
 
 /**
- * Dynamic OpenAI API Key implementation that retrieves the API key
- * from our configuration service (database first, then YAML fallback)
+ * Dynamic LLM Provider API Key implementation that retrieves the API key
  */
 @Slf4j
 @Component
 public class DynamicOpenAiApiKey implements ApiKey {
 
-    private final OpenAiConfigService openAiConfigService;
-
-    public DynamicOpenAiApiKey(OpenAiConfigService openAiConfigService) {
-        this.openAiConfigService = openAiConfigService;
+    private final GeneralConfigDao generalConfigDao;
+    
+    public DynamicOpenAiApiKey(GeneralConfigDao generalConfigDao) {
+        this.generalConfigDao = generalConfigDao;
     }
 
+    @NotNull
     @Override
     public String getValue() {
-        try {
-            OpenAiConfigDto effectiveConfig = 
openAiConfigService.getEffectiveConfig();
-            
-            if (effectiveConfig != null && effectiveConfig.isEnable() && 
effectiveConfig.getApiKey() != null) {
-                log.debug("Retrieved OpenAI API key from configuration 
service");
-                return effectiveConfig.getApiKey();
-            } else {
-                log.warn("No valid OpenAI API key found in configuration");
-                return null;
-            }
-        } catch (Exception e) {
-            log.error("Error retrieving OpenAI API key from configuration", e);
-            return null;
+        GeneralConfig providerConfig = generalConfigDao.findByType("provider");
+        ModelProviderConfig modelProviderConfig = 
JsonUtil.fromJson(providerConfig.getContent(), ModelProviderConfig.class);
+
+        if (modelProviderConfig != null && modelProviderConfig.isEnable() && 
modelProviderConfig.isStatus()) {
+            log.debug("Retrieved {} API key from configuration service", 
modelProviderConfig.getCode());
+            return modelProviderConfig.getApiKey();
+        } else {
+            log.warn("No valid LLM Provider API key found in configuration");
+            return "";
         }
     }
-}
\ No newline at end of file
+}
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java
index cfb3ecf52..ebe38342a 100644
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java
+++ 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java
@@ -22,7 +22,6 @@ import org.springframework.ai.chat.client.ChatClient;
 import org.springframework.ai.openai.OpenAiChatModel;
 import org.springframework.ai.openai.OpenAiChatOptions;
 import org.springframework.ai.openai.api.OpenAiApi;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
@@ -33,9 +32,6 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 public class LlmConfig {
 
-    @Value("${spring.ai.openai.chat.options.model}")
-    private String model;
-
     /**
      * Create OpenAI API instance with dynamic API key
      */
@@ -52,7 +48,7 @@ public class LlmConfig {
     @Bean
     public OpenAiChatOptions openAiChatOptions() {
         return OpenAiChatOptions.builder()
-                .model(model)
+                .model("model")
                 .temperature(0.3)
                 .build();
     }
@@ -73,4 +69,4 @@ public class LlmConfig {
         return ChatClient.create(openAiChatModel);
     }
 
-}
\ No newline at end of file
+}
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/OpenAiYamlConfig.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/OpenAiYamlConfig.java
deleted file mode 100644
index 3a0bf507d..000000000
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/OpenAiYamlConfig.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hertzbeat.ai.agent.config;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
-
-/**
- * OpenAI YAML Configuration - reads from spring.ai.openai.api-key
- */
-@Data
-@Component
-@ConfigurationProperties(prefix = "spring.ai.openai")
-public class OpenAiYamlConfig {
-
-    /**
-     * OpenAI API key from spring.ai.openai.api-key
-     */
-    private String apiKey;
-
-    /**
-     * Check if OpenAI is enabled (has API key)
-     */
-    public boolean isEnable() {
-        return apiKey != null && !apiKey.trim().isEmpty();
-    }
-}
\ No newline at end of file
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/OpenAiConfigController.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/OpenAiConfigController.java
deleted file mode 100644
index 195febf59..000000000
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/OpenAiConfigController.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hertzbeat.ai.agent.controller;
-
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.ai.agent.pojo.dto.OpenAiConfigDto;
-import org.apache.hertzbeat.ai.agent.service.OpenAiConfigService;
-import org.springframework.http.ResponseEntity;
-
-import jakarta.validation.Valid;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
-
-/**
- * OpenAI Configuration API
- */
-@RestController
-@RequestMapping(value = "/api/ai-agent/config", produces = 
{APPLICATION_JSON_VALUE})
-@Tag(name = "OpenAI Configuration API")
-@Slf4j
-public class OpenAiConfigController {
-
-    private final OpenAiConfigService openAiConfigService;
-
-    public OpenAiConfigController(OpenAiConfigService openAiConfigService) {
-        this.openAiConfigService = openAiConfigService;
-    }
-
-    @PostMapping("/openai")
-    @Operation(summary = "Save OpenAI configuration", description = "Save or 
update OpenAI configuration")
-    public ResponseEntity<Map<String, Object>> saveOpenAiConfig(@Valid 
@RequestBody OpenAiConfigDto config) {
-        try {
-            Map<String, Object> response = new HashMap<>();
-            
-            // Validate API key if enabled
-            if (config.isEnable() && config.getApiKey() != null && 
!config.getApiKey().trim().isEmpty()) {
-                OpenAiConfigService.ValidationResult validationResult = 
openAiConfigService.validateApiKey(config.getApiKey());
-                
-                if (!validationResult.isValid()) {
-                    log.warn("API key validation failed during save: {}", 
validationResult.getMessage());
-                    response.put("code", 1);
-                    response.put("msg", "API key validation failed: " + 
validationResult.getMessage());
-                    return ResponseEntity.ok(response);
-                }
-                log.info("API key validation successful during save");
-            }
-            
-            // Save the configuration
-            openAiConfigService.saveConfig(config);
-            
-            response.put("code", 0);
-            response.put("msg", "OpenAI configuration saved successfully");
-            
-            return ResponseEntity.ok(response);
-        } catch (Exception e) {
-            log.error("Failed to save OpenAI configuration", e);
-            
-            Map<String, Object> response = new HashMap<>();
-            response.put("code", 1);
-            response.put("msg", "Failed to save configuration: " + 
e.getMessage());
-            
-            return ResponseEntity.ok(response);
-        }
-    }
-
-    @GetMapping("/openai")
-    @Operation(summary = "Get OpenAI configuration", description = "Get 
current OpenAI configuration")
-    public ResponseEntity<Map<String, Object>> getOpenAiConfig() {
-        try {
-            OpenAiConfigDto config = openAiConfigService.getConfig();
-            
-            Map<String, Object> response = new HashMap<>();
-            response.put("code", 0);
-            response.put("data", config);
-            response.put("msg", "Success");
-            
-            return ResponseEntity.ok(response);
-        } catch (Exception e) {
-            log.error("Failed to get OpenAI configuration", e);
-            
-            Map<String, Object> response = new HashMap<>();
-            response.put("code", 1);
-            response.put("msg", "Failed to get configuration: " + 
e.getMessage());
-            
-            return ResponseEntity.ok(response);
-        }
-    }
-
-    @GetMapping("/openai/status")
-    @Operation(summary = "Check OpenAI configuration status", description = 
"Check if OpenAI is properly configured")
-    public ResponseEntity<Map<String, Object>> getOpenAiConfigStatus() {
-        try {
-            boolean configured = openAiConfigService.isConfigured();
-            OpenAiConfigDto effectiveConfig = 
openAiConfigService.getEffectiveConfig();
-            boolean hasDbConfig = openAiConfigService.getConfig() != null;
-            boolean hasYamlConfig = effectiveConfig != null && !hasDbConfig;
-            
-            // Validate the effective configuration
-            boolean validationPassed = false;
-            String validationMessage = "No configuration found";
-            
-            if (effectiveConfig != null && effectiveConfig.isEnable() && 
effectiveConfig.getApiKey() != null && 
!effectiveConfig.getApiKey().trim().isEmpty()) {
-                OpenAiConfigService.ValidationResult validationResult = 
openAiConfigService.validateApiKey(effectiveConfig.getApiKey());
-                validationPassed = validationResult.isValid();
-                validationMessage = validationResult.getMessage();
-                
-                if (!validationPassed) {
-                    log.warn("OpenAI API key validation failed during status 
check: {}", validationMessage);
-                }
-            }
-            
-            Map<String, Object> response = new HashMap<>();
-            response.put("code", 0);
-            response.put("data", Map.of(
-                "configured", configured && validationPassed,
-                "hasDbConfig", hasDbConfig,
-                "hasYamlConfig", hasYamlConfig,
-                "validationPassed", validationPassed,
-                "validationMessage", validationMessage
-            ));
-            response.put("msg", "Success");
-            
-            return ResponseEntity.ok(response);
-        } catch (Exception e) {
-            log.error("Failed to get OpenAI configuration status", e);
-            
-            Map<String, Object> response = new HashMap<>();
-            response.put("code", 1);
-            response.put("msg", "Failed to get status: " + e.getMessage());
-            
-            return ResponseEntity.ok(response);
-        }
-    }
-
-}
\ No newline at end of file
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/OpenAiConfigDao.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/OpenAiConfigDao.java
deleted file mode 100644
index b1ba96da2..000000000
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/OpenAiConfigDao.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hertzbeat.ai.agent.dao;
-
-import org.apache.hertzbeat.ai.agent.entity.OpenAiConfig;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
-import org.springframework.stereotype.Repository;
-
-/**
- * OpenAI Agent Configuration Dao
- */
-@Repository
-public interface OpenAiConfigDao extends JpaRepository<OpenAiConfig, String>, 
JpaSpecificationExecutor<OpenAiConfig> {
-    
-    /**
-     * Query by type
-     * @param type type
-     * @return Return the queried configuration information
-     */
-    OpenAiConfig findByType(String type);
-}
\ No newline at end of file
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/event/OpenAiConfigChangeEvent.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/event/AiProviderConfigChangeEvent.java
similarity index 84%
rename from 
hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/event/OpenAiConfigChangeEvent.java
rename to 
hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/event/AiProviderConfigChangeEvent.java
index b6bb92f37..410b57da9 100644
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/event/OpenAiConfigChangeEvent.java
+++ 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/event/AiProviderConfigChangeEvent.java
@@ -21,11 +21,11 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationEvent;
 
 /**
- * OpenAI configuration change event
+ * Ai Provider configuration change event
  */
-public class OpenAiConfigChangeEvent extends ApplicationEvent {
+public class AiProviderConfigChangeEvent extends ApplicationEvent {
 
-    public OpenAiConfigChangeEvent(ApplicationContext source) {
+    public AiProviderConfigChangeEvent(ApplicationContext source) {
         super(source);
     }
-}
\ No newline at end of file
+}
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/OpenAiConfigDto.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/ModelProviderConfig.java
similarity index 57%
rename from 
hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/OpenAiConfigDto.java
rename to 
hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/ModelProviderConfig.java
index c443e4b49..af96cfd03 100644
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/OpenAiConfigDto.java
+++ 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/ModelProviderConfig.java
@@ -24,24 +24,36 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 /**
- * OpenAI Configuration DTO - simplified to handle only API key
+ * Model Provider Configuration
  */
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
-@Schema(description = "OpenAI configuration")
-public class OpenAiConfigDto {
-
-    /**
-     * Whether to enable OpenAI, default is false
-     */
-    @Schema(title = "Enable OpenAI", description = "Whether OpenAI is 
enabled", example = "true")
+@Schema(description = "LLM Model Provider configuration")
+public class ModelProviderConfig {
+    
+    @Schema(title = "Enable Provider", description = "Whether Provider is 
enabled", example = "true")
     private boolean enable = false;
-
-    /**
-     * OpenAI API key
-     */
-    @Schema(title = "API Key", description = "OpenAI API key", example = 
"sk-...")
+    
+    @Schema(title = "Check the provider available status")
+    private boolean status = false;
+    
+    @Schema(title = "The error message when provider status check failed")
+    private String error;
+    
+    @Schema(title = "Model type, text-generate, vision")
+    private String type;
+    
+    @Schema(title = "Model Provider code, like openai, zai, bigmodel")
+    private String code;
+    
+    @Schema(title = "custom the provider server base url")
+    private String baseUrl;
+    
+    @Schema(title = "use the model id name, eg: gpt-5, glm-4.6")
+    private String model;
+    
+    @Schema(title = "API Key", description = "API key", example = "sk-...")
     @NotBlank(message = "API Key cannot be empty when enabled")
     private String apiKey;
-}
\ No newline at end of file
+}
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/OpenAiConfigService.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/AiConfigService.java
similarity index 69%
rename from 
hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/OpenAiConfigService.java
rename to 
hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/AiConfigService.java
index 1d15c46d5..ad379ba2b 100644
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/OpenAiConfigService.java
+++ 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/AiConfigService.java
@@ -17,26 +17,10 @@
 
 package org.apache.hertzbeat.ai.agent.service;
 
-import org.apache.hertzbeat.ai.agent.event.OpenAiConfigChangeEvent;
-import org.apache.hertzbeat.ai.agent.pojo.dto.OpenAiConfigDto;
-
 /**
- * OpenAI Configuration Service
- * Consolidated service for OpenAI configuration, validation, and client 
factory management
+ * Ai Configuration Service
  */
-public interface OpenAiConfigService {
-
-    /**
-     * Save OpenAI configuration
-     * @param config OpenAI configuration
-     */
-    void saveConfig(OpenAiConfigDto config);
-
-    /**
-     * Get OpenAI configuration
-     * @return OpenAI configuration
-     */
-    OpenAiConfigDto getConfig();
+public interface AiConfigService {
 
     /**
      * Check if OpenAI is properly configured
@@ -44,12 +28,6 @@ public interface OpenAiConfigService {
      */
     boolean isConfigured();
 
-    /**
-     * Get effective OpenAI configuration (DB first, then YAML fallback)
-     * @return effective configuration or null if not configured
-     */
-    OpenAiConfigDto getEffectiveConfig();
-
     /**
      * Validate OpenAI API key by calling the OpenAI API
      * @param apiKey the API key to validate
@@ -63,12 +41,6 @@ public interface OpenAiConfigService {
      */
     void reloadConfig();
 
-    /**
-     * Handle OpenAI configuration change events
-     * @param event OpenAI configuration change event
-     */
-    void onOpenAiConfigChange(OpenAiConfigChangeEvent event);
-
     /**
      * Validation result class
      */
@@ -97,4 +69,4 @@ public interface OpenAiConfigService {
             return message;
         }
     }
-}
\ No newline at end of file
+}
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/AiConfigServiceImpl.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/AiConfigServiceImpl.java
new file mode 100644
index 000000000..2f4ee7c4d
--- /dev/null
+++ 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/AiConfigServiceImpl.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hertzbeat.ai.agent.service.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.hertzbeat.ai.agent.event.AiProviderConfigChangeEvent;
+import org.apache.hertzbeat.ai.agent.pojo.dto.ModelProviderConfig;
+import org.apache.hertzbeat.ai.agent.service.AiConfigService;
+import org.apache.hertzbeat.base.dao.GeneralConfigDao;
+import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
+import org.apache.hertzbeat.common.util.JsonUtil;
+import org.springframework.context.event.EventListener;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Ai Configuration Service Implementation
+ */
+@Slf4j
+@Service
+public class AiConfigServiceImpl implements AiConfigService {
+    
+    private static final String OPENAI_MODELS_ENDPOINT = 
"https://api.openai.com/v1/models";;
+    private final RestTemplate restTemplate;
+
+    private final GeneralConfigDao generalConfigDao;
+
+    public AiConfigServiceImpl(GeneralConfigDao generalConfigDao, RestTemplate 
restTemplate) {
+        this.restTemplate = restTemplate;
+        this.generalConfigDao = generalConfigDao;
+    }
+
+    @Override
+    public boolean isConfigured() {
+        GeneralConfig providerConfig = generalConfigDao.findByType("provider");
+        ModelProviderConfig modelProviderConfig = 
JsonUtil.fromJson(providerConfig.getContent(), ModelProviderConfig.class);
+        return modelProviderConfig != null && modelProviderConfig.isStatus();
+    }
+
+    @Override
+    public ValidationResult validateApiKey(String apiKey) {
+        if (!StringUtils.hasText(apiKey)) {
+            return ValidationResult.failure("API key cannot be empty");
+        }
+
+        if (!apiKey.startsWith("sk-")) {
+            return ValidationResult.failure("Invalid API key format. OpenAI 
API keys should start with 'sk-'");
+        }
+
+        try {
+            HttpHeaders headers = new HttpHeaders();
+            headers.set("Authorization", "Bearer " + apiKey);
+            headers.set("Content-Type", "application/json");
+            
+            HttpEntity<String> entity = new HttpEntity<>(headers);
+            
+            log.debug("Validating OpenAI API key by calling models endpoint");
+            ResponseEntity<String> response = restTemplate.exchange(
+                OPENAI_MODELS_ENDPOINT,
+                HttpMethod.GET,
+                entity,
+                String.class
+            );
+
+            if (response.getStatusCode() == HttpStatus.OK) {
+                log.info("OpenAI API key validation successful");
+                return ValidationResult.success("API key is valid");
+            } else {
+                log.warn("OpenAI API key validation failed with status: {}", 
response.getStatusCode());
+                return ValidationResult.failure("API key validation failed: " 
+ response.getStatusCode());
+            }
+
+        } catch (Exception e) {
+            log.error("Error validating OpenAI API key", e);
+            String errorMessage = e.getMessage();
+            
+            // Parse common error messages
+            if (errorMessage.contains("401")) {
+                return ValidationResult.failure("Invalid API key - 
authentication failed");
+            } else if (errorMessage.contains("403")) {
+                return ValidationResult.failure("API key does not have 
permission to access models");
+            } else if (errorMessage.contains("429")) {
+                return ValidationResult.failure("Rate limit exceeded - please 
try again later");
+            } else if (errorMessage.contains("timeout") || 
errorMessage.contains("connect")) {
+                return ValidationResult.failure("Network error - unable to 
connect to OpenAI API");
+            } else {
+                return ValidationResult.failure("API key validation failed: " 
+ errorMessage);
+            }
+        }
+    }
+
+    @Override
+    public void reloadConfig() {
+        synchronized (this) {
+            
+        }
+    }
+
+    /**
+     * OpenAI configuration change event listener
+     */
+    @EventListener(AiProviderConfigChangeEvent.class)
+    public void onAiProviderConfigChange(AiProviderConfigChangeEvent event) {
+        log.info("Provider configuration change event received");
+        reloadConfig();
+    }
+}
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ConversationServiceImpl.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ConversationServiceImpl.java
index c63bb29b6..534435e28 100644
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ConversationServiceImpl.java
+++ 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ConversationServiceImpl.java
@@ -24,7 +24,7 @@ import org.apache.hertzbeat.ai.agent.pojo.dto.ConversationDto;
 import org.apache.hertzbeat.ai.agent.pojo.dto.MessageDto;
 import org.apache.hertzbeat.ai.agent.service.ChatClientProviderService;
 import org.apache.hertzbeat.ai.agent.service.ConversationService;
-import org.apache.hertzbeat.ai.agent.service.OpenAiConfigService;
+import org.apache.hertzbeat.ai.agent.service.AiConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.codec.ServerSentEvent;
 import org.springframework.stereotype.Service;
@@ -53,7 +53,7 @@ public class ConversationServiceImpl implements 
ConversationService {
     private ChatClientProviderService chatClientProviderService;
 
     @Autowired
-    private OpenAiConfigService openAiConfigService;
+    private AiConfigService openAiConfigService;
 
     @Override
     public ConversationDto createConversation() {
@@ -78,7 +78,7 @@ public class ConversationServiceImpl implements 
ConversationService {
         if (!openAiConfigService.isConfigured()) {
             ChatResponseDto errorResponse = ChatResponseDto.builder()
                     .conversationId(conversationId)
-                    .response("OpenAI is not configured. Please configure your 
OpenAI API key in the settings or application.yml file.")
+                    .response("Provider is not configured. Please configure 
your OpenAI API key in the settings or application.yml file.")
                     .build();
             return Flux.just(ServerSentEvent.builder(errorResponse)
                     .event("error")
@@ -273,4 +273,4 @@ public class ConversationServiceImpl implements 
ConversationService {
 
 
 
-}
\ No newline at end of file
+}
diff --git 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/OpenAiConfigServiceImpl.java
 
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/OpenAiConfigServiceImpl.java
deleted file mode 100644
index 7014de2e4..000000000
--- 
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/OpenAiConfigServiceImpl.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hertzbeat.ai.agent.service.impl;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.ai.agent.config.OpenAiYamlConfig;
-import org.apache.hertzbeat.ai.agent.dao.OpenAiConfigDao;
-import org.apache.hertzbeat.ai.agent.entity.OpenAiConfig;
-import org.apache.hertzbeat.ai.agent.event.OpenAiConfigChangeEvent;
-import org.apache.hertzbeat.ai.agent.pojo.dto.OpenAiConfigDto;
-import org.apache.hertzbeat.ai.agent.service.OpenAiConfigService;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.event.EventListener;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.StringUtils;
-import org.springframework.web.client.RestTemplate;
-
-/**
- * OpenAI Configuration Service Implementation
- * Consolidated service for OpenAI configuration, validation, and client 
factory management
- */
-@Slf4j
-@Service
-public class OpenAiConfigServiceImpl implements OpenAiConfigService {
-
-    private static final String CONFIG_TYPE = "openai";
-    private static final String OPENAI_MODELS_ENDPOINT = 
"https://api.openai.com/v1/models";;
-    
-    private final OpenAiConfigDao openAiConfigDao;
-    private final ObjectMapper objectMapper;
-    private final ApplicationContext applicationContext;
-    private final OpenAiYamlConfig yamlConfig;
-    private final RestTemplate restTemplate;
-    
-    // Client factory cache
-    private volatile OpenAiConfigDto currentConfig;
-
-    public OpenAiConfigServiceImpl(OpenAiConfigDao openAiConfigDao, 
-                                  ObjectMapper objectMapper,
-                                  ApplicationContext applicationContext,
-                                  OpenAiYamlConfig yamlConfig) {
-        this.openAiConfigDao = openAiConfigDao;
-        this.objectMapper = objectMapper;
-        this.applicationContext = applicationContext;
-        this.yamlConfig = yamlConfig;
-        this.restTemplate = new RestTemplate();
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void saveConfig(OpenAiConfigDto config) {
-        try {
-            String contentJson = objectMapper.writeValueAsString(config);
-            
-            OpenAiConfig openAiConfig = OpenAiConfig.builder()
-                    .type(CONFIG_TYPE)
-                    .content(contentJson)
-                    .build();
-            
-            openAiConfigDao.save(openAiConfig);
-            log.info("OpenAI configuration saved successfully");
-            
-            applicationContext.publishEvent(new 
OpenAiConfigChangeEvent(applicationContext));
-            
-        } catch (JsonProcessingException e) {
-            throw new IllegalArgumentException("Failed to save OpenAI 
configuration: " + e.getMessage());
-        }
-    }
-
-    @Override
-    public OpenAiConfigDto getConfig() {
-        OpenAiConfig config = openAiConfigDao.findByType(CONFIG_TYPE);
-        if (config == null || !StringUtils.hasText(config.getContent())) {
-            return null;
-        }
-        
-        try {
-            return objectMapper.readValue(config.getContent(), 
OpenAiConfigDto.class);
-        } catch (JsonProcessingException e) {
-            throw new IllegalArgumentException("Failed to parse OpenAI 
configuration: " + e.getMessage());
-        }
-    }
-
-    @Override
-    public boolean isConfigured() {
-        OpenAiConfigDto effective = getEffectiveConfig();
-        return effective != null && effective.isEnable() && 
StringUtils.hasText(effective.getApiKey());
-    }
-
-    @Override
-    public OpenAiConfigDto getEffectiveConfig() {
-        OpenAiConfigDto dbConfig = getConfig();
-        if (dbConfig != null && dbConfig.isEnable() && 
StringUtils.hasText(dbConfig.getApiKey())) {
-            log.debug("Using database OpenAI configuration");
-            return dbConfig;
-        }
-        
-        if (yamlConfig != null && yamlConfig.isEnable() && 
StringUtils.hasText(yamlConfig.getApiKey())) {
-            log.debug("Using YAML OpenAI configuration from 
spring.ai.openai.api-key");
-            OpenAiConfigDto yamlDto = new OpenAiConfigDto();
-            yamlDto.setEnable(true);
-            yamlDto.setApiKey(yamlConfig.getApiKey());
-            return yamlDto;
-        }
-        
-        log.debug("No valid OpenAI configuration found");
-        return null;
-    }
-
-    @Override
-    public ValidationResult validateApiKey(String apiKey) {
-        if (!StringUtils.hasText(apiKey)) {
-            return ValidationResult.failure("API key cannot be empty");
-        }
-
-        if (!apiKey.startsWith("sk-")) {
-            return ValidationResult.failure("Invalid API key format. OpenAI 
API keys should start with 'sk-'");
-        }
-
-        try {
-            HttpHeaders headers = new HttpHeaders();
-            headers.set("Authorization", "Bearer " + apiKey);
-            headers.set("Content-Type", "application/json");
-            
-            HttpEntity<String> entity = new HttpEntity<>(headers);
-            
-            log.debug("Validating OpenAI API key by calling models endpoint");
-            ResponseEntity<String> response = restTemplate.exchange(
-                OPENAI_MODELS_ENDPOINT,
-                HttpMethod.GET,
-                entity,
-                String.class
-            );
-
-            if (response.getStatusCode() == HttpStatus.OK) {
-                log.info("OpenAI API key validation successful");
-                return ValidationResult.success("API key is valid");
-            } else {
-                log.warn("OpenAI API key validation failed with status: {}", 
response.getStatusCode());
-                return ValidationResult.failure("API key validation failed: " 
+ response.getStatusCode());
-            }
-
-        } catch (Exception e) {
-            log.error("Error validating OpenAI API key", e);
-            String errorMessage = e.getMessage();
-            
-            // Parse common error messages
-            if (errorMessage.contains("401")) {
-                return ValidationResult.failure("Invalid API key - 
authentication failed");
-            } else if (errorMessage.contains("403")) {
-                return ValidationResult.failure("API key does not have 
permission to access models");
-            } else if (errorMessage.contains("429")) {
-                return ValidationResult.failure("Rate limit exceeded - please 
try again later");
-            } else if (errorMessage.contains("timeout") || 
errorMessage.contains("connect")) {
-                return ValidationResult.failure("Network error - unable to 
connect to OpenAI API");
-            } else {
-                return ValidationResult.failure("API key validation failed: " 
+ errorMessage);
-            }
-        }
-    }
-
-    @Override
-    public void reloadConfig() {
-        synchronized (this) {
-            currentConfig = null; // Force reload
-        }
-    }
-
-    /**
-     * OpenAI configuration change event listener
-     */
-    @EventListener(OpenAiConfigChangeEvent.class)
-    public void onOpenAiConfigChange(OpenAiConfigChangeEvent event) {
-        log.info("[OpenAiConfigService] OpenAI configuration change event 
received");
-        reloadConfig();
-    }
-}
\ No newline at end of file
diff --git 
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/constants/GeneralConfigTypeEnum.java
 
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/constants/GeneralConfigTypeEnum.java
index 9a461dfcd..ce54a7030 100644
--- 
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/constants/GeneralConfigTypeEnum.java
+++ 
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/constants/GeneralConfigTypeEnum.java
@@ -55,5 +55,10 @@ public enum GeneralConfigTypeEnum {
     /**
      * system store config
      */
-    oss
+    oss,
+
+    /**
+     * model llm provider
+     */
+    provider
 }
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/GeneralConfigController.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/GeneralConfigController.java
index f88444e7b..5d365431f 100644
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/GeneralConfigController.java
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/GeneralConfigController.java
@@ -51,11 +51,11 @@ import java.util.stream.Collectors;
 import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
 
 /**
- * Alert sender Configuration API
+ * Generate Configuration API
  */
 @RestController
 @RequestMapping(value = "/api/config", produces = {APPLICATION_JSON_VALUE})
-@Tag(name = "Alert sender Configuration API")
+@Tag(name = "Generate Configuration API")
 @Slf4j
 public class GeneralConfigController {
 
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ModelProviderConfigServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ModelProviderConfigServiceImpl.java
new file mode 100644
index 000000000..e5755a1af
--- /dev/null
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ModelProviderConfigServiceImpl.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hertzbeat.manager.service.impl;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.lang.reflect.Type;
+import org.apache.hertzbeat.ai.agent.pojo.dto.ModelProviderConfig;
+import org.apache.hertzbeat.base.dao.GeneralConfigDao;
+import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
+import org.springframework.stereotype.Service;
+
+/**
+ * llm model provider config service impl
+ */
+@Service
+public class ModelProviderConfigServiceImpl extends 
AbstractGeneralConfigServiceImpl<ModelProviderConfig> {
+
+    /**
+     *
+     * <p>Constructor, passing in GeneralConfigDao, ObjectMapper and type.</p>
+     *
+     * @param generalConfigDao ConfigDao object
+     * @param objectMapper     JSON tool object
+     */
+    public ModelProviderConfigServiceImpl(GeneralConfigDao generalConfigDao, 
ObjectMapper objectMapper) {
+        super(generalConfigDao, objectMapper);
+    }
+    
+    @Override
+    public String type() {
+        return GeneralConfigTypeEnum.provider.name();
+    }
+    
+    @Override
+    public TypeReference<ModelProviderConfig> getTypeReference() {
+        return new TypeReference<>() {
+            @Override
+            public Type getType() {
+                return ModelProviderConfig.class;
+            }
+        };
+    }
+}
diff --git a/hertzbeat-manager/src/main/resources/application-test.yml 
b/hertzbeat-manager/src/main/resources/application-test.yml
index bd76e9d93..4aa13715f 100644
--- a/hertzbeat-manager/src/main/resources/application-test.yml
+++ b/hertzbeat-manager/src/main/resources/application-test.yml
@@ -189,16 +189,3 @@ grafana:
   expose-url: http://127.0.0.1:3000
   username: admin
   password: admin
-
-# See the documentation for details : 
https://hertzbeat.apache.org/zh-cn/docs/help/aiConfig
-ai:
-  # AI Type:zhiPu、alibabaAi、kimiAi、sparkDesk、ollama、openRouter
-  type:
-  # Model name:glm-4、qwen-turboo、moonshot-v1-8k、generalv3.5
-  model:
-  # api key
-  api-key:
-  #At present, only IFLYTEK large model needs to be filled in
-  api-secret:
-  # The URL of the ollama AI service
-  api-url:
diff --git a/hertzbeat-manager/src/main/resources/application.yml 
b/hertzbeat-manager/src/main/resources/application.yml
index 9679a359b..c4f463601 100644
--- a/hertzbeat-manager/src/main/resources/application.yml
+++ b/hertzbeat-manager/src/main/resources/application.yml
@@ -37,14 +37,6 @@ spring:
           resource: true
           prompt: true
           completion: true
-    chat:
-      client:
-        enabled: false
-    openai:
-      api-key: OPENAI_API_KEY
-      chat:
-        options:
-          model: gpt-4.1-nano-2025-04-14
 
   mvc:
     static-path-pattern: /**
@@ -321,16 +313,3 @@ grafana:
   expose-url: http://127.0.0.1:3000
   username: admin
   password: admin
-
-# See the documentation for details : 
https://hertzbeat.apache.org/zh-cn/docs/help/aiConfig
-ai:
-  # AI Type:zhiPu、alibabaAi、kimiAi、sparkDesk、ollama、openRouter
-  type:
-  # Model name:glm-4、qwen-turboo、moonshot-v1-8k、generalv3.5
-  model:
-  # api key
-  api-key:
-  #At present, only IFLYTEK large model needs to be filled in
-  api-secret:
-  # The URL of the ollama AI service
-  api-url:
diff --git a/home/docs/download.md b/home/docs/download.md
index 269cf1f09..ed0edb64f 100644
--- a/home/docs/download.md
+++ b/home/docs/download.md
@@ -22,7 +22,7 @@ Previous releases of HertzBeat may be affected by security 
issues, please use th
 
 | Version | Date       | Download                                              
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
 
|---------|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
-| v1.7.3  | 2025.09.05 | 
[apache-hertzbeat-1.7.3-bin.tar.gz](https://www.apache.org/dyn/closer.lua/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz)
 (Server) ( 
[signature](https://downloads.apache.org/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz.asc)
 , 
[sha512](https://downloads.apache.org/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz.sha512)
 ) <br/> 
[apache-hertzbeat-collector-1.7.3-bin.tar.gz](https://www.apache.org/dyn/closer.lua/hertzbeat/1.7.3/apache-hertzbeat-collector-1.
 [...]
+| v1.7.3  | 2025.09.05 | 
[apache-hertzbeat-1.7.3-bin.tar.gz](https://www.apache.org/dyn/closer.lua/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz)
 (Server) ( 
[signature](https://downloads.apache.org/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz.asc)
 , 
[sha512](https://downloads.apache.org/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz.sha512)
 ) <br/> 
[apache-hertzbeat-collector-1.7.3-bin.tar.gz](https://www.apache.org/dyn/closer.lua/hertzbeat/1.7.3/apache-hertzbeat-collector-1.
 [...]
 
 ## Release Docker Image
 
diff --git a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/download.md 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/download.md
index 72c0abbd4..04ec4a2a6 100644
--- a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/download.md
+++ b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/download.md
@@ -22,7 +22,7 @@ sidebar_label: Download
 
 | 版本     | 日期         | 下载                                                     
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
 
|--------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
-| v1.7.3 | 2025.09.05 | 
[apache-hertzbeat-1.7.3-bin.tar.gz](https://www.apache.org/dyn/closer.lua/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz)
 (Server) ( 
[signature](https://downloads.apache.org/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz.asc)
 , 
[sha512](https://downloads.apache.org/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz.sha512)
 ) <br/> 
[apache-hertzbeat-collector-1.7.3-bin.tar.gz](https://www.apache.org/dyn/closer.lua/hertzbeat/1.7.3/apache-hertzbeat-collector-1.7
 [...]
+| v1.7.3 | 2025.09.05 | 
[apache-hertzbeat-1.7.3-bin.tar.gz](https://www.apache.org/dyn/closer.lua/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz)
 (Server) ( 
[signature](https://downloads.apache.org/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz.asc)
 , 
[sha512](https://downloads.apache.org/hertzbeat/1.7.3/apache-hertzbeat-1.7.3-bin.tar.gz.sha512)
 ) <br/> 
[apache-hertzbeat-collector-1.7.3-bin.tar.gz](https://www.apache.org/dyn/closer.lua/hertzbeat/1.7.3/apache-hertzbeat-collector-1.7
 [...]
 
 ## Docker 镜像版本
 
diff --git a/web-app/src/app/pojo/ModelProviderConfig.ts 
b/web-app/src/app/pojo/ModelProviderConfig.ts
new file mode 100644
index 000000000..717409609
--- /dev/null
+++ b/web-app/src/app/pojo/ModelProviderConfig.ts
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export class ModelProviderConfig {
+  enable: boolean = false;
+  status: boolean = false;
+  error!: string;
+  type!: string;
+  code!: string;
+  baseUrl!: string;
+  model!: string;
+  apiKey!: string;
+}
diff --git a/web-app/src/app/service/general-config.service.ts 
b/web-app/src/app/service/general-config.service.ts
index 02141ee5b..f72c9b11b 100644
--- a/web-app/src/app/service/general-config.service.ts
+++ b/web-app/src/app/service/general-config.service.ts
@@ -22,6 +22,7 @@ import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
 
 import { Message } from '../pojo/Message';
+import { ModelProviderConfig } from '../pojo/ModelProviderConfig';
 
 const general_config_uri = '/config';
 
@@ -39,6 +40,14 @@ export class GeneralConfigService {
     return this.http.get<Message<any>>(`${general_config_uri}/${type}`);
   }
 
+  public saveModelProviderConfig(body: ModelProviderConfig): 
Observable<Message<any>> {
+    return this.http.post<Message<any>>(`${general_config_uri}/provider`, 
body);
+  }
+
+  public getModelProviderConfig(): Observable<Message<ModelProviderConfig>> {
+    return 
this.http.get<Message<ModelProviderConfig>>(`${general_config_uri}/provider`);
+  }
+
   public updateAppTemplateConfig(body: any, app: string): 
Observable<Message<void>> {
     return 
this.http.put<Message<void>>(`${general_config_uri}/template/${app}`, body);
   }
diff --git a/web-app/src/app/service/openai-config.service.ts 
b/web-app/src/app/service/openai-config.service.ts
deleted file mode 100644
index a82c47815..000000000
--- a/web-app/src/app/service/openai-config.service.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { HttpClient } from '@angular/common/http';
-import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs';
-
-import { Message } from '../pojo/Message';
-
-export interface OpenAiConfig {
-  enable: boolean;
-  apiKey: string;
-}
-
-export interface OpenAiConfigStatus {
-  configured: boolean;
-  hasDbConfig: boolean;
-  hasYamlConfig: boolean;
-  validationPassed: boolean;
-  validationMessage: string;
-}
-
-const openai_config_uri = '/ai-agent/config';
-
-@Injectable({
-  providedIn: 'root'
-})
-export class OpenAiConfigService {
-  constructor(private http: HttpClient) {}
-
-  public saveOpenAiConfig(config: OpenAiConfig): Observable<Message<any>> {
-    return this.http.post<Message<any>>(`${openai_config_uri}/openai`, config);
-  }
-
-  public getOpenAiConfig(): Observable<Message<OpenAiConfig>> {
-    return this.http.get<Message<OpenAiConfig>>(`${openai_config_uri}/openai`);
-  }
-
-  public getOpenAiConfigStatus(): Observable<Message<OpenAiConfigStatus>> {
-    return 
this.http.get<Message<OpenAiConfigStatus>>(`${openai_config_uri}/openai/status`);
-  }
-}
diff --git a/web-app/src/app/shared/components/ai-chat/chat.component.html 
b/web-app/src/app/shared/components/ai-chat/chat.component.html
index 5642b1276..f55bd9387 100644
--- a/web-app/src/app/shared/components/ai-chat/chat.component.html
+++ b/web-app/src/app/shared/components/ai-chat/chat.component.html
@@ -160,9 +160,9 @@
 <!-- OpenAI Configuration Modal -->
 <nz-modal
   [(nzVisible)]="showConfigModal"
-  nzTitle="OpenAI Configuration"
+  nzTitle="Ai Provider Configuration"
   (nzOnCancel)="onCloseConfigModal()"
-  (nzOnOk)="onSaveOpenAiConfig()"
+  (nzOnOk)="onSaveAiProviderConfig()"
   nzMaskClosable="false"
   [nzClosable]="false"
   nzWidth="600px"
@@ -173,10 +173,10 @@
   <div *nzModalContent class="-inner-content">
     <form nz-form nzLayout="vertical">
       <nz-form-item>
-        <nz-form-label nzRequired="true">OpenAI API Key</nz-form-label>
+        <nz-form-label nzRequired="true">API Key</nz-form-label>
         <nz-form-control nzErrorTip="API Key is required">
-          <input nz-input [(ngModel)]="openAiConfig.apiKey" name="apiKey" 
type="password" placeholder="sk-..." required />
-          <p class="form-help">Your OpenAI API key (starts with sk-). The key 
will be validated when saved.</p>
+          <input nz-input [(ngModel)]="aiProviderConfig.apiKey" name="apiKey" 
type="password" placeholder="sk-..." required />
+          <p class="form-help">Your Provider API key. The key will be 
validated when saved.</p>
         </nz-form-control>
       </nz-form-item>
     </form>
diff --git a/web-app/src/app/shared/components/ai-chat/chat.component.ts 
b/web-app/src/app/shared/components/ai-chat/chat.component.ts
index 3a3efa5a4..c7f8f1436 100644
--- a/web-app/src/app/shared/components/ai-chat/chat.component.ts
+++ b/web-app/src/app/shared/components/ai-chat/chat.component.ts
@@ -22,8 +22,9 @@ import { I18NService } from '@core';
 import { NzMessageService } from 'ng-zorro-antd/message';
 import { NzModalService } from 'ng-zorro-antd/modal';
 
+import { ModelProviderConfig } from '../../../pojo/ModelProviderConfig';
 import { AiChatService, ChatMessage, ConversationDto } from 
'../../../service/ai-chat.service';
-import { OpenAiConfigService, OpenAiConfig, OpenAiConfigStatus } from 
'../../../service/openai-config.service';
+import { GeneralConfigService } from '../../../service/general-config.service';
 import { ThemeService } from '../../../service/theme.service';
 
 @Component({
@@ -46,10 +47,7 @@ export class ChatComponent implements OnInit, 
AfterViewChecked {
   isOpenAiConfigured = false;
   showConfigModal = false;
   configLoading = false;
-  openAiConfig: OpenAiConfig = {
-    enable: false,
-    apiKey: ''
-  };
+  aiProviderConfig: ModelProviderConfig = new ModelProviderConfig();
 
   constructor(
     private aiChatService: AiChatService,
@@ -58,7 +56,7 @@ export class ChatComponent implements OnInit, 
AfterViewChecked {
     private i18n: I18NService,
     private cdr: ChangeDetectorRef,
     private themeSvc: ThemeService,
-    private openAiConfigService: OpenAiConfigService
+    private generalConfigSvc: GeneralConfigService
   ) {}
 
   ngOnInit(): void {
@@ -428,61 +426,46 @@ export class ChatComponent implements OnInit, 
AfterViewChecked {
   }
 
   /**
-   * Check OpenAI configuration status
+   * Check provider configuration status
    */
   checkOpenAiConfiguration(): void {
-    this.openAiConfigService.getOpenAiConfigStatus().subscribe({
+    this.generalConfigSvc.getModelProviderConfig().subscribe({
       next: response => {
-        if (response.code === 0) {
-          this.isOpenAiConfigured = response.data.configured;
-          if (this.isOpenAiConfigured) {
+        if (response.code === 0 && response.data) {
+          this.aiProviderConfig = response.data;
+          if (!response.data.enable) {
             this.loadConversations();
           } else {
-            this.showOpenAiConfigDialog(response.data);
+            this.showAiProviderConfigDialog(response.data.error);
           }
-        } else {
-          console.error('Failed to check OpenAI configuration:', response.msg);
-          this.showOpenAiConfigDialog();
         }
       },
       error: error => {
-        console.error('Error checking OpenAI configuration:', error);
-        this.showOpenAiConfigDialog();
+        console.error('Failed to load model provider config:', error);
+        this.showAiProviderConfigDialog();
       }
     });
   }
 
   /**
-   * Show OpenAI configuration dialog
+   * Show ai configuration dialog
    */
-  showOpenAiConfigDialog(status?: OpenAiConfigStatus): void {
-    // Load existing configuration if available
-    this.loadOpenAiConfig();
-
+  showAiProviderConfigDialog(error?: string): void {
     let contentMessage = `
       <div style="margin-bottom: 16px;">
-        <p>To use AI Agent Chat, please configure your OpenAI API key.</p>
+        <p>To use AI Agent Chat, please configure your Model Provider.</p>
     `;
 
-    if (status && !status.validationPassed && status.validationMessage) {
+    if (error) {
       contentMessage += `
         <div style="margin-bottom: 12px; padding: 8px; background: #fff2f0; 
border: 1px solid #ffccc7; border-radius: 4px;">
-          <strong>Configuration Issue:</strong> ${status.validationMessage}
+          <strong>Configuration Issue:</strong> ${error}
         </div>
       `;
     }
 
-    contentMessage += `
-        <p>You can either:</p>
-        <ul>
-          <li>Configure it here (stored in database)</li>
-          <li>Add it to your application.yml file under 
<code>spring.ai.openai.api-key</code></li>
-        </ul>
-      </div>
-    `;
-
     const modalRef = this.modal.create({
-      nzTitle: 'OpenAI Configuration Required',
+      nzTitle: 'Ai Model Provider Configuration Required',
       nzContent: contentMessage,
       nzWidth: 600,
       nzClosable: false,
@@ -500,27 +483,11 @@ export class ChatComponent implements OnInit, 
AfterViewChecked {
     });
   }
 
-  /**
-   * Load OpenAI configuration
-   */
-  loadOpenAiConfig(): void {
-    this.openAiConfigService.getOpenAiConfig().subscribe({
-      next: response => {
-        if (response.code === 0 && response.data) {
-          this.openAiConfig = { ...this.openAiConfig, ...response.data };
-        }
-      },
-      error: error => {
-        console.error('Failed to load OpenAI config:', error);
-      }
-    });
-  }
-
   /**
    * Show configuration modal
    */
   onShowConfigModal(): void {
-    this.loadOpenAiConfig();
+    this.checkOpenAiConfiguration();
     this.showConfigModal = true;
   }
 
@@ -534,23 +501,23 @@ export class ChatComponent implements OnInit, 
AfterViewChecked {
   /**
    * Save OpenAI configuration
    */
-  onSaveOpenAiConfig(): void {
-    if (!this.openAiConfig.apiKey.trim()) {
+  onSaveAiProviderConfig(): void {
+    if (!this.aiProviderConfig.apiKey.trim()) {
       this.message.error('API Key is required');
       return;
     }
 
     // Always enable when saving an API key
-    this.openAiConfig.enable = true;
+    this.aiProviderConfig.enable = true;
 
     this.configLoading = true;
     this.message.info('Validating API key...', { nzDuration: 2000 });
 
-    this.openAiConfigService.saveOpenAiConfig(this.openAiConfig).subscribe({
+    
this.generalConfigSvc.saveModelProviderConfig(this.aiProviderConfig).subscribe({
       next: response => {
         this.configLoading = false;
         if (response.code === 0) {
-          this.message.success('OpenAI API key validated and saved 
successfully!');
+          this.message.success('Model Provider configuration saved 
successfully!');
           this.showConfigModal = false;
           this.isOpenAiConfigured = true;
           this.loadConversations();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to