聊聊langchain4j的MCP

本文主要研究一下langchain4j对Model Context Protocol (MCP) 的支持

MCP

MCP协议规定了两种传输方式:

  • HTTP:客户端请求一个SSE(Server-Sent Events)通道以从服务器接收事件,然后通过HTTP POST请求发送命令。这种方式适用于需要跨网络通信的场景,通常用于分布式系统或需要高并发的场景。
  • stdio:客户端可以将MCP服务器作为本地子进程运行,并通过标准输入/输出直接与其通信。这种方式适用于本地集成和命令行工具,适合简单的本地批处理任务。

如果需要让ChatModel或AI service运行由MCP服务器提供的工具,则需要创建一个MCP tool provider

McpToolProvider

McpTransport

McpTransport transport = new StdioMcpTransport.Builder()
    .command(List.of("/usr/bin/npm", "exec", "@modelcontextprotocol/server-everything@0.6.2"))
    .logEvents(true) // only if you want to see the traffic in the log
    .build();

对于HTTP方式则如下:

McpTransport transport = new HttpMcpTransport.Builder()
    .sseUrl("http://localhost:3001/sse")
    .logRequests(true) // if you want to see the traffic in the log
    .logResponses(true)
    .build();

McpClient

McpClient mcpClient = new DefaultMcpClient.Builder()
    .transport(transport)
    .logMessageHandler(new MyLogMessageHandler())
    .build();

基于McpTransport创建McpClient,可以指定logMessageHandler来打印相关信息,可以通过client.listResources()、client.listResourceTemplates()来返回MCP的resources

provider

ToolProvider toolProvider = McpToolProvider.builder()
    .mcpClients(List.of(mcpClient))
    .build();

基于McpClient来创建McpToolProvider

AiService

Bot bot = AiServices.builder(Bot.class)
    .chatLanguageModel(model)
    .toolProvider(toolProvider)
    .build();

AiServices.builder提供了方法来设置toolProvider

示例

public static void main(String[] args) throws Exception {

    ChatLanguageModel model = OpenAiChatModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .modelName("gpt-4o-mini")
        .logRequests(true)
        .logResponses(true)
        .build();

    McpTransport transport = new StdioMcpTransport.Builder()
        .command(List.of("/usr/local/bin/docker", "run", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "-i", "mcp/github"))
        .logEvents(true)
        .build();

    McpClient mcpClient = new DefaultMcpClient.Builder()
        .transport(transport)
        .build();

    ToolProvider toolProvider = McpToolProvider.builder()
        .mcpClients(List.of(mcpClient))
        .build();

    Bot bot = AiServices.builder(Bot.class)
        .chatLanguageModel(model)
        .toolProvider(toolProvider)
        .build();

    try {
        String response = bot.chat("Summarize the last 3 commits of the LangChain4j GitHub repository");
        System.out.println("RESPONSE: " + response);
    } finally {
        mcpClient.close();
    }
}

这里使用stdio的方式来连接docker部署的GitHub MCP server,通过chat告诉LLM去总结LangChain4j这个github仓库最近的3个commits

返回结果示例如下:

Here are the summaries of the last three commits in the LangChain4j GitHub repository:

1. **Commit [36951f9](https://github.com/langchain4j/langchain4j/commit/36951f9649c1beacd8b9fc2d910a2e23223e0d93)** (Date: 2025-02-05)
   - **Author:** Dmytro Liubarskyi
   - **Message:** Updated to `upload-pages-artifact@v3`.
   - **Details:** This commit updates the GitHub Action used for uploading pages artifacts to version 3.

2. **Commit [6fcd19f](https://github.com/langchain4j/langchain4j/commit/6fcd19f50c8393729a0878d6125b0bb1967ac055)** (Date: 2025-02-05)
   - **Author:** Dmytro Liubarskyi
   - **Message:** Updated to `checkout@v4`, `deploy-pages@v4`, and `upload-pages-artifact@v4`.
   - **Details:** This commit updates multiple GitHub Actions to their version 4.

3. **Commit [2e74049](https://github.com/langchain4j/langchain4j/commit/2e740495d2aa0f16ef1c05cfcc76f91aef6f6599)** (Date: 2025-02-05)
   - **Author:** Dmytro Liubarskyi
   - **Message:** Updated to `setup-node@v4` and `configure-pages@v4`.
   - **Details:** This commit updates the `setup-node` and `configure-pages` GitHub Actions to version 4.

All commits were made by the same author, Dmytro Liubarskyi, on the same day, focusing on updating various GitHub Actions to newer versions.

源码

ToolProvider

langchain4j/src/main/java/dev/langchain4j/service/tool/ToolProvider.java

@FunctionalInterface
public interface ToolProvider {

    /**
     * Provides tools for the request to the LLM.
     *
     * @param request {@link ToolProviderRequest} contains {@link UserMessage} and chat memory id (see {@link MemoryId}).
     * @return {@link ToolProviderResult} contains tools that should be included in the request to the LLM.
     */
    ToolProviderResult provideTools(ToolProviderRequest request);
}

langchain4j定义了ToolProvider接口,每次调用AI服务时,它都会被调用,并为该次调用提供相应的工具,其provideTools返回ToolProviderResult

McpToolProvider

public class McpToolProvider implements ToolProvider {

    private final List<McpClient> mcpClients;
    private final boolean failIfOneServerFails;
    private static final Logger log = LoggerFactory.getLogger(McpToolProvider.class);

    private McpToolProvider(Builder builder) {
        this.mcpClients = new ArrayList<>(builder.mcpClients);
        this.failIfOneServerFails = Utils.getOrDefault(builder.failIfOneServerFails, false);
    }

    @Override
    public ToolProviderResult provideTools(final ToolProviderRequest request) {
        ToolProviderResult.Builder builder = ToolProviderResult.builder();
        for (McpClient mcpClient : mcpClients) {
            try {
                List<ToolSpecification> toolSpecifications = mcpClient.listTools();
                for (ToolSpecification toolSpecification : toolSpecifications) {
                    builder.add(
                            toolSpecification, (executionRequest, memoryId) -> mcpClient.executeTool(executionRequest));
                }
            } catch (Exception e) {
                if (failIfOneServerFails) {
                    throw new RuntimeException("Failed to retrieve tools from MCP server", e);
                } else {
                    log.warn("Failed to retrieve tools from MCP server", e);
                }
            }
        }
        return builder.build();
    }

    //......
}    

McpToolProvider要求构造器传入McpToolProvider.Builder,provideTools会遍历mcpClients,之后遍历mcpClient.listTools(),构建每个tool对应的executor(mcpClient.executeTool(executionRequest))

小结

langchain4j提供了langchain4j-mcp模块来支持MCP协议,它通过McpToolProvider来实现ToolProvider接口,以tool的方式来对接mcp。

doc

LangChain4J 是 LangChain 的 Java 版本,主要用于构建语言模型驱动的应用程序。MCP(Multi Chain Provider)是一种支持多链管理的方式,可以让你更方便地切换和集成不同的大模型服务提供商。 下面是一个简单的示例教程,展示如何将 LangChain4J 和 MCP 结合起来使用: --- ### 步骤 1:引入依赖项 首先需要确保项目的 `pom.xml` 文件中有以下 Maven 依赖项: ```xml <dependency> <groupId>io.langchain</groupId> <artifactId>langchain4j</artifactId> <version>最新版本号</version> </dependency> ``` --- ### 步骤 2:配置多链提供者 (MCP) 假设我们有多个大模型供应商,如阿里云 Qwen、百度文心一言等,并希望动态选择其中的一个作为后端处理请求。 #### 创建配置文件 (`config.json`) ```json { "chains": [ { "name": "qwen", "type": "QwenModelProvider", "apiKey": "your_qwen_api_key" }, { "name": "baidu", "type": "BaiduWenxinProvider", "apiKey": "your_baidu_api_key" } ] } ``` --- ### 步骤 3:编写核心代码 以下是结合 LangChain4J 和 MCP 动态加载不同链路的核心逻辑代码: ```java import io.langchain4j.model.chat.ChatMessage; import io.langchain4j.model.chat.ChatResponse; import io.langchain4j.chain.Chain; public class LangChain4JMcpExample { public static void main(String[] args) throws Exception { // 加载配置文件并初始化 MCP 提供者 MultiChainProvider mcp = new JsonConfiguredMcp("path/to/config.json"); // 根据需求选择某个具体的链条名称 String selectedChainName = "qwen"; // 这里可以选择 qwen 或 baidu 等 // 获取指定的大模型实例 ChatModel chatModel = mcp.getChatModel(selectedChainName); // 构建输入消息 List<ChatMessage> messages = Arrays.asList( ChatMessage.fromHuman("你好!"), ChatMessage.fromAi("您好,请问有什么我可以帮您的吗?") ); // 调用模型生成回复 ChatResponse response = chatModel.generate(messages); // 输出结果 System.out.println("AI 回复:" + response.message().content()); } } // 假设这是一个用于解析 JSON 并封装多链功能的工具类 class JsonConfiguredMcp implements MultiChainProvider { private Map<String, ChatModel> chainMap; public JsonConfiguredMcp(String configFilePath) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); ConfigData configData = objectMapper.readValue(new File(configFilePath), ConfigData.class); this.chainMap = new HashMap<>(); for (ChainInfo info : configData.chains()) { if ("QwenModelProvider".equals(info.type())) { this.chainMap.put(info.name(), new QwenModel(info.apiKey())); } else if ("BaiduWenxinProvider".equals(info.type())) { this.chainMap.put(info.name(), new BaiduWenxinModel(info.apiKey())); } } } @Override public ChatModel getChatModel(String name) { return chainMap.get(name); } } record ChainInfo(String name, String type, String apiKey) {} record ConfigData(List<ChainInfo> chains) {} ``` --- ### 解释上述代码的功能 1. **多链管理**:通过读取外部配置文件来动态添加不同服务商的支持。 2. **动态选择链条**:用户可以根据实际业务场景,在运行时自由切换到所需的 AI 模型。 3. **简化接口调用**:无论是哪一种模型,最终都只需要统一调用其公共 API 接口即可完成任务。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值