|

Spring AI 2.0入門:Spring Bootで生成AIアプリを作る

はじめに

生成AIアプリというと、Pythonで作るイメージを持つ人も多いかもしれません。
しかし、Java / Spring Boot の世界でも生成AIアプリを作るための仕組みが整ってきています。

その中心にあるのが Spring AI です。

Spring AI は、Spring Bootアプリケーションから OpenAI、Anthropic、Google GenAI、Amazon Bedrock、Mistral AI、DeepSeek、Ollama などのAIモデルを扱いやすくするためのプロジェクトです。Spring AI 2.0では、Spring Boot 4.0 / 4.1 と Spring Framework 7.0 を前提に設計され、ChatClient が利用者向けの中心的なAPIとして位置づけられています。

この記事では、Spring Boot + Spring AI 2.0 を使って、シンプルな生成AIチャットAPIを作る方法を解説します。

対象読者は次のような人です。

・Spring Bootで生成AIアプリを作ってみたい人
・JavaからAIモデルを呼び出したい人
・Spring AI 2.0の基本的な使い方を知りたい人
・ChatClientの実装例を見たい人
・まずはREST APIとしてAIチャットを作りたい人

Spring AIとは?

Spring AIは、Spring BootアプリケーションからAIモデルを扱うための抽象化レイヤーです。

通常、AIモデルを直接呼び出す場合は、各ベンダーのAPI仕様に合わせてHTTPリクエストを組み立てたり、レスポンスをパースしたりする必要があります。

Spring AIを使うと、Springらしい書き方でAIモデルを呼び出せます。

イメージとしては、次のような立ち位置です。

Spring Bootアプリ
    ↓
Spring AI
    ↓
OpenAI / Anthropic / Gemini / Bedrock / Ollama など

Spring AIの ChatClient は、Spring開発者に馴染みのある WebClient や RestClient に近い流れるようなAPIで、AIモデルとやり取りするためのインターフェースです。

今回作るもの

今回は、以下のようなREST APIを作ります。

POST /api/ai/chat

リクエスト例:

{
  "message": "Spring BootでAIアプリを作るメリットを教えて"
}

レスポンス例:

{
  "answer": "Spring BootでAIアプリを作るメリットは、既存のWeb APIやDB連携、認証、監視などの仕組みを活かしながら生成AI機能を組み込める点です..."
}

構成はシンプルです。

Controller
  ↓
ChatClient
  ↓
AIモデル

まずは「ちゃんと動く」ことを優先し、RAG、Vector DB、MCPなどは別記事で扱う前提にします。

前提条件

この記事では、以下を前提にします。

・Java 21以上
・Spring Boot 4系
・Spring AI 2.0系
・Gradle
・application.yml
・OpenAI Chat Modelを利用

Spring AIのOpenAI Chat向けドキュメントでは、Spring Bootの自動構成を有効にするために spring-ai-starter-model-openai を追加する例が示されています。

build.gradleの設定

まず、build.gradle に依存関係を追加します。

既存のSpring Bootプロジェクトがある場合は、以下の依存関係を追加してください。

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.ai:spring-ai-starter-model-openai'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Spring AIのバージョン管理にはBOMを使うのが安全です。Spring AI公式ドキュメントでも、依存関係の整合性を保つためにSpring AI BOMを利用することが案内されています。

GradleでBOMを明示する場合は、例えば次のようにします。

dependencyManagement {
    imports {
        mavenBom "org.springframework.ai:spring-ai-bom:2.0.0"
    }
}

Spring InitializrでSpring AI関連の依存を追加した場合は、必要なBOM設定が自動で入ることがあります。既存プロジェクトへ手動追加する場合は、依存関係のバージョンが揃っているか確認しておきましょう。

application.ymlの設定

次に、src/main/resources/application.yml を設定します。

spring:
  application:
    name: spring-ai-chat-sample

  ai:
    model:
      chat: openai
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        model: ${OPENAI_CHAT_MODEL:gpt-5-mini}

ポイントは、APIキーを直接書かないことです。

api-key: ${OPENAI_API_KEY}

このように環境変数から読み込む形にしておくと、GitにAPIキーを誤ってコミットするリスクを下げられます。Spring AIのOpenAIドキュメントでも、application.yml で spring.ai.openai.api-key: ${OPENAI_API_KEY} のように環境変数を参照する例が示されています。

WindowsのPowerShellで環境変数を設定する場合は、次のようにします。

$env:OPENAI_API_KEY="your-api-key"
$env:OPENAI_CHAT_MODEL="gpt-5-mini"

macOS / Linuxの場合は次のようにします。

export OPENAI_API_KEY="your-api-key"
export OPENAI_CHAT_MODEL="gpt-5-mini"

ChatClientとは?

Spring AIでまず覚えるべきなのが ChatClient です。

ChatClient は、AIモデルにプロンプトを送り、回答を受け取るための高レベルAPIです。Spring AIのドキュメントでは、Spring Bootの自動構成によって ChatClient.Builder がBeanとして作成され、それをControllerなどに注入して利用できると説明されています。

基本形は次のようになります。

String answer = chatClient
        .prompt()
        .user("Spring Bootについて教えて")
        .call()
        .content();

かなり読みやすいですね。

処理の流れはこうです。

prompt()  : AIに送るプロンプトを作り始める
user()    : ユーザー入力を設定する
call()    : AIモデルを呼び出す
content() : 生成された回答本文を取り出す

リクエスト・レスポンス用のDTOを作る

まずは、チャットAPIの入力と出力を表すクラスを作ります。

package com.example.demo.ai;

public record ChatRequest(
        String message
) {
}
package com.example.demo.ai;

public record ChatResponse(
        String answer
) {
}

Java recordを使うと、シンプルなDTOを短く書けます。

ChatControllerを作る

次に、REST APIを作成します。

package com.example.demo.ai;

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

@RestController
@RequestMapping("/api/ai")
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder
                .defaultSystem("""
                        あなたはSpring Bootに詳しいJavaエンジニアです。
                        回答は日本語で、初心者にもわかりやすく説明してください。
                        必要に応じて箇条書きやコード例を使ってください。
                        """)
                .build();
    }

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

        return new ChatResponse(answer);
    }
}

ここで重要なのは、コンストラクタで ChatClient.Builder を受け取っている点です。

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

Spring AIでは、Spring Bootの自動構成により ChatClient.Builder がBeanとして提供されます。そのため、自分でHTTPクライアントを組み立てたり、OpenAI用のクライアントを明示的に生成したりしなくても、ChatClient 経由でAIモデルを呼び出せます。

defaultSystemでAIの振る舞いを決める

defaultSystem は、AIに対する前提条件や振る舞いを指定するための設定です。

今回の例では、次のように指定しています。

.defaultSystem("""
        あなたはSpring Bootに詳しいJavaエンジニアです。
        回答は日本語で、初心者にもわかりやすく説明してください。
        必要に応じて箇条書きやコード例を使ってください。
        """)

これにより、毎回ユーザーが「日本語で答えて」「初心者向けに説明して」と書かなくても、回答の方向性を揃えやすくなります。

生成AIアプリでは、このSystemメッセージが意外と重要です。

例えば、業務アプリなら次のような指定が考えられます。

・社内ヘルプデスクとして回答する
・曖昧な場合は断定せず確認を促す
・個人情報は回答に含めない
・コード例はJava 21 / Spring Boot 4前提にする
・回答は300文字以内にする

最初はController内に書いてもよいですが、本格的なアプリでは設定ファイルやDBで管理するのもよいです。

実行してみる

アプリを起動します。

./gradlew bootRun

Windowsの場合は次のように実行します。

gradlew.bat bootRun

起動できたら、curlでAPIを呼び出してみます。

curl -X POST http://localhost:8080/api/ai/chat \
  -H "Content-Type: application/json" \
  -d '{"message":"Spring AIを使うメリットを3つ教えて"}'

レスポンス例です。

{
  "answer": "Spring AIを使うメリットは主に3つあります。1つ目は、Spring Bootの自動構成によりAIモデルとの接続設定が簡単になることです。2つ目は、ChatClientを使って統一的なAPIでAIモデルを呼び出せることです。3つ目は、既存のWeb API、DB、認証、監視などのSpring Boot資産と組み合わせやすいことです。"
}

これで、Spring Bootから生成AIモデルを呼び出す最小構成ができました。

Serviceクラスに分ける

Controllerにすべて書いても動きますが、実務ではServiceクラスに分けたほうが見通しがよくなります。

package com.example.demo.ai;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;

@Service
public class AiChatService {

    private final ChatClient chatClient;

    public AiChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder
                .defaultSystem("""
                        あなたはSpring Bootに詳しいJavaエンジニアです。
                        回答は日本語で、実務で使える説明をしてください。
                        """)
                .build();
    }

    public String chat(String message) {
        return chatClient
                .prompt()
                .user(message)
                .call()
                .content();
    }
}

Controller側は薄くできます。

package com.example.demo.ai;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/ai")
public class ChatController {

    private final AiChatService aiChatService;

    public ChatController(AiChatService aiChatService) {
        this.aiChatService = aiChatService;
    }

    @PostMapping("/chat")
    public ChatResponse chat(@RequestBody ChatRequest request) {
        String answer = aiChatService.chat(request.message());
        return new ChatResponse(answer);
    }
}

この形にしておくと、後から以下の処理を追加しやすくなります。

・入力チェック
・ログ出力
・利用回数制限
・会話履歴の保存
・RAG連携
・プロンプトテンプレート化
・モデル切り替え

入力チェックを追加する

生成AIアプリでは、ユーザー入力をそのままAIに渡すだけだと危険な場合があります。

まずは最低限、空文字や長すぎる入力を防ぎましょう。

package com.example.demo.ai;

public record ChatRequest(
        String message
) {
    public ChatRequest {
        if (message == null || message.isBlank()) {
            throw new IllegalArgumentException("message is required");
        }

        if (message.length() > 1000) {
            throw new IllegalArgumentException("message is too long");
        }
    }
}

実務では、Bean Validationを使って以下のように書くのもよいです。

package com.example.demo.ai;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record ChatRequest(
        @NotBlank
        @Size(max = 1000)
        String message
) {
}

Controller側では @Valid を付けます。

@PostMapping("/chat")
public ChatResponse chat(@Valid @RequestBody ChatRequest request) {
    String answer = aiChatService.chat(request.message());
    return new ChatResponse(answer);
}

よくあるエラーと対処

1. APIキーが設定されていない

エラー例です。

OpenAI API key is not set

対処として、環境変数を確認します。

echo $OPENAI_API_KEY

Windows PowerShellでは以下です。

echo $env:OPENAI_API_KEY

application.yml では、APIキーを直接書かず、環境変数から読む形にしましょう。

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

2. モデル名が間違っている

エラー例です。

model not found

対処として、application.yml のモデル名を確認します。

spring:
  ai:
    openai:
      chat:
        model: ${OPENAI_CHAT_MODEL:gpt-5-mini}

モデル名は時期や契約状態によって利用可否が変わることがあります。まずは公式ドキュメントや管理画面で利用可能なモデルを確認しましょう。

3. 依存関係が解決できない

エラー例です。

Could not find org.springframework.ai:spring-ai-starter-model-openai

対処として、Spring AI BOMが設定されているか確認します。

dependencyManagement {
    imports {
        mavenBom "org.springframework.ai:spring-ai-bom:2.0.0"
    }
}

また、Spring BootとSpring AIのバージョンの組み合わせも確認してください。Spring AI 2.0はSpring Boot 4.0 / 4.1、Spring Framework 7.0向けに設計されています。

4. temperature指定でエラーになる

モデルによっては temperature をサポートしない場合があります。

そのため、最初の設定では temperature を書かず、まずは最小構成で動かすのがおすすめです。

spring:
  ai:
    openai:
      chat:
        model: ${OPENAI_CHAT_MODEL:gpt-5-mini}

動作確認後、利用するモデルがサポートしているパラメータだけ追加していきましょう。

生成AIアプリで気をつけたいこと

Spring AIを使うと、かなり簡単に生成AIアプリを作れます。
ただし、本番利用を考える場合は、以下の点も重要です。

・APIキーをソースコードに書かない
・ユーザー入力の長さを制限する
・個人情報や機密情報を送信しない設計にする
・エラー時のレスポンスを整える
・利用回数や料金を監視する
・ログにプロンプトや個人情報をそのまま出さない
・タイムアウトやリトライを考える

特に業務アプリでは、「AIに何を送ってよいか」を設計段階で決めておくことが大切です。

次に学ぶとよいテーマ

今回の実装は、Spring AIの最小構成です。

ここから発展させるなら、次のテーマがおすすめです。

・ChatClientでプロンプトテンプレートを使う
・会話履歴を保持する
・RAGで社内ドキュメント検索を組み込む
・Vector Storeと連携する
・MCPサーバーを作って外部ツールをAIから呼び出す
・OllamaでローカルLLMを使う
・生成AI APIの利用料金を抑える

特に、Spring Bootエンジニアにとっては RAG と MCP は次のステップとして相性が良いです。

RAGを使うと、社内ドキュメントやDBの情報を元に回答できます。
MCPを使うと、AIから外部システムの機能を呼び出せるようになります。

まとめ

この記事では、Spring AI 2.0を使ってSpring Bootで生成AIチャットAPIを作る方法を紹介しました。

ポイントは以下です。

・Spring AIを使うとSpring BootからAIモデルを扱いやすい
・Spring AI 2.0ではChatClientが中心的なAPI
・Gradleではspring-ai-starter-model-openaiを追加する
・application.ymlではAPIキーを環境変数から読む
・ChatClient.Builderを注入してChatClientを作る
・prompt().user().call().content()でAIの回答を取得できる
・実務ではService分離、入力チェック、APIキー管理が重要

まずはこの記事のようなシンプルなチャットAPIを作り、そこからRAG、MCP、ツール呼び出し、会話履歴などへ広げていくのがおすすめです。

Spring Bootで既にWeb APIを作っている人にとって、Spring AIはかなり自然に導入できます。
既存のController、Service、設定ファイル、ログ、認証などの資産を活かしながら、生成AI機能を少しずつ追加できるのが大きなメリットです。

是非フォローしてください

最新の情報をお伝えします

類似投稿