diff --git a/.idea/encodings.xml b/.idea/encodings.xml index eb5644e..91c7e1e 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -7,6 +7,8 @@ + + diff --git a/langchain4j-ai-mcp/pom.xml b/langchain4j-ai-mcp/pom.xml new file mode 100644 index 0000000..33cc09c --- /dev/null +++ b/langchain4j-ai-mcp/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-mcp + + + 17 + 17 + UTF-8 + + + + + + dev.langchain4j + langchain4j-mcp + + + + + dev.langchain4j + langchain4j-community-dashscope-spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + dev.langchain4j + langchain4j-reactor + 1.9.1-beta17 + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + + + + \ No newline at end of file diff --git a/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/McpApplication.java b/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/McpApplication.java new file mode 100644 index 0000000..28dd2b4 --- /dev/null +++ b/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/McpApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class McpApplication { + + public static void main(String[] args) { + SpringApplication.run(McpApplication.class,args); + } +} diff --git a/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/config/BaiduMcpConfig.java b/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/config/BaiduMcpConfig.java new file mode 100644 index 0000000..b9b61b1 --- /dev/null +++ b/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/config/BaiduMcpConfig.java @@ -0,0 +1,57 @@ +package com.iwe3.langchain4j.config; + +import com.iwe3.langchain4j.service.McpService; +import dev.langchain4j.mcp.McpToolProvider; +import dev.langchain4j.mcp.client.DefaultMcpClient; +import dev.langchain4j.mcp.client.McpClient; +import dev.langchain4j.mcp.client.transport.McpTransport; +import dev.langchain4j.mcp.client.transport.stdio.StdioMcpTransport; +import dev.langchain4j.model.chat.StreamingChatModel; +import dev.langchain4j.service.AiServices; +import dev.langchain4j.service.tool.ToolProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; +import java.util.Map; + +@Configuration +public class BaiduMcpConfig { + + @Autowired + private StreamingChatModel streamingChatModel; + + @Bean + public McpService mcpService(){ + /**1.构建McpTransport协议 + * + * 1.1 cmd:启动 Windows 命令行解释器。 + * 1.2 /c:告诉 cmd 执行完后面的命令后关闭自身。 + * 1.3 npx:npx = npm execute package,Node.js 的一个工具,用于执行 npm 包中的可执行文件。 + * 1.4 -y 或 --yes:自动确认操作(类似于默认接受所有提示)。 + * 1.5 @baidumap/mcp-server-baidu-map:要通过 npx 执行的 npm 包名 + * 1.6 BAIDU_MAP_API_KEY 是访问百度地图开放平台API的AK + */ + McpTransport transport = new StdioMcpTransport.Builder() + .command(List.of("cmd", "/c", "npx", "-y", "@baidumap/mcp-server-baidu-map")) + .environment(Map.of("BAIDU_MAP_API_KEY", System.getenv("BAIDU_MAP_API_KEY"))) + .build(); + + // 2.构建McpClient客户端 + McpClient mcpClient = new DefaultMcpClient.Builder() + .transport(transport) + .build(); + + // 3.创建工具集和原生的FunctionCalling类似 + ToolProvider toolProvider = McpToolProvider.builder() + .mcpClients(mcpClient) + .build(); + + // 4.通过AiServivces给我们自定义接口McpService构建实现类并将工具集和大模型赋值给AiService + return AiServices.builder(McpService.class) + .streamingChatModel(streamingChatModel) + .toolProvider(toolProvider) + .build(); + } +} diff --git a/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/controller/McpCallServerController.java b/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/controller/McpCallServerController.java new file mode 100644 index 0000000..7941d53 --- /dev/null +++ b/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/controller/McpCallServerController.java @@ -0,0 +1,37 @@ +package com.iwe3.langchain4j.controller; + +import com.iwe3.langchain4j.service.McpService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; + + +/** + * @Description: 知识出处 + * 第1步,如何进行mcp编码 + * https://docs.langchain4j.dev/tutorials/mcp#creating-an-mcp-tool-provider + * + * 第2步,如何使用baidu map mcp,它提供了哪些功能对外服务 + * https://mcp.so/zh/server/baidu-map/baidu-maps?tab=tools + * + * http://localhost:9012/lc4j/mcp/chat?question=查询117.173.150.122归属地 + * http://localhost:9012/lc4j/mcp/chat?question=查询都江堰天气 + * http://localhost:9012/lc4j/mcp/chat?question=查询成都成华区到都江堰路线规划 + */ +@RestController +public class McpCallServerController { + + @Autowired + private McpService mcpService; + + @GetMapping("/lc4j/mcp/chat") + public Flux chat(@RequestParam("question") String question) throws Exception + { + // 调用我们定义的HighApi接口,通过大模型对百度mcpserver调用 + return mcpService.chat(question); + + } +} + diff --git a/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/service/McpService.java b/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/service/McpService.java new file mode 100644 index 0000000..35b75cd --- /dev/null +++ b/langchain4j-ai-mcp/src/main/java/com/iwe3/langchain4j/service/McpService.java @@ -0,0 +1,8 @@ +package com.iwe3.langchain4j.service; + +import reactor.core.publisher.Flux; + +public interface McpService +{ + Flux chat(String question); +} \ No newline at end of file diff --git a/langchain4j-ai-mcp/src/main/resources/application.yml b/langchain4j-ai-mcp/src/main/resources/application.yml new file mode 100644 index 0000000..50c510f --- /dev/null +++ b/langchain4j-ai-mcp/src/main/resources/application.yml @@ -0,0 +1,27 @@ +server: + port: 9012 + servlet: + encoding: + charset: UTF-8 + enabled: true + force: true + +spring: + application: + name: langchain4j-ai-mcp + +langchain4j: + community: + dashscope: + streaming-chat-model: + api-key: ${DASH_SCOPE_API_KEY} + model-name: qwen-plus + chat-model: + api-key: ${DASH_SCOPE_API_KEY} + model-name: qwen-plus + +# 只有日志级别调整为debug级别,同时配置以上 langchain 日志输出开关才有效 +logging: + level: + dev: + langchain4j: DEBUG \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/pom.xml b/langchain4j-ai-xiaoai-agent/pom.xml index 482270a..9eae851 100644 --- a/langchain4j-ai-xiaoai-agent/pom.xml +++ b/langchain4j-ai-xiaoai-agent/pom.xml @@ -18,6 +18,19 @@ 4.3.0 + + + + dev.langchain4j + langchain4j-mcp + + + + dev.langchain4j + langchain4j-http-client-jdk + + + dev.langchain4j diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/XiaoAIAgentApplication.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/XiaoAIAgentApplication.java index 81ea110..c834c0d 100644 --- a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/XiaoAIAgentApplication.java +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/XiaoAIAgentApplication.java @@ -3,10 +3,13 @@ package com.iwe3.langchain4j; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; @MapperScan("com.iwe3.langchain4j.mapper") @SpringBootApplication public class XiaoAIAgentApplication { + public static void main(String[] args) { SpringApplication.run(XiaoAIAgentApplication.class,args); } diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/BaiduMcpConfig.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/BaiduMcpConfig.java new file mode 100644 index 0000000..c6e5b76 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/BaiduMcpConfig.java @@ -0,0 +1,62 @@ +package com.iwe3.langchain4j.config; + +import com.iwe3.langchain4j.mcp.BaiduMcpService; +import dev.langchain4j.mcp.McpToolProvider; +import dev.langchain4j.mcp.client.DefaultMcpClient; +import dev.langchain4j.mcp.client.McpClient; +import dev.langchain4j.mcp.client.transport.McpTransport; +import dev.langchain4j.mcp.client.transport.stdio.StdioMcpTransport; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.chat.StreamingChatModel; +import dev.langchain4j.service.AiServices; +import dev.langchain4j.service.tool.ToolProvider; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; +import java.util.Map; + +@Configuration +public class BaiduMcpConfig { + + @Resource + private ChatModel chatModelQwen; + + @Bean + public BaiduMcpService baiduMcpService(){ + + /**1.构建McpTransport协议 + * + * 1.1 cmd:启动 Windows 命令行解释器。 + * 1.2 /c:告诉 cmd 执行完后面的命令后关闭自身。 + * 1.3 npx:npx = npm execute package,Node.js 的一个工具,用于执行 npm 包中的可执行文件。 + * 1.4 -y 或 --yes:自动确认操作(类似于默认接受所有提示)。 + * 1.5 @baidumap/mcp-server-baidu-map:要通过 npx 执行的 npm 包名 + * 1.6 BAIDU_MAP_API_KEY 是访问百度地图开放平台API的AK + */ + var transport = new StdioMcpTransport.Builder() + .command(List.of("cmd", "/c", "npx", "-y", "@baidumap/mcp-server-baidu-map")) + .environment(Map.of("BAIDU_MAP_API_KEY", System.getenv("BAIDU_MAP_API_KEY"))) + .build(); + + // 2.构建McpClient客户端 + var mcpClient = new DefaultMcpClient.Builder() + .transport(transport) + .build(); + + // 3.创建工具集和原生的FunctionCalling类似 + var toolProvider = McpToolProvider.builder() + .mcpClients(mcpClient) + .build(); + + // 4.通过AiServivces给我们自定义接口McpService构建实现类并将工具集和大模型赋值给AiService + return AiServices.builder(BaiduMcpService.class) + .chatModel(chatModelQwen) + .toolProvider(toolProvider) + .build(); + } +} + + + diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java index 506c9ea..cd15388 100644 --- a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -1,6 +1,8 @@ package com.iwe3.langchain4j.config; +import dev.langchain4j.model.chat.ChatModel; import dev.langchain4j.model.chat.StreamingChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.model.openai.OpenAiStreamingChatModel; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -20,4 +22,19 @@ public class LLMConfig { .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") .build(); } + + /** + * 普通对话接口 chatModelQwen + * @return + */ + @Bean + public ChatModel chatModelQwen(){ + /*大模型3件套:apikey ,model-name,base-url */ + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } + } diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/mcp/BaiduMcpService.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/mcp/BaiduMcpService.java new file mode 100644 index 0000000..d6fad85 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/mcp/BaiduMcpService.java @@ -0,0 +1,6 @@ +package com.iwe3.langchain4j.mcp; + +public interface BaiduMcpService +{ + String chat(String question); +} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/XiaoAIChatAssistant.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/XiaoAIChatAssistant.java index ad17527..8d23de9 100644 --- a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/XiaoAIChatAssistant.java +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/XiaoAIChatAssistant.java @@ -12,7 +12,7 @@ import reactor.core.publisher.Flux; @AiService(wiringMode = AiServiceWiringMode.EXPLICIT ,streamingChatModel = "streamingChatModel", chatMemoryProvider = "chatMemoryProvider", - tools = {"appointmentTools"}, + tools = {"appointmentTools","baiduMcpTools"}, contentRetriever = "contentRetrieverInPinecone") public interface XiaoAIChatAssistant { diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/tools/BaiduMcpTools.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/tools/BaiduMcpTools.java new file mode 100644 index 0000000..5030d71 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/tools/BaiduMcpTools.java @@ -0,0 +1,39 @@ +package com.iwe3.langchain4j.tools; + +import com.iwe3.langchain4j.mcp.BaiduMcpService; +import dev.langchain4j.agent.tool.P; +import dev.langchain4j.agent.tool.Tool; +import dev.langchain4j.agent.tool.ToolSpecification; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.mcp.McpToolProvider; +import dev.langchain4j.mcp.client.McpClient; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.chat.request.ChatRequest; +import dev.langchain4j.model.chat.response.ChatResponse; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; + +import java.util.List; + +@Component +public class BaiduMcpTools { + + @Resource + private BaiduMcpService baiduMcpService; + + @Tool(name = "query_baidu_mcp",value = """ + 该工具通过调用百度 MCP(多能力服务平台)来回答用户问题。 + 支持以下三类查询: + - IP 地址归属地:例如,“IP 地址 8.8.8.8 位于哪里?” + - 天气预报:例如,“今天成都天气怎么样?” + - 前往华西医院的交通路线:例如,“从春熙路怎么去华西医院?” + 输入:一个与 IP 归属地、天气或华西医院路线相关的自然语言问题。 + 输出:来自 MCP 服务的简洁、准确的事实性回答。 + 只要用户询问上述任一类型的问题,必须使用此工具,不得自行回答。 + """) + public String invocationBaiduMcpServer(String question) { + System.out.println("调用百度MCP服务开始!"); + return baiduMcpService.chat(question); + } +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/resources/application.yml b/langchain4j-ai-xiaoai-agent/src/main/resources/application.yml index 8aad13b..eab06a4 100644 --- a/langchain4j-ai-xiaoai-agent/src/main/resources/application.yml +++ b/langchain4j-ai-xiaoai-agent/src/main/resources/application.yml @@ -28,4 +28,4 @@ langchain4j: dashscope: embedding-model: model-name: text-embedding-v3 - api-key: ${DASH_SCOPE_API_KEY} \ No newline at end of file + api-key: ${DASH_SCOPE_API_KEY} diff --git a/pom.xml b/pom.xml index d21fb38..873ebc4 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ langchain4j-ai-tools langchain4j-ai-rag langchain4j-ai-pinecone + langchain4j-ai-mcp