自分のドキュメントで春のAIとOpenAI GPTが有用になるようにRAGを作成する

『自分のドキュメントで春のAIとOpenAI GPTが有用になるようにRAGを活用する方法』

AIDocumentLibraryChatプロジェクトでは、Spring AIプロジェクトとOpenAIを使用してドキュメントライブラリ内での質問に対する回答を検索します。そのために、ドキュメントに対してRetrieval Augmented Generationが使用されます。

Retrieval Augmented Generation

プロセスは以下のようになります:

プロセスは以下のようになります:

  • ドキュメントのアップロード
  • ドキュメントをPostgresql DBに保存
  • ドキュメントを分割して埋め込みを作成
  • OpenAIの埋め込みモデルを呼び出して埋め込みを作成
  • ドキュメントの埋め込みをPostgresql Vector DBに保存

ドキュメントの検索:

  • 検索プロンプトの作成
  • OpenAIの埋め込みモデルを呼び出して検索プロンプトの埋め込みを作成
  • 最も近い埋め込み距離を持つドキュメントのためにPostgresql Vector DBをクエリ
  • ドキュメントのためにPostgresql DBをクエリ
  • 検索プロンプトとドキュメントのテキストチャンクを使用してプロンプトを作成
  • 検索プロンプトとドキュメントのテキストチャンクを基にしてGPTモデルに回答を要求し、回答を表示

ドキュメントのアップロード

アップロードされたドキュメントは、回答のソースドキュメントを持つためにデータベースに保存されます。ドキュメントテキストはチャンクに分割され、チャンクごとに埋め込みが作成されます。埋め込みはOpenAIの埋め込みモデルによって作成され、テキストチャンクを表す1500以上の次元のベクトルです。埋め込みは、テキストチャンクとソースドキュメントのIDを持つAIドキュメントに保存されます。

ドキュメントの検索では、検索プロンプトを取得し、Open AIの埋め込みモデルを使用して埋め込みに変換します。埋め込みは、ベクトルデータベース内で最も近い近傍ベクトルを検索するために使用されます。つまり、検索プロンプトと最も類似性のあるテキストチャンクの埋め込みです。AIDocument内のIDは、関連データベースのドキュメントを読み取るために使用されます。AIDocumentの検索プロンプトとテキストチャンクにより、ドキュメントプロンプトが作成されます。次に、OpenAI GPTモデルがプロンプトを呼び出して、検索プロンプトとドキュメントの文脈に基づいた回答を作成します。これにより、提供されたドキュメントに密接に基づいた回答が作成され、精度が向上します。GPTモデルの回答が返され、回答のソースを提供するドキュメントのリンクとともに表示されます。

アーキテクチャ

このプロジェクトのアーキテクチャは、Spring BootとSpring AIを中心に構築されています。Angular UIは、ドキュメントリストの表示、ドキュメントのアップロード、回答とソースドキュメントである検索プロンプトの提供のためのユーザーインターフェースを提供します。これは、レストインターフェースを介してSpring Bootバックエンドと通信します。Spring Bootバックエンドは、フロントエンド向けのレストコントローラーを提供し、OpenAIモデルおよびPostgresql Vectorデータベースとの通信にSpring AIを使用します。ドキュメントは、PostgresqlリレーショナルデータベースでJpaを使用して保存されます。Postgresqlデータベースは、リレーショナルデータベースとベクトルデータベースをDockerイメージで組み合わせたものです。

実装

フロントエンド

フロントエンドはAngularで構築された遅延読み込みのスタンドアロンコンポーネントに基づいています。遅延読み込みのスタンドアロンコンポーネントは、app.config.tsで設定されています:

この設定では、ルートを設定し、httpクライアントとアニメーションを有効にします。

遅延読み込みのルートはapp.routes.tsで定義されています:

‘loadChildren’では、’import(“…”).then((mod) => mod.XXX)’が提供されたパスからルートを遅延読み込みし、’mod.XXX’で定義された公開ルートを設定します。

遅延読み込みのルート’docsearch’は、index.tsを使用して定数をエクスポートします:

これにより、doc-search.routes.tsがエクスポートされます:

それは ‘DocSearchComponent’ へのルーティングを定義します。

ファイルのアップロードは、テンプレート doc-import.component.html の中の DocImportComponent で見つけることができます:

ファイルのアップロードは ‘<input type=”file” (change)=”onFileInputChange($event)”>’ タグで行われます。これはアップロード機能を提供し、各アップロード後に ‘onFileInputChange(…)’ メソッドを呼び出します。

‘Upload’ ボタンはクリック時に ‘upload()’ メソッドを呼び出してファイルをサーバーに送信します。

doc-import.component.ts はテンプレートのためのメソッドを持っています:

これはモジュールのインポートと注入された ‘DestroyRef’ を持つスタンドアロンコンポーネントです。

‘onFileInputChange(…)’ メソッドは、イベントパラメーターを取り、その ‘files’ プロパティを ‘files’ 定数に格納します。次に最初のファイルをチェックし、 ‘file’ コンポーネントプロパティに格納します。

‘upload()’ メソッドは ‘file’ プロパティをチェックし、ファイルのアップロード用の ‘FormData()’ を作成します。 ‘formData’ 定数にはデータ型(’file’)、コンテンツ(’this.file’)、およびファイル名(’this.file.name’)が追加されます。そして、 ‘documentService’ を使用して ‘FormData()’ オブジェクトをサーバーに送信します。 ‘takeUntilDestroyed(this.destroyRef)’ 関数は、コンポーネントが破棄された後に Rxjs パイプラインの購読を解除します。これにより、Angular でのパイプラインの購読解除が非常に便利になります。

バックエンド

バックエンドは、Spring AI フレームワークを使用した Spring Boot アプリケーションです。Spring AI は OpenAI モデルとベクトルデータベースリクエストへのリクエストを管理します。

Liquibase データベース設定

データベースの設定は Liquibase を使用して行われ、スクリプトは db.changelog-1.xml で見つけることができます:

changeset 4 では、Jpa ドキュメントエンティティのテーブルが作成され、プライマリキー ‘id’ が設定されます。コンテンツのタイプ/サイズは不明であり、そのため ‘blob’ に設定されます。changeset 5 では、Jpa エンティティのシーケンスが作成され、Hibernate 6 シーケンスのデフォルトプロパティが使用されます。

changeset 6 では、’uuid-ossp’ 拡張機能によって作成される ‘uuid’ 型のプライマリキー ‘id’ を持つ ‘vector_store’ テーブルが作成されます。 ‘content’ 列は、柔軟なサイズを持つ ‘text’(他のデータベースでは ‘clob’)の型です。 ‘metadata’ 列は、AIDocuments のメタデータを ‘json’ 型で格納します。 ’embedding’ 列は、OpenAI の次元数の埋め込みベクトルを格納します。

changeset 7 では、’embeddings’ 列の高速検索のためのインデックスが設定されます。Liquibase の ‘<createIndex …>’ のパラメーターが限られているため、 ‘<sql>’ を直接使用して作成されます。

Spring Boot / Spring AI 実装

フロントエンドのための DocumentController は次のようになります:

‘handleDocumentUpload(…)’ は、’/rest/document/upload’ パスで ‘documentService’ を使用してアップロードされたファイルを処理します。

‘getDocumentList()’ は、ドキュメントリストの取得リクエストを処理し、ドキュメントコンテンツを削除してレスポンスサイズを節約します。

‘getDocumentContent(…)’ は、ドキュメントコンテンツの取得リクエストを処理します。 ‘documentService’ でドキュメントを読み込み、 ‘DocumentType’ を ‘MediaType’ にマッピングします。そして、コンテンツとコンテンツタイプを返し、ブラウザはコンテンツタイプに基づいてコンテンツを開きます。

‘postDocumentSearch(…)’メソッドは、リクエストの内容を’SearchDto’オブジェクトに入れ、’documentService.queryDocuments(…)’の呼び出しによって生成されたAIの結果を返します。

DocumentServiceの’method ‘storeDocument(…)’は次のようになります。

‘storeDocument(…)’メソッドは、ドキュメントを関係データベースに保存します。そして、ドキュメントは’ByteArrayResource’に変換され、Spring AIの’TikaDocumentReader’で読み込まれてAIDocumentリストに変換されます。その後、AIDocumentリストは’splitToTokenLimit(…)’メソッドを使用してドキュメントをチャンクに分割し、メタデータマップの’stored document’の’id’と共に新しいAIDocumentsに変換されます。メタデータの’id’により、AIDocumentsに一致するドキュメントエンティティをロードすることが可能になります。次に、AIDocumentsの埋め込みが暗黙的に作成され、’documentVsRepository.add(…)’メソッドを呼び出してOpenAIの埋め込みモデルを呼び出し、埋め込みを持つAIDocumentsをベクトルデータベースに保存します。最後に結果が返されます。

‘queryDocument(…)’メソッドは次のようになります。

このメソッドは、ベクトルデータベースから’searchDto.getSearchString()’に最も一致するドキュメントを最初にロードします。そのために、OpenAIの埋め込みモデルを呼び出して検索文字列を埋め込みに変換し、その埋め込みを使用してベクトルデータベースから最も距離が近いAIDocumentsをクエリします(検索埋め込みとデータベース埋め込みの間の距離)。その後、最も距離が近いAIDocumentは’mostSimilar’変数に保存されます。次に、ドキュメントのチャンクのすべてのAIDocumentは、メタデータの’id’を使用してドキュメントエンティティの’id’と一致させることで収集されます。 ‘systemMessage’は’documentChunks’または’mostSimilar’の内容で作成されます。 ‘getSystemMessage(…)’メソッドはこれらを受け取り、contentChunksをOpenAI GPTモデルが扱えるサイズに切り取り、’Message’を返します。その後、’systemMessage’と’userMessage’は’prompt’に変換され、’aiClient.generate(prompt)’でOpenAi GPTモデルに送信されます。その後、AIの回答が利用可能になり、ドキュメントエンティティは’mostSimilar’ AIDocumentのメタデータのidを使用してロードされます。 ‘AiResult’は検索文字列、GPTの回答、ドキュメントエンティティを含んで作成され、返されます。

Spring AIの’vector database repository DocumentVsRepositoryBean‘は次のようになります。

このリポジトリには’vectorStore’プロパティがあり、ベクトルデータベースにアクセスするために使用されます。これはコンストラクタで注入されたパラメータを使用して’new PgVectorStore(…)’の呼び出しで作成されます。PgVectorStoreクラスは、Postgresqlベクトルデータベース拡張として提供されます。それには、OpenAIの埋め込みモデルを使用する’embeddingClient’とデータベースにアクセスする’jdbcTemplate’があります。

‘add(…)’メソッドは、OpenAIの埋め込みモデルを呼び出し、AIDocumentsをベクトルデータベースに追加します。

‘retrieve(…)’メソッドは、ベクトルデータベースから最も距離が近い埋め込みをクエリします。

結論

Angularにより、フロントエンドの作成が容易になりました。遅延読み込みを使用したスタンドアロンコンポーネントにより、初期ロードを小さくすることができました。Angular Materialコンポーネントは、実装に大いに役立ち、使いやすいです。

Spring BootとSpring AIにより、大規模な言語モデルの使用が容易になりました。Spring AIは、埋め込みの作成を隠し、AIDocumentsをベクトルデータベースに格納するための使いやすいインターフェースを提供しています(複数のデータベースをサポートしています)。最も近いAIDocumentsを読み込むための検索プロンプトの埋め込みも自動的に行われ、ベクトルデータベースのインターフェースはシンプルです。Spring AIのプロンプトクラスは、OpenAI GPTモデルのプロンプト作成も簡単にします。モデルの呼び出しは注入された’aiClient’を使用して行われ、結果が返されます。

Spring AIは、Springチームによる非常に優れたフレームワークです。実験的バージョンでは問題はありませんでした。

Spring AIを使用することで、大規模な言語モデルを自分自身のドキュメントで簡単に使用することができます。

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more