diff --git a/modules/ai/src/main/java/com/bytedesk/ai/mcp_server/McpServerRestController.java b/modules/ai/src/main/java/com/bytedesk/ai/mcp_server/McpServerRestController.java index 0a6b27f5ca..46f62da371 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/mcp_server/McpServerRestController.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/mcp_server/McpServerRestController.java @@ -29,6 +29,10 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; +/** + * https://spring.io/blog/2025/09/16/spring-ai-mcp-intro-blog + * McpServer Management Controller - Content mcpServer management and categorization APIs +*/ @RestController @RequestMapping("/api/v1/mcp/server") @AllArgsConstructor diff --git a/modules/ai/src/main/java/com/bytedesk/ai/workflow/alibaba/CustomerServiceController.java b/modules/ai/src/main/java/com/bytedesk/ai/workflow/alibaba/CustomerServiceController.java index 401b99261f..bff79c65be 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/workflow/alibaba/CustomerServiceController.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/workflow/alibaba/CustomerServiceController.java @@ -13,77 +13,77 @@ */ package com.bytedesk.ai.workflow.alibaba; -import java.util.HashMap; -import java.util.Map; +// import java.util.HashMap; +// import java.util.Map; -import com.alibaba.cloud.ai.graph.CompileConfig; -import com.alibaba.cloud.ai.graph.CompiledGraph; -import com.alibaba.cloud.ai.graph.exception.GraphStateException; -import com.alibaba.cloud.ai.graph.OverAllState; -import com.alibaba.cloud.ai.graph.StateGraph; -import com.alibaba.cloud.ai.graph.action.EdgeAction; -import com.alibaba.cloud.ai.graph.observation.GraphObservationLifecycleListener; -import io.micrometer.observation.ObservationRegistry; -import lombok.extern.slf4j.Slf4j; +// import com.alibaba.cloud.ai.graph.CompileConfig; +// import com.alibaba.cloud.ai.graph.CompiledGraph; +// import com.alibaba.cloud.ai.graph.exception.GraphStateException; +// import com.alibaba.cloud.ai.graph.OverAllState; +// import com.alibaba.cloud.ai.graph.StateGraph; +// import com.alibaba.cloud.ai.graph.action.EdgeAction; +// import com.alibaba.cloud.ai.graph.observation.GraphObservationLifecycleListener; +// import io.micrometer.observation.ObservationRegistry; +// import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +// import org.springframework.beans.factory.ObjectProvider; +// import org.springframework.beans.factory.annotation.Qualifier; +// import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +// import org.springframework.web.bind.annotation.GetMapping; +// import org.springframework.web.bind.annotation.RequestMapping; +// import org.springframework.web.bind.annotation.RestController; -@Slf4j -@RestController -@RequestMapping("/customer") -@ConditionalOnProperty(prefix = "spring.ai.workflow.graph", name = "enabled", havingValue = "true", matchIfMissing = false) -public class CustomerServiceController { +// @Slf4j +// @RestController +// @RequestMapping("/customer") +// @ConditionalOnProperty(prefix = "spring.ai.workflow.graph", name = "enabled", havingValue = "true", matchIfMissing = false) +// public class CustomerServiceController { - private CompiledGraph compiledGraph; +// private CompiledGraph compiledGraph; - public CustomerServiceController(@Qualifier("workflowGraph") StateGraph stateGraph, - ObjectProvider observationRegistry) throws GraphStateException { - this.compiledGraph = stateGraph.compile(CompileConfig.builder() - .withLifecycleListener(new GraphObservationLifecycleListener( - observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP))) - .build()); - } +// public CustomerServiceController(@Qualifier("workflowGraph") StateGraph stateGraph, +// ObjectProvider observationRegistry) throws GraphStateException { +// this.compiledGraph = stateGraph.compile(CompileConfig.builder() +// .withLifecycleListener(new GraphObservationLifecycleListener( +// observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP))) +// .build()); +// } - // http://localhost:9003/customer/chat?query=我收到的产品有快递破损,需要退换货? - // http://localhost:9003/customer/chat?query=我的产品不能正常工作了,要怎么去做维修? - // http://localhost:9003/customer/chat?query=商品收到了,非常好,下次还会买。 - @GetMapping("/chat") - public String simpleChat(String query) throws Exception { - return compiledGraph.invoke(Map.of("input", query)).get().value("solution").get().toString(); - } +// // http://localhost:9003/customer/chat?query=我收到的产品有快递破损,需要退换货? +// // http://localhost:9003/customer/chat?query=我的产品不能正常工作了,要怎么去做维修? +// // http://localhost:9003/customer/chat?query=商品收到了,非常好,下次还会买。 +// @GetMapping("/chat") +// public String simpleChat(String query) throws Exception { +// return compiledGraph.invoke(Map.of("input", query)).get().value("solution").get().toString(); +// } - public static class FeedbackQuestionDispatcher implements EdgeAction { - @Override - public String apply(OverAllState state) throws Exception { - String classifierOutput = (String) state.value("classifier_output").orElse(""); - log.info("classifierOutput: {}", classifierOutput); - if (classifierOutput.contains("positive")) { - return "positive"; - } - return "negative"; - } - } +// public static class FeedbackQuestionDispatcher implements EdgeAction { +// @Override +// public String apply(OverAllState state) throws Exception { +// String classifierOutput = (String) state.value("classifier_output").orElse(""); +// log.info("classifierOutput: {}", classifierOutput); +// if (classifierOutput.contains("positive")) { +// return "positive"; +// } +// return "negative"; +// } +// } - public static class SpecificQuestionDispatcher implements EdgeAction { - @Override - public String apply(OverAllState state) throws Exception { - String classifierOutput = (String) state.value("classifier_output").orElse(""); - log.info("classifierOutput: {}", classifierOutput); - Map classifierMap = new HashMap<>(); - classifierMap.put("after-sale", "after-sale"); - classifierMap.put("quality", "quality"); - classifierMap.put("transportation", "transportation"); - for (Map.Entry entry : classifierMap.entrySet()) { - if (classifierOutput.contains(entry.getKey())) { - return entry.getValue(); - } - } - return "others"; - } - } -} +// public static class SpecificQuestionDispatcher implements EdgeAction { +// @Override +// public String apply(OverAllState state) throws Exception { +// String classifierOutput = (String) state.value("classifier_output").orElse(""); +// log.info("classifierOutput: {}", classifierOutput); +// Map classifierMap = new HashMap<>(); +// classifierMap.put("after-sale", "after-sale"); +// classifierMap.put("quality", "quality"); +// classifierMap.put("transportation", "transportation"); +// for (Map.Entry entry : classifierMap.entrySet()) { +// if (classifierOutput.contains(entry.getKey())) { +// return entry.getValue(); +// } +// } +// return "others"; +// } +// } +// } diff --git a/modules/ai/src/main/java/com/bytedesk/ai/workflow/alibaba/WorkflowAutoConfiguration.java b/modules/ai/src/main/java/com/bytedesk/ai/workflow/alibaba/WorkflowAutoConfiguration.java index 66208c775d..65e0d6469e 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/workflow/alibaba/WorkflowAutoConfiguration.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/workflow/alibaba/WorkflowAutoConfiguration.java @@ -13,88 +13,88 @@ */ package com.bytedesk.ai.workflow.alibaba; -import com.alibaba.cloud.ai.graph.GraphRepresentation; -import com.alibaba.cloud.ai.graph.KeyStrategy; -import com.alibaba.cloud.ai.graph.StateGraph; -import com.alibaba.cloud.ai.graph.exception.GraphStateException; -import com.alibaba.cloud.ai.graph.node.QuestionClassifierNode; -import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy; +// import com.alibaba.cloud.ai.graph.GraphRepresentation; +// import com.alibaba.cloud.ai.graph.KeyStrategy; +// import com.alibaba.cloud.ai.graph.StateGraph; +// import com.alibaba.cloud.ai.graph.exception.GraphStateException; +// import com.alibaba.cloud.ai.graph.node.QuestionClassifierNode; +// import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy; -import lombok.extern.slf4j.Slf4j; +// import lombok.extern.slf4j.Slf4j; -import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; -import org.springframework.ai.chat.model.ChatModel; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +// import org.springframework.ai.chat.client.ChatClient; +// import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; +// import org.springframework.ai.chat.model.ChatModel; +// import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +// import org.springframework.context.annotation.Bean; +// import org.springframework.context.annotation.Configuration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +// import java.util.HashMap; +// import java.util.List; +// import java.util.Map; -import static com.alibaba.cloud.ai.graph.StateGraph.END; -import static com.alibaba.cloud.ai.graph.StateGraph.START; -import static com.alibaba.cloud.ai.graph.action.AsyncEdgeAction.edge_async; -import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async; +// import static com.alibaba.cloud.ai.graph.StateGraph.END; +// import static com.alibaba.cloud.ai.graph.StateGraph.START; +// import static com.alibaba.cloud.ai.graph.action.AsyncEdgeAction.edge_async; +// import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async; -/** - * - */ -@Slf4j -@Configuration -@ConditionalOnProperty(prefix = "spring.ai.workflow.graph", name = "enabled", havingValue = "true", matchIfMissing = false) -public class WorkflowAutoConfiguration { +// /** +// * +// */ +// @Slf4j +// @Configuration +// @ConditionalOnProperty(prefix = "spring.ai.workflow.graph", name = "enabled", havingValue = "true", matchIfMissing = false) +// public class WorkflowAutoConfiguration { - @Bean - public StateGraph workflowGraph(ChatModel chatModel) throws GraphStateException { +// @Bean +// public StateGraph workflowGraph(ChatModel chatModel) throws GraphStateException { - ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(new SimpleLoggerAdvisor()).build(); +// ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(new SimpleLoggerAdvisor()).build(); - QuestionClassifierNode feedbackClassifier = QuestionClassifierNode.builder() - .chatClient(chatClient) - .inputTextKey("input") - .outputKey("classifier_output") - .categories(List.of("positive feedback", "negative feedback")) - .classificationInstructions( - List.of("Try to understand the user's feeling when he/she is giving the feedback.")) - .build(); +// QuestionClassifierNode feedbackClassifier = QuestionClassifierNode.builder() +// .chatClient(chatClient) +// .inputTextKey("input") +// .outputKey("classifier_output") +// .categories(List.of("positive feedback", "negative feedback")) +// .classificationInstructions( +// List.of("Try to understand the user's feeling when he/she is giving the feedback.")) +// .build(); - QuestionClassifierNode specificQuestionClassifier = QuestionClassifierNode.builder() - .chatClient(chatClient) - .inputTextKey("input") - .outputKey("classifier_output") - .categories(List.of("after-sale service", "transportation", "product quality", "others")) - .classificationInstructions(List - .of("What kind of service or help the customer is trying to get from us? Classify the question based on your understanding.")) - .build(); +// QuestionClassifierNode specificQuestionClassifier = QuestionClassifierNode.builder() +// .chatClient(chatClient) +// .inputTextKey("input") +// .outputKey("classifier_output") +// .categories(List.of("after-sale service", "transportation", "product quality", "others")) +// .classificationInstructions(List +// .of("What kind of service or help the customer is trying to get from us? Classify the question based on your understanding.")) +// .build(); - StateGraph stateGraph = new StateGraph("Consumer Service Workflow Demo", () -> { - Map strategies = new HashMap<>(); - strategies.put("input", new ReplaceStrategy()); - strategies.put("classifier_output", new ReplaceStrategy()); - strategies.put("solution", new ReplaceStrategy()); - return strategies; - }).addNode("feedback_classifier", node_async(feedbackClassifier)) - .addNode("specific_question_classifier", node_async(specificQuestionClassifier)) - .addNode("recorder", node_async(new RecordingNode())) +// StateGraph stateGraph = new StateGraph("Consumer Service Workflow Demo", () -> { +// Map strategies = new HashMap<>(); +// strategies.put("input", new ReplaceStrategy()); +// strategies.put("classifier_output", new ReplaceStrategy()); +// strategies.put("solution", new ReplaceStrategy()); +// return strategies; +// }).addNode("feedback_classifier", node_async(feedbackClassifier)) +// .addNode("specific_question_classifier", node_async(specificQuestionClassifier)) +// .addNode("recorder", node_async(new RecordingNode())) - .addEdge(START, "feedback_classifier") - .addConditionalEdges("feedback_classifier", - edge_async(new CustomerServiceController.FeedbackQuestionDispatcher()), - Map.of("positive", "recorder", "negative", "specific_question_classifier")) - .addConditionalEdges("specific_question_classifier", - edge_async(new CustomerServiceController.SpecificQuestionDispatcher()), - Map.of("after-sale", "recorder", "transportation", "recorder", "quality", "recorder", "others", - "recorder")) - .addEdge("recorder", END); +// .addEdge(START, "feedback_classifier") +// .addConditionalEdges("feedback_classifier", +// edge_async(new CustomerServiceController.FeedbackQuestionDispatcher()), +// Map.of("positive", "recorder", "negative", "specific_question_classifier")) +// .addConditionalEdges("specific_question_classifier", +// edge_async(new CustomerServiceController.SpecificQuestionDispatcher()), +// Map.of("after-sale", "recorder", "transportation", "recorder", "quality", "recorder", "others", +// "recorder")) +// .addEdge("recorder", END); - GraphRepresentation graphRepresentation = stateGraph.getGraph(GraphRepresentation.Type.PLANTUML, - "workflow graph"); +// GraphRepresentation graphRepresentation = stateGraph.getGraph(GraphRepresentation.Type.PLANTUML, +// "workflow graph"); - log.info("workflow graph: {}", graphRepresentation.content()); +// log.info("workflow graph: {}", graphRepresentation.content()); - return stateGraph; - } +// return stateGraph; +// } -} +// }