Простой клиент 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 [email protected] 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","[email protected]","1234567890"),
new Employee("Joy two","[email protected]","0987654321"),
new Employee("Joy three","[email protected]","1122334455"),
new Employee("Joy four","[email protected]","5566778899"),
new Employee("Joy five","[email protected]","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 - [email protected] - 1234567890
2. Joy two - [email protected] - 0987654321
3. Joy three - [email protected] - 1122334455
4. Joy four - [email protected] - 5566778899
5. Joy five - [email protected] - 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
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

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