Enterprise Java

Getting Started with Spring AI

Integrating artificial intelligence (AI) into applications is becoming necessary for businesses looking to stay ahead. The Spring Framework in the Java ecosystem brings AI capabilities to the forefront with Spring AI. Spring AI aims to make it easier to develop applications with built-in artificial intelligence features, without unnecessary complexity. It provides a set of core building blocks that simplify the creation of AI applications.

These building blocks are flexible, allowing us to switch between different components with minimal effort. For instance, Spring AI includes a ChatClient interface that can be implemented for various AI services, like OpenAI, making it easy to swap out one service for another with minimal code changes. This Spring AI tutorial is designed to guide developers through integrating AI and machine learning features into their Spring-based applications.

1. Core Concepts in Spring AI

In this section, we will delve into some essential concepts related to generative AI and how they are implemented in Spring AI.

1.1 ChatClient

The ChatClient is a core component that facilitates interaction with AI services. It handles sending prompts to an AI model like OpenAI’s GPT and retrieving the generated responses, allowing us to focus on implementing business logic rather than managing low-level API interactions. Spring Boot automatically configures ChatClient using the properties defined in our application.properties or application.yml file.

1.2 Prompt and PromptTemplate

In Spring AI, Prompt and PromptTemplate are tools designed to streamline the process of generating dynamic and structured prompts for AI models. They simplify the interaction with AI services, enabling us to create contextually relevant inputs for generating responses.

1.2.1 What is Prompt?

A Prompt represents the input that is sent to an AI model. It is essentially a string or set of instructions that guides the AI in generating a relevant and coherent response. In Spring AI, the Prompt class is used to encapsulate this input, making it easier to manage and manipulate.

1.2.2 What are Prompt Templates?

PromptTemplate is a feature that allows us to define reusable and dynamic prompt templates. It helps in creating structured prompts by defining placeholders that can be replaced with actual values at runtime. This is useful for generating prompts based on varying inputs or contexts. Here is a simple example of a prompt template:

Write a {adjective} review of a {genre} book titled "{title}".

Explanation

  • {adjective}: Describes the tone of the review, such as “critical,” or “enthusiastic.”
  • {genre}: Specifies the genre of the book, like “mystery,” “science fiction,” or “romance.”
  • {title}: The title of the book being reviewed.

Usage Example: For an enthusiastic review of a science fiction book titled “Space Odyssey,” the filled prompt would be: “Write an enthusiastic review of a science fiction book titled ‘Space Odyssey‘.”

1.3 What is ChatResponse in Spring AI?

In Spring AI, ChatResponse is a class that represents the output received from an AI model after sending a prompt. It is a data structure provided by Spring AI that contains the results returned by an AI model. It encapsulates the AI’s response, including the generated content and other relevant metadata.

2. Setting Up the API Key for Spring AI

To interact with external AI services like OpenAI using Spring AI, we need to set up an API key. This API key is essential for authenticating our application with the AI service provider, enabling us to send prompts and receive responses securely. Here is a guide to setting up an API key in our Spring Boot application.

2.1 Obtain the API Key

First, we must obtain an API key from our AI service provider. Here is how we can do it for OpenAI:

  • Sign up or log in to your OpenAI account at https://platform.openai.com/. You can create an account if you haven’t already. If you have a ChatGPT account, you can use the same credentials to log in.
  • Navigate to the API section in your dashboard. Here, a link labelled Create new secret key opens a form to generate a secret key. When you click on Create a secret key, a secret key will be generated.
  • Copy the API key to use in your Spring Boot application.

2.2 Store the API Key Securely

It is important to store the API key securely and avoid hardcoding it directly into the application’s source code. A common approach is to use environment variables. If using a Mac, we can set the API key as an environment variable on our system like this:

export OPENAI_API_KEY=your_openai_api_key

3. Adding OpenAI Dependency to Your Application

To start using Spring AI with OpenAI, we must add the spring-ai-openai-spring-boot-starter dependency to our Spring Boot project. We can use the Spring Initializr to generate the basic structure.

spring initialzr screenshoot for spring ai tutorial

The above setup adds the following necessary dependencies for Sring AI to our pom.xml file:

	<properties>
		<java.version>21</java.version>
		<spring-ai.version>1.0.0-M2</spring-ai.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.ai</groupId>
			<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
		</dependency>

	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.ai</groupId>
				<artifactId>spring-ai-bom</artifactId>
				<version>${spring-ai.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>


	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

4. A Simple Example: Basic AI Prompt

To understand how Spring AI works, let’s start with a simple example. In this example, we will create a Spring Boot REST controller that uses Spring AI to generate a motivational quote.

@RestController
@RequestMapping("/ai")
public class MotivationController {

    private final ChatClient chatClient;

    public MotivationController(ChatClient.Builder chatClient) {
        this.chatClient = chatClient.build();
    }

    @GetMapping("/motivate")
    Map<String, String> getMotivationalQuote() {
        String prompt = "Give me a motivational quote to start my day.";
        String response = chatClient.prompt().user(prompt).call().content();
        return Map.of("prompt", prompt, "answer", response);
    }
   
}

In this example, we’ve created a REST controller MotivationController with a single endpoint /motivate. When accessed, this endpoint sends a basic prompt to the AI model. The prompt in this case is "Give me a motivational quote to start my day". The /motivate endpoint triggers the AI to generate a motivational quote.

The AI then generates a quote, and the controller returns both the prompt and the quote in a JSON format. To test the application, you can open your web browser and navigate to http://localhost:8080/ai/motivate or you can use a tool like Postman to send a GET request to the same URL.

Using curl, we can send a GET request to the /ai/motivate endpoint.

curl -X GET http://localhost:8080/ai/motivate

When you run the above curl command, the application will process the request and return a JSON response. The JSON will contain the original prompt and the motivational quote generated by the AI.

An example output might look like this:

{
  "prompt": "Give me a motivational quote to start my day.",
  "answer": "Success is not final, failure is not fatal: It is the courage to continue that counts."
}

5. A More Advanced Example: Using Prompt Templates and Bean Parsing

Now let’s explore a more complex example that demonstrates the power of Spring AI by using prompt templates and parsing the response into a Java object.

@RestController
@RequestMapping("/ai")
public class MovieController {

    private final ChatClient chatClient;

    public MovieController(ChatClient.Builder chatClient) {
        this.chatClient = chatClient.build();
    }

    @GetMapping("/recommend/{genre}")
    public MovieRecommendation getMovieRecommendation(@PathVariable("genre") String genre) {
        BeanOutputConverter<MovieRecommendation> parser = new BeanOutputConverter<>(MovieRecommendation.class);

        String prompt = """
            Can you recommend a great movie in the {genre} genre?
            Please include the title, director, and a brief synopsis.
            {format}
        """;

        PromptTemplate template = new PromptTemplate(prompt);
        Map<String, Object> model = Map.of("genre", genre, "format", parser.getFormat());

        Prompt createdPrompt = template.create(model);
        String responseText = chatClient.prompt(createdPrompt).call().content();

        return parser.convert(responseText);
    }
}

In the above code example, the BeanOutputConverter class plays a crucial role in converting the textual response from an AI model into a structured Java object, specifically a MovieRecommendation object.

AI-generated text is often unstructured and may not easily map to a Java object. The BeanOutputConverter class is designed to handle the transformation of raw text into a Java object. In this case, it converts the response from the AI model (which is in text form) into a MovieRecommendation object.

The {format} in the prompt is a placeholder that the BeanOutputConverter replaces with a specific format. This format tells the AI how to structure its response so it matches the MovieRecommendation class. Including {format} in the prompt helps the AI generate output in a format like String, Map, List, XML, or JSON that the BeanOutputConverter can easily convert into a Java object.

Here is the MovieRecommendation class:

public class MovieRecommendation {

    private String title;
    private String director;
    private String synopsis;

    public MovieRecommendation() {
    }

    public MovieRecommendation(String title, String director, String synopsis) {
        this.title = title;
        this.director = director;
        this.synopsis = synopsis;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDirector() {
        return director;
    }

    public void setDirector(String director) {
        this.director = director;
    }

    public String getSynopsis() {
        return synopsis;
    }

    public void setSynopsis(String synopsis) {
        this.synopsis = synopsis;
    }

    @Override
    public String toString() {
        return "MovieRecommendation{" +
                "title='" + title + '\'' +
                ", director='" + director + '\'' +
                ", synopsis='" + synopsis + '\'' +
                '}';
    }
}

We can test the API by sending a GET request to the /ai/recommend/{genre} endpoint with the following curl command:

curl -X GET http://localhost:8080/ai/recommend/science-fiction

The AI might respond with a recommendation with an output that might look like this:

{
  "title": "Interstellar",
  "director": "Christopher Nolan",
  "synopsis": "A team of explorers travels through a wormhole in space in an attempt to ensure humanity's survival."
}

6. Conclusion

In this Spring AI tutorial, we explored how to leverage the power of Spring Boot and AI to create RESTful services. By integrating the ChatClient from the spring-ai-openai-spring-boot-starter, we demonstrated how to generate dynamic prompts and parse AI-generated responses into structured Java objects.

7. Download the Source Code

This was a tutorial on Spring AI.

Download
You can download the full source code of this example here: Spring AI Tutorial

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