1.框架介绍

        无耳 Solon(OpenSolon) | 官网 (Spring 替换方案)

        Ollama

2. Solon ai

    官网文档:无耳 Solon(OpenSolon) | Solon AI 开发

    mcp文档:无耳 Solon(OpenSolon) | mcp - 发布 Tool 服务,使用 Tool 服务

 3.代码参考

        pom配置:

<dependencies>
        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-boot-undertow</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-logging-logback</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.31</version>
        </dependency>

        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-ai</artifactId>
        </dependency>

        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-ai-mcp</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.modelcontextprotocol.sdk</groupId>
                    <artifactId>mcp</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.noear.mcp.sdk</groupId>
            <artifactId>mcp</artifactId>
            <version>0.9.0-M1</version>
        </dependency>

    </dependencies>

       mcp server1:

package com.wht.mcp.server;

import org.noear.solon.ai.chat.annotation.ToolMapping;
import org.noear.solon.ai.chat.annotation.ToolParam;
import org.noear.solon.annotation.Component;

@Component
public class McpServerTool {
    //
    // 建议开启编译参数:-parameters (否则,要再配置参数的 name)
    //
    @ToolMapping(description = "查询天气预报")
    public String getWeather(@ToolParam(description = "城市位置") String location) {
        System.err.println("location:" + location);
        return location + "晴,30度";
    }

}

        mcp server2:

package com.wht.mcp;

import org.noear.solon.ai.chat.annotation.ToolMapping;
import org.noear.solon.ai.chat.annotation.ToolParam;
import org.noear.solon.annotation.Component;

@Component
public class McpServerTool {

    @ToolMapping(description = "查询游玩地方")
    public String getSpot(@ToolParam(description = "天气") String weather) {

        System.err.println("weather:" + weather);
        return weather.contains("雨") ? "图书馆或者海洋馆" : "动物园或者植物园";
    }

}

上述的server1和server2是两个工程提供的服务,用来演示solon-ai-mcp对接多个mcp server的情况

        mcp client:

package com.wht.mcp;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.ChatResponse;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.ai.mcp.client.McpClientWrapper;
import java.util.List;
import java.util.Scanner;

/**
 * @author by HaiTao.Wang on 2025/4/10.
 */
public class McpClient {

    @SneakyThrows
    public static void main(String[] args) {

        McpClientWrapper mcpClient1 = new McpClientWrapper("http://localhost:8080", "/mcp/sse");
        McpClientWrapper mcpClient2 = new McpClientWrapper("http://localhost:8081", "/mcp/sse");

        ChatModel chatModel = ChatModel.of("http://127.0.0.1:11434/api/chat")
                .provider("ollama")
                .model("qwen2.5:latest")
                .defaultToolsAdd(mcpClient1.toTools())
                .defaultToolsAdd(mcpClient2.toTools())
                .build();


        System.err.println("请开始向 AI 提问!");
        Scanner scanner = new Scanner(System.in);
        String userInput = scanner.nextLine();
        while (StrUtil.isNotEmpty(userInput)) {

            ChatMessage system = ChatMessage.ofSystem("您是一名精通问题总结的助手,我的问题中可能只包含一个请求,也可能包含多个问题,请帮我总结并抽取出来,保证不会丢失关键信息.");
            ChatMessage user = ChatMessage.ofUser(StrUtil.format("我现在的问题是“{}” 请仔细理解并总结,直接返回答案,不要进行其他额外的赘述。答案的模板必须遵循下面的形式:\\n\n" +
                    " 问题一###问题二###问题三\n" +
                    " 例如:我的问题是“查询凤起路地铁站附近100米范围内的管线信息,同时帮我查一下西湖区面积大于100的地下停车场信息”,经过解析结果使用模板输出:\\n\n" +
                    " 查询凤起路地铁站附近100米范围内的管线信息###查询西湖区面积大于100的地下停车场信息。\n"
                    , userInput));

            ChatResponse systemChatResponse = chatModel.prompt( CollUtil.newArrayList(user, system)).call();
            System.err.println("用户的问题:" + systemChatResponse.getMessage());

            //把对话记录到这里
            List<ChatMessage> messageList = CollUtil.newArrayList();
            CollUtil.newArrayList(systemChatResponse.getMessage().getContent().split("###"))
                    .forEach(question -> {
                        try {
                            messageList.add(ChatMessage.ofUser(question));
                            ChatResponse response = chatModel.prompt(messageList).call();
//                            System.err.println(response.getMessage());
                            messageList.add(response.getMessage());
                        }catch (Exception e){}

                    });

            System.err.println("AI的回答:" + CollUtil.getLast(messageList).getContent());

            if ("q".equals(userInput)) {
                break;
            }

            //等待用户输入
            userInput = scanner.nextLine();

        }

        System.err.println("对话结束!");
    }
}

上述代码,简单实现了多任务场景下的问答。即把用户的问题提炼出多个任务,然后分别去问答这些任务最后得出结果。

验证:

Logo

一站式 AI 云服务平台

更多推荐