2023年7月7日金曜日

Cohereでembeddingを生成しPineconeに保存して問い合わせてみる

 ベクトル・データベースのPineconeは、無料でインデックスをひとつ作成することができます。その無料枠で作成したインデックスにCohereのEmbed APIで生成したembeddingを保存し、問い合わせを実行するアプリケーションを作ってみました。

以下の処理を実装しています。

  1. オラクル・データベースの表に検索対象となる文書を保存します。
  2. 上記の保存された文書を引数にしてCohere Embed APIを呼び出し、embeddingを生成します。生成したembeddingは、文書に紐づけてオラクル・データベースに保存します。
  3. オラクル・データベースに保存されている文書のidとembeddingを、PineconeのインデックスにUpsertします。
  4. 画面から問い合わせとなる文字列を入力します。問い合わせ文字列を引数にしてCohere Embed APIを呼び出し、embeddingを生成します。生成したembeddingでPineconeのインデックスにQueryを発行します。
  5. 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呼び出し時に指定するWeb資格証明を作成します。

Web資格証明名前Pinecone API Access静的IDPINECONE_APIとしています。静的IDは、これから紹介するPL/SQLコードに含まれています。

資格証明タイプとしてHTTPヘッダーを選び、資格証明名としてApi-Keyを指定します。資格証明シークレットとして、PineconeのコンソールでコピーしたAPI Keyを設定します。

PineconeのAPIはHTTPヘッダーApi-Keyの値として、APIキーを渡すことで認証されます。


Pineconeのインデックスを作成します。

Pinecone ConsoleのIndexesを開き、Create Indexを実行します。


作成するインデックスのDimensions768を指定します。今回は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のアプリケーション作成の参考になれば幸いです。