mcpField
S
spring-ai

spring-ai

github.com/claude-dev-suite開発4648 回インストール6 日前に更新
リポジトリ

spring-ai について

生成 AI 機能を構築する Spring 開発者向けの Spring AI リファレンススキルです。チャット、構造化出力、ストリーミング、関数呼び出し、埋め込み、ベクトルストアを扱います。

主な機能

  1. 01ChatClient によるチャット呼び出し
  2. 02構造化出力とストリーミング
  3. 03関数呼び出し
  4. 04テキスト埋め込み
  5. 05ベクトルストアと RAG

活用シーン

  1. 01Spring サービスへのモデルチャットの追加
  2. 02構造化されたモデル応答の生成
  3. 03長い応答のストリーミング処理
  4. 04ベクトルストアを使った RAG クエリの構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill spring-ai

インストール後、Claude Code で/spring-aiを入力して読み込まれたか確認します。

同梱ファイルadvanced.md

詳細

Spring AI - クイックリファレンス

完全なリファレンス:画像生成、マルチモーダル/ビジョン、アドバイザー/ミドルウェア、テストパターン、プロンプトテンプレートについては、advanced.md を参照してください。

詳細な知識:包括的なドキュメントについては、technology に spring-ai を指定して mcp__documentation__fetch_docs を使用してください。

依存関係


<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>


<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
</dependency>


<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>


<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
</dependency>

設定

OpenAI
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-4o
          temperature: 0.7
          max-tokens: 1000
      embedding:
        options:
          model: text-embedding-3-small
Azure OpenAI
spring:
  ai:
    azure:
      openai:
        api-key: ${AZURE_OPENAI_KEY}
        endpoint: ${AZURE_OPENAI_ENDPOINT}
        chat:
          options:
            deployment-name: gpt-4o
            temperature: 0.7
Ollama(ローカル)
spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        options:
          model: llama3
          temperature: 0.7

基本的なチャット

@Service
@RequiredArgsConstructor
public class ChatService {

    private final ChatClient chatClient;

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

    // With system prompt
    public String chatWithContext(String message) {
        return chatClient.prompt()
            .system("You are a helpful assistant specialized in Spring Boot.")
            .user(message)
            .call()
            .content();
    }

    // With parameters
    public String chatWithParams(String message, String topic) {
        return chatClient.prompt()
            .system(s -> s.text("You are an expert in {topic}.")
                .param("topic", topic))
            .user(message)
            .call()
            .content();
    }
}
ChatClient ビルダー
@Configuration
public class ChatClientConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder
            .defaultSystem("You are a helpful AI assistant.")
            .defaultOptions(ChatOptionsBuilder.builder()
                .withTemperature(0.7)
                .withMaxTokens(1000)
                .build())
            .build();
    }
}

構造化出力

public record BookRecommendation(
    String title,
    String author,
    String genre,
    String summary,
    int rating
) {}

@Service
public class BookService {

    private final ChatClient chatClient;

    public BookRecommendation getRecommendation(String preferences) {
        return chatClient.prompt()
            .user("Recommend a book based on: " + preferences)
            .call()
            .entity(BookRecommendation.class);
    }

    public List<BookRecommendation> getRecommendations(String preferences, int count) {
        return chatClient.prompt()
            .user("Recommend " + count + " books based on: " + preferences)
            .call()
            .entity(new ParameterizedTypeReference<List<BookRecommendation>>() {});
    }
}

ストリーミング

@Service
public class StreamingChatService {

    private final ChatClient chatClient;

    public Flux<String> streamChat(String message) {
        return chatClient.prompt()
            .user(message)
            .stream()
            .content();
    }

    // WebFlux controller
    @GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamResponse(@RequestParam String message) {
        return streamChat(message);
    }
}

関数呼び出し

@Configuration
public class FunctionConfig {

    @Bean
    @Description("Get current weather for a location")
    public Function<WeatherRequest, WeatherResponse> currentWeather() {
        return request -> weatherService.getWeather(request.location());
    }

    @Bean
    @Description("Search for products by name")
    public Function<ProductSearchRequest, List<Product>> searchProducts() {
        return request -> productService.search(request.query(), request.maxResults());
    }
}

public record WeatherRequest(String location) {}
public record WeatherResponse(String location, double temperature, String conditions) {}

@Service
public class AssistantService {

    private final ChatClient chatClient;

    public String assistWithFunctions(String message) {
        return chatClient.prompt()
            .user(message)
            .functions("currentWeather", "searchProducts")
            .call()
            .content();
    }
}

埋め込み

@Service
@RequiredArgsConstructor
public class EmbeddingService {

    private final EmbeddingModel embeddingModel;

    public float[] getEmbedding(String text) {
        EmbeddingResponse response = embeddingModel.embedForResponse(List.of(text));
        return response.getResult().getOutput();
    }

    public List<float[]> getEmbeddings(List<String> texts) {
        EmbeddingResponse response = embeddingModel.embedForResponse(texts);
        return response.getResults().stream()
            .map(e -> e.getOutput())
            .toList();
    }
}

ベクトルストア(RAG)

設定
spring:
  ai:
    vectorstore:
      pgvector:
        dimensions: 1536
        index-type: HNSW
        distance-type: COSINE_DISTANCE
RAG クエリ
@Service
@RequiredArgsConstructor
public class RagService {

    private final VectorStore vectorStore;
    private final ChatClient chatClient;

    public String queryWithContext(String question) {
        // Retrieve relevant documents
        List<Document> relevantDocs = vectorStore.similaritySearch(
            SearchRequest.query(question)
                .withTopK(5)
                .withSimilarityThreshold(0.7)
        );

        // Build context
        String context = relevantDocs.stream()
            .map(Document::getContent)
            .collect(Collectors.joining("\n\n"));

        // Generate response with context
        return chatClient.prompt()
            .system("""
                You are a helpful assistant. Answer questions based on the provided context.
                If the answer is not in the context, say "I don't have information about that."

                Context:
                {context}
                """)
            .user(question)
            .call()
            .content();
    }
}
QuestionAnswerAdvisor
@Configuration
public class RagConfig {

    @Bean
    public ChatClient ragChatClient(ChatClient.Builder builder, VectorStore vectorStore) {
        return builder
            .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
            .build();
    }
}

// Usage is simple - advisor handles RAG automatically
@Service
public class SimpleRagService {

    private final ChatClient ragChatClient;

    public String answer(String question) {
        return ragChatClient.prompt()
            .user(question)
            .call()
            .content();
    }
}

ベストプラクティス

推奨事項非推奨事項
予測可能な結果を得るために構造化出力を使用する自由形式のテキストを手動で解析する
適切なエラー処理を実装するAPI の失敗を無視する
長い応答にはストリーミングを使用する大規模な生成処理をブロックする
可能な場合は埋め込みをキャッシュする埋め込みを繰り返し再生成する
適切なトークン上限を設定するトークン数を無制限にする

本番環境チェックリスト

  • API キーを安全に管理する(環境変数)
  • レート制限を実装する
  • エラー処理とリトライを設定する
  • トークン使用量を監視する
  • 必要に応じて応答をキャッシュする
  • ベクトルストアに適切なインデックスを作成する
  • 埋め込みの次元数に一貫性を持たせる
  • プロンプトインジェクションを防止する
  • コストを監視し、アラートを設定する
  • フォールバックモデルを設定する

このスキルを使用すべきでない場合

  • OpenAI/Anthropic の生 API - それぞれの SDK を直接使用してください
  • ML モデルのトレーニング - Python フレームワーク(PyTorch、TensorFlow)を使用してください
  • Spring 以外のアプリケーション - LangChain またはネイティブ SDK を使用してください
  • 単純なテキスト生成 - 些細なユースケースには過剰な場合があります

アンチパターン

アンチパターン問題解決策
API キーをハードコードするセキュリティリスク環境変数を使用する
トークン上限がないコストの急増max-tokens を適切に設定する
長いリクエストに同期処理を使うスレッドのブロックストリーミングを使用する
レート制限を無視するAPI エラー、利用停止バックオフ付きのリトライを実装する
埋め込みをキャッシュしない高コスト埋め込みをローカルにキャッシュする
プロンプトインジェクションの脆弱性セキュリティリスクユーザー入力をサニタイズする

トラブルシューティング(クイックガイド)

問題診断解決策
API キーが無効エラーメッセージを確認するOPENAI_API_KEY 環境変数を確認する
レート制限を超過した429 エラーリトライロジックを追加し、リクエスト数を減らす
大きなプロンプトでタイムアウトする接続タイムアウトストリーミングを使用し、タイムアウトを延長する
埋め込みの次元数が一致しないベクトルストアのエラー埋め込みモデルの次元数を一致させる
構造化出力に失敗するJSON 解析エラースキーマを簡素化し、例を追加する

リファレンスドキュメント

コメント