検索拡張生成

検索拡張生成 (RAG) は、長い形式のコンテンツ、事実の正確性、コンテキスト認識に苦労する大規模言語モデルの制限を克服するのに役立つ技術です。

Spring AI は、カスタム RAG フローを自分で構築したり、Advisor API を使用してすぐに使用できる RAG フローを使用したりできるモジュール式アーキテクチャを提供することで、RAG をサポートします。

概念セクションで検索拡張生成について詳しく学びます。

アドバイザー

Spring AI は、Advisor API を使用して一般的な RAG フローをすぐにサポートします。

QuestionAnswerAdvisor

ベクトルデータベースには、AI モデルが認識していないデータが格納されます。ユーザーの質問が AI モデルに送信されると、QuestionAnswerAdvisor はベクトルデータベースに対してユーザーの質問に関連するドキュメントを照会します。

ベクトルデータベースからのレスポンスはユーザーテキストに追加され、AI モデルがレスポンスを生成するためのコンテキストを提供します。

すでに VectorStore にデータをロードしていると仮定すると、QuestionAnswerAdvisor のインスタンスを ChatClient に提供することで、検索拡張生成 (RAG) を実行できます。

ChatResponse response = ChatClient.builder(chatModel)
        .build().prompt()
        .advisors(new QuestionAnswerAdvisor(vectorStore))
        .user(userText)
        .call()
        .chatResponse();

この例では、QuestionAnswerAdvisor は ベクトルデータベース内のすべてのドキュメントに対して類似性検索を実行します。検索するドキュメントの種類を制限するために、SearchRequest はすべての VectorStores 間で移植可能な SQL のようなフィルター式を使用します。

このフィルター式は、QuestionAnswerAdvisor の作成時に構成できるため、すべての ChatClient リクエストに常に適用されます。また、実行時にリクエストごとに提供することもできます。

しきい値が 0.8 である QuestionAnswerAdvisor のインスタンスを作成し、上位の 6 結果を返す方法を次に示します。

var qaAdvisor = new QuestionAnswerAdvisor(this.vectorStore,
        SearchRequest.builder().similarityThreshold(0.8d).topK(6).build());

動的フィルター式

FILTER_EXPRESSION アドバイザーコンテキストパラメーターを使用して、実行時に SearchRequest フィルター式を更新します。

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.builder().build()))
    .build();

// Update filter expression at runtime
String content = this.chatClient.prompt()
    .user("Please answer my question XYZ")
    .advisors(a -> a.param(QuestionAnswerAdvisor.FILTER_EXPRESSION, "type == 'Spring'"))
    .call()
    .content();

FILTER_EXPRESSION パラメーターを使用すると、指定された式に基づいて検索結果を動的にフィルタリングできます。

RetrievalAugmentationAdvisor (インキュベーション)

Spring AI には、独自の RAG フローを構築するために使用できる RAG モジュールのライブラリが含まれています。RetrievalAugmentationAdvisor は、モジュラーアーキテクチャに基づいて、最も一般的な RAG フローのすぐに使用できる実装を提供する実験的な Advisor です。

RetrievalAugmentationAdvisor は実験的な機能であり、将来のリリースで変更される可能性があります。

シーケンシャル RAG フロー

ナイーブ RAG
Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
        .documentRetriever(VectorStoreDocumentRetriever.builder()
                .similarityThreshold(0.50)
                .vectorStore(vectorStore)
                .build())
        .build();

String answer = chatClient.prompt()
        .advisors(retrievalAugmentationAdvisor)
        .user(question)
        .call()
        .content();

デフォルトでは、RetrievalAugmentationAdvisor は取得したコンテキストが空であることを許可しません。その場合、モデルはユーザークエリに応答しないように指示します。次のようにして空のコンテキストを許可できます。

Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
        .documentRetriever(VectorStoreDocumentRetriever.builder()
                .similarityThreshold(0.50)
                .vectorStore(vectorStore)
                .build())
        .queryAugmenter(ContextualQueryAugmenter.builder()
                .allowEmptyContext(true)
                .build())
        .build();

String answer = chatClient.prompt()
        .advisors(retrievalAugmentationAdvisor)
        .user(question)
        .call()
        .content();
高度な RAG
Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
        .queryTransformer(RewriteQueryTransformer.builder()
                .chatClientBuilder(chatClientBuilder.build().mutate())
                .build())
        .documentRetriever(VectorStoreDocumentRetriever.builder()
                .similarityThreshold(0.50)
                .vectorStore(vectorStore)
                .build())
        .build();

String answer = chatClient.prompt()
        .advisors(retrievalAugmentationAdvisor)
        .user(question)
        .call()
        .content();

モジュール

Spring AI は、論文 "モジュラー RAG: RAG システムをレゴのような再構成可能な フレームワークに変換する (英語) " で詳述されているモジュール性の概念に触発されたモジュラー RAG アーキテクチャを実装します。

WARNING

モジュラー RAG は実験的な機能であり、将来のリリースで変更される可能性があります。

事前取得

事前取得モジュールは、ユーザークエリを処理して、可能な限り最良の検索結果を実現するロールを担います。

クエリ変換

入力クエリを変換して検索タスクの効率を高め、不完全なクエリ、あいまいな用語、複雑な語彙、サポートされていない言語などの課題に対処するコンポーネント。

CompressionQueryTransformer

CompressionQueryTransformer は、大規模な言語モデルを使用して、会話履歴とフォローアップクエリを、会話の本質を捉えるスタンドアロンクエリに圧縮します。

このトランスフォーマーは、会話履歴が長く、フォローアップクエリが会話のコンテキストに関連している場合に役立ちます。

Query query = Query.builder()
        .text("And what is its second largest city?")
        .history(new UserMessage("What is the capital of Denmark?"),
                new AssistantMessage("Copenhagen is the capital of Denmark."))
        .build();

QueryTransformer queryTransformer = CompressionQueryTransformer.builder()
        .chatClientBuilder(chatClientBuilder)
        .build();

Query transformedQuery = queryTransformer.transform(query);

このコンポーネントで使用されるプロンプトは、ビルダーで使用可能な promptTemplate() メソッドを使用してカスタマイズできます。

RewriteQueryTransformer

RewriteQueryTransformer は、大規模な言語モデルを使用してユーザークエリを書き換え、ベクトルストアや Web 検索エンジンなどのターゲットシステムを照会するときに、より良い結果を提供します。

このトランスフォーマーは、ユーザークエリが冗長、曖昧、検索結果の品質に影響を与える可能性のある無関係な情報が含まれている場合に役立ちます。

Query query = new Query("I'm studying machine learning. What is an LLM?");

QueryTransformer queryTransformer = RewriteQueryTransformer.builder()
        .chatClientBuilder(chatClientBuilder)
        .build();

Query transformedQuery = queryTransformer.transform(query);

このコンポーネントで使用されるプロンプトは、ビルダーで使用可能な promptTemplate() メソッドを使用してカスタマイズできます。

TranslationQueryTransformer

TranslationQueryTransformer は、大規模な言語モデルを使用して、ドキュメントの埋め込みを生成するために使用される埋め込みモデルでサポートされているターゲット言語にクエリを変換します。クエリがすでにターゲット言語である場合は、変更されずに返されます。クエリの言語が不明な場合も、変更されずに返されます。

このトランスフォーマーは、埋め込みモデルが特定の言語でトレーニングされ、ユーザークエリが別の言語である場合に役立ちます。

Query query = new Query("Hvad er Danmarks hovedstad?");

QueryTransformer queryTransformer = TranslationQueryTransformer.builder()
        .chatClientBuilder(chatClientBuilder)
        .targetLanguage("english")
        .build();

Query transformedQuery = queryTransformer.transform(query);

このコンポーネントで使用されるプロンプトは、ビルダーで使用可能な promptTemplate() メソッドを使用してカスタマイズできます。

クエリ拡張

入力クエリをクエリのリストに拡張し、代替クエリ形式を提供したり、複雑な問題をより単純なサブクエリに分解したりすることで、クエリの形式が不適切などの課題に対処するコンポーネントです。

MultiQueryExpander

MultiQueryExpander は、大規模な言語モデルを使用してクエリを複数の意味的に多様なバリエーションに拡張し、さまざまな視点を捉えます。これは、追加のコンテキスト情報を取得したり、関連する結果を見つける可能性を高めたりできます。

MultiQueryExpander queryExpander = MultiQueryExpander.builder()
    .chatClientBuilder(chatClientBuilder)
    .numberOfQueries(3)
    .build();
List<Query> queries = expander.expand(new Query("How to run a Spring Boot app?"));

デフォルトでは、MultiQueryExpander は拡張クエリのリストに元のクエリを含めます。ビルダーの includeOriginal メソッドを使用してこの動作を無効にすることができます。

MultiQueryExpander queryExpander = MultiQueryExpander.builder()
    .chatClientBuilder(chatClientBuilder)
    .includeOriginal(false)
    .build();

このコンポーネントで使用されるプロンプトは、ビルダーで使用可能な promptTemplate() メソッドを使用してカスタマイズできます。

検索

検索モジュールは、ベクトルストアなどのデータシステムを照会し、最も関連性の高いドキュメントを取得するロールを担います。

検索エンジン、ベクトルストア、データベース、ナレッジグラフなどの基盤となるデータソースから Documents を取得するコンポーネント。

VectorStoreDocumentRetriever

VectorStoreDocumentRetriever は、入力クエリと意味的に類似するドキュメントをベクトルストアから取得します。メタデータ、類似度しきい値、上位 k の結果に基づくフィルタリングをサポートします。

DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
    .vectorStore(vectorStore)
    .similarityThreshold(0.73)
    .topK(5)
    .filterExpression(new FilterExpressionBuilder()
        .eq("genre", "fairytale")
        .build())
    .build();
List<Document> documents = retriever.retrieve(new Query("What is the main character of the story?"));

フィルター式は静的または動的にすることができます。動的フィルター式の場合は、Supplier を渡すことができます。

DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
    .vectorStore(vectorStore)
    .filterExpression(() -> new FilterExpressionBuilder()
        .eq("tenant", TenantContextHolder.getTenantIdentifier())
        .build())
    .build();
List<Document> documents = retriever.retrieve(new Query("What are the KPIs for the next semester?"));

ドキュメント結合

複数のクエリに基づいて複数のデータソースから取得したドキュメントを 1 つのドキュメントコレクションに結合するコンポーネントです。結合プロセスの一環として、重複するドキュメントや相互ランキング戦略も処理できます。

ConcatenationDocumentJoiner

ConcatenationDocumentJoiner は、複数のクエリに基づいて複数のデータソースから取得されたドキュメントを連結して、単一のドキュメントコレクションにまとめます。重複するドキュメントがある場合は、最初に出現したものが保持されます。各ドキュメントのスコアはそのまま保持されます。

Map<Query, List<List<Document>>> documentsForQuery = ...
DocumentJoiner documentJoiner = new ConcatenationDocumentJoiner();
List<Document> documents = documentJoiner.join(documentsForQuery);

回収後

取得後モジュールは、取得したドキュメントを処理して、可能な限り最良の生成結果を実現するロールを担います。

ドキュメントランキング

クエリとの関連性に基づいてドキュメントを順序付けおよびランク付けし、最も関連性の高いドキュメントをリストの先頭に表示して、途中で失われるなどの課題に対処するコンポーネント。

DocumentSelector とは異なり、このコンポーネントはリストからドキュメント全体を削除するのではなく、リスト内のドキュメントの順序 / スコアを変更します。DocumentCompressor とは異なり、このコンポーネントはドキュメントの内容を変更しません。

ドキュメントの選択

取得されたドキュメントのリストから無関係なドキュメントや冗長なドキュメントを削除し、モデルの中間損失やコンテキストの長さの制限などの課題に対処するコンポーネント。

DocumentRanker とは異なり、このコンポーネントはリスト内のドキュメントの順序 / スコアを変更せず、無関係なドキュメントや冗長なドキュメントを削除します。DocumentCompressor とは異なり、このコンポーネントはドキュメントの内容を変更せず、ドキュメント全体を削除します。

ドキュメント圧縮

各ドキュメントのコンテンツを圧縮して、取得した情報のノイズと冗長性を削減し、モデルによる中間損失やコンテキストの長さの制限などの課題に対処するコンポーネントです。

DocumentSelector とは異なり、このコンポーネントはリストからドキュメント全体を削除せず、ドキュメントの内容を変更します。DocumentRanker とは異なり、このコンポーネントはリスト内のドキュメントの順序 / スコアを変更しません。

世代

生成モジュールは、ユーザーのクエリと取得したドキュメントに基づいて最終的なレスポンスを生成するロールを担います。

クエリ拡張

入力クエリを追加データで拡張するためのコンポーネント。ユーザークエリに回答するために必要なコンテキストを大規模な言語モデルに提供できます。

ContextualQueryAugmenter

ContextualQueryAugmenter は、提供されたドキュメントのコンテンツからのコンテキストデータを使用してユーザークエリを拡張します。

QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder().build();

デフォルトでは、ContextualQueryAugmenter は取得されたコンテキストが空になることを許可しません。その場合、モデルはユーザークエリに応答しないように指示されます。

allowEmptyContext オプションを有効にすると、取得したコンテキストが空の場合でもモデルがレスポンスを生成できるようになります。

QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder()
        .allowEmptyContext(true)
        .build();

このコンポーネントで使用されるプロンプトは、ビルダーで使用可能な promptTemplate() および emptyContextPromptTemplate() メソッドを使用してカスタマイズできます。