spring-projects / spring-ai

An Application Framework for AI Engineering
https://docs.spring.io/spring-ai/reference/index.html
Apache License 2.0
3.26k stars 837 forks source link

Jackson Parse Error for OpenAI API ChatCompletion#usage #1369

Open the-mgi opened 1 month ago

the-mgi commented 1 month ago

Unreconized field "completion_tokens_details" coming in response from openai api. the error is occuring at class org.springframework.ai.openai.api.OpenAiApi.ChatCompletion#usage and in Usage we have no Usage#completion_tokens_details

Bug description there's not @JsonIgnoreProperties(ignoreUnkown=true)

Environment macOS spring framework ai version 1.0.0-M2

Steps to reproduce Call OpenAiChatModel#call

Expected behavior it should not throw an error if there's an unmapped field

Minimal Complete Reproducible example

PromptTemplate template = new PromptTemplate(promptString);
                template.add("desc", product.getMetaDescription());
                template.add("name", product.getProductName());
                String desc = this.aiChatModel.call(template.create()).getResult().getOutput().getContent();
                a.setDesc(desc);

encountered a similar bug a while back which was resolved here https://github.com/spring-projects/spring-ai/issues/1178

stack trace com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "completion_tokens_details" (class org.springframework.ai.openai.api.OpenAiApi$Usage), not marked as ignorable (3 known properties: "completion_tokens", "prompt_tokens", "total_tokens"]) at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION disabled); line: 22, column: 35] (through reference chain: org.springframework.ai.openai.api.OpenAiApi$ChatCompletion["usage"]->org.springframework.ai.openai.api.OpenAiApi$Usage["completion_tokens_details"]) at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61) at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:1153) at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:2241) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1793) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1771) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:279) at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:470) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1493) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:348) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:545) at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:576) at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:446) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1493) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:348) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342) at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2125) at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1501) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:395) ... 18 common frames omitted

kashyappvb commented 1 month ago

Even we are facing exact same issue tried using 1.0.0-M2, 1.0.0-SNAPSHOT version for below

org.springframework.ai:spring-ai-bom

org.springframework.ai:spring-ai-openai-spring-boot-starter

Code : ChatResponse chatResponse = chatClient.prompt().user(payload).call().chatResponse();

Temporary solution worked for us:

@Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return mapper; }

dafriz commented 1 month ago

An alternative to the above work around - If you are using Spring Boot and want to keep using the existing auto configured ObjectMapper, but change this one property you can use:

@Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        return builder -> builder.failOnUnknownProperties(false);
}

completion_tokens_details - it's a new field added by OpenAI with the release of the o1 models with a nested reasoning_tokens field.

markpollack commented 6 days ago

We recently updated how object mapper is configured in Spring AI to better support Kotlin. Will revist for M4. Thanks for reporting.