spring-projects / spring-projects/spring-ai
Issue while using native structured output with tools
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.5k
- Forks
- 2.9k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 6
Description
I have tried using native structured output for all my examples of this project. It works well except for tools and MCP examples.
You can find on tools-with-native-structured-output branch the issue encountered for tools and MCP examples while on the main branch these examples work as expected without using AdvisorParams.ENABLE_NATIVE_STRUCTURED_OUTPUT advisor specification.
Here is the exception raised on tools-with-native-structured-output branch for tools example with Ollama profile:
tools.jackson.core.exc.StreamReadException: Unrecognized token 'The': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); byte offset: #UNKNOWN]
at tools.jackson.core.JsonParser._constructReadException(JsonParser.java:1856) ~[jackson-core-3.1.2.jar:3.1.2]
at tools.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:3130) ~[jackson-core-3.1.2.jar:3.1.2]
at tools.jackson.core.json.ReaderBasedJsonParser._handleOddValue(ReaderBasedJsonParser.java:2075) ~[jackson-core-3.1.2.jar:3.1.2]
at tools.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:809) ~[jackson-core-3.1.2.jar:3.1.2]
at tools.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:2734) ~[jackson-databind-3.1.2.jar:3.1.2]
at tools.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2629) ~[jackson-databind-3.1.2.jar:3.1.2]
at tools.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1586) ~[jackson-databind-3.1.2.jar:3.1.2]
at org.springframework.ai.converter.BeanOutputConverter.convert(BeanOutputConverter.java:194) ~[spring-ai-model-2.0.0-RC1.jar:2.0.0-RC1]
at org.springframework.ai.converter.BeanOutputConverter.convert(BeanOutputConverter.java:51) ~[spring-ai-model-2.0.0-RC1.jar:2.0.0-RC1]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doSingleWithBeanOutputConverter(DefaultChatClient.java:618) ~[spring-ai-client-chat-2.0.0-RC1.jar:2.0.0-RC1]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doSingleWithBeanOutputConverter(DefaultChatClient.java:591) ~[spring-ai-client-chat-2.0.0-RC1.jar:2.0.0-RC1]
at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.entity(DefaultChatClient.java:571) ~[spring-ai-client-chat-2.0.0-RC1.jar:2.0.0-RC1]
at com.github.nicolaskrier.experimental.spring.ai.tools.ToolsExample.searchPope(ToolsExample.java:96) ~[classes/:na]
at com.github.nicolaskrier.experimental.spring.ai.tools.ToolsExample.searchPope(ToolsExample.java:81) ~[classes/:na]
at com.github.nicolaskrier.experimental.spring.ai.tools.ToolsExample.lambda$applicationRunner$0(ToolsExample.java:70) ~[classes/:na]
at org.springframework.boot.SpringApplication.lambda$callRunner$0(SpringApplication.java:788) ~[spring-boot-4.1.0-RC1.jar:4.1.0-RC1]
at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:82) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:86) ~[spring-core-7.0.7.jar:7.0.7]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) ~[spring-boot-4.1.0-RC1.jar:4.1.0-RC1]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:788) ~[spring-boot-4.1.0-RC1.jar:4.1.0-RC1]
at org.springframework.boot.SpringApplication.lambda$callRunners$0(SpringApplication.java:776) ~[spring-boot-4.1.0-RC1.jar:4.1.0-RC1]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:186) ~[na:na]
at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:571) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:560) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:153) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:176) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:632) ~[na:na]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:776) ~[spring-boot-4.1.0-RC1.jar:4.1.0-RC1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:328) ~[spring-boot-4.1.0-RC1.jar:4.1.0-RC1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1365) ~[spring-boot-4.1.0-RC1.jar:4.1.0-RC1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-4.1.0-RC1.jar:4.1.0-RC1]
at com.github.nicolaskrier.experimental.spring.ai.tools.ToolsExample.main(ToolsExample.java:108) ~[classes/:na]
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the failure from the tools-with-native-structured-output branch, starting with ToolsExample.java around searchPope and the Ollama profile. Read the BeanOutputConverter stack-trace path and compare the tools and MCP examples with main; done means native structured output works for both without the JSON parsing exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring, spring-boot
- Domain
- ai, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100