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

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

commit a3cfaf2be6244e091d8480a28cb514cfd297df17
Author: tomsun28 <[email protected]>
AuthorDate: Fri Oct 31 00:48:37 2025 +0800

    refactor
    
    Signed-off-by: tomsun28 <[email protected]>
---
 .../hertzbeat/manager/config/AiProperties.java     |  60 ----
 .../hertzbeat/manager/controller/AiController.java |  68 ----
 .../hertzbeat/manager/service/ai/AiService.java    |  44 ---
 .../manager/service/ai/AlibabaAiServiceImpl.java   | 118 -------
 .../manager/service/ai/KimiAiServiceImpl.java      |  96 ------
 .../manager/service/ai/OllamaAiService.java        |  95 ------
 .../manager/service/ai/OpenRouterServiceImpl.java  |  97 ------
 .../manager/service/ai/SparkDeskAiServiceImpl.java | 104 ------
 .../manager/service/ai/ZhiPuServiceImpl.java       | 100 ------
 .../service/ai/factory/AiServiceFactoryImpl.java   |  64 ----
 .../manager/controller/AiControllerTest.java       |  88 -----
 .../manager/service/AiServiceFactoryTest.java      | 125 --------
 home/docs/help/ai_agent_chat.md                    |  15 +-
 .../current/help/ai_agent_chat.md                  | 356 +++++++++++++++++++++
 home/sidebars.json                                 |   1 -
 script/application.yml                             |  68 +++-
 .../hertzbeat-mysql-iotdb/conf/application.yml     |   7 -
 .../hertzbeat-mysql-tdengine/conf/application.yml  |   7 -
 .../conf/application.yml                           |   7 -
 .../conf/application.yml                           |   7 -
 20 files changed, 423 insertions(+), 1104 deletions(-)

diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/config/AiProperties.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/config/AiProperties.java
deleted file mode 100644
index f2528769d..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/config/AiProperties.java
+++ /dev/null
@@ -1,60 +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.manager.config;
-
-import lombok.Data;
-import org.apache.hertzbeat.common.constants.ConfigConstants;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * AiProperties
- */
-
-@Data
-@Configuration
-@ConfigurationProperties(prefix =
-        ConfigConstants.FunctionModuleConstants.AI)
-public class AiProperties {
-
-    /**
-     * AI Type: zhiPu, alibabaAi, kimiAi, sparkDesk
-     */
-    private String type;
-
-    /**
-     * Model name: glm-4, qwen-turboo, moonshot-v1-8k, generalv3.5
-     */
-    private String model;
-
-    /**
-     * API key
-     */
-    private String apiKey;
-
-    /**
-     * At present, only IFLYTEK large model needs to be filled in
-     */
-    private String apiSecret;
-
-    /**
-     * API URL for the Ollama AI service.
-     */
-    private String apiUrl;
-
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/AiController.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/AiController.java
deleted file mode 100644
index fb1a192b0..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/AiController.java
+++ /dev/null
@@ -1,68 +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.manager.controller;
-
-import static org.springframework.http.MediaType.TEXT_EVENT_STREAM_VALUE;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.hertzbeat.manager.config.AiProperties;
-import org.apache.hertzbeat.manager.pojo.dto.AiControllerRequestParam;
-import org.apache.hertzbeat.manager.service.ai.AiService;
-import org.apache.hertzbeat.manager.service.ai.factory.AiServiceFactoryImpl;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import reactor.core.publisher.Flux;
-
-/**
- * AI Management API
- */
-@Tag(name = "AI Manage API")
-@RestController
-@RequestMapping(value = "/api/ai")
-public class AiController {
-
-    /**
-     * AI beanFactory
-     */
-    @Autowired(required = false)
-    private AiServiceFactoryImpl aiServiceFactory;
-
-    @Autowired
-    private AiProperties aiProperties;
-
-    /**
-     * request AI
-     * @param requestParam          request text
-     * @return                      AI response
-     */
-    @PostMapping(path = "/get", produces = {TEXT_EVENT_STREAM_VALUE})
-    @Operation(summary = "Artificial intelligence questions and Answers",
-            description = "Artificial intelligence questions and Answers")
-    public Flux<ServerSentEvent<String>> requestAi(@Parameter(description = 
"Request text", example = "Who are you")
-                                                       @RequestBody 
AiControllerRequestParam requestParam)  {
-        Assert.notNull(aiServiceFactory, "please check that your type value is 
consistent with the documentation on the website");
-        AiService aiServiceImplBean = 
aiServiceFactory.getAiServiceImplBean(aiProperties.getType());
-        return aiServiceImplBean.requestAi(requestParam.getText());
-    }
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/AiService.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/AiService.java
deleted file mode 100644
index de8e683ed..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/AiService.java
+++ /dev/null
@@ -1,44 +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.manager.service.ai;
-
-
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.springframework.http.codec.ServerSentEvent;
-import reactor.core.publisher.Flux;
-
-
-/**
- * AI Service
- */
-public interface AiService {
-
-    /**
-     * get AI type
-     * @return     type
-     */
-    AiTypeEnum getType();
-
-    /**
-     * AI response
-     * @param text  text
-     * @return      AI response
-     */
-    Flux<ServerSentEvent<String>> requestAi(String text);
-
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/AlibabaAiServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/AlibabaAiServiceImpl.java
deleted file mode 100644
index f9c1236ab..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/AlibabaAiServiceImpl.java
+++ /dev/null
@@ -1,118 +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.manager.service.ai;
-
-import java.util.List;
-import java.util.Objects;
-import javax.annotation.PostConstruct;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.common.constants.AiConstants;
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.apache.hertzbeat.manager.config.AiProperties;
-import org.apache.hertzbeat.manager.pojo.dto.AiMessage;
-import org.apache.hertzbeat.manager.pojo.dto.AliAiRequestParamDTO;
-import org.apache.hertzbeat.manager.pojo.dto.AliAiResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
-
-
-/**
- * alibaba Ai
- */
-@Service("AlibabaAiServiceImpl")
-@ConditionalOnProperty(prefix = "ai", name = "type", havingValue = "alibabaAi")
-@Slf4j
-public class AlibabaAiServiceImpl implements AiService {
-
-    @Autowired
-    private AiProperties aiProperties;
-
-    private WebClient webClient;
-
-    @PostConstruct
-    private void init() {
-        this.webClient = WebClient.builder()
-                .baseUrl(AiConstants.AliAiConstants.URL)
-                .defaultHeader(HttpHeaders.CONTENT_TYPE, 
MediaType.APPLICATION_JSON_VALUE)
-                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + 
aiProperties.getApiKey())
-                //sse
-                .defaultHeader(HttpHeaders.ACCEPT, 
MediaType.TEXT_EVENT_STREAM_VALUE)
-                .exchangeStrategies(ExchangeStrategies.builder()
-                        .codecs(item -> 
item.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
-                        .build())
-                .build();
-    }
-
-    @Override
-    public AiTypeEnum getType() {
-        return AiTypeEnum.alibabaAi;
-    }
-
-    @Override
-    public Flux<ServerSentEvent<String>> requestAi(String text) {
-        checkParam(text, aiProperties.getModel(), aiProperties.getApiKey());
-        AliAiRequestParamDTO aliAiRequestParamDTO = 
AliAiRequestParamDTO.builder()
-                .model(aiProperties.getModel())
-                .input(AliAiRequestParamDTO.Input.builder()
-                        .messages(List.of(new 
AiMessage(AiConstants.AliAiConstants.REQUEST_ROLE, text)))
-                        .build())
-                .parameters(AliAiRequestParamDTO.Parameters.builder()
-                        .maxTokens(AiConstants.AliAiConstants.MAX_TOKENS)
-                        .temperature(AiConstants.AliAiConstants.TEMPERATURE)
-                        .enableSearch(true)
-                        .resultFormat("message")
-                        .incrementalOutput(true)
-                        .build())
-                .build();
-
-        return webClient.post()
-                .body(BodyInserters.fromValue(aliAiRequestParamDTO))
-                .retrieve()
-                .bodyToFlux(AliAiResponse.class)
-                .map(aliAiResponse -> {
-                    if (Objects.nonNull(aliAiResponse)) {
-                        List<AliAiResponse.Choice> choices = 
aliAiResponse.getOutput().getChoices();
-                        if (CollectionUtils.isEmpty(choices)) {
-                            return ServerSentEvent.<String>builder().build();
-                        }
-                        String content = 
choices.get(0).getMessage().getContent();
-                        return ServerSentEvent.<String>builder()
-                                .data(content)
-                                .build();
-                    }
-                    return ServerSentEvent.<String>builder().build();
-                })
-                .doOnError(error -> log.info("AlibabaAiServiceImpl.requestAi 
exception:{}", error.getMessage()));
-    }
-
-    private void checkParam(String param, String apiKey, String model) {
-        Assert.notNull(param, "text is null");
-        Assert.notNull(model, "model is null");
-        Assert.notNull(apiKey, "ai.api-key is null");
-    }
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/KimiAiServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/KimiAiServiceImpl.java
deleted file mode 100644
index 506394915..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/KimiAiServiceImpl.java
+++ /dev/null
@@ -1,96 +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.manager.service.ai;
-
-import java.util.List;
-import javax.annotation.PostConstruct;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.common.constants.AiConstants;
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.apache.hertzbeat.manager.config.AiProperties;
-import org.apache.hertzbeat.manager.pojo.dto.AiMessage;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiRequestParamDTO;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
-
-/**
- * Kimi Ai
- */
-@Service("KimiAiServiceImpl")
-@ConditionalOnProperty(prefix = "ai", name = "type", havingValue = "kimiAi")
-@Slf4j
-public class KimiAiServiceImpl implements AiService {
-
-    @Autowired
-    private AiProperties aiProperties;
-
-    private WebClient webClient;
-
-    @PostConstruct
-    private void init() {
-        this.webClient = WebClient.builder()
-                .baseUrl(AiConstants.KimiAiConstants.URL)
-                .defaultHeader(HttpHeaders.CONTENT_TYPE, 
MediaType.APPLICATION_JSON_VALUE)
-                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + 
aiProperties.getApiKey())
-                .exchangeStrategies(ExchangeStrategies.builder()
-                        .codecs(item -> 
item.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
-                        .build())
-                .build();
-    }
-
-    @Override
-    public AiTypeEnum getType() {
-        return AiTypeEnum.kimiAi;
-    }
-
-    @Override
-    public Flux<ServerSentEvent<String>> requestAi(String text) {
-        checkParam(text, aiProperties.getModel(), aiProperties.getApiKey());
-        OpenAiRequestParamDTO zhiPuRequestParamDTO = 
OpenAiRequestParamDTO.builder()
-                .model(aiProperties.getModel())
-                .stream(Boolean.TRUE)
-                .maxTokens(AiConstants.KimiAiConstants.MAX_TOKENS)
-                .temperature(AiConstants.KimiAiConstants.TEMPERATURE)
-                .messages(List.of(new 
AiMessage(AiConstants.KimiAiConstants.REQUEST_ROLE, text)))
-                .build();
-
-        return webClient.post()
-                .body(BodyInserters.fromValue(zhiPuRequestParamDTO))
-                .retrieve()
-                .bodyToFlux(String.class)
-                .filter(aiResponse -> !"[DONE]".equals(aiResponse))
-                .map(OpenAiResponse::convertToResponse)
-                .doOnError(error -> log.info("KimiAiServiceImpl.requestAi 
exception:{}", error.getMessage()));
-    }
-
-    private void checkParam(String param, String model, String apiKey) {
-        Assert.notNull(param, "text is null");
-        Assert.notNull(model, "model is null");
-        Assert.notNull(apiKey, "ai.api-key is null");
-    }
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/OllamaAiService.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/OllamaAiService.java
deleted file mode 100644
index 8d3a7b313..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/OllamaAiService.java
+++ /dev/null
@@ -1,95 +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.manager.service.ai;
-
-import io.jsonwebtoken.lang.Assert;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.common.constants.AiConstants;
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.apache.hertzbeat.manager.config.AiProperties;
-import org.apache.hertzbeat.manager.pojo.dto.AiMessage;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiRequestParamDTO;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.stereotype.Service;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
-
-import javax.annotation.PostConstruct;
-import java.util.List;
-
-/**
- * Ollama service
- */
-@Service("OllamaServiceImpl")
-@ConditionalOnProperty(prefix = "ai", name = "type", havingValue = "ollama")
-@Slf4j
-public class OllamaAiService implements AiService{
-    @Autowired
-    private AiProperties aiProperties;
-
-    private WebClient webClient;
-
-    @PostConstruct
-    private void init() {
-        Assert.notNull(aiProperties.getApiUrl(), "Ollama API URL is null");
-        this.webClient = WebClient.builder()
-                .baseUrl(aiProperties.getApiUrl())
-                .defaultHeader(HttpHeaders.CONTENT_TYPE, 
MediaType.APPLICATION_JSON_VALUE)
-                .exchangeStrategies(ExchangeStrategies.builder()
-                        .codecs(item -> 
item.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
-                        .build())
-                .build();
-    }
-
-    @Override
-    public AiTypeEnum getType() {
-        return AiTypeEnum.ollama;
-    }
-
-    @Override
-    public Flux<ServerSentEvent<String>> requestAi(String text) {
-        checkParam(text, aiProperties.getModel());
-        OpenAiRequestParamDTO ollamaParam = OpenAiRequestParamDTO.builder()
-                .model(aiProperties.getModel())
-                .stream(Boolean.TRUE)
-                .maxTokens(AiConstants.OllamaConstants.MAX_TOKENS)
-                .temperature(AiConstants.OllamaConstants.TEMPERATURE)
-                .messages(List.of(new 
AiMessage(AiConstants.OllamaConstants.REQUEST_ROLE, text)))
-                .build();
-
-        return webClient.post()
-                .body(BodyInserters.fromValue(ollamaParam))
-                .retrieve()
-                .bodyToFlux(String.class)
-                .filter(aiResponse -> !"[DONE]".equals(aiResponse))
-                .map(OpenAiResponse::convertToResponse)
-                .doOnError(error -> log.info("OllamaAiService.requestAi 
exception:{}", error.getMessage()));
-    }
-
-    private void checkParam(String param, String model) {
-        Assert.notNull(param, "text is null");
-        Assert.notNull(model, "model is null");
-    }
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/OpenRouterServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/OpenRouterServiceImpl.java
deleted file mode 100644
index 417c92d25..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/OpenRouterServiceImpl.java
+++ /dev/null
@@ -1,97 +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.manager.service.ai;
-
-import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.common.constants.AiConstants;
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.apache.hertzbeat.manager.config.AiProperties;
-import org.apache.hertzbeat.manager.pojo.dto.AiMessage;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiRequestParamDTO;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
-
-import javax.annotation.PostConstruct;
-import java.util.List;
-
-/**
- * OpenRouter service
- */
-@Service("OpenRouterServiceImpl")
-@ConditionalOnProperty(prefix = "ai", name = "type", havingValue = 
"openRouter")
-@Slf4j
-public class OpenRouterServiceImpl implements AiService {
-
-    @Autowired
-    private AiProperties aiProperties;
-
-    private WebClient webClient;
-
-    @PostConstruct
-    private void init() {
-        this.webClient = WebClient.builder()
-                .baseUrl(AiConstants.OpenRouterConstants.URL)
-                .defaultHeader(HttpHeaders.CONTENT_TYPE, 
MediaType.APPLICATION_JSON_VALUE)
-                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + 
aiProperties.getApiKey())
-                .exchangeStrategies(ExchangeStrategies.builder()
-                        .codecs(item -> 
item.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
-                        .build())
-                .build();
-    }
-
-    @Override
-    public AiTypeEnum getType() {
-        return AiTypeEnum.openRouter;
-    }
-
-    @Override
-    public Flux<ServerSentEvent<String>> requestAi(String text) {
-        checkParam(text, aiProperties.getModel(), aiProperties.getApiKey());
-        OpenAiRequestParamDTO openRouterParam = OpenAiRequestParamDTO.builder()
-                .model(aiProperties.getModel())
-                .stream(Boolean.TRUE)
-                .maxTokens(AiConstants.OpenRouterConstants.MAX_TOKENS)
-                .temperature(AiConstants.OpenRouterConstants.TEMPERATURE)
-                .messages(List.of(new 
AiMessage(AiConstants.OpenRouterConstants.REQUEST_ROLE, text)))
-                .build();
-
-        return webClient.post()
-                .body(BodyInserters.fromValue(openRouterParam))
-                .retrieve()
-                .bodyToFlux(String.class)
-                .filter(aiResponse -> !"[DONE]".equals(aiResponse))
-                .map(OpenAiResponse::convertToResponse)
-                .doOnError(error -> 
log.info("OpenRouterAiServiceImpl.requestAi exception:{}", error.getMessage()));
-    }
-
-    private void checkParam(String param, String model, String apiKey) {
-        Assert.notNull(param, "text is null");
-        Assert.notNull(model, "model is null");
-        Assert.notNull(apiKey, "ai.api-key is null");
-    }
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/SparkDeskAiServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/SparkDeskAiServiceImpl.java
deleted file mode 100644
index c35b1f664..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/SparkDeskAiServiceImpl.java
+++ /dev/null
@@ -1,104 +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.manager.service.ai;
-
-import java.util.List;
-import javax.annotation.PostConstruct;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.common.constants.AiConstants;
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.apache.hertzbeat.manager.config.AiProperties;
-import org.apache.hertzbeat.manager.pojo.dto.AiMessage;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiRequestParamDTO;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
-
-
-/**
- * sparkDesk AI
- */
-@Service("SparkDeskAiServiceImpl")
-@ConditionalOnProperty(prefix = "ai", name = "type", havingValue = "sparkDesk")
-@Slf4j
-public class SparkDeskAiServiceImpl implements AiService {
-
-    @Autowired
-    private AiProperties aiProperties;
-
-    private WebClient webClient;
-
-    @PostConstruct
-    private void init() {
-        StringBuilder sb = new StringBuilder();
-        String bearer = sb.append("Bearer ")
-                          .append(aiProperties.getApiKey())
-                          
.append(":").append(aiProperties.getApiSecret()).toString();
-
-        this.webClient = WebClient.builder()
-                .baseUrl(AiConstants.SparkDeskConstants.SPARK_ULTRA_URL)
-                .defaultHeader(HttpHeaders.CONTENT_TYPE, 
MediaType.APPLICATION_JSON_VALUE)
-                .defaultHeader(HttpHeaders.AUTHORIZATION, bearer)
-                .exchangeStrategies(ExchangeStrategies.builder()
-                        .codecs(item -> 
item.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
-                        .build())
-                .build();
-    }
-
-    @Override
-    public AiTypeEnum getType() {
-        return AiTypeEnum.sparkDesk;
-    }
-
-    @Override
-    public Flux<ServerSentEvent<String>> requestAi(String text) {
-        checkParam(text, aiProperties.getApiKey(), aiProperties.getModel());
-        OpenAiRequestParamDTO zhiPuRequestParamDTO = 
OpenAiRequestParamDTO.builder()
-                .model(aiProperties.getModel())
-                //sse
-                .stream(Boolean.TRUE)
-                .maxTokens(AiConstants.SparkDeskConstants.MAX_TOKENS)
-                .temperature(AiConstants.SparkDeskConstants.TEMPERATURE)
-                .messages(List.of(new 
AiMessage(AiConstants.SparkDeskConstants.REQUEST_ROLE, text)))
-                .build();
-
-        return webClient.post()
-                .body(BodyInserters.fromValue(zhiPuRequestParamDTO))
-                .retrieve()
-                .bodyToFlux(String.class)
-                .filter(aiResponse -> !"[DONE]".equals(aiResponse))
-                .map(OpenAiResponse::convertToResponse)
-                .doOnError(error -> log.info("SparkDeskAiServiceImpl.requestAi 
exception:{}", error.getMessage()));
-
-    }
-
-    private void checkParam(String param, String apiKey, String model) {
-        Assert.notNull(param, "text is null");
-        Assert.notNull(model, "model is null");
-        Assert.notNull(apiKey, "ai.api-key is null");
-    }
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/ZhiPuServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/ZhiPuServiceImpl.java
deleted file mode 100644
index 1a8ef2d93..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/ZhiPuServiceImpl.java
+++ /dev/null
@@ -1,100 +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.manager.service.ai;
-
-
-import java.util.List;
-import javax.annotation.PostConstruct;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.hertzbeat.common.constants.AiConstants;
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.apache.hertzbeat.manager.config.AiProperties;
-import org.apache.hertzbeat.manager.pojo.dto.AiMessage;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiRequestParamDTO;
-import org.apache.hertzbeat.manager.pojo.dto.OpenAiResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
-
-
-/**
- * ZhiPu AI
- */
-@Service("ZhiPuServiceImpl")
-@ConditionalOnProperty(prefix = "ai", name = "type", havingValue = "zhiPu")
-@Slf4j
-public class ZhiPuServiceImpl implements AiService {
-
-    @Autowired
-    private AiProperties aiProperties;
-
-    private WebClient webClient;
-
-    @PostConstruct
-    private void init() {
-        this.webClient = WebClient.builder()
-                .baseUrl(AiConstants.ZhiPuConstants.URL)
-                .defaultHeader(HttpHeaders.CONTENT_TYPE, 
MediaType.APPLICATION_JSON_VALUE)
-                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + 
aiProperties.getApiKey())
-                .exchangeStrategies(ExchangeStrategies.builder()
-                        .codecs(item -> 
item.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
-                        .build())
-                .build();
-    }
-
-    @Override
-    public AiTypeEnum getType() {
-        return AiTypeEnum.zhiPu;
-    }
-
-    @Override
-    public Flux<ServerSentEvent<String>> requestAi(String text) {
-        checkParam(text, aiProperties.getModel(), aiProperties.getApiKey());
-        OpenAiRequestParamDTO zhiPuRequestParamDTO = 
OpenAiRequestParamDTO.builder()
-                .model(aiProperties.getModel())
-                //sse
-                .stream(Boolean.TRUE)
-                .maxTokens(AiConstants.ZhiPuConstants.MAX_TOKENS)
-                .temperature(AiConstants.ZhiPuConstants.TEMPERATURE)
-                .messages(List.of(new 
AiMessage(AiConstants.ZhiPuConstants.REQUEST_ROLE, text)))
-                .build();
-
-        return webClient.post()
-                .body(BodyInserters.fromValue(zhiPuRequestParamDTO))
-                .retrieve()
-                .bodyToFlux(String.class)
-                .filter(aiResponse -> !"[DONE]".equals(aiResponse))
-                .map(OpenAiResponse::convertToResponse)
-                .doOnError(error -> log.info("ZhiPuServiceImpl.requestAi 
exception:{}", error.getMessage()));
-    }
-
-    private void checkParam(String param, String model, String apiKey) {
-        Assert.notNull(param, "text is null");
-        Assert.notNull(model, "model is null");
-        Assert.notNull(apiKey, "ai.api-key is null");
-    }
-
-}
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/factory/AiServiceFactoryImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/factory/AiServiceFactoryImpl.java
deleted file mode 100644
index 8e0954c7a..000000000
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/ai/factory/AiServiceFactoryImpl.java
+++ /dev/null
@@ -1,64 +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.manager.service.ai.factory;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import javax.annotation.PostConstruct;
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.apache.hertzbeat.manager.service.ai.AiService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.stereotype.Component;
-import org.springframework.util.Assert;
-import org.springframework.util.CollectionUtils;
-
-/**
- * AI bean factory
- */
-@Component
-@ConditionalOnProperty(prefix = "ai", name = "type")
-public class AiServiceFactoryImpl {
-
-    @Autowired(required = false)
-    private List<AiService> aiService;
-
-    private Map<AiTypeEnum, AiService> aiServiceFactoryMap = new HashMap<>();
-
-    @PostConstruct
-    public void init() {
-        if (CollectionUtils.isEmpty(aiService)) {
-            return;
-        }
-        aiServiceFactoryMap = aiService.stream()
-                .collect(Collectors.toMap(AiService::getType, 
Function.identity()));
-    }
-
-    public AiService getAiServiceImplBean(String type) {
-        Assert.notNull(type, "type is null");
-        AiTypeEnum typeByName = AiTypeEnum.getTypeByName(type);
-        Assert.notNull(typeByName, "The current type is not supported,please 
check that your type value is consistent with the documentation on the 
website");
-        AiService aiServiceImpl = aiServiceFactoryMap.get(typeByName);
-        Assert.notNull(aiServiceImpl, "No bean for current type found");
-        return aiServiceImpl;
-    }
-
-}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/controller/AiControllerTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/controller/AiControllerTest.java
deleted file mode 100644
index e61595324..000000000
--- 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/controller/AiControllerTest.java
+++ /dev/null
@@ -1,88 +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.manager.controller;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
-import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
-import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import org.apache.hertzbeat.manager.config.AiProperties;
-import org.apache.hertzbeat.manager.service.ai.AiService;
-import org.apache.hertzbeat.manager.service.ai.factory.AiServiceFactoryImpl;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-import reactor.core.publisher.Flux;
-
-/**
- * test case for {@link AiController}
- */
-
-@ExtendWith(MockitoExtension.class)
-class AiControllerTest {
-
-    private MockMvc mockMvc;
-
-    @Mock
-    private AiServiceFactoryImpl aiServiceFactory;
-
-    @Mock
-    private AiProperties aiProperties;
-
-    @Mock
-    private AiService aiService;
-
-    @InjectMocks
-    private AiController aiController;
-
-    @BeforeEach
-    public void setup() {
-
-        mockMvc = MockMvcBuilders.standaloneSetup(aiController).build();
-    }
-
-    @Test
-    public void testRequestAi() throws Exception {
-
-        String responseText = "response";
-        Flux<ServerSentEvent<String>> responseFlux = 
Flux.just(ServerSentEvent.builder(responseText).build());
-
-        
when(aiServiceFactory.getAiServiceImplBean(anyString())).thenReturn(aiService);
-        when(aiService.requestAi(anyString())).thenReturn(responseFlux);
-        when(aiProperties.getType()).thenReturn("alibabaAi");
-
-        String requestBody = "{\"text\":\"Who are you\"}";
-
-        mockMvc.perform((MockMvcRequestBuilders.post("/api/ai/get")
-                .content(requestBody)
-                .contentType(MediaType.APPLICATION_JSON)
-                .accept(MediaType.TEXT_EVENT_STREAM)))
-                .andExpect(status().isOk())
-                
.andExpect(content().contentType(MediaType.TEXT_EVENT_STREAM_VALUE))
-                .andExpect(content().string("data:response\n\n"));
-    }
-
-}
diff --git 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/AiServiceFactoryTest.java
 
b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/AiServiceFactoryTest.java
deleted file mode 100644
index 60f5e627d..000000000
--- 
a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/AiServiceFactoryTest.java
+++ /dev/null
@@ -1,125 +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.manager.service;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.when;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import org.apache.hertzbeat.common.constants.AiTypeEnum;
-import org.apache.hertzbeat.manager.service.ai.AiService;
-import org.apache.hertzbeat.manager.service.ai.factory.AiServiceFactoryImpl;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.test.util.ReflectionTestUtils;
-
-/**
- * test case for {@link AiServiceFactoryImpl}
- */
-
-@ExtendWith(MockitoExtension.class)
-class AiServiceFactoryTest {
-
-    @Mock
-    private List<AiService> aiService;
-
-    @Mock
-    private AiService aiService1;
-
-    @Mock
-    private AiService aiService2;
-
-    @InjectMocks
-    private AiServiceFactoryImpl aiServiceFactory;
-
-    @BeforeEach
-    public void setup() {
-
-        when(aiService1.getType()).thenReturn(AiTypeEnum.alibabaAi);
-        when(aiService2.getType()).thenReturn(AiTypeEnum.zhiPu);
-
-        aiService = Arrays.asList(aiService1, aiService2);
-        ReflectionTestUtils.setField(aiServiceFactory, "aiService", aiService);
-
-        aiServiceFactory.init();
-    }
-
-    @Test
-    public void testInit() {
-
-        Map<AiTypeEnum, AiService> expectedMap = aiService.stream()
-                .collect(Collectors.toMap(AiService::getType, 
Function.identity()));
-
-        Map<AiTypeEnum, AiService> actualMap = (Map<AiTypeEnum, AiService>) 
ReflectionTestUtils.getField(aiServiceFactory, "aiServiceFactoryMap");
-
-        assertEquals(expectedMap, actualMap);
-    }
-
-    @Test
-    public void testGetAiServiceImplBean_Success() {
-
-        AiService service = 
aiServiceFactory.getAiServiceImplBean(AiTypeEnum.alibabaAi + "");
-        assertNotNull(service);
-        assertEquals(aiService1, service);
-
-        service = aiServiceFactory.getAiServiceImplBean(AiTypeEnum.zhiPu + "");
-        assertNotNull(service);
-        assertEquals(aiService2, service);
-    }
-
-    @Test
-    public void testGetAiServiceImplBeanTypeNotFound() {
-
-        Exception exception = assertThrows(
-                IllegalArgumentException.class,
-                () -> aiServiceFactory.getAiServiceImplBean("InvalidType")
-        );
-
-        assertTrue(exception.getMessage().contains("The current type is not 
supported"));
-    }
-
-    @Test
-    public void testGetAiServiceImplBeanNoBean() {
-
-        aiServiceFactory.init();
-
-        when(aiService1.getType()).thenReturn(AiTypeEnum.kimiAi);
-        List<AiService> singleServiceList = 
Collections.singletonList(aiService1);
-        ReflectionTestUtils.setField(aiServiceFactory, "aiService", 
singleServiceList);
-        aiServiceFactory.init();
-
-        Exception exception = assertThrows(
-                IllegalArgumentException.class,
-                () -> 
aiServiceFactory.getAiServiceImplBean(AiTypeEnum.sparkDesk + "")
-        );
-
-        assertTrue(exception.getMessage().contains("No bean for current type 
found"));
-    }
-
-}
diff --git a/home/docs/help/ai_agent_chat.md b/home/docs/help/ai_agent_chat.md
index 66e6413a6..e817960c3 100644
--- a/home/docs/help/ai_agent_chat.md
+++ b/home/docs/help/ai_agent_chat.md
@@ -49,26 +49,15 @@ Before using the AI Agent Chat, ensure:
 
 ### OpenAI API Key Setup
 
-The AI Agent Chat uses OpenAI's GPT models. You need to configure an OpenAI 
API key in one of two ways:
+The AI Agent Chat uses OpenAI's GPT models. You need to configure an OpenAI 
API key in this ways:
 
-#### Method 1: Database Configuration via UI (Recommended)
+#### Database Configuration via UI
 
 1. Navigate to the AI Agent Chat interface
 2. If no API key is configured, you'll see a configuration dialog
 3. Enter your OpenAI API key
 4. Click **Save Configuration**
 
-#### Method 2: YAML Configuration
-
-Add to your `application.yml`:
-
-```yaml
-spring:
-  ai:
-    openai:
-      api-key: sk-your-openai-api-key-here
-```
-
 ### Configuration Priority
 
 - **Database configuration** takes priority over YAML configuration
diff --git 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/ai_agent_chat.md 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/ai_agent_chat.md
new file mode 100644
index 000000000..6c6de6291
--- /dev/null
+++ 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/ai_agent_chat.md
@@ -0,0 +1,356 @@
+---
+id: ai_agent_chat
+title: AI 智能助手聊天用户指南
+sidebar_label: AI 智能助手聊天
+keywords: [AI, 聊天, 智能助手, 监控, AI Agent, OpenAI]
+---
+
+> HertzBeat AI 智能助手聊天是一个智能监控 AI 助手,通过自然语言对话帮助您管理监控器、配置告警并优化基础设施监控。
+
+## 概述
+
+AI 智能助手聊天功能提供了一个交互式聊天界面,您可以:
+
+**监控器管理:**
+
+- 🔍 按状态、类型、主机和标签查询和过滤现有监控器
+- ➕ 为网站、API、数据库和服务添加新的监控器
+- 📊 获取可用监控器类型及其参数的详细信息
+- ⚡ 检查监控器状态并排除监控问题
+
+**告警管理:**
+
+- 🚨 通过综合过滤(类型、状态、搜索)查询活跃告警
+- 📈 获取告警摘要统计和分布
+- 🔔 查看单个和分组告警
+- 📋 分析告警模式和趋势
+
+**指标分析:**
+
+- 📊 检索任何监控器的实时指标数据
+- 📈 访问可自定义时间范围的历史指标
+- 💾 检查仓库存储系统状态
+- 🔍 查询特定指标字段和标签
+
+**告警规则管理:**
+
+- ⚙️ 配置告警规则和阈值
+- 📝 管理不同监控器类型的告警定义
+- 🎯 设置自定义告警条件
+
+## 先决条件
+
+在使用 AI 智能助手聊天之前,请确保:
+
+1. **OpenAI 配置**:必须配置有效的 OpenAI API 密钥。可选地,您可以在 `application.yml` 中的 
`spring.ai.openai.chat.options.model` 下更改模型(默认为 `gpt-4.1-nano`)。
+2. **数据库连接**:HertzBeat 数据库必须可访问以进行监控器操作
+
+## 配置
+
+### OpenAI API 密钥设置
+
+AI 智能助手聊天使用 OpenAI 的 GPT 模型。您需要通过以下方式配置 OpenAI API 密钥:
+
+#### 通过 UI 进行数据库配置
+
+1. 导航到 AI 智能助手聊天界面
+2. 如果未配置 API 密钥,您将看到配置对话框
+3. 输入您的 OpenAI API 密钥
+4. 点击 **保存配置**
+
+### 配置优先级
+
+- **数据库配置** 优先于 YAML 配置
+- 配置更改立即生效,无需重启
+- 保存前会自动验证无效的 API 密钥
+
+## 使用 AI 智能助手聊天
+
+### 访问聊天界面
+
+1. 在 HertzBeat Web 界面中导航到 **AI 智能助手聊天** 部分
+2. 您将看到 HertzBeat 监控 AI 助手欢迎屏幕
+3. 在聊天输入框中开始输入您的问题
+
+### 示例对话
+
+#### 添加新监控器
+
+```text
+您:为我的网站 https://example.com 添加一个新的 HTTP 监控器
+AI 助手:我将帮助您为 https://example.com 添加一个 HTTP 监控器。
+让我使用以下配置创建该监控器:
+- 名称:example.com 网站监控器
+- 类型:HTTP
+- 主机:example.com
+- 端口:443 (HTTPS)
+- 路径:/
+- 间隔:60 秒
+
+监控器创建成功,ID:12345
+```
+
+#### 列出现有监控器
+
+```text
+您:显示我所有当前的监控器
+AI 助手:以下是您当前的监控器:
+
+1. **Linux 服务器** (ID: 1001)
+   - 状态:✅ 在线
+   - 主机:192.168.1.100
+   - 最后检查:2 分钟前
+
+2. **MySQL 数据库** (ID: 1002) 
+   - 状态:⚠️ 警告
+   - 主机:db.example.com
+   - 最后检查:30 秒前
+
+3. **网站监控器** (ID: 1003)
+   - 状态:✅ 在线
+   - 主机:https://example.com
+   - 最后检查:1 分钟前
+
+您想了解任何特定监控器的详细信息吗?
+```
+
+#### 获取监控器类型信息
+
+```text
+您:监控 PostgreSQL 数据库需要哪些参数?
+AI 助手:要监控 PostgreSQL 数据库,您需要这些参数:
+
+**必需参数:**
+- **主机**:数据库服务器 IP/主机名
+- **端口**:PostgreSQL 端口(默认:5432)
+- **数据库**:要连接的数据库名称
+- **用户名**:数据库用户名
+- **密码**:数据库密码
+
+**可选参数:**
+- **超时**:连接超时(默认:6000ms)
+- **查询超时**:SQL 查询超时(默认:3000ms)
+- **SSL**:启用 SSL 连接(默认:false)
+
+您想让我帮助您添加一个 PostgreSQL 监控器吗?
+```
+
+#### 告警管理
+
+```text
+您:显示过去 24 小时内的所有严重告警
+AI 助手:以下是过去 24 小时内的严重告警:
+
+🚨 **活跃告警(3 个触发中)**
+1. **高 CPU 使用率** - Linux 服务器 (ID: 1001)
+   - 状态:🔥 触发中
+   - 触发时间:2 小时前
+   - 严重程度:严重
+   - 消息:CPU 使用率 95% > 阈值 90%
+
+2. **数据库连接失败** - MySQL 数据库 (ID: 1002)
+   - 状态:🔥 触发中
+   - 触发时间:45 分钟前
+   - 严重程度:严重
+   - 消息:10 秒后连接超时
+
+3. **网站响应时间** - 网站监控器 (ID: 1003)
+   - 状态:⚠️ 警告
+   - 触发时间:15 分钟前
+   - 严重程度:警告
+   - 消息:响应时间 5.2s > 阈值 3s
+
+**告警摘要:**
+- 总告警数:12
+- 触发中:3(2 个严重,1 个警告)
+- 已解决:9
+
+您想让我帮助调查任何特定的告警吗?
+```
+
+#### 指标分析
+
+```text
+您:显示我的 Linux 服务器过去 6 小时的 CPU 使用率
+AI 助手:以下是您的 Linux 服务器(监控器 ID:1001)过去 6 小时的 CPU 使用率数据:
+
+📊 **CPU 使用率指标 - 过去 6 小时**
+
+时间          | 使用率 (%) | 负载平均 | 进程数
+14:00-15:00   | 45.2%     | 1.2      | 156
+15:00-16:00   | 67.8%     | 2.1      | 178
+16:00-17:00   | 89.4%     | 3.8      | 195
+17:00-18:00   | 92.1%     | 4.2      | 203
+18:00-19:00   | 94.7%     | 4.8      | 210
+19:00-20:00   | 88.3%     | 3.5      | 188
+
+**分析:**
+- 峰值使用率:19:00 时 94.7%
+- 平均使用率:79.6%
+- 趋势:高使用率持续 3+ 小时
+- 当前状态:下降中(88.3%)
+
+**实时指标:**
+- 当前 CPU:76.2%
+- 内存使用率:82.1%
+- 磁盘 I/O:正常
+
+您想让我检查历史数据进行比较或调查高使用率的原因吗?
+```
+
+#### 告警规则配置
+
+```text
+您:当我的网站响应时间超过 5 秒时设置告警规则
+AI 助手:我将帮助您创建网站响应时间监控的告警规则。
+
+**告警规则配置:**
+- **监控器类型**:HTTP/网站
+- **指标**:响应时间
+- **条件**:大于 5 秒
+- **严重程度**:警告
+- **评估**:每 60 秒检查一次
+- **通知**:邮件 + 仪表板
+
+**建议规则:**
+```yaml
+name: "网站响应时间告警"
+condition: "response_time > 5000ms"
+severity: "warning"
+description: "当网站响应时间超过 5 秒时告警"
+evaluation_interval: 60s
+for: 2m  # 条件持续 2 分钟后告警
+```
+
+此规则将:
+
+1. 每分钟监控响应时间
+2. 如果响应时间 > 5s 持续 2+ 分钟则触发告警
+3. 通过配置的渠道发送通知
+4. 在仪表板中显示警告状态
+
+您想让我应用此配置还是修改任何设置?
+```
+
+### 聊天功能
+
+#### 消息历史
+
+- 所有对话都会自动保存
+- 从侧边栏访问以前的对话
+- 搜索对话历史
+- 导出对话日志
+
+#### 实时响应
+
+- 流式响应提供即时反馈
+- 输入指示器显示助手正在处理时
+- 如需要可取消正在进行的请求
+
+#### 对话管理
+
+- 为不同主题创建新对话
+- 重命名对话以便更好地组织
+- 删除旧对话以保持整洁
+注意:对话不会保存在数据库中
+
+## 故障排除
+
+### 常见问题
+
+#### 聊天界面无法加载
+
+**症状**:聊天界面无限显示加载旋转器
+**解决方案**:
+
+1. 检查浏览器控制台中的 JavaScript 错误
+2. 确保与 HertzBeat 服务器的网络连接
+
+#### "服务不可用"消息
+
+**症状**:聊天显示"HertzBeat AI 监控服务不可用"
+**解决方案**:
+1. 验证 OpenAI API 密钥配置
+2. 检查应用程序日志中的错误
+3. 确保数据库连接
+
+#### 无效 API 密钥错误
+
+**症状**:配置对话框显示"无效 API 密钥"错误
+**解决方案**:
+
+1. 验证您的 OpenAI API 密钥以 `sk-` 开头
+2. 检查 API 密钥是否有足够的积分/配额
+3. 直接使用 OpenAI API 测试 API 密钥
+4. 确保 API 密钥中没有多余的空格
+
+#### 监控器创建失败
+
+**症状**:AI 建议监控器配置但创建失败
+**解决方案**:
+
+1. 验证您有创建监控器的权限
+2. 检查是否已存在同名监控器
+3. 确保目标主机/服务可访问
+4. 查看监控器参数验证错误
+
+### 调试模式
+
+通过设置日志级别为 DEBUG 来启用调试日志:
+
+```yaml
+logging:
+  level:
+    org.apache.hertzbeat.ai.agent: DEBUG
+```
+
+## 最佳实践
+
+### 有效的聊天使用
+
+1. **具体明确**:"为 api.example.com 端口 8080 添加 HTTP 监控器" vs "添加一个监控器"
+2. **提供上下文**:说明您想要生产环境还是测试环境监控器
+3. **询问后续问题**:如需要请求配置详细信息
+4. **使用自然语言**:AI 理解对话式请求
+
+### 监控器管理
+
+1. **命名约定**:使用描述性的监控器名称
+2. **文档记录**:要求 AI 记录复杂配置
+
+### 安全考虑
+
+1. **API 密钥安全**:安全存储 OpenAI API 密钥
+2. **访问控制**:限制 AI 聊天访问给授权用户
+3. **数据隐私**:注意聊天日志中的敏感信息
+4. **网络安全**:确保与 OpenAI API 的安全连接
+
+## 高级功能
+
+### 批量操作
+
+```text
+您:为我的预发布环境中的所有服务添加 HTTP 监控器:
+- api-staging.example.com:8080
+- web-staging.example.com:80  
+- admin-staging.example.com:3000
+```
+
+## 限制
+
+- 需要活跃的互联网连接访问 OpenAI API
+- OpenAI API 使用会根据令牌消耗产生费用
+- 复杂的多步骤操作可能需要多次交互
+- 某些高级配置可能需要手动设置
+- 可能会根据 OpenAI 计划应用速率限制
+
+## 支持
+
+对于 AI 智能助手聊天的问题:
+
+1. 首先查看此文档
+2. 查看应用程序日志中的错误
+3. 独立测试 OpenAI API 连接
+4. 联系 HertzBeat 支持并提供具体错误消息
+
+---
diff --git a/home/sidebars.json b/home/sidebars.json
index e5ab4b430..0674eff5e 100755
--- a/home/sidebars.json
+++ b/home/sidebars.json
@@ -290,7 +290,6 @@
         "help/mcp_sse_server",
         "help/collector",
         "help/ai_agent_chat",
-        "help/ai_config",
         "help/risc-v",
         "help/issue"
       ]
diff --git a/script/application.yml b/script/application.yml
index e776cb983..c4f463601 100644
--- a/script/application.yml
+++ b/script/application.yml
@@ -19,6 +19,25 @@ spring:
     name: ${HOSTNAME:@hertzbeat@}${PID}
   profiles:
     active: prod
+  ai:
+    mcp:
+      server:
+        enabled: true
+        stdio: false
+        name: sse-mcp-server
+        version: 1.0.0
+        resource-change-notification: true
+        tool-change-notification: true
+        prompt-change-notification: true
+        sse-endpoint: /api/sse
+        sse-message-endpoint: /api/mcp/message
+        type: SYNC
+        capabilities:
+          tool: true
+          resource: true
+          prompt: true
+          completion: true
+
   mvc:
     static-path-pattern: /**
   jackson:
@@ -38,6 +57,7 @@ spring:
       max-file-size: 100MB
       max-request-size: 100MB
 
+
 management:
   health:
     mail:
@@ -124,13 +144,26 @@ spring:
 
 common:
   queue:
-    # memory or kafka
+    # memory, kafka, redis
     type: memory
     # properties when queue type is kafka
     kafka:
       servers: 127.0.0.1:9092
       metrics-data-topic: async-metrics-data
+      service-discovery-data-topic: service-discovery-data
       alerts-data-topic: async-alerts-data
+      log-entry-data-topic: async-log-entry-data
+      log-entry-data-to-storage-topic: log-entry-data-to-storage-topic
+    redis:
+      redis-host: 127.0.0.1
+      redis-port: 6379
+      metrics-data-queue-name-for-service-discovery: service_discovery
+      metrics-data-queue-name-to-persistent-storage: 
metrics:to_persistent_storage
+      metrics-data-queue-name-to-alerter: metrics:to_alerter
+      metrics-data-queue-name-to-real-time-storage: metrics:to_realtime_storage
+      alerts-data-queue-name: alerts
+      log-entry-queue-name: log:to_alerter
+      log-entry-to-storage-queue-name: log:to_storage
 
 warehouse:
   store:
@@ -143,10 +176,28 @@ warehouse:
       # (please set this configuration reasonably as history records can 
affect performance when it is large)
       max-history-record-num: 6000
     victoria-metrics:
+      # Standalone mode toggle — must be set to false when using cluster mode
       enabled: false
       url: http://localhost:8428
       username: root
       password: root
+      insert:
+        buffer-size: 100
+        flush-interval: 3
+        compression:
+          enabled: false
+      cluster:
+        enabled: false
+        select:
+          url: http://localhost:8481
+          username: root
+          password: root
+        insert:
+          url: http://localhost:8480
+          username: root
+          password: root
+          buffer-size: 1000
+          flush-interval: 3
     td-engine:
       enabled: false
       driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
@@ -161,6 +212,11 @@ warehouse:
       database: public
       username: greptime
       password: greptime
+    questdb:
+      enabled: false
+      url: localhost:9000
+      username: admin
+      password: quest
     iot-db:
       enabled: false
       host: 127.0.0.1
@@ -244,10 +300,16 @@ alerter:
       region: AWS_REGION_FOR_END_USER_MESSAGING
     twilio:
       account-sid: YOUR_ACCOUNT_SID
-      auth-token: YOUR_AUTH_TOKEN 
+      auth-token: YOUR_AUTH_TOKEN
       twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
 scheduler:
   server:
     enabled: true
     port: 1158
-    
+
+grafana:
+  enabled: false
+  url: http://127.0.0.1:3000
+  expose-url: http://127.0.0.1:3000
+  username: admin
+  password: admin
diff --git a/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml 
b/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
index d98df3fe9..1e847ec97 100644
--- a/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
+++ b/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
@@ -240,10 +240,3 @@ grafana:
   url: http://127.0.0.1:3000
   username: admin
   password: admin
-
-ai:
-  type:
-  model:
-  api-key:
-  api-secret:
-  api-url:
diff --git 
a/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml 
b/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
index b2f0e77af..8f55b0399 100644
--- a/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
+++ b/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
@@ -238,10 +238,3 @@ grafana:
   username: admin
   password: admin
 
-ai:
-  type:
-  model:
-  api-key:
-  api-secret:
-  api-url:
-
diff --git 
a/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml 
b/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
index c48aa31d8..b85eadbce 100644
--- 
a/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
+++ 
b/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
@@ -240,10 +240,3 @@ grafana:
   url: http://127.0.0.1:3000
   username: admin
   password: admin
-
-ai:
-  type:
-  model:
-  api-key:
-  api-secret:
-  api-url:
diff --git 
a/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
 
b/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
index 15f3660b5..6d3ad2306 100644
--- 
a/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
+++ 
b/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
@@ -239,10 +239,3 @@ grafana:
   url: http://127.0.0.1:3000
   username: admin
   password: admin
-
-ai:
-  type:
-  model:
-  api-key:
-  api-secret:
-  api-url:


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

Reply via email to