Spring AIを使用して質問に答えるKotlinアプリを作成する — チュートリアル
このチュートリアルでは、Spring AIを介してLLMに接続し、ベクトルデータベースにドキュメントを保存して、それらのドキュメントのコンテキストを使用して質問に答えるKotlinアプリを構築する方法を学びます。
このチュートリアルでは、以下のツールを使用します。
- Webアプリケーションを構成および実行するためのベースとして Spring Boot を使用。
- LLMとのやり取りおよびコンテキストに基づく検索を行うために Spring AI を使用。
- プロジェクトの生成およびアプリケーションロジックの実装に IntelliJ IDEA を使用。
- 類似性検索のためのベクトルデータベースとして Qdrant を使用。
- Qdrantをローカルで実行するために Docker を使用。
- LLMプロバイダーとして OpenAI を使用。
始める前に
IntelliJ IDEAの最新バージョンをダウンロードしてインストールし、Ultimateサブスクリプションを使用してください。
IntelliJ IDEA Ultimateサブスクリプションを使用していない場合、または別のIDEを使用している場合は、Webベースのプロジェクトジェネレーターを使用してSpring Bootプロジェクトを生成できます。
APIにアクセスするために、OpenAIプラットフォームでOpenAI APIキーを作成してください。
Qdrantベクトルデータベースをローカルで実行するために Docker をインストールしてください。
Dockerをインストールした後、ターミナルを開き、次のコマンドを実行してコンテナを起動します。
bashdocker run -p 6333:6333 -p 6334:6334 qdrant/qdrant
プロジェクトの作成
プロジェクトを生成する別の方法として、Spring Boot Webベースプロジェクトジェネレーターを使用することもできます。
IntelliJ IDEA Ultimate Editionで新しいSpring Bootプロジェクトを作成します。
IntelliJ IDEAで、File | New | Project を選択します。
左側のパネルで、New Project | Spring Boot を選択します。
New Project ウィンドウで以下のフィールドとオプションを指定します。
Name: springAIDemo
Language: Kotlin
Type: Gradle - Kotlin
このオプションは、ビルドシステムとDSLを指定します。
Package name: com.example.springaidemo
JDK: Java JDK
このチュートリアルでは Oracle OpenJDK version 21.0.1 を使用しています。 JDKがインストールされていない場合は、ドロップダウンリストからダウンロードできます。
Java: 17
Java 17がインストールされていない場合は、JDKドロップダウンリストからダウンロードできます。

すべてのフィールドを指定したことを確認し、Next をクリックします。
Spring Boot フィールドで最新の安定したSpring Bootバージョンを選択します。
このチュートリアルに必要な以下の依存関係を選択します。
- Web | Spring Web
- AI | OpenAI
- SQL | Qdrant Vector Database

Create をクリックしてプロジェクトを生成し、セットアップします。
IDEが新しいプロジェクトを生成して開きます。プロジェクトの依存関係のダウンロードとインポートには時間がかかる場合があります。
その後、Projectビューに以下の構造が表示されます。

生成されたGradleプロジェクトは、Mavenの標準ディレクトリレイアウトに対応しています。
main/kotlinフォルダの下に、アプリケーションに属するパッケージとクラスがあります。- アプリケーションの開始点は、
SpringAiDemoApplication.ktファイルのmain()メソッドです。
プロジェクト構成の更新
build.gradle.ktsGradleビルドファイルを以下のように更新します。kotlinplugins { kotlin("jvm") version "2.4.0" kotlin("plugin.spring") version "2.4.0" // 残りのプラグイン }springAiVersionを1.0.0に設定します。kotlinextra["springAiVersion"] = "1.0.0"Sync Gradle Changes ボタンをクリックして、Gradleファイルを同期します。
src/main/resources/application.propertiesファイルを以下のように更新します。text# OpenAI spring.ai.openai.api-key=YOUR_OPENAI_API_KEY spring.ai.openai.chat.options.model=gpt-4o-mini spring.ai.openai.embedding.options.model=text-embedding-ada-002 # Qdrant spring.ai.vectorstore.qdrant.host=localhost spring.ai.vectorstore.qdrant.port=6334 spring.ai.vectorstore.qdrant.collection-name=kotlinDocs spring.ai.vectorstore.qdrant.initialize-schema=truespring.ai.openai.api-keyプロパティにOpenAI APIキーを設定してください。SpringAiDemoApplication.ktファイルを実行してSpring Bootアプリケーションを起動します。 起動したら、ブラウザで Qdrant collections ページを開いて結果を確認します。
ドキュメントをロードおよび検索するためのコントローラーの作成
ドキュメントを検索し、Qdrantコレクションに保存するためのSpring @RestController を作成します。
src/main/kotlin/org/example/springaidemoディレクトリにKotlinSTDController.ktという名前の新しいファイルを作成し、以下のコードを追加します。kotlinpackage org.example.springaidemo // 必要なSpringおよびユーティリティクラスをインポートします import org.slf4j.LoggerFactory import org.springframework.ai.document.Document import org.springframework.ai.vectorstore.SearchRequest import org.springframework.ai.vectorstore.VectorStore import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import org.springframework.web.client.RestTemplate import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid @RestController @RequestMapping("/kotlin") class KotlinSTDController( private val restTemplate: RestTemplate, private val vectorStore: VectorStore, ) { private val logger = LoggerFactory.getLogger(this::class.java) @OptIn(ExperimentalUuidApi::class) @PostMapping("/load-docs") fun load() { // Kotlinドキュメントからドキュメントのリストをロードします val kotlinStdTopics = listOf( "collections-overview", "constructing-collections", "iterators", "ranges", "sequences", "collection-operations", "collection-transformations", "collection-filtering", "collection-plus-minus", "collection-grouping", "collection-parts", "collection-elements", "collection-ordering", "collection-aggregate", "collection-write", "list-operations", "set-operations", "map-operations", "read-standard-input", "opt-in-requirements", "scope-functions", "time-measurement", ) // ドキュメントのベースURL val url = "https://raw.githubusercontent.com/JetBrains/kotlin-web-site/refs/heads/master/docs/topics/" // URLから各ドキュメントを取得し、ベクトルストアに追加します kotlinStdTopics.forEach { topic -> val data = restTemplate.getForObject("$url$topic.md", String::class.java) data?.let { it -> val doc = Document.builder() // ランダムなUUIDでドキュメントを構築します .id(Uuid.random().toString()) .text(it) .metadata("topic", topic) .build() vectorStore.add(listOf(doc)) logger.info("Document $topic loaded.") } ?: logger.warn("Failed to load document for topic: $topic") } } @GetMapping("docs") fun query( @RequestParam query: String = "operations, filtering, and transformations", @RequestParam topK: Int = 2 ): List<Document>? { val searchRequest = SearchRequest.builder() .query(query) .topK(topK) .build() val results = vectorStore.similaritySearch(searchRequest) logger.info("Found ${results?.size ?: 0} documents for query: '$query'") return results } }SpringAiDemoApplication.ktファイルを更新して、RestTemplateビーンを宣言します。kotlinpackage org.example.springaidemo import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.context.annotation.Bean import org.springframework.web.client.RestTemplate @SpringBootApplication class SpringAiDemoApplication { @Bean fun restTemplate(): RestTemplate = RestTemplate() } fun main(args: Array<String>) { runApplication<SpringAiDemoApplication>(*args) }アプリケーションを実行します。
ターミナルで、ドキュメントをロードするために
/kotlin/load-docsエンドポイントにPOSTリクエストを送信します。bashcurl -X POST http://localhost:8080/kotlin/load-docsドキュメントがロードされたら、GETリクエストで検索できます。
Bashcurl -X GET http://localhost:8080/kotlin/docs
結果は Qdrant collections ページでも確認できます。
AIチャットエンドポイントの実装
ドキュメントがロードされたら、最後のステップは、Spring AIの検索拡張生成 (Retrieval-Augmented Generation: RAG) サポートを通じてQdrant内のドキュメントを使用して質問に答えるエンドポイントを追加することです。
KotlinSTDController.ktファイルを開き、以下のクラスをインポートします。kotlinimport org.springframework.ai.chat.client.ChatClient import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor import org.springframework.ai.chat.prompt.Prompt import org.springframework.ai.chat.prompt.PromptTemplate import org.springframework.web.bind.annotation.RequestBodyChatRequestデータクラスを定義します。kotlin// チャットクエリのリクエストペイロードを表します data class ChatRequest(val query: String, val topK: Int = 3)コントローラーのコンストラクタパラメータに
ChatClient.Builderを追加します。kotlinclass KotlinSTDController( private val chatClientBuilder: ChatClient.Builder, private val restTemplate: RestTemplate, private val vectorStore: VectorStore, )コントローラークラス内で、
ChatClientインスタンスを作成します。kotlin// シンプルなロギングアドバイザーを使用してチャットクライアントを構築します private val chatClient = chatClientBuilder.defaultAdvisors(SimpleLoggerAdvisor()).build()KotlinSTDController.ktファイルの最後に、以下のロジックで新しいchatAsk()エンドポイントを追加します。kotlin@PostMapping("/chat/ask") fun chatAsk(@RequestBody request: ChatRequest): String? { // プレースホルダーを使用してプロンプトテンプレートを定義します val promptTemplate = PromptTemplate( """ {query}. Please provide a concise answer based on the "Kotlin standard library" documentation. """.trimIndent() ) // プレースホルダーを実際の値で置き換えてプロンプトを作成します val prompt: Prompt = promptTemplate.create(mapOf("query" to request.query)) // クエリを関連ドキュメントで拡張するための検索アドバイザーを構成します val retrievalAdvisor = QuestionAnswerAdvisor.builder(vectorStore) .searchRequest( SearchRequest.builder() .similarityThreshold(0.7) .topK(request.topK) .build() ) .promptTemplate(promptTemplate) .build() // 検索アドバイザーと共にプロンプトをLLMに送信し、生成されたコンテンツを取得します val response = chatClient.prompt(prompt) .advisors(retrievalAdvisor) .call() .content() logger.info("Chat response generated for query: '${request.query}'") return response }アプリケーションを実行します。
ターミナルで、新しいエンドポイントにPOSTリクエストを送信して結果を確認します。
bashcurl -X POST "http://localhost:8080/kotlin/chat/ask" \ -H "Content-Type: application/json" \ -d '{"query": "What are the performance implications of using lazy sequences in Kotlin for large datasets?", "topK": 3}'
おめでとうございます!これで、OpenAIに接続し、Qdrantに保存されたドキュメントから取得したコンテキストを使用して質問に答えるKotlinアプリが完成しました。 別のクエリを試したり、他のドキュメントをインポートしたりして、さらなる可能性を探ってみてください。
完成したプロジェクトは、Spring AI demo GitHubリポジトリで確認できます。
次のステップ
- Kotlin AI Examples で他のSpring AIの例を探索する
- Spring BootとClaudeを使用したタスク管理アプリケーションの作成
