ApsaraDB RDS for PostgreSQL は、Qwen やテキスト埋め込みモデルなど、Alibaba Cloud Model Studio の高度なモデルを統合する rds_ai 拡張機能のサポートを導入しました。このトピックでは、SQL 文を実行してデータベース内で Retrieval-Augmented Generation (RAG) を実装するために rds_ai 拡張機能を使用する方法について説明します。
前提条件
RDS インスタンスは PostgreSQL 16 を実行している。
RDS インスタンスはマイナーエンジンバージョン 20241230 以降を実行している。
マイナーエンジンバージョンをアップグレードするには、「マイナーエンジンバージョンを更新する」をご参照ください。
RDS インスタンスに特権アカウントが作成されている。詳細については、「アカウントを作成する」をご参照ください。
Alibaba Cloud Model Studio がアクティブ化されており、モデルを呼び出すための API キーが利用可能である。詳細については、「API キーを取得する」をご参照ください。
RDS インスタンスのネットワークが外部モデルにアクセスできるように構成されている。詳細については、「ネットワーク構成」をご参照ください。
ソリューションの概要
このトピックで説明するソリューションは、コーディングなしで RAG を実装したい単純なシナリオに最適です。
このソリューションを使用すると、SQL 文を実行することで RAG ベースの操作を効率的に実装できます。 RAG の専門家である必要はなく、RAG フレームワーク、ランタイム環境、または複雑なコンポーネントの O&M について心配する必要もありません。
このソリューションには、次の主要な段階が含まれます。
ドキュメントのチャンク化: SQL 文を実行して、ドキュメントを複数のチャンクに分割します。
テキスト埋め込み: rds_ai を使用して、テキストを埋め込みと tsvector に変換します。
マルチモーダル検索: rds_ai を使用して、埋め込みやキーワードなど、さまざまなディメンションから情報を取得します。
結果の再ランク付け: rds_ai を使用して、関連性の最適化のために検索結果を再ランク付けします。
大規模言語モデル (LLM) の呼び出し: rds_ai を使用して、RAG ベースの Q&A のために LLM を呼び出します。
ステップ 1: rds_ai をインストールして構成する
rds_ai 拡張機能をインストールします。
ApsaraDB RDS コンソールの [インスタンス] ページに移動します。 上部のナビゲーションバーで、RDS for PostgreSQL インスタンスが存在するリージョンを選択し、インスタンスリストで RDS インスタンスの ID をクリックします。
左側のナビゲーションウィンドウで、[プラグイン] をクリックします。
[拡張機能マーケットプレイス] タブで、rds_ai セクションの [インストール] をクリックします。
表示されたダイアログボックスで、データベースとアカウントを選択し、[インストール] をクリックします。
インスタンスの状態が [インスタンスのメンテナンス中] から [実行中] に変わるまで待ちます。
説明インストールには約 1 分かかります。 ページを更新してインスタンスの状態を確認できます。
RDS for PostgreSQL インスタンスに接続する、データベースの public スキーマで rds_ai 拡張機能を構成します。
すべてのデフォルトモデルを呼び出すために使用される API キーを構成します。
-- rds_ai.model_list で指定されたすべてのモデルを呼び出すために使用される API キーを構成します。 SELECT rds_ai.update_model(model_name,'token','sk-****') FROM rds_ai.model_list;rds_ai 拡張機能は、pgsql-http 拡張機能に基づいてモデルをリモートで呼び出します。 そのため、長時間実行される呼び出しを中断するためにタイムアウト設定を構成する必要があります。
重要次のタイムアウト設定は現在のセッションでのみ使用できます。 新しいセッションを確立するときに、再度構成する必要があります。
-- リクエストのタイムアウト期間をミリ秒単位で構成します。 SET http.timeout_msec TO 200000; SELECT http.http_set_curlopt('CURLOPT_TIMEOUT', '200000'); -- 接続のタイムアウト期間を構成します。 SELECT http.http_set_curlopt('CURLOPT_CONNECTTIMEOUT_MS', '200000');
ステップ 2: RAG のデータを準備する
SQL を使用してナレッジベースのドキュメントデータをデータベースに挿入します。 挿入する前に、テキスト内の特殊文字をエスケープします。 たとえば、\n を使用して改行を置き換えます。
ドキュメントデータを格納する doc という名前のテーブルと、チャンクを格納する chunk という名前のテーブルを作成します。 次に、2 つのテーブルにインデックスを作成します。
CREATE TABLE doc ( id SERIAL PRIMARY KEY, title VARCHAR(255), content TEXT ); CREATE TABLE chunk ( id SERIAL PRIMARY KEY, doc_id INTEGER NOT NULL, text TEXT, embedding VECTOR(1024), ts_vector_extra tsvector ); -- 作成されたテーブルにインデックスを作成します。 CREATE INDEX idx_doc_id ON chunk (doc_id); CREATE INDEX ON chunk USING hnsw (embedding vector_cosine_ops); CREATE INDEX chunk_text_gin ON chunk USING gin (ts_vector_extra); CREATE INDEX ON chunk USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);split_text 関数を作成して、長いテキストを固定長でチャンクに分割し、チャンクのオーバーラップ長を指定します。 この関数は参照用です。 複雑なテキストを分割するには、専用のテキストチャンク化フレームワークを使用することをお勧めします。
CREATE OR REPLACE FUNCTION split_text( input_text TEXT, chunk_size INT, chunk_overlap INT ) RETURNS SETOF TEXT AS $$ DECLARE current_idx INT; start_idx INT; chunk TEXT; BEGIN -- オーバーラップ長がチャンク長を超える場合の例外を処理します。 IF chunk_overlap >= chunk_size THEN RAISE EXCEPTION 'chunk_overlap must be less than chunk_size'; END IF; current_idx := 1; LOOP -- 開始位置を指定します。 start_idx := current_idx - chunk_overlap; IF start_idx < 1 THEN start_idx := 1; END IF; chunk := substr(input_text, start_idx, chunk_size); IF chunk IS NULL OR length(chunk) = 0 THEN EXIT; END IF; RETURN NEXT chunk; current_idx := current_idx + chunk_size - chunk_overlap; END LOOP; END; $$ LANGUAGE plpgsql;トリガーを作成して、ドキュメントデータが doc テーブルに挿入されている間に、分割データが自動的に chunk テーブルに挿入され、埋め込みと tsvector に変換されるようにします。
ドキュメントデータが複雑でチャンクに分割するのが難しい場合は、「ステップ 3: ドキュメントデータをバッチで埋め込みに変換する」を参照して、データをバッチで埋め込みに変換します。
-- doc テーブルにデータが追加または削除されたときに、split_text 関数を自動的に実行して分割データを chunk テーブルに挿入するトリガーを作成します。 CREATE OR REPLACE FUNCTION insert_into_chunk() RETURNS TRIGGER AS $$ BEGIN INSERT INTO chunk (doc_id, text) SELECT NEW.id, result FROM split_text(NEW.content, 300, 50) AS result; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER after_insert_doc AFTER INSERT ON doc FOR EACH ROW EXECUTE FUNCTION insert_into_chunk(); CREATE OR REPLACE FUNCTION delete_from_chunk() RETURNS TRIGGER AS $$ BEGIN DELETE FROM chunk WHERE doc_id = OLD.id; RETURN OLD; END; $$ LANGUAGE plpgsql; CREATE TRIGGER after_delete_doc AFTER DELETE ON doc FOR EACH ROW EXECUTE FUNCTION delete_from_chunk(); -- chunk テーブルのチャンクを埋め込みに変換するために rds_ai.embed 関数を自動的に実行するトリガーを作成します。 CREATE OR REPLACE FUNCTION update_chunk_embedding() RETURNS TRIGGER AS $$ BEGIN NEW.embedding := rds_ai.embed(NEW.text)::vector; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER set_chunk_embedding BEFORE INSERT OR UPDATE ON chunk FOR EACH ROW EXECUTE FUNCTION update_chunk_embedding(); -- キーワードベースの検索のために chunk テーブルのチャンクを tsvector に自動的に変換するトリガーを作成します。 CREATE TRIGGER embedding_tsvector_update BEFORE UPDATE OR INSERT ON chunk FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger( 'ts_vector_extra', 'pg_catalog.english', 'text' );ナレッジベースのドキュメントデータを doc テーブルに挿入します。 ステートメントのデータは参照用です。
INSERT INTO doc (title, content) VALUES ('A Brief History of PostgreSQL', 'The object-relational database management system now known as PostgreSQL is derived from the POSTGRES package written at the University of California, Berkeley. After more than two decades of development, PostgreSQL is the most advanced open-source database available in the world.\n\n2.1. The POSTGRES Project at Berkeley\nThe POSTGRES project, led by Professor Michael Stonebraker, was sponsored by the Defense Advanced Research Projects Agency (DARPA), the Army Research Office (ARO), the National Science Foundation (NSF), and ESL, Inc. The implementation of POSTGRES began in 1986. The original concepts of the system are detailed in [ston86]. The initial data model definition is found in [rowe87]. The design of the rule system at that time is described in [ston87a]. The theoretical foundation and architecture of the storage manager are described in detail in [ston87b].\n\nSince then, POSTGRES has undergone several major version updates. The first demonstration system was available in 1987 and was exhibited at the ACM-SIGMOD conference in 1988. Version 1 was released in June 1989 (see [ston90a]) for some external users. In response to criticism of the first rule system ([ston89]), the rule system was redesigned ([ston90b]), and version 2, using the new rule system, was released in June 1990. Version 3 appeared in 1991, adding support for multiple storage managers and improving the query executor and rewriting the rule system. Subsequent versions, until the release of Postgres95 (see below), focused mainly on portability and reliability.\n\nPOSTGRES has been used to implement many different research and production applications. These applications include a financial data analysis system, a jet engine performance monitoring package, an asteroid tracking database, a medical information database, and some geographic information systems. POSTGRES has also been used by many universities for teaching purposes. Finally, Illustra Information Technologies (later merged into Informix, which is now owned by IBM) commercialized the code. In late 1992, POSTGRES became the primary data manager for the Sequoia 2000 scientific computing project.\n\nIn 1993, the number of external users nearly doubled. As the number of users increased, the time spent on source code maintenance increased and took up too much time that should have been used for database research. To reduce the support burden, the POSTGRES project at Berkeley officially ended at version 4.2.\n\n2.2. Postgres95\nIn 1994, Andrew Yu and Jolly Chen added an SQL language interpreter to POSTGRES. They subsequently released the source code under the new name Postgres95 on the Internet for everyone to use, becoming the open-source successor to the original POSTGRES Berkeley code.\n\nThe source code of Postgres95 is entirely ANSI C, and the code size was reduced by 25%. Many internal modifications improved performance and maintainability. The 1.0.x version of Postgres95 was about 30-50% faster than version 4.2 of POSTGRES when running the Wisconsin Benchmark test. In addition to fixing some bugs, the following are some major improvements:\n\nThe original query language PostQUEL was replaced by SQL (implemented on the server side). The interface library libpq was named after PostQUEL. Before PostgreSQL, subqueries were not supported (see below), but they could be simulated in Postgres95 by user-defined SQL functions. Aggregate functions were re-implemented. Support for GROUP BY query clauses was also added.\n\nA new program for interactive SQL queries using the Readline of GNU was added (psql). This program largely replaced the old monitor program.\n\nA new frontend library (libpgtcl) was added to support Tcl-based clients. A sample shell (pgtclsh) provided new Tcl commands for interaction between Tcl programs and the Postgres95 server.\n\nThe interface for large objects was completely rewritten. The inversion file system was removed, retaining inversion as the only mechanism for storing large objects.\n\nThe instance-level rule system was removed. However, rules still exist in the form of rewrite rules.\n\nA brief tutorial introducing SQL and Postgres95 features was added to the released source code.\n\nPostgres95 could be compiled using unpatched GCC (fixing double-precision data alignment issues).\n\n\n2.3. PostgreSQL\nBy 1996, it was clear that the name Postgres95 was outdated. We chose a new name, PostgreSQL, to reflect the relationship between the original POSTGRES and the latest version with SQL capabilities. The version number also started from 6.0, returning to the sequence initially started by the Berkeley POSTGRES project.\n\nMany people continue to use Postgres to refer to PostgreSQL (now rarely in all uppercase letters) due to tradition or easier pronunciation. This usage is widely accepted as a nickname or alias.\n\nThe development of Postgres95 focused on identifying and understanding existing issues in the backend code. The development of PostgreSQL shifted to some controversial features and functions, with work in all areas being carried out simultaneously.\n\n Changes to PostgreSQL since then can be found in Appendix E.'), ('Overview of MySQL Database Management System', 'MySQL は最も人気のあるオープンソースの SQL データベース管理システムであり、MySQL AB によって開発、リリース、およびサポートされています。 MySQL AB は、複数の MySQL 開発者によって設立された営利企業です。 オープンソースの価値観、手法、そして成功したビジネスモデルを組み合わせた、第 2 世代のオープンソース企業です。\n\nMySQL の Web サイト (http://www.mysql.com/) では、MySQL と MySQL に関する最新情報が提供されています。\n\n· MySQL はデータベース管理システムです。\n\nデータベースは、構造化されたデータのコレクションです。 簡単な買い物リストから美術館、企業ネットワークの膨大な情報まで、あらゆるものがデータベースになり得ます。 データベースにデータを追加したり、コンピューターデータベースに格納されているデータにアクセスして処理したりするには、MySQL サーバーなどのデータベース管理システムを使用する必要があります。 コンピューターは大量のデータを処理するのに理想的なツールであるため、データベース管理システムは、スタンドアロンユーティリティとして、または他のアプリケーションのコンポーネントとして、コンピューティングにおいて重要な中心的役割を果たします。\n\nMySQL はリレーショナルデータベース管理システムです。\n\nリレーショナルデータベースは、すべてのデータを 1 つの大きなリポジトリに入れるのではなく、異なるテーブルにデータを格納します。 これにより、速度と柔軟性が向上します。 MySQL の SQL は、構造化照会言語を指します。 SQL は、ANSI/ISO SQL 標準で定義されている、データベースにアクセスするために最も一般的に使用される標準化された言語です。 SQL 標準は 1986 年以降進化しており、いくつかのバージョンがあります。 このマニュアルでは、SQL-92 は 1992 年にリリースされた標準を指し、SQL:1999 は 1999 年にリリースされた標準を指し、SQL:2003 は現在のバージョンの標準を指します。 SQL 標準という用語は、SQL 標準の現在のバージョンを指すために使用します。\n\nMySQL ソフトウェアはオープンソースソフトウェアです。\n\nオープンソースとは、誰でもソフトウェアを使用および変更できることを意味します。 誰でもインターネットから MySQL ソフトウェアを無料でダウンロードできます。 必要に応じて、ソースコードを調べて、ニーズに合わせて適切な変更を加えることができます。 MySQL ソフトウェアは GPL (GNU 一般公的使用許諾) (http://www.mysql.com/company/legal/licensing/) の下でライセンスされています。\n\nMySQL データベースサーバーは高速で信頼性が高く、使いやすいです。\n\n探しているものが見つかった場合は、試してみてください。 MySQL サーバーには、ユーザーとの緊密な協力によって開発された一連の実用的な機能もあります。 ベンチマークホームページでは、MySQL サーバーと他のデータベースマネージャーの比較結果を提供しています。 7.1.4 MySQL ベンチマークスイートを参照してください。\n\nMySQL サーバーは当初、大規模なデータベースを処理するために開発されたもので、既存のソリューションよりも高速です。 長年にわたり、多くの要求の厳しい本番環境で正常に使用されてきました。 MySQL は常に進化していますが、MySQL サーバーは現在、豊富で便利な機能を提供しています。 接続性、速度、セキュリティに優れているため、MySQL はインターネット上のデータベースへのアクセスに非常に適しています。\n\nMySQL サーバーは、クライアント/サーバーモードまたは組み込みシステムで動作します。\n\nMySQL データベースソフトウェアは、さまざまなバックエンドをサポートするマルチスレッド SQL サーバー、いくつかの異なるクライアントプログラムとライブラリ、多数の管理ツール、および広範なアプリケーションプログラミングインターフェイス (API) で構成されるクライアント/サーバーシステムです。\n\nMySQL サーバーを、アプリケーションにリンクできる組み込みマルチスレッドライブラリとして提供することもできます。これにより、より小さく、より高速で、より管理しやすい製品が実現します。\n\n大量の共有 MySQL ソフトウェアが利用可能です。\n\nお気に入りのアプリケーションと言語が MySQL データベースサーバーをサポートしている可能性が非常に高いです。\n\nMySQL の公式の発音は My Ess Que Ell (マイシークェルではなく) ですが、マイシークェルまたはその他のローカルな方法で発音しても構いません。'), ('What is SQL Server?', 'Microsoft SQL Server は、リレーショナルデータベース管理システム (RDBMS) です。 アプリケーションとツールは SQL Server インスタンスまたはデータベースに接続し、Transact-SQL (T-SQL) を使用して通信します。\n\nデプロイメントオプション\nSQL Server は Windows または Linux にインストールしたり、Linux コンテナにデプロイしたり、Azure 仮想マシンまたはその他の仮想マシンプラットフォームにデプロイしたりできます。 以前にボックス製品として参照していた可能性があります。\n\nサポートされている SQL Server のバージョンはライセンス契約によって異なりますが、このドキュメントでは、SQL Server 2016 (13.x) 以降のバージョンについて説明します。 SQL Server 2014 (12.x) 以前のバージョンのドキュメントについては、以前のバージョンの SQL Server のドキュメントを参照してください。 現在サポートされている SQL Server のバージョンを確認するには、SQL Server のサポート終了オプションを参照してください。\n\n次の製品とサービスも、基盤となる SQL Server データベースエンジンを使用します。\n\nAzure SQL Database\nAzure SQL Managed Instance\nMicrosoft Analytics Platform System (PDW)\nAzure Synapse Analytics\nAzure SQL Edge\nWindows 上のさまざまなバージョンの SQL Server でサポートされている機能のリストについては、以下を参照してください。\n\nSQL Server 2022 のバージョンとサポートされている機能\nSQL Server 2019 のバージョンとサポートされている機能\nSQL Server 2017 でサポートされているバージョンと機能\nSQL Server 2016 でサポートされているバージョンと機能\nSQL Server のコンポーネントとテクノロジ\nこのセクションでは、SQL Server で使用可能な主要なテクノロジをいくつか紹介します。\n\nコンポーネント\t説明\nデータベースエンジン\tデータベースエンジンは、データを格納、処理、および保護するための中核サービスです。 データベースエンジンは、企業内で最も要求の厳しいデータ消費アプリケーションの要件を満たすために、制御されたアクセスとトランザクション処理を提供します。 データベースエンジンは、業務継続性を維持するために、業務継続性とデータベースリカバリ (SQL Server) の包括的なサポートも提供します。\nMachine Learning Services (MLS)\tSQL Server Machine Learning Services は、一般的な R 言語と Python 言語を使用して、機械学習を企業のワークフローに統合することをサポートします。\n\nMachine Learning Services (データベース内) は R と Python を SQL Server と統合し、ユーザーはストアドプロシージャを呼び出すことで、モデルを簡単に生成、再トレーニング、およびスコアリングできます。 Machine Learning Server は、R と Python のエンタープライズレベルのサポートを提供し、ユーザーは SQL Server なしでそれらを使用できます。\nIntegration Services (SSIS)\tSQL Server Integration Services は、データウェアハウスの ETL (抽出、変換、書き出し) 処理のためのパッケージなど、高パフォーマンスのデータ統合ソリューションを構築するためのプラットフォームです。\nAnalysis Services (SSAS)\tSQL Server Analysis Services は、個人、チーム、および企業のビジネスインテリジェンスのための分析データプラットフォームおよびツールセットです。 サーバーとクライアントの設計者は、Power Pivot、Excel、および SharePoint Server 環境を使用して、従来の OLAP ソリューション、新しい表形式モデリングソリューション、セルフサービス分析とコラボレーションをサポートします。 Analysis Services にはデータマイニングも含まれており、大量のデータに隠されているパターンと関係を発見できます。\nReporting Services (SSRS)\tSQL Server Reporting Services は、Web 対応のエンタープライズレベルのレポート機能を提供します。 ユーザーは、複数のデータソースからコンテンツを抽出するレポートを作成し、さまざまな形式でレポートを公開し、セキュリティとサブスクリプションを一元管理できます。\nレプリケーション\tSQL Server レプリケーションは、あるデータベースから別のデータベースにデータとデータベースオブジェクトをコピーおよび配布し、データベース間で同期して整合性を維持するための一連のテクノロジです。 レプリケーションを使用すると、データをさまざまな場所に配布し、ローカルエリアネットワーク (LAN)、ワイドエリアネットワーク (WAN)、ダイヤルアップ接続、無線接続、およびインターネットを介してリモートユーザーまたはモバイルユーザーに配布できます。\nData Quality Services (DQS)\tData Quality Services は、ナレッジドリブンなデータクレンジングソリューションを提供します。 DQS を使用すると、ナレッジベースを生成し、このナレッジベースとコンピューター支援およびインタラクティブな方法を使用して、データの修正と重複排除を実行できます。 クラウドベースの参照データサービスを使用し、DQS を SQL Server Integration Services および Master Data Services と統合するデータ管理ソリューションを生成できます。\nMaster Data Services (MDS)\tMaster Data Services は、SQL Server のマスターデータ管理ソリューションです。 Master Data Services 上に構築されたソリューションは、レポートと分析が適切な情報に基づいていることを保証するのに役立ちます。 Master Data Services を使用すると、マスターデータのための中央リポジトリを作成し、マスターデータの変更履歴の監査可能な安全なレコードを維持できます。\n') ;chunk テーブルのデータを表示します。 データには、ドキュメントデータから分割されたテキストチャンクと、チャンクから変換された埋め込みと tsvector が含まれている必要があります。
SELECT * FROM chunk;
ステップ 3: ドキュメントデータをバッチで埋め込みに変換する
ステップ 2: RAG のデータを準備する のサブステップ 4 に従って自動テキスト埋め込みのトリガーを作成した場合は、このステップをスキップします。
ドキュメントデータが複雑でチャンクに分割するのが難しいシナリオでは、LangChain などの RAG フレームワークを使用してテキスト埋め込みのスクリプトを開発することをお勧めします。 この方法を使用すると、データベース内の既存の chunk テーブルにテキスト埋め込みを実装することもできます。 rds_ai.embed 関数を呼び出してドキュメントデータを再帰的に変換するか、カスタム関数を呼び出してドキュメントデータをバッチで変換できます。
ドキュメントデータを再帰的に変換する
rds_ai.embed 関数を再帰的に呼び出して、各レコードのテキストを埋め込みに変換し、embedding という名前の列に保存します。
-- rds_ai.embed を再帰的に呼び出して、テーブル内のすべてのデータを埋め込みに変換します。 UPDATE chunk SET embedding = rds_ai.embed(text)::vector;ドキュメントデータをバッチで変換する
rds_ai.add_model を呼び出して、text-embedding-v3-batch モデルを作成します。
SELECT rds_ai.add_model( 'text-embedding-v3-batch', -- モデル名 'POST', -- リクエストメソッド ARRAY[('Authorization', 'Bearer %s')]::http.http_header[], -- リクエストヘッダー 'https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings', -- リクエスト URL 'application/json', -- リクエストコンテンツタイプ '{ "model": "text-embedding-v3", "input": %s }', -- リクエスト本文 'SELECT %L::jsonb->''data''' -- レスポンスを処理する SQL );text-embedding-v3-batch モデルを呼び出すために使用される API キーを構成します
SELECT rds_ai.update_model( 'text-embedding-v3-batch', 'token', 'sk-xxxxxx' );モデルをテストします。
SELECT * FROM rds_ai.invoke_model( 'text-embedding-v3-batch', ARRAY['["01","02","03"]'] );
上記の埋め込み方法のいずれかを、テスト結果に基づいて選択できます。 ただし、ドキュメントデータを再帰的に埋め込みに変換することをお勧めします。次のコードは例を示しています。
DO $$
DECLARE
batch_size INT := 20; -- 埋め込み呼び出しのバッチサイズ。モデルに基づいて調整できます
pointer INT := 0; -- テーブルをトラバースするためのポインター
record_count INT; -- テーブル内のレコードの総数
input_text TEXT; -- 埋め込むフィールドの連結文字列。["item1", "item2",..., "item n"] 形式
json_results JSON; -- 埋め込み API 呼び出しからの JSON レスポンス
json_item JSON; -- インデックスと埋め込みフィールドを含む JSON 配列レスポンスからの単一要素
idx INT; -- JSON レスポンスからのインデックス
BEGIN
-- レコードの総数を取得します
SELECT COUNT(*) INTO record_count FROM chunk;
-- 各バッチをループします
WHILE pointer < record_count LOOP
-- 入力を構築します
SELECT json_agg(text::TEXT) INTO input_text
FROM (
SELECT text
FROM chunk
ORDER BY id
LIMIT batch_size OFFSET pointer
) AS subquery;
-- 埋め込みモデルを呼び出します
json_results := rds_ai.invoke_model('text-embedding-v3-batch', ARRAY[input_text]);
-- モデルの結果をループし、対応する行を更新します
FOR idx IN 0..json_array_length(json_results) - 1 LOOP
json_item := json_results->idx;
UPDATE chunk
SET embedding = (SELECT (json_item->>'embedding')::VECTOR(1024))
WHERE id = (SELECT id FROM chunk ORDER BY id LIMIT 1 OFFSET pointer + idx);
END LOOP;
-- 次のバッチのポインターを更新します
pointer := pointer + batch_size;
RAISE NOTICE '%/% has done.', pointer, record_count;
END LOOP;
END;
$$ LANGUAGE plpgsql;ステップ 4: マルチモーダル検索を実装する
埋め込みとキーワードに基づいてデータ検索を実装します。 次のコードは例を示しています。
CREATE OR REPLACE FUNCTION multi_retrieve(query TEXT)
RETURNS TABLE(ret_chunk text, score numeric, method text, rank int) AS $$
DECLARE
rec RECORD;
BEGIN
-- キーワードで検索します
FOR rec IN
SELECT
text,
subquery.score,
'retrieve_by_key_word' AS method,
RANK() OVER (ORDER BY subquery.score DESC) AS rank_id
FROM (
SELECT
text,
ts_rank(
ts_vector_extra,
to_tsquery(replace(
text(plainto_tsquery('pg_catalog.english', query)), '&', '|'
))
) AS score
FROM chunk
WHERE ts_vector_extra @@ to_tsquery(replace(
text(plainto_tsquery('pg_catalog.english', query)), '&', '|'
))
) AS subquery
ORDER BY subquery.score DESC
LIMIT 5
LOOP
ret_chunk := rec.text;
score := rec.score;
method := rec.method;
rank := rec.rank_id;
RETURN NEXT;
END LOOP;
-- ベクターで検索します
FOR rec IN
SELECT
*,
'retrieve_by_vector' AS method,
RANK() OVER (ORDER BY distance) AS rank_id
FROM rds_ai.retrieve(
query,
'public',
'chunk',
'text',
'embedding',
distance_type => 'cosine',
topn => 5
)
LOOP
ret_chunk := rec.chunk;
score := rec.distance;
method := rec.method;
rank := rec.rank_id;
RETURN NEXT;
END LOOP;
END;
$$ LANGUAGE plpgsql;埋め込みのみに基づいてデータを検索するには、rds_ai.retrieve 関数を呼び出します。
次のステートメントを実行して、マルチモーダル検索が機能するかどうかをテストできます。
SELECT *
FROM multi_retrieve('Introduce the origins of the PostgreSQL database.')
ORDER BY METHOD, RANK;ステップ 5: 結果を再ランク付けする
マルチモーダル検索結果を再ランク付けする
rds_ai.rank 関数または RFF 関数を使用して、マルチモーダル検索結果を再ランク付けできます。
rds_ai.rank を使用して再ランク付けする
DROP FUNCTION get_reranked_results(text, integer);
CREATE OR REPLACE FUNCTION get_reranked_results(query TEXT, top_n INT DEFAULT 1)
RETURNS TABLE(score FLOAT, value TEXT) AS $$
DECLARE
result_array TEXT[];
BEGIN
SELECT array_agg(ret_chunk)
INTO result_array
FROM multi_retrieve(query);
RETURN QUERY
SELECT *
FROM rds_ai.rank(query, result_array)
ORDER BY score_value DESC
LIMIT top_n;
END $$ LANGUAGE plpgsql;
SELECT * FROM get_reranked_results('Introduce the origins of the PostgreSQL database.');RFF 関数を使用して再ランク付けする
-- 共通の RFF 関数の集計関数を作成します。
CREATE TYPE score_agg_state AS (
vector_score numeric,
keyword_score numeric
);
CREATE OR REPLACE FUNCTION score_agg_transfn(state score_agg_state, rank numeric, method text)
RETURNS score_agg_state AS $$
BEGIN
CASE method
WHEN 'retrieve_by_vector' THEN
state.vector_score := COALESCE(1 / (60+rank), 0);
WHEN 'retrieve_by_key_word' THEN
state.keyword_score := COALESCE(1 / (60+rank), 0);
END CASE;
RETURN state;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION score_agg_finalfn(state score_agg_state)
RETURNS numeric AS $$
BEGIN
RETURN COALESCE(state.vector_score, 0) + COALESCE(state.keyword_score, 0);
END;
$$ LANGUAGE plpgsql;
CREATE AGGREGATE rff_function(numeric, text)(
SFUNC = score_agg_transfn,
STYPE = score_agg_state,
FINALFUNC = score_agg_finalfn,
INITCOND = '(0, 0)'
);関数を呼び出して結果を再ランク付けします。
CREATE OR REPLACE FUNCTION get_reranked_results(query TEXT, top_n INT DEFAULT 1)
RETURNS TABLE(score numeric, value TEXT) AS $$
BEGIN
RETURN QUERY
SELECT
rff_function(rank, method) AS score, -- rff_function(rank, method) を使用してスコアを計算します
ret_chunk AS value
FROM
multi_retrieve(query)
GROUP BY
value
ORDER BY
score DESC
LIMIT top_n;
END $$ LANGUAGE plpgsql;埋め込みベースの検索結果を再ランク付けする
次の SQL 文を実行して rds_ai.rank 関数を呼び出し、埋め込みベースの検索の結果を再ランク付けできます。
DROP FUNCTION get_reranked_results(text, integer);
CREATE OR REPLACE FUNCTION get_reranked_results(query TEXT, top_n INT DEFAULT 1)
RETURNS TABLE(score FLOAT, value TEXT) AS $$
DECLARE
result_array TEXT[];
BEGIN
SELECT array_agg(chunk)
INTO result_array
FROM rds_ai.retrieve(query, 'public', 'chunk', 'text', 'embedding');
RETURN QUERY
SELECT *
FROM rds_ai.rank(query, result_array)
ORDER BY score_value DESC
LIMIT top_n;
END $$ LANGUAGE plpgsql;
-- テスト
SELECT * FROM get_reranked_results('Introduce the origins of the PostgreSQL database.');ステップ 6: LLM を呼び出して結果を返す
マルチモーダル検索結果を返す
データベース内の結果の改行などの特殊文字をエスケープする escape_for_json 関数を作成します。 rds_ai.prompt 関数を呼び出して返される結果は、パラメーターによってアセンブルされた JSON オブジェクトであるため、このステップは不可欠です。
CREATE OR REPLACE FUNCTION escape_for_json(input TEXT) RETURNS TEXT AS $$ BEGIN RETURN replace(replace(input, '"', '\\"'), E'\n', '\\n'); END; $$ LANGUAGE plpgsql;マルチモーダル検索結果を返す rag という名前の関数を作成します。 次のコードは例を示しています。
CREATE OR REPLACE FUNCTION rag(query TEXT) RETURNS TEXT AS $$ DECLARE prompt_content TEXT; result TEXT; BEGIN -- get_reranked_results 関数を使用して再ランク付けされた結果を取得し、それらを配列に集約します WITH rank_result AS ( SELECT string_agg(value, ',') AS prompt_content_pre FROM get_reranked_results(query) ) -- rank_result クエリからプロンプトを生成し、モデルの回答を取得します SELECT 'Based on the following content' || prompt_content_pre || 'answer my question,' || query INTO prompt_content FROM rank_result; -- rds_ai.prompt 関数を使用して AI モデルの回答を取得します SELECT rds_ai.prompt(escape_for_json(prompt_content)) INTO result; -- 結果を返します RETURN result; END; $$ LANGUAGE plpgsql;rag 関数を呼び出して、マルチモーダル検索を使用して取得した回答を取得します。
SELECT rag('Introduce the origins of the PostgreSQL database.');
埋め込みベースの検索結果を返す
埋め込みベースの検索結果を取得するには、次のステートメントを実行して rds_ai.rag 関数を呼び出します。
SELECT *
FROM rds_ai.rag (
'Introduce the origins of the PostgreSQL database.',
'public',
'chunk',
'text',
'embedding'
);