• 用户输入自然语言我上周买的手机为什么还没发货?

  • LLM 自动决策

    • 识别意图:订单问题
    • 自动匹配 Skill:订单查询技能
  • LLM 自动生成 MCP 调用

    • 调用 query_order
    • 调用 query_logistics
  • 执行 MCP 工具去后端 / 数据库 / 接口查数据

  • LLM 整理结果 → 返回自然语言回答

  • AiConfig 注册工具

    LlmTools
  •   @Bean
        public DecisionAgent decisionAgent(ChatModel chatLanguageModel,
                                           ChatMemoryStore chatMemoryStore,
                                           com.example.ai.tools.LlmTools llmTools) {
            ChatMemory chatMemory = MessageWindowChatMemory.builder()
                    .maxMessages(20)
                    .chatMemoryStore(chatMemoryStore)
                    .build();
    
            return AiServices.builder(DecisionAgent.class)
                    .chatModel(chatLanguageModel)
                    .chatMemory(chatMemory)
                    .tools(llmTools)
                    .build();
        }

    在LlmTools 工具中定义要实现的业务内容,由LLm大模型识别用户意图,然后自行调用

  • LlmTools

    package com.example.ai.tools;
    
    import dev.langchain4j.agent.tool.Tool;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    @Slf4j
    @Component
    public class LlmTools {
    
        @Tool("对文本进行摘要总结,提取核心要点,保持简洁")
        public String summarize(String text) {
            log.info("LlmTools - summarize called with text length: {}", text.length());
            
            String prompt = """
                    请对以下文本进行摘要总结:
                    
                    {{text}}
                    
                    要求:
                    1. 提取核心要点
                    2. 保持简洁,不超过200字
                    3. 使用中文
                    """.replace("{{text}}", text);
            
            return prompt;
        }
    
        @Tool("翻译文本到指定语言,如中文、English、日语等")
        public String translate(String text, String targetLanguage) {
            log.info("LlmTools - translate called with text length: {}, targetLanguage: {}", text.length(), targetLanguage);
            
            String prompt = """
                    请将以下文本翻译成{{targetLanguage}}:
                    
                    {{text}}
                    
                    要求:
                    1. 翻译准确完整
                    2. 保持原文风格
                    """.replace("{{text}}", text)
                     .replace("{{targetLanguage}}", targetLanguage);
            
            return prompt;
        }
    
        @Tool("分析文本的情感倾向,判断是正面、中性还是负面")
        public String analyzeSentiment(String text) {
            log.info("LlmTools - analyzeSentiment called with text length: {}", text.length());
            
            String prompt = """
                    请分析以下文本的情感倾向:
                    
                    {{text}}
                    
                    要求:
                    1. 判断情感类型:正面、中性、负面
                    2. 给出简短理由
                    3. 使用中文回答
                    """.replace("{{text}}", text);
            
            return prompt;
        }
    
        @Tool("搜索知识库获取相关信息")
        public String searchKnowledge(String query) {
            log.info("LlmTools - searchKnowledge called with query: {}", query);
            
            return "搜索知识库: " + query;
        }
    
        @Tool("获取当前时间")
        public String getCurrentTime() {
            String currentTime = java.time.LocalDateTime.now()
                    .format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            log.info("LlmTools - getCurrentTime called, returning: {}", currentTime);
            return currentTime;
        }
    }

    由LLM大模型 识别意图自主使用Skill来调用哪个mcp工具 

  • Skill

    package com.example.ai.skill;
    
    import com.example.ai.config.AiConfig.DecisionAgent;
    import com.example.ai.mcp.LlmMcpServer;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    import reactor.core.publisher.Flux;
    
    import java.util.Map;
    
    @Slf4j
    @Component
    public class LlmSkill {
    
        private final LlmMcpServer llmMcpServer;
        private final DecisionAgent decisionAgent;
    
        public LlmSkill(LlmMcpServer llmMcpServer, DecisionAgent decisionAgent) {
            this.llmMcpServer = llmMcpServer;
            this.decisionAgent = decisionAgent;
        }
    
        public Map<String, Object> chat(Map<String, Object> params) {
            String sessionId = (String) params.get("sessionId");
            String message = (String) params.get("message");
            String systemPrompt = (String) params.getOrDefault("systemPrompt", null);
    
            log.info("LlmSkill - chat called with sessionId: {}, message: {}", sessionId, 
                    message != null ? message.substring(0, Math.min(50, message.length())) : "null");
    
            String response;
            if (systemPrompt != null && !systemPrompt.isEmpty()) {
                response = llmMcpServer.chat(sessionId, message, systemPrompt);
            } else {
                response = llmMcpServer.chat(sessionId, message);
            }
    
            return Map.of(
                    "response", response,
                    "sessionId", sessionId
            );
        }
    
        public Map<String, Object> autoDecisionChat(Map<String, Object> params) {
            String sessionId = (String) params.get("sessionId");
            String message = (String) params.get("message");
    
            log.info("LlmSkill - autoDecisionChat called with sessionId: {}, message: {}", sessionId, 
                    message != null ? message.substring(0, Math.min(50, message.length())) : "null");
    
            String response = decisionAgent.chat(message);
    
            log.info("LlmSkill - autoDecisionChat response: {}", 
                    response.substring(0, Math.min(100, response.length())));
    
            return Map.of(
                    "response", response,
                    "sessionId", sessionId,
                    "usedTool", true
            );
        }
    
        public Map<String, Object> streamChat(Map<String, Object> params) {
            String sessionId = (String) params.get("sessionId");
            String message = (String) params.get("message");
            String systemPrompt = (String) params.getOrDefault("systemPrompt", null);
    
            log.info("LlmSkill - streamChat called with sessionId: {}, message: {}", sessionId,
                    message != null ? message.substring(0, Math.min(50, message.length())) : "null");
    
            Flux<String> stream;
            if (systemPrompt != null && !systemPrompt.isEmpty()) {
                stream = llmMcpServer.streamChat(sessionId, message, systemPrompt);
            } else {
                stream = llmMcpServer.streamChat(sessionId, message);
            }
    
            return Map.of(
                    "stream", stream,
                    "streamId", sessionId + "_" + System.currentTimeMillis(),
                    "sessionId", sessionId
            );
        }
    
        public Map<String, Object> summarize(Map<String, Object> params) {
            String text = (String) params.get("text");
    
            log.info("LlmSkill - summarize called with text length: {}", 
                    text != null ? text.length() : 0);
    
            String summary = llmMcpServer.summarize(text);
    
            return Map.of("summary", summary);
        }
    
        public Map<String, Object> translate(Map<String, Object> params) {
            String text = (String) params.get("text");
            String targetLanguage = (String) params.get("targetLanguage");
    
            log.info("LlmSkill - translate called with text length: {}, targetLanguage: {}",
                    text != null ? text.length() : 0, targetLanguage);
    
            String translation = llmMcpServer.translate(text, targetLanguage);
    
            return Map.of(
                    "translation", translation,
                    "targetLanguage", targetLanguage
            );
        }
    
        public Map<String, Object> analyzeSentiment(Map<String, Object> params) {
            String text = (String) params.get("text");
    
            log.info("LlmSkill - analyzeSentiment called with text length: {}",
                    text != null ? text.length() : 0);
    
            String result = llmMcpServer.analyzeSentiment(text);
    
            String sentiment = extractSentiment(result);
            String reason = extractReason(result);
    
            return Map.of(
                    "sentiment", sentiment,
                    "reason", reason
            );
        }
    
        public Map<String, Object> clearSession(Map<String, Object> params) {
            String sessionId = (String) params.get("sessionId");
    
            log.info("LlmSkill - clearSession called with sessionId: {}", sessionId);
    
            llmMcpServer.clearSession(sessionId);
    
            return Map.of(
                    "success", true,
                    "sessionId", sessionId
            );
        }
    
        private String extractSentiment(String result) {
            if (result.contains("正面")) {
                return "正面";
            } else if (result.contains("负面")) {
                return "负面";
            } else if (result.contains("中性")) {
                return "中性";
            }
            return "中性";
        }
    
        private String extractReason(String result) {
            int reasonIndex = result.indexOf("理由");
            if (reasonIndex != -1) {
                return result.substring(reasonIndex + 2).trim();
            }
            return result;
        }
    }

    Mcp执行工具

  • package com.example.ai.mcp;
    
    import dev.langchain4j.memory.ChatMemory;
    import dev.langchain4j.memory.chat.MessageWindowChatMemory;
    import dev.langchain4j.model.chat.ChatModel;
    import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
    import dev.langchain4j.service.AiServices;
    import dev.langchain4j.service.SystemMessage;
    import dev.langchain4j.service.UserMessage;
    import dev.langchain4j.store.memory.chat.ChatMemoryStore;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import reactor.core.publisher.Flux;
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    @Slf4j
    @Component
    public class LlmMcpServer {
    
        private final ChatModel chatModel;
        private final OllamaStreamingChatModel streamingChatModel;
        private final ChatMemoryStore chatMemoryStore;
    
    
        @Value("${ai.llm.system-prompt:你是一位专业的AI助手,请友好、专业地回答用户问题。}")
        private String systemPrompt;
    
        private final Map<String, LlmAgent> agentCache = new ConcurrentHashMap<>();
    
        public interface LlmAgent {
            @SystemMessage("""
                    {{system_prompt}}
                    
                    当前时间:{{current_time}}
                    """)
            String chat(@UserMessage String userMessage,
                       @dev.langchain4j.service.V("system_prompt") String systemPrompt,
                       @dev.langchain4j.service.V("current_time") String currentTime);
    
            @SystemMessage("{{system_prompt}}")
            Flux<String> streamChat(@UserMessage String userMessage,
                                   @dev.langchain4j.service.V("system_prompt") String systemPrompt);
        }
    
        public LlmMcpServer(ChatModel chatModel,
                            OllamaStreamingChatModel streamingChatModel,
                            ChatMemoryStore chatMemoryStore) {
            this.chatModel = chatModel;
            this.streamingChatModel = streamingChatModel;
            this.chatMemoryStore = chatMemoryStore;
        }
    
        public String chat(String sessionId, String message) {
            return chat(sessionId, message, systemPrompt);
        }
    
        public String chat(String sessionId, String message, String customSystemPrompt) {
            LlmAgent agent = agentCache.computeIfAbsent(sessionId, sid -> {
                ChatMemory chatMemory = MessageWindowChatMemory.builder()
                        .id(sid)
                        .maxMessages(20)
                        .chatMemoryStore(chatMemoryStore)
                        .build();
    
                return AiServices.builder(LlmAgent.class)
                        .chatModel(chatModel)
                        .chatMemory(chatMemory)
                        .build();
            });
    
            String currentTime = LocalDateTime.now()
                    .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    
            String response = agent.chat(message, customSystemPrompt, currentTime);
    
            log.info("LLM MCP - Session[{}] User: {} | Response: {}",
                    sessionId,
                    message.substring(0, Math.min(50, message.length())),
                    response.substring(0, Math.min(100, response.length())));
    
            return response;
        }
    
        public Flux<String> streamChat(String sessionId, String message) {
            return streamChat(sessionId, message, systemPrompt);
        }
    
        public Flux<String> streamChat(String sessionId, String message, String customSystemPrompt) {
            LlmAgent agent = agentCache.computeIfAbsent(sessionId, sid -> {
                ChatMemory chatMemory = MessageWindowChatMemory.builder()
                        .id(sid)
                        .maxMessages(20)
                        .chatMemoryStore(chatMemoryStore)
                        .build();
    
                return AiServices.builder(LlmAgent.class)
                        .streamingChatModel(streamingChatModel)
                        .chatMemory(chatMemory)
                        .build();
            });
    
            log.info("LLM MCP - Streaming Session[{}] User: {}",
                    sessionId,
                    message.substring(0, Math.min(50, message.length())));
    
            return agent.streamChat(message, customSystemPrompt);
        }
    
        public void clearSession(String sessionId) {
            agentCache.remove(sessionId);
            chatMemoryStore.deleteMessages(sessionId);
            log.info("LLM MCP - Session[{}] cleared", sessionId);
        }
    
        public String summarize(String text) {
            String prompt = """
                    请对以下文本进行摘要总结:
                    
                    {{text}}
                    
                    要求:
                    1. 提取核心要点
                    2. 保持简洁,不超过200字
                    3. 使用中文
                    """;
    
            prompt = prompt.replace("{{text}}", text);
    
            LlmAgent summarizer = AiServices.builder(LlmAgent.class)
                    .chatModel(chatModel)
                    .build();
    
            return summarizer.chat(prompt, "你是一位专业的文本摘要助手。",
                    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
    
        public String translate(String text, String targetLanguage) {
            String prompt = """
                    请将以下文本翻译成{{target_language}}:
                    
                    {{text}}
                    
                    要求:
                    1. 翻译准确完整
                    2. 保持原文风格
                    """;
    
            prompt = prompt.replace("{{text}}", text)
                           .replace("{{target_language}}", targetLanguage);
    
            LlmAgent translator = AiServices.builder(LlmAgent.class)
                    .chatModel(chatModel)
                    .build();
    
            return translator.chat(prompt, "你是一位专业的翻译助手,精通多种语言。",
                    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
    
        public String analyzeSentiment(String text) {
            String prompt = """
                    请分析以下文本的情感倾向:
                    
                    {{text}}
                    
                    要求:
                    1. 判断情感类型:正面、中性、负面
                    2. 给出简短理由
                    3. 使用中文回答
                    """;
    
            prompt = prompt.replace("{{text}}", text);
    
            LlmAgent analyzer = AiServices.builder(LlmAgent.class)
                    .chatModel(chatModel)
                    .build();
    
            return analyzer.chat(prompt, "你是一位专业的情感分析助手。",
                    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
    }
    

接收用户请求的controller

package com.example.ai.controller;

import com.example.ai.skill.LlmSkill;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;
import java.util.UUID;

@Slf4j
@RestController
@RequestMapping("/api/llm")
@RequiredArgsConstructor
public class LlmController {

    private final LlmSkill llmSkill;

    @PostMapping("/auto-decision")
    public ResponseEntity<Map<String, Object>> autoDecisionChat(@RequestBody AutoDecisionRequest request) {
        log.info("收到自动决策请求 - sessionId: {}, message: {}", 
                request.sessionId, 
                request.message != null ? request.message.substring(0, Math.min(50, request.message.length())) : "null");
        
        String sessionId = request.sessionId != null ? request.sessionId : UUID.randomUUID().toString();
        
        Map<String, Object> result = llmSkill.autoDecisionChat(Map.of(
                "sessionId", sessionId,
                "message", request.message
        ));
        
        return ResponseEntity.ok(result);
    }

    @PostMapping("/chat")
    public ResponseEntity<Map<String, Object>> chat(@RequestBody ChatRequest request) {
        log.info("收到普通聊天请求 - sessionId: {}, message: {}", 
                request.sessionId, 
                request.message != null ? request.message.substring(0, Math.min(50, request.message.length())) : "null");
        
        String sessionId = request.sessionId != null ? request.sessionId : UUID.randomUUID().toString();
        
        Map<String, Object> params = Map.of(
                "sessionId", sessionId,
                "message", request.message
        );
        
        if (request.systemPrompt != null && !request.systemPrompt.isEmpty()) {
            params = Map.of(
                    "sessionId", sessionId,
                    "message", request.message,
                    "systemPrompt", request.systemPrompt
            );
        }
        
        Map<String, Object> result = llmSkill.chat(params);
        
        return ResponseEntity.ok(result);
    }

    @PostMapping("/summarize")
    public ResponseEntity<Map<String, Object>> summarize(@RequestBody SummarizeRequest request) {
        log.info("收到摘要请求 - text length: {}", request.text != null ? request.text.length() : 0);
        
        Map<String, Object> result = llmSkill.summarize(Map.of("text", request.text));
        
        return ResponseEntity.ok(result);
    }

    @PostMapping("/translate")
    public ResponseEntity<Map<String, Object>> translate(@RequestBody TranslateRequest request) {
        log.info("收到翻译请求 - text length: {}, targetLanguage: {}", 
                request.text != null ? request.text.length() : 0, 
                request.targetLanguage);
        
        Map<String, Object> result = llmSkill.translate(Map.of(
                "text", request.text,
                "targetLanguage", request.targetLanguage
        ));
        
        return ResponseEntity.ok(result);
    }

    @PostMapping("/sentiment")
    public ResponseEntity<Map<String, Object>> analyzeSentiment(@RequestBody SentimentRequest request) {
        log.info("收到情感分析请求 - text length: {}", request.text != null ? request.text.length() : 0);
        
        Map<String, Object> result = llmSkill.analyzeSentiment(Map.of("text", request.text));
        
        return ResponseEntity.ok(result);
    }

    @DeleteMapping("/session/{sessionId}")
    public ResponseEntity<Map<String, Object>> clearSession(@PathVariable String sessionId) {
        log.info("收到清除会话请求 - sessionId: {}", sessionId);
        
        Map<String, Object> result = llmSkill.clearSession(Map.of("sessionId", sessionId));
        
        return ResponseEntity.ok(result);
    }

    public record AutoDecisionRequest(String sessionId, String message) {}
    
    public record ChatRequest(String sessionId, String message, String systemPrompt) {}
    
    public record SummarizeRequest(String text) {}
    
    public record TranslateRequest(String text, String targetLanguage) {}
    
    public record SentimentRequest(String text) {}
}

 完成代码可以参考

https://gitee.com/bluethky/ai-service-1.4.git

欢迎各位同学互相交流

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐