Enterprise Java

Using Spring AI Structured Output: List, Map, and Bean Converters

In Spring AI, structured output converters play a crucial role in handling the responses returned by AI models. Specifically, MapOutputConverter, ListOutputConverter, and BeanOutputConverter are built-in classes that help in structuring AI responses into common formats such as Map, List, and custom Java Beans. This article explores these structured output converters and explains how to use them effectively.

1. Structured Output API in Spring AI

Structured Output API in Spring AI API allows us to work with AI-generated responses by converting raw text into structured formats such as lists, maps, or Java beans. This approach simplifies the extraction of meaningful data from the model’s responses.

The core element of this API is the StructuredOutputConverter interface, which provides the foundation for mapping the text-based AI output to structured formats like Java objects or arrays.

1.1 StructuredOutputConverter Interface

The StructuredOutputConverter<T> interface enables you to transform the AI’s raw text responses into structured data, such as mapping them to a Java class or converting them into an array of values. The interface is defined as follows:

public interface StructuredOutputConverter<T> extends Converter<String, T>, FormatProvider {
}

This interface extends two key components:

  • Spring’s Converter<String, T> interface, which is responsible for converting the String output into the target type T.
  • FormatProvider interface, which provides the format that the AI model will use to return structured data. The FormatProvider is defined as:
public interface FormatProvider {
    String getFormat();
}

By combining these interfaces, StructuredOutputConverter ensures that the AI response can be formatted according to a predefined structure and then converted into a strongly typed Java object, whether it’s a list, a map, or a custom Java bean.

1.2 Key Converters in the Structured Output API

  • ListOutputConverter: Converts the AI response into a list of items (such as strings or numbers).
  • MapOutputConverter: Transforms the response into a map of key-value pairs.
  • BeanOutputConverter: Maps the response to a custom Java class or record for handling more complex objects.

1.3 Setting Up and Configuring the OpenAI API Key

Start by setting the API key as an environment variable. This ensures that our application can securely access the key without hardcoding it into our code.

Set the OpenAI API Key as an Environment Variable

On your machine, set the API key with the following command:

export OPENAI_API_KEY=[your_api_key_copied_from_openai_site]

Configure the API Key in Your Application

Our application should read this environment variable to access the OpenAI API key. To configure this, update the application.properties file with the following entry:

spring.ai.openai.api-key=${OPENAI_API_KEY}

Add Required Maven Dependencies

For interacting with OpenAI’s ChatGPT in this article, we need to include the appropriate Maven dependency in our project. Add the following dependency to the pom.xml file:

<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>

Setting up the API key and including the necessary dependencies ensures that our application can securely communicate with OpenAI’s services.

2. List Output Converter

The ListOutputConverter is useful when you need to convert the AI’s response into a list of items. For example, generating a list of items from a prompt. Here is a code example for List output conversion.

    public void listOutputConverter(OpenAiChatModel chatClient) {
        ListOutputConverter listConverter = new ListOutputConverter(new DefaultConversionService());

        String format = listConverter.getFormat();
        String template = """
            Provide a list of 3 {subject}
            {format}
            """;
        PromptTemplate promptTemplate = new PromptTemplate(template,
                Map.of("subject", "fruits", "format", format));
        Prompt prompt = new Prompt(promptTemplate.createMessage());
        Generation generation = chatClient.call(prompt).getResult();

        List<String> fruits = listConverter.convert(generation.getOutput().getContent());

        System.out.println(fruits);
    }

In this example, the ListOutputConverter is used to convert the AI’s output into a List. The format variable provides the expected format for the AI response. The PromptTemplate defines the structure of the prompt, asking the AI to provide a list of three fruits. Once the AI generates the response, the ListOutputConverter parses the response into a List<String>, which is then printed.

The output might look like this:

[Fruit: Apple, Fruit: Banana, Fruit: Orange]

3. Map Output Converter

The MapOutputConverter is ideal when the AI’s response can be structured as key-value pairs, such as a JSON object. Here is a code example for Map output conversion.

    public void mapOutputConverter(OpenAiChatModel chatClient) {
        MapOutputConverter mapConverter = new MapOutputConverter();

        String format = mapConverter.getFormat();
        String template = """
            Provide a dictionary of {subject}
            {format}
            """;
        PromptTemplate promptTemplate = new PromptTemplate(template,
                Map.of("subject", "animal types and their average lifespan", "format", format));
        Prompt prompt = new Prompt(promptTemplate.createMessage());
        Generation generation = chatClient.call(prompt).getResult();

        Map<String, Object> lifespans = mapConverter.convert(generation.getOutput().getContent());

        System.out.println(lifespans);
    }

Here, the MapOutputConverter is used to transform the AI-generated response into a Map. The format variable specifies the expected format for the output. The PromptTemplate constructs a prompt asking for a dictionary of animal types and their average lifespans. The AI’s response is then converted into a Map<String, Object> by the MapOutputConverter, and the result is printed.

The output might look like this:

{Elephant=60 years, Dog=13 years, Cat=15 years, Parrot=50 years}

4. Bean Output Converter

For more complex objects, we can use the BeanOutputConverter, which allows us to map the AI’s response to a custom Java bean. Here is a code example demonstrating Bean output conversion.

    public void beanOutputConverter(OpenAiChatModel chatClient) {

        record MovieRecommendation(String title, List<String> genres, int releaseYear) {

        }

        BeanOutputConverter<MovieRecommendation> beanOutputConverter = new BeanOutputConverter<>(MovieRecommendation.class);
        String format = beanOutputConverter.getFormat();
        String movieTitle = "Inception";

        String template = """
            Provide a detailed movie recommendation for {title}.
            {format}
            """;

        Generation generation = chatClient.call(
                new Prompt(new PromptTemplate(template, Map.of("title", movieTitle, "format", format)).createMessage()))
                .getResult();

        MovieRecommendation recommendation = beanOutputConverter.convert(generation.getOutput().getContent());

        System.out.println(recommendation);
    }

}

In this example, the MovieRecommendation record is defined to encapsulate the movie title, genres, and release year. The BeanOutputConverter is used to map the AI’s response to this record. The prompt requests a detailed recommendation for the movie “Inception.” After receiving the response, the BeanOutputConverter parses it into a MovieRecommendation instance, which is then printed.

The code above might produce an output like this:

MovieRecommendation[title=Inception, genres=[Sci-Fi, Action, Thriller], releaseYear=2010]

5. Conclusion

In this article, we explored the Structured Output API in Spring AI, focusing on handling AI-generated responses in various structured formats. We examined three main converters: ListOutputConverter, MapOutputConverter, and BeanOutputConverter, which simplify transforming raw text into structured data such as lists, maps, and Java beans.

6. Download the Source Code

This article covered structured output converters.

Download
You can download the full source code of this example here: structured output converters

Omozegie Aziegbe

Omos holds a Master degree in Information Engineering with Network Management from the Robert Gordon University, Aberdeen. Omos is currently a freelance web/application developer who is currently focused on developing Java enterprise applications with the Jakarta EE framework.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button