Spring AI Concept and Project

Spring AI Learning Roadmap

                Spring AI


                     │


      ┌──────────────┼───────────────┐


      ▼              ▼               ▼


   Prompt        ChatClient      ChatModel


                     │


                     ▼


             Message Roles


                     │


                     ▼


                 Advisors


                     │


                     ▼


            Prompt Templates


                     │


                     ▼


          Chat History (Memory)


                     │


                     ▼


                  RAG


                     │


                     ▼


           Function Calling


                     │


                     ▼


              MCP (AI Agents)



1. Message Roles ⭐⭐⭐⭐⭐

LLMs don't just receive text; they receive messages with roles.

There are three common roles:

RolePurpose
SystemTells the AI how to behave
UserThe user's question
AssistantPrevious AI responses

Example:

System:
You are a Java expert.

User:
Explain Spring Boot.

Assistant:
Spring Boot is...

The model understands who said what.

In Your Project

System:
You are ASK AI.

User:
How to create scheduler?

Assistant:
Follow these steps...

2. Advisors ⭐⭐⭐⭐⭐

An Advisor intercepts or enriches a request before it reaches the model.

Think of it like a Spring MVC interceptor or a filter.

User

↓

Advisor

↓

ChatModel

↓

LLM

Examples:

  • Add company policies
  • Add user information
  • Add chat history
  • Add RAG context
  • Log prompts

For example, every prompt could automatically get:

You are AskAI.
Answer only from Confluence.

without repeating it in your controller.


3. Prompt Templates ⭐⭐⭐⭐☆

Instead of hardcoding prompts:

"You are a Java expert. Explain " + topic

Use placeholders:

You are a Java expert.

Explain:

{topic}

At runtime:

topic = Spring Boot

becomes:

You are a Java expert.

Explain:

Spring Boot

This keeps prompts reusable and easier to maintain.


4. Chat History (Memory) ⭐⭐⭐⭐⭐

Without memory:

User:

Who is James Gosling?

AI answers.

Then:

Where was he born?

The AI may not know "he" refers to James Gosling.


With memory:

User:
Who is James Gosling?

AI:
Creator of Java.

User:
Where was he born?

The previous conversation is included, so the AI understands the reference.

This is essential for chatbots.


5. RAG (Retrieval-Augmented Generation) ⭐⭐⭐⭐⭐⭐

This is the most important topic for your project.

Without RAG:

Question

↓

GPT

↓

General Internet Knowledge

With RAG:

Question

↓

Vector Search

↓

Confluence

↓

Relevant Documents

↓

GPT

↓

Answer

This is exactly how you'll build your DBAssist AI Assistant.


6. Function Calling (Tool Calling) ⭐⭐⭐⭐⭐

Suppose the user asks:

Show failed schedulers.

The AI doesn't know your database.

Instead:

User

↓

AI

↓

Calls Java Method

↓

Database

↓

Result

↓

AI Explains

For example, your application could have:

schedulerService.getFailedSchedulers()

The AI invokes that method, gets live data, and answers using the result.


7. MCP (Model Context Protocol) ⭐⭐⭐⭐⭐⭐

MCP is a standard protocol that lets AI communicate with external systems.

Instead of hardcoding integrations:

AI

↓

Database

↓

Confluence

↓

GitHub

↓

Jira

the AI talks to MCP servers.

An MCP server can expose:

  • Confluence
  • Jira
  • GitHub
  • Databases
  • File systems

The AI discovers available tools and uses them when appropriate.


Your Future Project

This is how your final enterprise application could work:

User

↓

Spring Boot

↓

ChatClient

↓

Advisor
(Add company policy)

↓

Memory
(Previous conversation)

↓

RAG
(Search Confluence)

↓

Function Calling
(Database/API)

↓

OpenAI / Ollama

↓

Answer



ChatModel and ChatClient.

Think of it like Spring Data JPA:

  • DataSource → Connection to the database
  • JdbcTemplate/JPA Repository → Easy way to query the database

Similarly:

  • ChatModel → Connection to the AI model
  • ChatClient → Easy way to chat with the AI


1. ChatModel

ChatModel is the low-level interface that communicates directly with the LLM (OpenAI, Gemini, Claude, etc.).

It is responsible for:

  • Sending requests to the AI provider
  • Receiving responses
  • Managing authentication
  • Converting Java objects to API requests
  • Parsing the API response

Think of it as:


Your Application
      │
      ▼
 ChatModel
      │
      ▼
 OpenAI / Gemini API



Building a “Hello World” App with Spring AI & Open AI

Step 1-
@RestController
@RequestMapping("/api")
public class ChatController {

private final ChatClient chatClient;

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

@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt(message)
.call()
.content();
}
}

Step 2:-

Generate a API key and configure in app – 
• Goto the website https://platform.openai.com/ and generate a API key 
• Configure your API key in application.properties or application.yml: 
spring.ai.openai.api-key=${OPENAI_API_KEY

PostMan -

Test with these URLs

Test 1

http://localhost:8080/api/chat?message=Hello


Test 2

http://localhost:8080/api/chat?message=What is Java?


Test 3

http://localhost:8080/api/chat?message=Who are you?




Building a “Hello World” App with Spring AI & Ollama


What is Ollama? Ollama is a developer-friendly tool that allows you to run large language models (LLMs) locally on your machine — easily and efficiently. Built for privacy, speed, and offline use.


Key features of Ollama:

 Local execution: Run AI models entirely on your machine without internet dependency.

Model library: Access to popular open-source models through a simple download system 

API access: Provides REST API endpoints so you can integrate models into your applications 

Cross-platform: Works on macOS, Linux, and Windows 

To get started with Ollama, visit https://ollama.com/


1. Install model in local using ollama - We can install a model with a simple command like mentioned below,

ollama run llama3.2:1b

2. Add Required Dependencies - Enables Spring Boot web and ollama integration

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>openai</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name/>
<description/>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
<spring-ai.version>2.0.0</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

3. configure properties in Spring AI app

Configure below properties in application.properties or application.yml.

API key is not required as the model is available in local.

spring.ai.model.chat=ollama

spring.ai.ollama.chat.model=llama3.2:1


4. Create the Chat Controller

package com.example.openai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/apis")
public class ChatController {

private final ChatClient chatClient;

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

@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt(message)
.call()
.content();
}
}

You now have a minimal working Spring AI app that connects to ollama and responds to your prompts.



Working with Multiple Chat Models in Spring AI


Multiple Chat Models means your application can use more than one AI model at the same time.

For example:

  • OpenAI for general questions
  • Ollama for local/private questions
  • Gemini for image analysis

Instead of using only one model:

User

   │

   ▼

OpenAI

You can have:

                 User

                   │

        ┌──────────┼──────────┐

        ▼          ▼          ▼

    OpenAI      Ollama     Gemini

Why use Multiple Models?

Suppose you're building Application-

TaskModel
General ChatOpenAI
Company DocumentsOllama
Screenshot AnalysisGemini

.The application chooses the best model for each task.


Why Companies Use Multiple Models

A common pattern is:

  • OpenAI → Best quality for customer-facing conversations.
  • Ollama → Keeps sensitive company data on internal infrastructure.
  • Gemini → Image understanding.
  • Claude → Long-document analysis.

The application routes each request to the most appropriate model.



In real-world applications, it's common to integrate multiple chat models for better flexibility, performance, and 

user experience. Here are some practical scenarios:

Why Use Multiple Chat Models?

Task-Based Model Selection

Use a powerful model for complex reasoning and a lightweight model for basic queries.

Fallback Strategy

Automatically switch to another model if the primary one is unavailable.

A/B Testing

Test different models or configurations to compare accuracy, latency, and cost.

User Preference

Allow users to choose their preferred model for interaction.

Specialized Models

Combine models with different strengths (e.g., one for code, another for creative writing).


Case 1: Single Model (Default Behavior)

Suppose your application.properties contains:

spring.ai.openai.api-key=xxxx

Spring Boot sees only one AI model (OpenAI).

During startup, it creates:

OpenAiChatModel Bean

        │

        ▼

ChatClient.Builder Bean


Internally, it's similar to:

@Bean

ChatClient.Builder chatClientBuilder(ChatModel chatModel) {


    return ChatClient.builder(chatModel);


}

Since there is only one ChatModel, Spring knows exactly which one to use.

Now your code works:

public ChatController(ChatClient.Builder builder) {

    this.chatClient = builder.build();

}


Everything is automatic.



Case 2: Multiple Models

Now suppose you add both:

spring.application.name=openai
logging.pattern.console=%green(%d{HH:mm:ss.SSS}) %blue(%-5level) %red([%thread]) %yellow(%logger{15}) - %msg%n
spring.ai.ollama.chat=ollama
spring.ai.ollama.chat.model=llama3.2
spring.ai.chat.client.enabled=false
spring.ai.openai.api-key=${OPENAI_API_KEY}
package com.example.openai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class MultiModelChatController {

private final ChatClient openAiChatClient;
private final ChatClient ollamaChatClient;


public MultiModelChatController(@Qualifier("openAiChatClient") ChatClient openAiChatClient,
@Qualifier("ollamaChatClient") ChatClient ollamaChatClient) {
this.openAiChatClient = openAiChatClient;
this.ollamaChatClient = ollamaChatClient;
}
@GetMapping("/openai/chat")
public String openAIChat(@RequestParam ("message") String message)
{
return openAiChatClient.prompt(message).call().content();
}
@GetMapping("/ollama/chat")
public String ollamaChat(@RequestParam("message") String message) {
return ollamaChatClient.prompt(message).call().content();
}
}
package com.example.openai.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ChatClientConfig {

@Bean
public ChatClient openAiChatClient(OpenAiChatModel openAiChatModel) {
return ChatClient.create(openAiChatModel);
}

@Bean
public ChatClient ollamaChatClient(OllamaChatModel ollamaChatModel) {
ChatClient.Builder chatClientBuilder = ChatClient.builder(ollamaChatModel);
return chatClientBuilder.build();
}
}

Spring creates:

OpenAiChatModel Bean 

 OllamaChatModel Bean


Now Spring has a problem.


Which ChatModel should be used?

When Spring tries to auto-create:

@Bean

ChatClient.Builder builder(ChatModel model)

it asks:

Which ChatModel?

There are now two:

ChatModel


├── OpenAiChatModel


└── OllamaChatModel


Result

You'll get an error like:

No qualifying bean of type ChatModel


expected single matching bean


but found 2


This is exactly the same problem you see with multiple DataSource beans or multiple JdbcTemplate beans.


Why Disable Auto Configuration?

Spring AI normally creates:

ChatClient.Builder

for you.

But now you don't want one builder.

You want

OpenAI Builder

for you.

But now you don't want one builder.

You want

OpenAI Builder

AND Ollama Builder


Therefore you tell Spring:

Therefore you tell Spring:

spring.ai.chat.client.enabled=false

This means:

"Spring, don't create the default ChatClient.Builder. I'll create my own."

Then You Create Them Yourself.


Why Does Spring AI Recommend This?

Because only you know your business logic.

For example:

User asks about company documentation │ ▼ Ollama ---------------------------- User asks a general question │ ▼ OpenAI

Spring cannot infer this routing automatically,

so it lets you create separate builders and choose the appropriate one in your application.

 What You've Built So Far • A simple Spring AI app that sends prompts and receives responses • Great start—but it only scratches the surface


====================================Part2============================================

Understanding Message Roles in LLMs

System → Instructions to AI User → Question from the user Assistant → AI's previous response Tool (Function) → Result returned by a tool/function





Comments

Popular posts from this blog

Two Sum II - Input Array Is Sorted

Comparable Vs. Comparator in Java

Async/await