KINTO Tech Blog
生成AI

Spring AIを試してみた

Cover Image for Spring AIを試してみた

はじめに

こんにちは。KINTOテクノロジーズ(以下KTC)プラットフォームグループ Platform Engineeringチームで内製ツールの開発・運用を担当している山田です。普段はアプリケーションエンジニアとして、JavaとSpring Bootを使ったバックエンドや、JavaScriptとReactを使ったフロントエンドでCMDB(Configuration Management Database)の開発をしています。ここ1年ほどは生成AIブームに乗り、CMDBにRAGやText-to-SQLを活用したチャットボットの開発にも取り組んでいます。

こちらはText-to-SQLについて書いた前回の記事です。ご興味ある方はぜひご覧ください!
https://blog.kinto-technologies.com/posts/2025-01-16-generativeAI_and_Text-to-SQL/

今回は生成AI関連で、2025年5月20日にGAされたSpring AIを試してみた内容をご紹介したいと思います。

Spring AIの概要

2025年5月20日にGAされたSpringエコシステムの一つで、生成AI関連のフレームワークです。生成AI分野ではPythonベースのLlamaIndexやLangChainが有名ですが、既存のSpringアプリケーションに生成AI機能を追加したい場合や、Javaで生成AI開発をやってみたい方にとっての選択肢になるかと思います。

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

検証内容

今回はSpring AIを使って、以下の2つの機能を実装してみました。

  1. チャット機能(LLM対話): AWS BedrockのClaude 3.7 Sonnetモデルを利用した対話機能
  2. Embedding機能: CohereのエンベディングモデルとChroma(ベクトルデータベース)を組み合わせた文書埋め込み・類似文書検索機能

技術スタック

  • Spring Boot 3.5.0
  • Java 21
  • Spring AI 1.0.0
  • Gradle
  • Chroma 1.0.0
  • AWS Bedrock
    • LLMモデル:Anthropic Claude 3.7 Sonnet
    • Embeddingモデル:Cohere Embed Multilingual v3

環境構築

依存関係の設定

まずはbuild.gradleにSpring AIを使うための依存関係を追加します。

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.5.0'
    id 'io.spring.dependency-management' version '1.1.7'
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

ext {
    set('springAiVersion', "1.0.0")
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.ai:spring-ai-starter-model-bedrock-converse'
    implementation 'org.springframework.ai:spring-ai-starter-model-bedrock'
    implementation 'org.springframework.ai:spring-ai-bedrock'
    implementation 'org.springframework.ai:spring-ai-starter-vector-store-chroma'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

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

アプリケーション設定

application.ymlでAWS Bedrockの認証情報やモデル選択、ベクトルストアの接続情報を設定します。

spring:
  application:
    name: spring-ai-sample
  
  ai:
    bedrock:
      aws:
        region: ap-northeast-1
        access-key: ${AWS_ACCESS_KEY_ID}
        secret-key: ${AWS_SECRET_ACCESS_KEY}
        session-token: ${AWS_SESSION_TOKEN}
      converse:
        chat:
          options:
            model: arn:aws:bedrock:ap-northeast-1:{account_id}:inference-profile/apac.anthropic.claude-3-7-sonnet-20250219-v1:0
      cohere:
        embedding:
          model: cohere.embed-multilingual-v3
    model:
      embedding: bedrock-cohere
    vectorstore:
      chroma:
        client:
          host: http://localhost
          port: 8000
        initialize-schema: true

設定はこれだけです。あとはアプリケーション内で必要なクラスを簡単にDIできるようになります。

実装例

1. 生成AI(LLM)との対話機能

Spring AIではChatClientインターフェースを使って、簡単にLLMとの対話を実装できます。

サービス層の実装

ChatServiceクラスでLLMとの対話機能を実装します。

@Service
public class ChatService {
    private final ChatClient chatClient;

    public ChatService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    public String generate(String message) {
        return this.chatClient.prompt(message).call().content();
    }
}

ChatClient.BuilderをDIすることで、設定ファイルに基づいたクライアントを自動的に構築できます。

コントローラーの実装

RESTコントローラーでAPIエンドポイントを提供します。

@RestController
public class ChatController {
    private final ChatService chatService;
    private final EmbeddingService embeddingService;

    public ChatController(ChatService chatService, EmbeddingService embeddingService) {
        this.chatService = chatService;
        this.embeddingService = embeddingService;
    }

    @PostMapping("/generate")
    public ResponseEntity<String> generate(@RequestBody ChatRequest request) {
        return ResponseEntity.ok(chatService.generate(request.getMessage()));
    }

}

これで/generateエンドポイントにメッセージをPOSTすると、Claude 3.7 Sonnetによる応答を受け取ることができます。

以下が呼び出し例です。

curl -X POST http://localhost:8080/generate -H "Content-Type: application/json" -d '{"message": "こんにちわわ"}'

こんにちは!何かお手伝いできることはありますか?

2. Embedding検索機能の実装

次に、ドキュメントをベクトル化して検索する機能を実装します。

Embeddingサービスの実装

このサービスでは、サンプルテキストをDocumentオブジェクトとしてベクトル化し、Chromaに保存します。そして「Spring」というクエリに対して類似度の高いドキュメントを検索します。この処理の裏側では、Cohere Embed Multilingual v3モデルによるテキストのベクトル変換が行われています。

@Service
public class EmbeddingService {
    private final VectorStore vectorStore;

    public EmbeddingService(VectorStore vectorStore) {
        this.vectorStore = vectorStore;
    }

    public List<Document> embed() {
        List<Document> documents = List.of(
            new Document("Spring AI is a framework for building AI applications with the familiar Spring ecosystem and programming model."),
            new Document("LlamaIndex is a data framework for LLM applications to ingest, structure, and access private or domain-specific data."),
            new Document("LangChain is a framework for developing applications powered by language models through composability.")
        );

        vectorStore.add(documents);
        return vectorStore.similaritySearch(SearchRequest.builder().query("Spring").topK(5).build());
    }
}

APIエンドポイントの実装

@GetMapping("/embedding")
public ResponseEntity<List<Document>> embedding() {
    return ResponseEntity.ok(embeddingService.embed());
}

この実装により、/embeddingエンドポイントにアクセスすると、サンプルドキュメントのベクトル化と検索が行われ、その結果が返されます。

以下が呼び出し例です。「Spring」という言葉が入ったドキュメントの類似度(score)が一番高い結果になっていますね。

curl http://localhost:8080/embedding

[
  {
    "id": "af885f07-20c9-4db4-913b-95406f1cb0cb",
    "text": "Spring AI is a framework for building AI applications with the familiar Spring ecosystem and programming model.",
    "media": null,
    "metadata": {
      "distance": 0.5593532
    },
    "score": 0.44064682722091675
  },
  {
    "id": "5a8b8071-b8d6-491e-b542-611d33e16159",
    "text": "LlamaIndex is a data framework for LLM applications to ingest, structure, and access private or domain-specific data.",
    "media": null,
    "metadata": {
      "distance": 0.6968217
    },
    "score": 0.3031783103942871
  },
  {
    "id": "336b3e07-1a70-4546-920d-c4869e77e4bb",
    "text": "LangChain is a framework for developing applications powered by language models through composability.",
    "media": null,
    "metadata": {
      "distance": 0.71094555
    },
    "score": 0.2890544533729553
  }
]

さいごに

簡単ではありますが、今回はSpring AIを使った生成AI機能についてご紹介しました。Spring AIを試してみて、Javaのシステムに生成AI関連の処理を組み込む場合には選択肢の一つになるかなと思いました。また、今回ご紹介したチャット機能やEmbedding検索機能を組み合わせることで、RAG機能も比較的簡単に実装できると感じています。

現時点では、生成AI関連の機能やエコシステムはLlamaIndexやLangChainといったPython系フレームワークの方が充実している印象ですが、Spring AIはリリースされたばかりなので今後の機能追加に期待したいと思います!

Facebook

関連記事 | Related Posts

We are hiring!

生成AIエンジニア/AIファーストG/東京・名古屋・大阪・福岡

AIファーストGについて生成AIの活用を通じて、KINTO及びKINTOテクノロジーズへ事業貢献することをミッションに2024年1月に新設されたプロジェクトチームです。生成AI技術は生まれて日が浅く、その技術を業務活用する仕事には定説がありません。

【データサイエンティスト】データサイエンスG/東京・名古屋・大阪

データ分析部について※データ分析部は、データサイエンスGが所属している部門です。クルマのサブスクというビジネスモデルを展開するKINTOでは、市場やお客様のニーズを捉え、最高の顧客体験を提供するために、マーケティング分析においても挑戦と創造が求められます。

イベント情報

Mobility Night #3 - マップビジュアライゼーション -