Using Spring AI 1.0.0 I see some differences between how multi-turn is handled with tools vs my own agentic loop.
Steps to reproduce:
1. Clone: https://github.com/jamesward/Sample-Model-Context-Protocol-Demos
2. Switch to multi-turn-mcp-confused branch
3. In modules/spring-ai-mcp-inter-agent-ecs start the MCP server: ./mvnw -pl server spring-boot:run
4. See the multi-turn work without Spring AI: in modules/java-mcp-bedrock-agent run ./mvnw compile exec:java
5. See the multi-turn fail to get the expected output with Spring AI: in modules/spring-ai-mcp-inter-agent-ecs run ./mvnw -pl client-server spring-boot:test-run
Both use the amazon.nova-micro-v1:0 model.
In the non-Spring AI agentic loop I get the expected result:
<thinking> To find employees with skills related to Java, I will first need to determine what skills are considered "related to Java". Then, I will use the "getEmployeesWithSkill" tool to find employees with these skills. </thinking>
<thinking> Now that I have the list of all possible employee skills, I can identify which skills are related to Java. Generally, skills like "Java", "JavaScript", "Spring Boot", "Node.js", "React", "Angular", "Docker", "Kubernetes", "AWS", "Git", and "CI/CD" are related to Java. I will use the "getEmployeesWithSkill" tool to find employees with these skills. </thinking>
<thinking> I have collected all the employees who have skills related to Java. Here is the list: </thinking>
1. John Miller: Java, JavaScript
2. Elizabeth Johnson: Java, Node.js, MongoDB, JavaScript
3. Patricia Garcia: Java, REST API
4. Mary Garcia: Kubernetes, Spring Boot, Java
5. Patricia Martinez: SQL, Git, Java
6. James Garcia: AWS, Git, Java, Spring Boot
7. Patricia Davis: Java, AWS, Node.js
8. Linda Johnson: Angular, Java, MongoDB, REST API
9. Patricia Smith: Node.js, Kotlin, Angular, Java
10. Jennifer Jones: Angular, REST API, Spring Boot, Java
11. Linda Brown: DevOps, Java, REST API
These employees have skills that are directly related to Java or are commonly used together with Java in the tech industry.
In the Spring AI agentic loop sometimes I get:
<thinking>
To find employees with skills related to Java, I need to use the tool that retrieves employees with a specific skill. However, I do not have direct access to the list of skills for all employees or a way to query for "Java" related skills specifically. Therefore, I will need to ask the User for the exact skill name related to Java that I should look for.
</thinking>
What is the exact skill related to Java that you are looking for?
I was also sometimes getting:
Model produced invalid sequence as part of ToolUse.
And sometimes I would get a response that incorrectly used the tools (not calling the right ones):
Here are the employees with Java skills, with their first names abbreviated to the first letter followed by a period:
1. W. Brown
2. E. Jones
3. W. Smith
4. M. Garcia
5. M. Johnson
6. E. Garcia
7. J. Martinez
8. R. Johnson
9. E. Brown
10. W. Garcia
11. P. Williams
12. J. Rodriguez
If you need any more information or further assistance, feel free to ask!
The non-Spring AI agent works consistently using the right tools. So I'm not sure why the Spring AI one never gets it right and has so much variability in the tool use.
Comment From: tzolov
@jamesward can you please verify if this issue is still present with the latest 1.1.1-SNAPSHOT version?
When I tested it my self I get valid results like:
Here are the employees who have skills related to Java:
1. Mary Garcia: JavaScript, React, Java
2. John Miller: MongoDB, Spring Boot, Java
3. Michael Rodriguez: JavaScript, Spring Boot, Java, MongoDB
4. Michael Johnson: Java, AWS, SQL
5. Jennifer Smith: Kotlin, Java
6. John Johnson: Docker, DevOps, Java, Angular
7. John Garcia: Spring Boot, React, DevOps, Java
8. Linda Brown: Java, Spring Boot, REST API
9. Robert Williams: Machine Learning, DevOps, Java, AWS, MongoDB
10. John Brown: JavaScript, Node.js, Java
11. James Williams: Java, Node.js, Kubernetes, CI/CD
These employees have at least one skill related to Java.
But I changed the configuration like this:
@Configuration
class AgentConfiguration {
// Expose the tool that uses the chat client as an MCP server
// @Bean
// public List<McpServerFeatures.SyncToolSpecification> myToolSpecs(MyTools myTools) {
// var toolCallbacks = List
// .of(MethodToolCallbackProvider.builder().toolObjects(myTools).build().getToolCallbacks());
// return McpToolUtils.toSyncToolSpecification(toolCallbacks);
// }
// Bedrock Converse chat client with employee database MCP client
// @Bean
// ChatClient chatClient(List<McpSyncClient> mcpSyncClients, ChatClient.Builder builder) {
// return builder
// .defaultToolCallbacks(new SyncMcpToolCallbackProvider(mcpSyncClients))
// // .defaultSystem("abbreviate employee first names with first letter and a period")
// .build();
// }
@Bean
ChatClient chatClient(ChatClient.Builder builder, ToolCallbackProvider toolCallbackProvider) {
return builder
.defaultToolCallbacks(toolCallbackProvider)
.build();
}
}
Not sure if this preservers the intended behavior?
Comment From: jamesward
Thanks Christian for looking into this. Trying this out with 1.1.1-SNAPSHOT and for some reason I'm getting:
SseClientTransport : Fatal SSE error, not retrying: 200 OK from GET http://localhost:8082/sse, but response failed with cause: reactor.netty.http.client.PrematureCloseException: Connection prematurely closed DURING response
I'm going to switch this over to Streamable HTTP.
Comment From: jamesward
I ran this a number of times and everything seems to be working great now! Yay & thank you!