ベクトル・データベースのPineconeは、無料でインデックスをひとつ作成することができます。その無料枠で作成したインデックスにCohereのEmbed APIで生成したembeddingを保存し、問い合わせを実行するアプリケーションを作ってみました。
以下の処理を実装しています。
- オラクル・データベースの表に検索対象となる文書を保存します。
- 上記の保存された文書を引数にしてCohere Embed APIを呼び出し、embeddingを生成します。生成したembeddingは、文書に紐づけてオラクル・データベースに保存します。
- オラクル・データベースに保存されている文書のidとembeddingを、PineconeのインデックスにUpsertします。
- 画面から問い合わせとなる文字列を入力します。問い合わせ文字列を引数にしてCohere Embed APIを呼び出し、embeddingを生成します。生成したembeddingでPineconeのインデックスにQueryを発行します。
- Pineconeより類似した文書のIDが返されるので、オラクル・データベースに保存された文書をIDを指定して取り出し、画面に印刷します。
以下のような動作になります。
上記のアプリケーションのエクスポートは以下に置いてあります。
https://github.com/ujnak/apexapps/blob/master/exports/pinecone-and-cohere-sample.zip
上記のアプリケーションを一からつくるということもないので、実装のポイントのみを解説します。
Pineconeのアカウントの作成方法については、他の説明を参照してください。 Google、GitHubまたはMicrosoftのアカウントと連携するため、それらのアカウントがあればすぐに作成できます。また、有料の機能を使用するにはアカウントをアップグレードする必要があります。
Pineconeの準備作業
PineconeのAPIを呼び出す際に使用するAPIキーを確認します。このAPIキーより、Oracle APEXのワークスペースにWeb資格証明を作成します。
Pineconeのコンソールを開き、ナビゲーション・メニューよりAPI Keysを開きます。作成済みのAPIキーをコピーします。
Web資格証明の名前はPinecone API Access、静的IDはPINECONE_APIとしています。静的IDは、これから紹介するPL/SQLコードに含まれています。
資格証明タイプとしてHTTPヘッダーを選び、資格証明名としてApi-Keyを指定します。資格証明シークレットとして、PineconeのコンソールでコピーしたAPI Keyを設定します。
PineconeのAPIはHTTPヘッダーApi-Keyの値として、APIキーを渡すことで認証されます。
Pineconeのインデックスを作成します。
Pinecone ConsoleのIndexesを開き、Create Indexを実行します。
作成するインデックスのDimensionsは768を指定します。今回はCohereのEmbed APIを呼び出してembeddingを生成します。その際に(日本語を扱うため)modelとしてembed-multilingual-v2.0を指定します。このembed-multilingual-v2.0のサイズが768なので、PineconeのインデックスのDimensionsを768にします。CohereのモデルのEmbedding SizeはCo.EmbedのAPIのリファレンスに記載されています。
Metricとしてcosine(コサイン類似度)を選択しています。こちらは他にdotproduct(ドット積)、euclidean(ユークリッド距離)を選択することができます。
作成したインデックスのURLを確認し、コピーします。
このインデックスはAPEXアプリケーションのアプリケーション定義の置換に、置換文字列G_INDEXの置換値として設定します。
アプリケーションのコード中ではG_INDEXとして、PineconeのAPIのエンドポイントを参照します。
Cohereの準備については、こちらの記事を参照してください。
以上でPineconeを使用する準備ができました。
表VEC_EMBEDDINGSの作成
以下のDDLを実行し、表VEC_EMBEDDINGSを作成します。
アプリケーションのユーザーが入力するのは、列TEXTの値だけです。
Cohereによるembeddingの生成
ボタンGENERATE_EMBEDDINGSをクリックしたときに、列TEXTの値をまとめてCohere Embed APIを呼び出し、embeddingを生成します。
ボタンのクリックにより実行されるプロセスは、Generate Embeddingsとして作成されています。
ソースのPL/SQLコードは以下です。
列EMBEDDINGが未設定の行をAPEXコレクションにコピーし、それを元にEmbed APIのリクエストを作成しています。Embed APIのリクエストには複数のテキストを含めることができます。
APIのリファレンスによると、1つのリクエストに含めることができるテキストの数は96が上限で、それぞれのテキストのトークンは512を超えないことが推奨されています。
要確認なのですが、英語のモデルであればトークン数は単語数と同じと思うのですが、多言語のモデルembed-multilingual-v2.0で特に日本語の場合は、トークン数は文字数と同じではないかと思います。それもあって表VEC_EMBEDDINGSの列TEXTをVARCHAR2(512 CHAR)としています。
CohereのEmbed APIのレスポンスにid属性が含まれています。ただし、リクエストに複数のテキストが含まれ、それぞれのembeddingがレスポンスに含まれています。idだけではレスポンスに含まれる個々のテキストとembeddingの組み合わせを特定できないため、テキスト(およびembedding)の出現順序を列EMBEDDING_SEQとして保存しています。列EMBEDDING_ID(Cohere Embed APIのレスポンスのid)と組み合わせて、テキストとembeddingを一意に特定します。
この列EMBEDDING_IDとEMBEDDING_SEQは、PineconeのUpsertを呼び出す際のベクトルのIDになります。
PineconeへのUpsertの実行
ボタンUPSERT_VECTORSをクリックしたときに、列EMBEDDINGにデータが記載され、列STATUSがCである行をまとめて、PineconeのUpsertリクエストを発行します。
ボタンのクリックにより実行されるプロセスは、Upsert Vectorsとして作成されています。
ソースのPL/SQLコードは以下です。
列EMBEDDING_IDとEMBEDDING_SEQよりidの値を作り、valuesにはCohereのEmbed APIが返してきたembeddingをそのまま渡します。vectors属性に、このオブジェクトの配列を指定し、PineconeのUpsertのリクエストとしています。
ここで指定したidの値を、表VEC_EMBEDDINGSの列VECTOR_IDとして保存します。
Pineconeのインデックスに対する問い合わせは、このidの値を検索結果として返します。表VEC_EMBEDDINGSの列VECTOR_IDから、元のテキストを見つけることができます。
Pineconeのインデックスへの問い合わせ
ボタンQUERYをクリックすると、Pineconeのインデックスへの問い合わせが発行されます。ボタン自体は、動的アクションによって動的コンテンツのリージョンであるResponseをリフレッシュしています。
PineconeのインデックスへのQuery APIの発行および結果の表示は、動的コンテンツに実装されています。
ソースのCLOBを返すPL/SQLファンクション本体は以下です。
問い合わせ文字列を引数として、CohereのEmbed APIを呼び出しembeddingを生成しています。
そのembeddingを、PineconeのQuery APIのリクエストのvectorとして渡しています。
結果としてインデックスに保存されているベクトルのidとscoreが返されます。idに一致するテキストを、表VEC_EMBEDDINGSの列VECTOR_IDから検索し表示しています。
今回作成したアプリケーションの説明は以上になります。
ベクトル類似性検索を試してみたい、ということでCohereのEmbed APIとPineconeを使ってみました。とりあえず動かすことはできたので目的は達成したのですが、インデックスのメンテナンスや検索結果の評価方法など、色々と考えないといけないことは多そうです。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完