JavaAI05-Chain、MCP
摘要 本文介绍了使用Chain多个ServiceAI的协作模式,通过多个AI模型分工合作提升任务处理效率。文章指出单一LLM处理所有任务存在高成本、低效和不可控风险等问题,提出将任务拆分为:1)由专门模型判断任务类型;2)根据类型调用相应处理服务。演示了Java实现方案,使用Deepseek模型进行任务分类,Qwen模型处理客服咨询,通过枚举定义任务类型并实现任务分发逻辑。这种链式协作模式降低了t
·
Chain多个ServiceAI
- 在一个应用中, 可能需要多个模型共同一起协作完成一个任务。
- 为什么要这样做呢?
- 某个LLM(大模型)可能并不需要知道那么多的tools。例如用户只是输入了很简单的常识问题给到LLM,这时让 LLM 访问数十或数百个tools的成本很高(LLM 调用中包含的每个tools都会消耗大量token),并且得到的结果可能也是意想不到的(LLM 可能会产生幻觉或被操纵以使用非预期的输入来调用tools)
- 从RAG(检索增强生成)的角度,同样,有时需要为 LLM 提供一些上下文,但并不是永远需要这样,因为成本很高(更多上下文 = 更多token),并且相应时间也会增加(更多上下文 = 更高的延迟)
- 而且,不同的AI适合不同的场景,例如推理和情感两种场景。
- 拓展:AI协作流水线有个很好的框架是 dify,由python编写
- Chain可以替换tools,实现效果
- Chain可以怎么用?
- 您可以一个接一个地调用 AI 服务(又称链接-chain)。
- 您可以使用确定性和 LLM 支持的if/else语句(AI 服务可以返回boolean)。
- 您可以使用确定性和 LLM 支持的switch语句(AI 服务可以返回enum)。
- 您可以使用确定性和 LLM 驱动的for/while循环(AI 服务可以返回int和其他数字类型)。
- 您可以在单元测试中模拟 AI 服务(因为它是一个接口)。
- 您可以单独地对每个 AI 服务进行集成测试。
- 并且我们可以自由的进行任务编排
演示
- 以下演示2个模型协调合作,1个负责任务拆分分配, 1个模型负责任务tools回调执行
- 新建一个项目
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.qi</groupId> <artifactId>LangChain4j_demo05</artifactId> <version>1.0-SNAPSHOT</version> <name>LangChain4j_demo05</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai</artifactId> <version>1.0.0-beta3</version> </dependency> <!-- 阿里云百炼 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId> <version>1.0.0-beta3</version> </dependency> <!-- langchain4j核心 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>1.0.0-beta3</version> </dependency> </dependencies> </project> - 任务类型枚举
package com.qi; import dev.langchain4j.model.output.structured.Description; //任务类型枚举 public enum TASK_TYPE { @Description("查询机票") QUERY_TICKET("查询机票"), @Description("取消预定") CANCEL_TICKET("取消预定"), @Description("修改预定") MODIFY_TICKET("修改预定"), @Description("其他") OTHER("其他") ; private String name; TASK_TYPE(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } - 工作类
package com.qi; import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; public class MilesOfSmiles { //分配任务 助手 interface GreetingExpert { @UserMessage("以下文本是什么任务: {{it}}") TASK_TYPE isTask(String text); } //航空公司客服 助手 interface ChatBot { @SystemMessage("你是一名航空公司客服代理,请为客户服务:") String reply(String userMessage); } //两个工作助手 private GreetingExpert greetingExpert; private ChatBot chatBot; public MilesOfSmiles(GreetingExpert greetingExpert, ChatBot chatBot) { this.greetingExpert = greetingExpert; this.chatBot = chatBot; } //分配任务的方法 public String handle(String userMessage) { TASK_TYPE task = greetingExpert.isTask(userMessage); switch (task) { case MODIFY_TICKET: return task.getName() + "调用修改预定service方法处理"; case QUERY_TICKET: return task.getName() + "调用查询机票service方法查询"; case CANCEL_TICKET: return task.getName() + "调用取消预定service方法处理"; case OTHER: return chatBot.reply(userMessage); //其他问题,让航空公司客服助手回答 } return null; } } - main执行程序
package com.qi; import dev.langchain4j.community.model.dashscope.QwenChatModel; import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.service.AiServices; import com.qi.MilesOfSmiles.GreetingExpert; import com.qi.MilesOfSmiles.ChatBot; public class Main { public static void main(String[] args) { ChatLanguageModel qwen = QwenChatModel .builder() .apiKey("sk-xxxxxx") .modelName("qwen-max") .build(); ChatLanguageModel deepseek = OpenAiChatModel .builder() .baseUrl("https://api.deepseek.com") .apiKey("sk-xxxxxx") .modelName("deepseek-reasoner") .build(); //分配任务让deepseek来干 GreetingExpert greetingExpert = AiServices.create(GreetingExpert.class, deepseek); //航空客服让千问来干 ChatBot chatBot = AiServices.create(ChatBot.class, qwen); //创建工作对象 MilesOfSmiles milesOfSmiles = new MilesOfSmiles(greetingExpert, chatBot); //用户发起任务 String greeting1 = milesOfSmiles.handle("任务一:我要退票!"); System.out.println(greeting1); System.out.println("_________________________"); String greeting2 = milesOfSmiles.handle("任务二:3*6等于多少?"); System.out.println(greeting2); } } - 控制台

MCP
- 就是tools的一种外部调用的方式
- 是一种协议,由 Anthropic(Claude 母公司)于 2024 年 11 月开源的标准化协议。
- 其实就是,利用一种json-rpc2.0的json格式,告知可用工具及参数、确定调用工具、反馈对应数据。
- 目标是统一大模型与外部数据源、工具的交互方式。
- 一般将一些公共的服务按MCP协议抽取成一个外部应用,然后在tools中用到的时候去调用。
- 常见的MCPServer有很多,例如获取GitHub信息的、操作浏览器的、查网页的、获取数据库的等等。
- MCPServer管理平台有很多,例如:https://mcp.so
在IDEA中使用
- 在插件中搜索 Cline 安装



- 此时会跳转登陆页面,使用谷歌账号登录即可
- 登录成功后,配置大模型,这里我们选择阿里的千问,需要填入apiKey。然后点击Done保存

- 配置MCPServer

- 可以看到这里提供了很多MCPServer,也可以在这里一键安装

IDEA中接入百度地图
在百度地图中创建应用
- 百度地图开放平台中,创建一个应用

- 白名单模式按需设置,允许全部则填写:0.0.0.0/0
应用中安装
- 我们还是选择在 mcp.so 网站中进行选择。


- 也可以前往github中查看详细文档。可以看到,提供了python和node.JS 两种接入方法

- 我们使用nodeJS的方式接入
{ "mcpServers": { "baidu-map": { "command": "npx", "args": [ "-y", "@baidumap/mcp-server-baidu-map" ], "env": { "BAIDU_MAP_API_KEY": "<YOUR_API_KEY>" } } } } - 写入idea中cline中

- 需要进行简单的修改(目的是解决 Windows 系统下直接执行 npx 命令可能失败的兼容性问题)
{ "mcpServers": { "baidu-map": { "command": "cmd", "args": [ "/c", "npx", "-y", "@baidumap/mcp-server-baidu-map" ], "env": { "BAIDU_MAP_API_KEY": "xxxxxx" } } } } - 然后把刚才百度地图应用的AK密钥填在上面 BAIDU_MAP_API_KEY 中即可
- 此时便能看到 baidu-map,点击Done保存

- 允许Cline使用MCP,自己看情况选择性勾选


- 此时我们提问:从北京西站到故宫开车需要多久。过程中需要我们批准他使用百度地图的MCPServer。

langchain4j接入MCPSercer
- langchain4j 没有提供mcp server的实现, 但是提供的mcp client的实现
- 我们基于上面的代码
- pom.xml
<!--mcp--> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-mcp</artifactId> <version>1.0.0-beta3</version> </dependency> - java
package com.qi2; import dev.langchain4j.community.model.dashscope.QwenChatModel; 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.ChatLanguageModel; import dev.langchain4j.service.AiServices; import dev.langchain4j.service.tool.ToolProvider; import java.util.List; import java.util.Map; public class Main { interface Bot { String chat(String userMessage); } public static void main(String[] args) throws Exception { // 1.构建模型 ChatLanguageModel model = QwenChatModel .builder() .apiKey("sk-xxxxxx") .modelName("qwen-max") .build(); // 2.构建MCP服务传输方式 有sse和stdio两种, 这里演示的是stdio McpTransport transport = new StdioMcpTransport.Builder() .command(List.of("cmd", "/c", "npx", "-y", "@baidumap/mcp-server-baidu-map", "mcp/github")) .environment(Map.of("BAIDU_MAP_API_KEY", "xxxxxx")) .logEvents(true) .build(); // 3.构建MCP客户端, 指定传输方式 McpClient mcpClient = new DefaultMcpClient.Builder() .transport(transport) .build(); // 4.构建MCP工具提供者, 指定MCP客户端 ToolProvider toolProvider = McpToolProvider.builder() .mcpClients(List.of(mcpClient)) //这里可以绑定多个MCPServer .build(); // 5.构建服务代理, 指定模型和工具提供者 Bot bot = AiServices.builder(Bot.class) .chatLanguageModel(model) .toolProvider(toolProvider) .build(); try { // 对话请求 String response = bot.chat("规划北京西到天安门的骑行路线"); System.out.println("RESPONSE: " + response); } finally { mcpClient.close(); } } } - 控制台

- 参考bilibili学习视频
更多推荐


所有评论(0)