Простой клиент MCP, который добавляет, используя ошибку POJO, вызывая ошибку JSON Parse, вызывая инструментJAVA

Программисты JAVA общаются здесь
Anonymous
Простой клиент MCP, который добавляет, используя ошибку POJO, вызывая ошибку JSON Parse, вызывая инструмент

Сообщение Anonymous »

Я изучаю MCP (протокол контекста модели), используя Spring AI, используя модель Ollama llama3.2 , работающая в контейнере Docker, подвергнутую HTTP: // localhost: 11434.
использует транспорт stdio, способный выполнять большинство операций, за исключением того, что сведения о том, что в нем подробно используются Server. Список для сотрудников, клиент MCP использует Spring-Boot-Web-Starter, чтобы получить ввод через корпус запроса, передавая вход, используя команду Curl.
import com.demo.mcp.server.data.Employee;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class EmployeeService {

private static final Logger logger = LoggerFactory.getLogger(EmployeeService.class);

private List employees = new ArrayList();

@Tool(name="t_list_all_employees", description = "This tool will use the list of employees that is managed in the in memory list within the application")
public List getEmployees() {
logger.info("getEmployees() invoked");
return employees;
}

@Tool(name="t_add_one_employee", description = "Add an employee to the employee list,"+
"before invoking this tool create the employee string with json template in following format" +
"{ \"name\": \"SET-WITH-USER-INPUT\", \"email\": \"SET-WITH-USER-INPUT\", \"phone\": \"SET-WITH-USER-INPUT\"}\"" +
" with this this method can add the employee to in memory list. For example, if the context include " +
"add an employee to the list where the employee name is joe I, email is joe@email.com and phone is 11231" +
"The employee name should be provided")
public Employee addEmployee(Employee employee) {
logger.info("Adding employee: {}", employee);
if(employee != null && employee.name() != null && !employee.name().isEmpty()) {
logger.info("Employee name is valid: {}", employee.name());
} else {
logger.warn("Invalid employee name provided: {}", employee);
throw new IllegalArgumentException("Employee name cannot be null or empty");
}
employees.add(employee);
return employee;
}

@Tool(name="t_fetch_employee_with_name", description = "This tool is used to get one employee based on user provided employee name from the in memory list in this app")
public Employee getEmployee(String name) {
logger.info("Getting employee by name: {}", name);
if (name == null || name.isEmpty()) {
logger.warn("Invalid employee name provided: {}", name);
throw new IllegalArgumentException("Employee name cannot be null or empty");
}
return employees.stream()
.filter(employee -> employee.name().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
}

@Tool(name="t_delete_employee", description = "This tool will delete the employee matching the user provided name from the in memory list in this app")
public void deleteEmployee(String name) {
if (name == null || name.isEmpty()) {
logger.warn("Invalid employee name provided for deletion: {}", name);
throw new IllegalArgumentException("Employee name cannot be null or empty");
}
logger.info("Deleting employee by name: {}", name);
employees.removeIf(employee -> employee.name().equalsIgnoreCase(name));
}

@PostConstruct
public void init() {
employees.addAll(List.of(
new Employee("Joy one","joy_one@email.com","1234567890"),
new Employee("Joy two","joe_two@email.com","0987654321"),
new Employee("Joy three","joy_three@email.com","1122334455"),
new Employee("Joy four","joy_four@email.com","5566778899"),
new Employee("Joy five","joy_five@email.com","9988776655")
));
}

}
< /code>
Pojo < /p>
public record Employee(String name, String email, String phone){}
< /code>
Основной контроллер клиента выглядит ниже < /p>
import io.modelcontextprotocol.client.McpSyncClient;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.definition.ToolDefinition;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequestMapping("/input")
@RestController
public class InputController {

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(InputController.class);

private final ChatClient chatClient;
List mcpSyncClients;

public InputController(ChatClient.Builder chatClientBuilder,
ToolCallbackProvider toolCallbackProvider,
List mcpSyncClients) {
this.chatClient = chatClientBuilder.build();
this.mcpSyncClients = mcpSyncClients;
List toolCallbacks = List.of(toolCallbackProvider.getToolCallbacks());
if (toolCallbacks.isEmpty()) {
System.out.println("No tools identified.");
} else {
for (ToolCallback toolCallback : toolCallbacks) {
ToolDefinition toolDefinition = toolCallback.getToolDefinition();
System.out.println("Tool Name: " + toolDefinition.name()+ "\nDescription: " + toolDefinition.description()+"\nSchema: " + toolDefinition.inputSchema()+"\n--------------------");
}
}
}
@PostMapping("/in")
public String input(@RequestBody String input) {
log.info("Input received: {}", input);
return chatClient.prompt()
.user(input)
.toolCallbacks(new SyncMcpToolCallbackProvider(mcpSyncClients))
.call()
.content();
}
}
< /code>

С запуском приложения может увидеть ниже ответ < /li>
< /ul>
$ curl -XPOST http://localhost:8080/input/in -d "can you get all the employees list from the server"
The list of all employees on the server is as follows:

1. Joy one - joy_one@email.com - 1234567890
2. Joy two - joe_two@email.com - 0987654321
3. Joy three - joy_three@email.com - 1122334455
4. Joy four - joy_four@email.com - 5566778899
5. Joy five - joy_five@email.com - 9988776655
< /code>
Когда я пытаюсь добавить нового сотрудника, увидите сообщение об ошибке. Очевидно, что LLM отправляет текст JSON и что текст не преобразуется в JSON.[client] [pool-2-thread-1] io.modelcontextprotocol.spec.McpSchema : Received JSON message: {"jsonrpc":"2.0","id":"31ade185-6","result":{"content":[{"type":"text","text":"Conversion from JSON to com.demo.mcp.server.data.Employee failed"}],"isError":true}}
[client] [pool-2-thread-1] i.m.spec.McpClientSession : Received Response: JSONRPCResponse[jsonrpc=2.0, id=31ade185-6, result={content=[{type=text, text=Conversion from JSON to com.demo.mcp.server.data.Employee failed}], isError=true}, error=null]
ERROR 1120 --- [client] [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.IllegalStateException: Error calling tool: [TextContent[audience=null, priority=null, text=Conversion from JSON to com.demo.mcp.server.data.Employee failed]]] with root cause

java.lang.IllegalStateException: Error calling tool: [TextContent[audience=null, priority=null, text=Conversion from JSON to com.demo.mcp.server.data.Employee failed]]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:118) ~[spring-ai-mcp-1.0.0.jar:1.0.0]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:126) ~[spring-ai-mcp-1.0.0.jar:1.0.0]
at org.springframework.ai.model.tool.DefaultToolCallingManager.lambda$executeToolCall$5(DefaultToolCallingManager.java:224) ~[spring-ai-model-1.0.0.jar:1.0.0]
at io.micrometer.observation.Observation.observe(Observation.java:564) ~[micrometer-observation-1.15.1.jar:1.15.1]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCall(DefaultToolCallingManager.java:221) ~[spring-ai-model-1.0.0.jar:1.0.0]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCalls(DefaultToolCallingManager.java:137) ~[spring-ai-model-1.0.0.jar:1.0.0]
at org.springframework.ai.ollama.OllamaChatModel.internalCall(OllamaChatModel.java:266) ~[spring-ai-ollama-1.0.0.jar:1.0.0]
at org.springframework.ai.ollama.OllamaChatModel.call(OllamaChatModel.java:219) ~[spring-ai-ollama-1.0.0.jar:1.0.0]
at org.springframework.ai.chat.client.advisor.ChatModelCallAdvisor.adviseCall(ChatModelCallAdvisor.java:54) ~[spring-ai-client-chat-1.0.0.jar:1.0.0]
at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.lambda$nextCall$1(DefaultAroundAdvisorChain.java:110) ~[spring-ai-client-chat-1.0.0.jar:1.0.0]
at io.micrometer.observation.Observation.observe(Observation.java:564) ~[micrometer-observation-1.15.1.jar:1.15.1]
at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.nextCall(DefaultAroundAdvisorChain.java:110) ~[spring-ai-client-chat-1.0.0.jar:1.0.0]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.lambda$doGetObservableChatClientResponse$1(DefaultChatClient.java:469) ~[spring-ai-client-chat-1.0.0.jar:1.0.0]
at io.micrometer.observation.Observation.observe(Observation.java:564) ~[micrometer-observation-1.15.1.jar:1.15.1]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doGetObservableChatClientResponse(DefaultChatClient.java:467) ~[spring-ai-client-chat-1.0.0.jar:1.0.0]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doGetObservableChatClientResponse(DefaultChatClient.java:446) ~[spring-ai-client-chat-1.0.0.jar:1.0.0]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.content(DefaultChatClient.java:441) ~[spring-ai-client-chat-1.0.0.jar:1.0.0]
at com.demo.mcp.client.controller.InputController.input(InputController.java:95) ~[classes/:na]
...

< /code>
Вопрос:-< /p>

Есть ли возможность перехватить ответ из LLM, прежде чем вывести службу инструментов на сервере? Имя сотрудника, электронная почта и телефон в аргументе в этом случае пользователь добавляется.


Подробнее здесь: https://stackoverflow.com/questions/796 ... ror-invoki

Вернуться в «JAVA»