路过留过 2025-04-24 10:40 采纳率: 0%
浏览 357
已结题

springAI,vllm,调用mcp

我使用springAI,调用vllm,让大模型调用mcp工具,一直报400错误,以下是我编写的代码
我添加了依赖:


<dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
            <version>1.0.0-M7</version>
        </dependency>
<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>1.0.0-M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

定义了chatClient:

@Bean
    ChatClient chatClient(ChatModel chatModel, List<McpSyncClient> mcpClients) {
        var toolCallbackProvider = new SyncMcpToolCallbackProvider(mcpClients);
        OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .model("/home/ai/models/Qwen/Qwen2.5-VL-7B-Instruct-AWQ")
                    .temperature(0.7)
                    .maxTokens(500)
                    .build();

        return ChatClient
                .builder(chatModel)
                .defaultSystem("你是一个专业的金融领域教授")
                .defaultTools(toolCallbackProvider.getToolCallbacks())
                .defaultOptions(options)
                .build();
    }

然后我定义了controller用于接口暴露

public McpController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @RequestMapping(value = "/generate_stream", method = RequestMethod.GET)
    public Flux<ServerSentEvent<Object>> generateStream(HttpServletResponse response,
                                                        @RequestParam("id") String id,
                                                        @RequestParam("prompt") String prompt) {
        response.setCharacterEncoding("UTF-8");
        var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, id, 10);
        return this.chatClient
                .prompt(prompt)
                .advisors(messageChatMemoryAdvisor)
                .stream()
                .chatResponse()
                .map(data->{
                    String text=data.getResult().getOutput().getText();
                    return ServerSentEvent.builder()
                            .data(text)
                            .build();
                }).doOnError(error->{
                    System.out.println(error);
                });
    }

然后是application.yml文件配置了mcp工具调用:

spring:
  ai:
    openai:
      base-url: http://192.168.8.4:8002  # vLLM ip
      api-key: sk-no-key-required
    mcp:
      client:
        type: SYNC
        enabled: true
        name: call-mcp-server
        request-timeout: 30s
        stdio:
          servers-configuration: classpath:mcp-server.json

接着是mcp-server.json文件,调用的高德mcp

{
    "mcpServers": {
        "amap-maps": {
            "command": "cmd",
            "args": ["/c","npx","-y",
            "@amap/amap-maps-mcp-server"],
            "env": {
                "AMAP_MAPS_API_KEY": "e0a48e0ccdf0a45d3e4019809eb79633"
            }
        }
    }
}

这一套结束之后,我调用接口localhost:8080/generate_stream?id=2&prompt=@agen 规划去西安游玩路线,vllm就会直接报400错误,但是我不加defaultTools调用大模型没有问题,或者我用通义千问也可以回调mcp,就是用我自己的模型不行,有遇见相似问题的吗,共同探讨的吗

  • 写回答

4条回答 默认 最新

  • 紫雾凌寒 新星创作者: 人工智能技术领域 2025-04-24 10:59
    关注

    让 “紫雾凌寒” 来帮你回答,本回答结合 DeepSeek

    如果还有问题,请评论或点击头像私信,如果有帮助到您, 请关注、采纳、点赞

    1. 关键点分析
      - 目前已知使用Spring AI调用VLLM时出现400错误,但提供的代码片段不完整,无法全面了解具体的调用逻辑和参数设置等情况。不过从报错400来看,很可能是请求参数格式不正确、参数缺失或者参数值不符合接收方的要求等原因导致。
    2. 解决方案
      - 首先,确保你的Spring AI配置和VLLM集成正确。假设你有一个简单的调用示例代码如下(这里只是示例框架,实际需根据你的业务逻辑和VLLM接口完善):
      ```java
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.RequestBody;
      import org.springframework.web.bind.annotation.RestController;

    import com.theokanning.openai.completion.CompletionRequest;
    import com.theokanning.openai.service.OpenAiService;

    @RestController
    public class VllmController {

       @Autowired
       private OpenAiService openAiService;
    
       @PostMapping("/vllm")
       public String callVllm(@RequestBody String input) {
           CompletionRequest completionRequest = CompletionRequest.builder()
                  .prompt(input)
                  .maxTokens(100)
                  .build();
           try {
               var completions = openAiService.createCompletion(completionRequest);
               return completions.getChoices().get(0).getText();
           } catch (Exception e) {
               e.printStackTrace();
               return "Error calling VLLM: " + e.getMessage();
           }
       }
    

    }
    - 关于调用MCP工具部分,你需要明确MCP工具接收的请求格式和参数要求。如果MCP工具通过HTTP接口接收请求,你可能需要按照以下方式构建请求:java
    import org.springframework.http.HttpEntity;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.MediaType;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;

    @RestController
    public class McpController {

       @GetMapping("/mcp")
       public String callMcp(@RequestParam String input) {
           RestTemplate restTemplate = new RestTemplate();
           HttpHeaders headers = new HttpHeaders();
           headers.setContentType(MediaType.APPLICATION_JSON);
           String requestBody = "{\"input\":\"" + input + "\"}";//假设MCP工具接收JSON格式请求这里根据实际情况调整
           HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
           ResponseEntity<String> response = restTemplate.postForEntity("MCP_TOOL_URL", entity, String.class);
           return response.getBody();
       }
    

    }
    - 然后在你的业务逻辑中,将VLLM的输出作为输入传递给MCP工具的调用接口:java
    @PostMapping(“/vllmAndMcp”)
    public String callVllmAndMcp(@RequestBody String input) {
    String vllmOutput = callVllm(input);
    if (!vllmOutput.startsWith(“Error”)) {
    return callMcp(vllmOutput);
    } else {
    return vllmOutput;
    }
    }
    `` 3. **多种解决方案的优缺点**: - **优点**: - **代码分层清晰**:上述代码示例将VLLM调用、MCP工具调用以及业务逻辑处理分别封装在不同的方法中,便于维护和扩展。例如,如果VLLM的调用逻辑发生变化,只需要修改callVllm方法,不会影响到其他部分的代码。 - **便于调试**:每个方法都有明确的功能,当出现问题时,可以方便地在每个方法内部进行调试,查看具体的参数传递和调用结果。比如在callVllm方法中打印completionRequest的内容,以检查请求参数是否正确。 - **缺点**: - **依赖外部服务**:过度依赖VLLM和MCP工具的接口稳定性。如果这些外部服务出现故障或者接口发生变化,可能需要对代码进行较大的修改。例如,MCP工具的请求格式改变,就需要同时修改callMcp`方法中的请求构建部分。
    - 性能开销:每次调用VLLM和MCP工具都需要进行网络请求,可能会带来一定的性能开销。特别是在高并发场景下,频繁的网络调用可能会影响系统的整体性能。
    4. 总结
    - 解决这个问题的关键在于仔细检查请求参数的格式和内容是否符合VLLM和MCP工具的要求。通过完善代码逻辑,逐步排查问题所在,比如在调用VLLM时确保输入参数正确,获取到正确的输出后再以合适的格式传递给MCP工具。同时,要注意外部服务的稳定性和接口变化,及时调整代码以适应这些情况。

    请注意,以上代码是基于常见的Spring和HTTP调用场景的示例,实际应用中需要根据VLLM和MCP工具的具体文档和接口进行详细调整。

    希望以上解答对您有所帮助。如果您有任何疑问,欢迎在评论区提出。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 4月24日
  • 修改了问题 4月24日
  • 创建了问题 4月24日