← Code Recipes
Frameworks & SDKs

Spring AI Free code examples in Java

AI for Spring Boot, with the conventions Java teams already have.

C# Python Java JavaScript

WHAT THIS PAGE COVERS

ChatClient and an advisor chain, wired the Spring way.

Model gpt-5.4-mini
Package spring-ai-openai-spring-boot-starter
Checked

Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.

Install

The starter auto-configures a ChatClient.Builder, so there is no client to construct. The API key goes in configuration like any other Spring property.

# Gradle
implementation("org.springframework.ai:spring-ai-openai-spring-boot-starter:2.0.1")

# application.properties
#   spring.ai.openai.api-key=${OPENAI_API_KEY}
#   spring.ai.openai.chat.options.model=gpt-5.4-mini

export OPENAI_API_KEY="sk-your-key"
The first call

ChatClient.Builder is injected, not built. That is the Spring idiom and it is what lets configuration, observability and retries be set centrally rather than at each call site.

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

@RestController
class AskController {

    private final ChatClient chatClient;

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

    @GetMapping("/ai")
    String generation(String userInput) {
        return this.chatClient.prompt()
            .user(userInput)
            .call()
            .content();
    }
}
Defaults in one place

A @Bean ChatClient with defaultSystem and defaultAdvisors means every call site inherits the system prompt and the chain. Nothing downstream repeats it, and changing it is one edit.

import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
class ChatConfig {

    @Bean
    ChatMemory chatMemory() {
        return MessageWindowChatMemory.builder().maxMessages(20).build();
    }

    @Bean
    ChatClient chatClient(ChatClient.Builder builder, ChatMemory chatMemory) {
        return builder
            .defaultSystem("You are a concise technical assistant.")
            .defaultAdvisors(
                MessageChatMemoryAdvisor.builder(chatMemory).build())
            .build();
    }
}
Memory and RAG as advisors

TWO ADVISORS, AND THE ORDER IS LOAD-BEARING. Memory first, so the retrieval advisor searches with the conversation's context rather than a pronoun. The conversation id is not optional — without it every user shares one history.

import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.VectorStore;

String answer = chatClient.prompt()
    .advisors(advisor -> advisor
        .advisors(
            // 1. Rewrites the prompt with the conversation so far.
            MessageChatMemoryAdvisor.builder(chatMemory).build(),
            // 2. Then retrieves against that, not against "it".
            QuestionAnswerAdvisor.builder(vectorStore).build())
        // REQUIRED. Omit it and every user shares one conversation.
        .param(ChatMemory.CONVERSATION_ID, conversationId))
    .user(userText)
    .call()
    .content();
Structured output and streaming

entity() maps the answer onto a record and retries the parse for you. stream() returns a Flux, which is the shape the rest of a reactive Spring application already speaks.

import reactor.core.publisher.Flux;

record StockAnswer(String productCode, int quantity, boolean reorderAdvised) {}

// Spring AI builds the schema from the record and validates the reply.
StockAnswer parsed = chatClient.prompt()
    .user("How many X-17 are in stock and should we reorder?")
    .call()
    .entity(StockAnswer.class);

// Streaming, for a UI that should not wait for the last token.
Flux<String> tokens = chatClient.prompt()
    .user("Explain B-trees in 200 words.")
    .stream()
    .content();

QUESTIONS

Which languages are the Spring AI examples in?

Java. Every sample runs as pasted and reads its credentials from an environment variable — no key is ever written into the code.

Which package do I install for Spring AI?

The samples use spring-ai-openai-spring-boot-starter. The install step on each language tab gives the exact command.

Which Spring AI model do these examples use?

gpt-5.4-mini, checked against the official documentation on 26 September 2026. Model ids change often; if a call returns a model-not-found error, check the current list in the official docs.

Where is the official Spring AI documentation?

https://docs.spring.io/spring-ai/reference/ — it is linked at the bottom of this page, and it is the authority whenever it disagrees with a sample here.

ALSO IN FRAMEWORKS & SDKS

The authority

Official Spring AI documentation

Model names, pricing and rate limits change faster than any page here can. When this page and the official docs disagree, the official docs are right.

Read the docs ↗

https://docs.spring.io/spring-ai/reference/

New drops, every week

Free tools & Claude templates, landing regularly.

We keep shipping new free tools, code recipes and Claude Code templates. Follow @freeyantra on Instagram or join the newsletter so you never miss one.

Follow @freeyantra

or get them by email

Double opt-in. Unsubscribe any time. Privacy