spring-projects / spring-projects/spring-ai

Issue while using native structured output with tools

Open
#6,327 12 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: feedback-provided structured output tool calling
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.