Skip to content

当需要调用MCP Server的多个tool时,MCP Client在调用第二个tool时出现反序列化错误(When multiple tools of the MCP Server need to be called, the MCP Client encounters a deserialization error when calling the second tool.) #2818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
LeanderCherry opened this issue Apr 21, 2025 · 6 comments

Comments

@LeanderCherry
Copy link

Bug description
英语不好中文描述了哈
我实现了一个通过百度进行天气查询的MCP Server,实现了两个Tool:String getDistrictId(String district)和String getWeatherForecastDistrictId(String districtId),在使用Spring AI的MCP Client进行查询”济南今天的天气“时,报如下错误,从基本的分析情况看时在调用getWeatherForecastDistrictId这个tool时出现的了错误,初步排查时第一次调用getDistrictId返回的response里text已经是String了,然后调用大模型获取下次需要调用的tool时给出的toolInputArguments应该时一个可以反序列化为Map的String,但实际给出的是'{"districtId": "370100"}',因此再次反序列化出现错误
2025-04-19T15:07:06.172+08:00 DEBUG 4904 --- [mcp] [nio-8089-exec-1] o.s.a.m.tool.DefaultToolCallingManager : Executing tool call: spring_ai_mcp_client_server1_getWeatherForecastDistrictId
2025-04-19T15:07:06.193+08:00 DEBUG 4904 --- [mcp] [nio-8089-exec-1] o.s.web.servlet.DispatcherServlet : Failed to complete request: java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of java.util.HashMap (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"districtId": "370100"}')
at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION disabled); line: 1, column: 1]
2025-04-19T15:07:06.195+08:00 ERROR 4904 --- [mcp] [nio-8089-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of java.util.HashMap (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"districtId": "370100"}')
at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION disabled); line: 1, column: 1]] with root cause

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of java.util.HashMap (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"districtId": "370100"}')
at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION disabled); line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1754) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1379) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromString(StdDeserializer.java:311) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:454) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:32) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4905) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3848) ~[jackson-databind-2.17.3.jar:2.17.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3831) ~[jackson-databind-2.17.3.jar:2.17.3]
at org.springframework.ai.model.ModelOptionsUtils.jsonToMap(ModelOptionsUtils.java:91) ~[spring-ai-model-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:112) ~[spring-ai-mcp-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:125) ~[spring-ai-mcp-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCall(DefaultToolCallingManager.java:227) ~[spring-ai-model-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCalls(DefaultToolCallingManager.java:139) ~[spring-ai-model-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.openai.OpenAiChatModel.internalCall(OpenAiChatModel.java:242) ~[spring-ai-openai-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.openai.OpenAiChatModel.internalCall(OpenAiChatModel.java:252) ~[spring-ai-openai-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.openai.OpenAiChatModel.call(OpenAiChatModel.java:180) ~[spring-ai-openai-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultChatClientRequestSpec$1.aroundCall(DefaultChatClient.java:680) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.lambda$nextAroundCall$1(DefaultAroundAdvisorChain.java:98) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
at io.micrometer.observation.Observation.observe(Observation.java:565) ~[micrometer-observation-1.13.8.jar:1.13.8]
at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.nextAroundCall(DefaultAroundAdvisorChain.java:98) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doGetChatResponse(DefaultChatClient.java:493) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.lambda$doGetObservableChatResponse$1(DefaultChatClient.java:482) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
at io.micrometer.observation.Observation.observe(Observation.java:565) ~[micrometer-observation-1.13.8.jar:1.13.8]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doGetObservableChatResponse(DefaultChatClient.java:482) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doGetChatResponse(DefaultChatClient.java:466) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.content(DefaultChatClient.java:516) ~[spring-ai-client-chat-1.0.0-M7.jar:1.0.0-M7]
at com.junxi.demo.ai.mcp.client.ctrl.WeatherWithMPCController.chat(WeatherWithMPCController.java:37) ~[classes/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) ~[spring-web-6.1.15.jar:6.1.15]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) ~[spring-web-6.1.15.jar:6.1.15]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.1.15.jar:6.1.15]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926) ~[spring-webmvc-6.1.15.jar:6.1.15]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831) ~[spring-webmvc-6.1.15.jar:6.1.15]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.1.15.jar:6.1.15]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.1.15.jar:6.1.15]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.15.jar:6.1.15]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.15.jar:6.1.15]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.1.15.jar:6.1.15]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.33.jar:6.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.15.jar:6.1.15]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.33.jar:6.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.33.jar:10.1.33]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.15.jar:6.1.15]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.15.jar:6.1.15]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.15.jar:6.1.15]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.15.jar:6.1.15]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:113) ~[spring-web-6.1.15.jar:6.1.15]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.15.jar:6.1.15]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.15.jar:6.1.15]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.15.jar:6.1.15]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.33.jar:10.1.33]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]

Environment
Please provide as many details as possible: Spring AI version, Java version, which vector store you use if any, etc
Spring AI version:1.0.0-M7
java version:21.0.2

Steps to reproduce
Steps to reproduce the issue.
Image
MCP Server实现见如上;MCP Client的核心实现如如下:

        this.chatClient  = chatClientBuilder
                .defaultSystem("你是一个专业的智能助手,回答需简洁准确")
                .defaultOptions(OpenAiChatOptions.builder()
                        .model("Qwen/QwQ-32B")
                        .build())
                .defaultTools(tools)
                .build();

Expected behavior
A clear and concise description of what you expected to happen.
根据实现预期应该是跟调用getDistrictId获取到济南的城市ID,然后调用getWeatherForecastDistrictId根据城市ID获取到济南当地的天气情况,实际在调用getWeatherForecastDistrictId时出现了上述的错误。

Minimal Complete Reproducible example
MCP Server的实现如下:

public class BaiDuWeatherService {
    // 百度免费天气API基础URL
    private static final String BASE_URL = "https://api.map.baidu.com";

    private final RestClient restClient;

    public BaiDuWeatherService() {
        this.restClient = RestClient.builder()
                .baseUrl(BASE_URL)
                .defaultHeader("Accept", "application/json")
                .build();
    }

    @Tool(description = "根据城市名称获取城市ID")
    public String getDistrictId(@ToolParam(description = "城市名称") String district) {
        return new BaiDuTools().getDistrictId(district);
    }

    @Tool(description = "根据城市ID获取天气")
    public String getWeatherForecastDistrictId(@ToolParam(description = "城市Id") String districtId) {
        String res = restClient.get()
                .uri(new BaiDuTools().getSn(districtId))
                .retrieve()
                .body(String.class);
        System.out.println(res);
        return res;
    }

    public static void main(String[] args) {
        BaiDuWeatherService service = new BaiDuWeatherService();
//        System.out.println(service.getWeatherForecastDistrictId(service.getDistrictId("北京")));
    }
}

BaiDuTools实现:

public class BaiDuTools {
    private static final String sk = "百度的SK"; //需替换为正式的
    private static final String ak = "百度的ak"; //需替换为正式的

    private static final Map<String, String> districts = new HashMap<>(4600); //总共3395个区县

    static {
        String csvFilePath = "F:\\Downloads\\weather_district_id.csv";
        String districtHeader = "district";
        String districtIdHeader = "district_id";

        try (BufferedReader reader = new BufferedReader(new FileReader(csvFilePath));
             CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withFirstRecordAsHeader())
             /*csvParser = new CSVParser(reader, CSVFormat.DEFAULT.builder().setHeader(districtIdHeader, districtHeader).setSkipHeaderRecord(true).build())*/) {

            CSVFormat.DEFAULT.builder().setSkipHeaderRecord(true);
            for (CSVRecord csvRecord : csvParser) {
                String district = csvRecord.get(districtHeader);
                String districtId = csvRecord.get(districtIdHeader);
                districts.put(district, districtId);
            }

            // 打印HashMap中的内容(可根据需要删除)
            for (Map.Entry<String, String> entry : districts.entrySet()) {
                System.out.println("District: " + entry.getKey() + ", District ID: " + entry.getValue());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public String getSn(String districtId) {
        Map<String, String> paramsMap = new LinkedHashMap<>();
        paramsMap.put("district_id", districtId);
        paramsMap.put("data_type", "all");
        paramsMap.put("ak", ak);

        // 调用下面的toQueryString方法,对LinkedHashMap内所有value作utf8编码,拼接返回结果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourak
        String paramsStr = toQueryString(paramsMap);

        // 对paramsStr前面拼接上/geocoder/v2/?,后面直接拼接yoursk得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyoursk
//        String wholeStr = "/geocoder/v2/?" + paramsStr + sk;
        String wholeStr = "/weather/v1/?" + paramsStr + sk;

        // 对上面wholeStr再作utf8编码
        String tempStr = URLEncoder.encode(wholeStr, StandardCharsets.UTF_8);
        System.out.println("sn is " + MD5(tempStr));
        // 调用下面的MD5方法得到最后的sn签名7de5a22212ffaa9e326444c75a58f9a0
        return "/weather/v1/?" + paramsStr + "&sn=" + MD5(tempStr);
    }

    public String getDistrictId(String district) {
        return districts.get(district);
    }

    // 对Map内所有value作utf8编码,拼接返回结果
    private String toQueryString(Map<?, ?> data) {
        StringBuilder queryString = new StringBuilder();
        for (Entry<?, ?> pair : data.entrySet()) {
            queryString.append(pair.getKey()).append("=");
            queryString.append(URLEncoder.encode((String) pair.getValue(),
                    StandardCharsets.UTF_8)).append("&");
        }
        if (!queryString.isEmpty()) {
            queryString.deleteCharAt(queryString.length() - 1);
        }
        return queryString.toString();
    }

    // 来自stackoverflow的MD5计算方法,调用了MessageDigest库函数,并把byte数组结果转换成16进制
    private String MD5(String md5) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest
                    .getInstance("MD5");
            byte[] array = md.digest(md5.getBytes());
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < array.length; ++i) {
                sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100), 1, 3);
            }
            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
        }
        return null;
    }
}

@LeanderCherry
Copy link
Author

To add:
There is no problem with verifying this MCP Server using Cherry Studio. See the figure below.
Image

@LeanderCherry LeanderCherry changed the title MCP Client中toolCall多进行了一次序列化 当需要调用MCP Server的多个tool时,MCP Client Apr 21, 2025
@LeanderCherry LeanderCherry changed the title 当需要调用MCP Server的多个tool时,MCP Client 当需要调用MCP Server的多个tool时,MCP Client在调用第二个tool时出现反序列化错误(When multiple tools of the MCP Server need to be called, the MCP Client encounters a deserialization error when calling the second tool.) Apr 21, 2025
@yangtuooc
Copy link
Contributor

  1. 工具调用的返回结果必须是一个JSON字符串
  2. 默认情况下会使用Jackson进行序列化

因此,在这段代码中你可以直接返回一个类对象或者Map对象

 @Tool(description = "根据城市ID获取天气")
    public Map<String,Object> getWeatherForecastDistrictId(@ToolParam(description = "城市Id") String districtId) {
        return restClient.get()
                .uri(new BaiDuTools().getSn(districtId))
                .retrieve()
                .body(Map.class);
    }

另外,你可以参考官方的文档,有明确的关于工具调用结果转换的说明:https://docs.spring.io/spring-ai/reference/api/tools.html#_result_conversion

@LeanderCherry
Copy link
Author

多谢答复。
但是同样的Server在Cherry Studio和Cline里使用都是正常的,我还是认为这是Spring AI的一个Bug

@yangtuooc
Copy link
Contributor

多谢答复。 但是同样的Server在Cherry Studio和Cline里使用都是正常的,我还是认为这是Spring AI的一个Bug

这是不同框架在设计层面上约束的差异,不算严格意义上的Bug

@LeanderCherry
Copy link
Author

不对呢,我看你发的文档里面的例子也是直接返回的String呢(如下图),为什么我第一个返回的是String就不行呢,而且实际上从功能实现角度讲返回String是最合理的(通过城市名称获取城市ID,城市ID实际就是一个String最合理)
Image

@LeanderCherry
Copy link
Author

多谢答复。 但是同样的Server在Cherry Studio和Cline里使用都是正常的,我还是认为这是Spring AI的一个Bug

这是不同框架在设计层面上约束的差异,不算严格意义上的Bug

忘记引用你的回复了,不好意思。
我看你发的文档里面的例子也是直接返回的String呢(如下图),为什么我第一个tool返回的是String就不行呢,而且实际上从功能实现角度讲返回String是最合理的(通过城市名称获取城市ID,城市ID实际是一个String)

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants