Skip to main content

Spring AI: Hello Spring AI

AI has rapidly become a standard capability in modern applications. Whether you are building chatbots, intelligent business workflows, or AI powered assistants, Large Language Models (LLMs) can significantly enhance your applications.

Until recently, Python has been the primary language for building AI applications. However, a new era has arrived for Java developers. With Spring AI, Java developers can now build AI powered applications using the familiar Spring programming model.

What Is Spring AI?

Building AI applications involves several challenges, such as interacting with AI providers, constructing prompts, managing conversations, parsing responses, and orchestrating AI workflows.

Spring AI addresses these challenges by providing the familiar Spring programming model for AI application development. It simplifies integration with AI providers such as OpenAI, Anthropic, AWS Bedrock, Google Gemini, local Ollama models, and many others.

Spring AI provides support for:

  • Chat conversations
  • Prompt construction and management
  • System prompts and conversation roles
  • Structured outputs
  • Tool calling
  • Memory
  • Retrieval Augmented Generation (RAG)
  • Model Context Protocol (MCP)
  • AI workflows and agentic patterns

Even better, getting started is remarkably simple. Bootstrapping a Spring AI application is often as easy as adding the appropriate Spring Boot starter dependency and configuring your AI provider using externalized configuration.

In this first article, we will build our first Spring AI application and explore two important abstractions in Spring AI:

  • ChatModel
  • ChatClient

Creating the Project

Head over to Spring Initializr and create a new Spring Boot project with the following dependencies:

  • Spring Web MVC
  • Spring AI OpenAI

Configuring OpenAI

I assume you already know how to obtain an OpenAI API key.

Once you have your API key, export it as an environment variable:

bash
export OPENAI_API_KEY=<your-api-key>

Next, update your application.yml with the following configuration:

yaml
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}

Before we write any code, let's first understand the core abstractions provided by Spring AI.

Understanding ChatModel

An LLM receives an input and generates an output. Spring AI represents this capability through the ChatModel interface.

java
public interface ChatModel {
    ChatResponse call(Prompt prompt);
}

A ChatModel is responsible for:

  • Accepting prompts as input
  • Communicating with the underlying AI provider
  • Receiving model responses
  • Representing responses using Spring AI objects

However, this is a relatively low level abstraction. Although we can use ChatModel directly, in most cases it is better to use the higher level API provided by ChatClient.

Understanding ChatClient

Think of ChatClient as the equivalent of RestClient for LLMs.

Instead of manually creating Prompt objects and parsing ChatResponse instances, ChatClient provides a fluent API that greatly simplifies AI interactions.

It is a convenience layer built on top of ChatModel.

Creating a ChatClient

When you use the appropriate Spring AI starter and configure the required properties, Spring Boot automatically creates a ChatClient.Builder bean.

We can inject this builder and use it to create a ChatClient instance.

java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiConfiguration {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder.build();
    }

}

We can now inject ChatClient into any Spring managed component in our application.

Basic Conversation with ChatClient

Now, let's inject ChatClient into a REST controller and build our first AI powered endpoint.

java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @PostMapping("/chat")
    public ChatResponse chat(@RequestBody ChatRequest request) {
        var response = chatClient.prompt()
                .user(request.message())
                .call()
                .content();

        return new ChatResponse(request.message(), response);
    }

    public record ChatRequest(String message) {
    }

    public record ChatResponse(String request, String response) {
    }

}

Let's understand what is happening here.

First, we create a prompt using:

java
chatClient.prompt()

Then, we provide the user's message:

java
.user(request.message())

We invoke the model using:

java
.call()

Finally, we retrieve the generated text content:

java
.content()

The fluent ChatClient API hides most of the lower level details and allows us to focus on our application logic.

Running the Application

Start the application:

bash
./gradlew bootRun

Now, call our /chat endpoint:

bash
curl -X POST http://localhost:8080/chat \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Explain Spring Boot in one sentence."
  }'

The response will look similar to this:

json
{
  "request": "Explain Spring Boot in one sentence.",
  "response": "Spring Boot simplifies the development of Spring applications by providing auto configuration, embedded servers, and production ready defaults."
}

Congratulations! We have built our first Spring AI application.

Although this is a simple example, we have already connected a Spring Boot application to an LLM and generated a response using the ChatClient API.

Summary

In this article, we introduced Spring AI and built our first chat application.

We explored the ChatModel abstraction, which represents the interaction with an AI model, and the higher level ChatClient API, which provides a fluent and convenient way to interact with LLMs.

Although the application is simple, the same concepts and abstractions will be used when building larger, production ready AI applications.

In the next articles, we will gradually explore prompts, structured outputs, memory, RAG, tool calling, and AI agents.

Comments