Spring AI Output Parsers Example

Spring AI provides several output parsers to handle the responses from AI models effectively. This tutorial will demonstrate how to use different output parsers in a Spring Boot application, including BeanOutputParser, MapOutputParser, and ListOutputParser.

Introduction

Output parsers in Spring AI allow you to process and format the responses from AI models into usable data structures such as beans, maps, and lists. This tutorial will walk you through the use of these parsers with step-by-step examples.

Prerequisites

  • Java 17 or later
  • Maven 3.8.1 or later
  • OpenAI API Key

1. Setting Up the Project

Step 1: Create a New Spring Boot Project

Use Spring Initializr to create a new Spring Boot project. Include dependencies for Spring Web and Spring AI.

Using Spring Initializr:

  • Go to start.spring.io
  • Select:
    • Project: Maven Project
    • Language: Java
    • Spring Boot: 3.3.0 (or latest)
    • Dependencies: Spring Web
  • Generate the project and unzip it.

Step 2: Add Dependencies

In your project's pom.xml, ensure you have the necessary dependencies.

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

2. Configuring the Application

Step 1: Add API Key to Configuration

Add your OpenAI API key to application.properties.

openai.api.key=your_openai_api_key
openai.api.url=https://api.openai.com/v1/completions

Step 2: Configure ChatClient

Create a configuration class to set up the ChatClient.

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ai.openai.OpenAiClient;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.ChatClient;

@Configuration
public class AppConfig {

    @Bean
    public OpenAiClient openAiClient() {
        return new OpenAiClient();
    }

    @Bean
    public ChatClient chatClient(OpenAiClient openAiClient) {
        return new OpenAiChatClient(openAiClient);
    }
}

3. Using Output Parsers

Step 1: Define the Output Models

Let's create models for the bean and other structures that will be parsed from the AI response.

Product.java

package com.example.demo.model;

public class Product {
    private String name;
    private double price;

    // Getters and setters
}

Step 2: Create the Output Parsers

Let's create services to demonstrate the different output parsers.

BeanOutputParserExample.java

package com.example.demo.service;

import com.example.demo.model.Product;
import org.springframework.ai.openai.ChatClient;
import org.springframework.ai.openai.model.ChatMessage;
import org.springframework.ai.openai.model.ChatRequest;
import org.springframework.ai.openai.model.ChatResponse;
import org.springframework.ai.output.BeanOutputParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class BeanOutputParserExample {

    private final ChatClient chatClient;

    @Autowired
    public BeanOutputParserExample(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public Product parseResponseToBean(String userMessage) {
        ChatMessage userMsg = new ChatMessage("user", userMessage);

        ChatRequest request = new ChatRequest();
        request.setMessages(List.of(userMsg));

        ChatResponse response = chatClient.sendMessage(request);

        BeanOutputParser<Product> parser = new BeanOutputParser<>(Product.class);
        return parser.parse(response.getReply());
    }
}

MapOutputParserExample.java

package com.example.demo.service;

import org.springframework.ai.openai.ChatClient;
import org.springframework.ai.openai.model.ChatMessage;
import org.springframework.ai.openai.model.ChatRequest;
import org.springframework.ai.openai.model.ChatResponse;
import org.springframework.ai.output.MapOutputParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class MapOutputParserExample {

    private final ChatClient chatClient;

    @Autowired
    public MapOutputParserExample(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public Map<String, Object> parseResponseToMap(String userMessage) {
        ChatMessage userMsg = new ChatMessage("user", userMessage);

        ChatRequest request = new ChatRequest();
        request.setMessages(List.of(userMsg));

        ChatResponse response = chatClient.sendMessage(request);

        MapOutputParser parser = new MapOutputParser();
        return parser.parse(response.getReply());
    }
}

ListOutputParserExample.java

package com.example.demo.service;

import org.springframework.ai.openai.ChatClient;
import org.springframework.ai.openai.model.ChatMessage;
import org.springframework.ai.openai.model.ChatRequest;
import org.springframework.ai.openai.model.ChatResponse;
import org.springframework.ai.output.ListOutputParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ListOutputParserExample {

    private final ChatClient chatClient;

    @Autowired
    public ListOutputParserExample(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public List<String> parseResponseToList(String userMessage) {
        ChatMessage userMsg = new ChatMessage("user", userMessage);

        ChatRequest request = new ChatRequest();
        request.setMessages(List.of(userMsg));

        ChatResponse response = chatClient.sendMessage(request);

        ListOutputParser<String> parser = new ListOutputParser<>(String.class);
        return parser.parse(response.getReply());
    }
}

Step 3: Create Controllers to Expose the Services

Create controllers to expose endpoints for each output parser example.

BeanOutputParserController.java

package com.example.demo.controller;

import com.example.demo.model.Product;
import com.example.demo.service.BeanOutputParserExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BeanOutputParserController {

    private final BeanOutputParserExample parserExample;

    @Autowired
    public BeanOutputParserController(BeanOutputParserExample parserExample) {
        this.parserExample = parserExample;
    }

    @GetMapping("/parseToBean")
    public Product parseToBean(@RequestParam String message) {
        return parserExample.parseResponseToBean(message);
    }
}

MapOutputParserController.java

package com.example.demo.controller;

import com.example.demo.service.MapOutputParserExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class MapOutputParserController {

    private final MapOutputParserExample parserExample;

    @Autowired
    public MapOutputParserController(MapOutputParserExample parserExample) {
        this.parserExample = parserExample;
    }

    @GetMapping("/parseToMap")
    public Map<String, Object> parseToMap(@RequestParam String message) {
        return parserExample.parseResponseToMap(message);
    }
}

ListOutputParserController.java

package com.example.demo.controller;

import com.example.demo.service.ListOutputParserExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class ListOutputParserController {

    private final ListOutputParserExample parserExample;

    @Autowired
    public ListOutputParserController(ListOutputParserExample parserExample) {
        this.parserExample = parserExample;
    }

    @GetMapping("/parseToList")
    public List<String> parseToList(@RequestParam String message) {
        return parserExample.parseResponseToList(message);
    }
}

4. Testing the Integration

Step 1: Run the Application

Run your Spring Boot application. Ensure the application starts without errors.

Step 2: Access the Endpoints

Use Postman, curl, or your browser to test the endpoints.

  1. Parse to Bean

    http://localhost:8080/parseToBean?message=Describe a product with name and price.
    

    Expected Response:

    {
        "name": "Laptop",
        "price": 999.99
    }
    
  2. Parse to Map

    http://localhost:8080/parseToMap?message=Describe a product with details.
    

    Expected Response:

    {
        "name": "Laptop",
        "price": 999.99,
        "brand": "BrandName",
        "inStock": true
    }
    
  3. Parse to List

    http://localhost:8080/parseToList?message=List some popular programming languages.
    

    Expected Response:

    [
        "Java",
        "Python",
        "JavaScript",
        "C#",
        "Ruby"
    ]
    

Conclusion

This tutorial demonstrated how to set up and use different output parsers in a Spring Boot application with Spring AI. We covered the following:

  1. BeanOutputParser: Parsing responses into Java objects.
  2. MapOutputParser: Parsing responses into maps.
  3. ListOutputParser: Parsing responses into lists.

By using these parsers, you can effectively process and utilize the AI-generated responses in your Spring Boot applications, enhancing their functionality and user experience. Explore further customization and enhancements to leverage the full potential of AI in your projects.

Comments