
1. Overview
Spring AI 2.0 brings the official OpenAI Java SDK into its standard OpenAI integration. We can use it through Spring’s abstractions while letting Spring Boot configure the underlying client.
In this tutorial, we’ll summarize a support request with ChatClient, configure Gemini as an optional provider, and migrate from the former separate SDK module.
2. How Spring AI Uses the OpenAI Java SDK
Spring AI provides a common API for working with language models. For this integration, ChatClient delegates to OpenAiChatModel, which translates Spring messages and options into requests handled by the official SDK.
Our application depends on Spring AI’s abstractions. The SDK handles the underlying API calls.
Spring Boot auto-configuration supplies the model and a ChatClient.Builder. This differs from using the OpenAI Java client directly, where we construct SDK requests ourselves.
Spring AI 2.0 removes the separate spring-ai-openai-sdk module. The standard OpenAI integration now uses the official SDK internally. In Spring AI 2.0.2, this integration uses the Chat Completions API and doesn’t support OpenAI’s Responses API.
3. Setting Up the Integration
Our example uses Java 21, Spring Boot 4.1.2, and Spring AI 2.0.2.
3.1. Maven Dependencies
In our Spring Boot project, let’s add the OpenAI starter:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>2.0.2</version> </dependency> The latest spring-ai-starter-model-openai version is available in the Maven Repository. Version 2.0.2 brings in openai-java-core 4.80.0 transitively, so we don’t need a separate SDK dependency.
3.2. Credentials and Model Configuration
We need an OpenAI API key and available API credits. Let’s supply the key through the OPENAI_API_KEY environment variable.
In application.yml, let’s configure the endpoint and limit the example’s response size:
spring: ai: openai: api-key: ${OPENAI_API_KEY} base-url: https://api.openai.com/v1 timeout: 30s max-retries: 0 chat: model: ${OPENAI_MODEL:gpt-6-luna} reasoning-effort: none max-completion-tokens: 256 The full base URL includes /v1. The SDK appends /chat/completions when making our request.
For GPT-6 Luna, reasoning-effort: none disables reasoning, while max-completion-tokens caps generated tokens. We also set a request timeout and disable automatic retries to keep this small example’s API calls predictable.
4. Calling OpenAI-Compatible Models Through ChatClient
We want to send a synthetic support request and ask for a one-sentence summary containing the problem and requested action.
4.1. Creating the Summary Service
Let’s inject the auto-configured builder into our service:
@Service public class SupportSummaryService { private final ChatClient chatClient; public SupportSummaryService(ChatClient.Builder builder) { this.chatClient = builder.defaultSystem( "Summarize the support request in one sentence. " + "Include the problem and the requested action. " + "Do not invent details.") .build(); } public String summarize(String request) { return chatClient.prompt() .user(request) .call() .content(); } } defaultSystem() establishes the summarization instruction. Each summarize() call adds the request as a user message, invokes the model synchronously, and returns its text.
The broader ChatClient fluent API also supports features such as streaming and structured output. Here, a plain string lets us focus on the SDK integration.
4.2. Verifying the OpenAI Call
Our Spring Boot test injects SupportSummaryService and exercises it with a duplicate-charge request:
String summary = summaryService.summarize( "I was charged twice for my subscription. Please refund the duplicate charge."); assertThat(summary).isNotBlank(); logger.info("OpenAI support summary: {}", summary); After setting our API key, let’s run the repository’s live test from the spring-ai-modules/spring-ai-openai directory:
$ export OPENAI_API_KEY='our-openai-api-key' mvn test -Dtest=OpenAiSupportSummaryLiveTest Both live tests use @EnabledIfEnvironmentVariable, so Maven reports a skipped test if the corresponding API key environment variable is missing or empty.
In our live run, OpenAI returned:
I was charged twice for my subscription and request a refund for the duplicate charge. The generated wording can vary, so we should check for nonblank output rather than an exact sentence.
4.3. Using Gemini as an Alternative
For an alternative without paid OpenAI access, we can use Gemini’s OpenAI-compatible endpoint. Gemini 3.5 Flash-Lite offers a free tier, subject to quotas and availability.
In application-gemini.yml, a separate Spring profile overrides the provider settings:
spring: ai: openai: api-key: ${GEMINI_API_KEY} base-url: https://generativelanguage.googleapis.com/v1beta/openai/ timeout: 120s chat: model: ${GEMINI_MODEL:gemini-3.5-flash-lite} reasoning-effort: low max-completion-tokens: 1024 The service and SDK stay the same, but model-specific options still matter. Gemini 3 models can’t disable thinking, so we should replace none with low and allow more tokens.
We allow up to 120 seconds per request. The live test’s 180-second limit prevents JUnit from interrupting the request first.
The Gemini live test activates this profile itself, so we only need its key and test name:
$ export GEMINI_API_KEY='our-gemini-api-key' mvn test -Dtest=GeminiSupportSummaryLiveTest Our Gemini 3.5 Flash-Lite run returned:
The user was charged twice for their subscription and is requesting a refund for the duplicate charge. 5. Migrating From the Separate SDK Module
This migration applies to the former spring-ai-openai-sdk integration. The upgrade notes describe its removal in Spring AI 2.0.
Applications already using the standard OpenAI module can keep their existing configuration properties, with chat.options.* retained as deprecated aliases. However, code that builds OpenAiChatModel manually needs updating.
In 2.0.2, OpenAiApi is gone. The model builder no longer provides openAiApi(), defaultOptions(), or retryTemplate(). It accepts the SDK’s OpenAIClient through openAiClient() and model settings through options().
5.1. Updating the Starter and Properties
When moving from Spring AI 1.1.x to 2.0.2, we also need a compatible Spring Boot 4 application. We should replace spring-ai-starter-model-openai-sdk with the starter shown in Section 3.1.
A configuration for the old SDK starter could contain:
spring.ai.openai-sdk.api-key=${OPENAI_API_KEY} spring.ai.openai-sdk.base-url=https://api.openai.com/v1 spring.ai.openai-sdk.chat.options.model=gpt-6-luna For Spring AI 2.0.2, the equivalent properties are:
spring.ai.openai.api-key=${OPENAI_API_KEY} spring.ai.openai.base-url=https://api.openai.com/v1 spring.ai.openai.chat.model=gpt-6-luna The prefix changes from spring.ai.openai-sdk to spring.ai.openai. Let’s use the flat chat.model property. The older chat.options.model spelling still works in 2.0.2, but it’s deprecated.
5.2. Updating Model Classes and Options
Code that referenced the separate module’s types needs these replacements:
- OpenAiSdkChatModel becomes OpenAiChatModel
- OpenAiSdkChatOptions becomes OpenAiChatOptions
The package changes from org.springframework.ai.openaisdk to org.springframework.ai.openai. This affects explicit model construction and programmatic options, even when the application’s prompt stays the same.
The former OpenAiSdkChatModel builder already used openAiClient() and options(), so these method names carry over when we rename the class.
Our service only uses ChatClient.Builder and ChatClient, so it doesn’t reference either SDK-specific class. The starter and configuration change while its summarization code remains unchanged.
6. Conclusion
In this article, we used Spring AI’s standard OpenAI starter to summarize a support request through the official Java SDK. The same service worked with Gemini after changing the endpoint, credentials, and model options.
For applications using the removed SDK module, migration involves the starter, property prefix, and SDK-suffixed classes. Keeping application code centered on ChatClient limits the changes needed in the service layer.
The complete example is available over on GitHub.
The post Using the Official OpenAI Java SDK With Spring AI first appeared on Baeldung.


