ベクトル・ストアとOCI生成AI APIキーによるドキュメントの検索

ベクトル・ストアを作成し、ドキュメントをアップロードおよび取り込み、OCI生成AI APIキーを使用してcurlまたはOpenAI Python SDKでそのコンテンツを検索します。

概要

ベクトル・ストアは、ドキュメントを意味で検索できるようにします。ファイルをアップロードしてストアに取り込み、自然言語の質問で検索します。このサービスは、関連する通路、ファイル名、および関連性スコアを返します。取得したパスは、言語モデル・アプリケーションのコンテキストを提供することもできます。

ベクトル・ストアを使用して、独自のドキュメント解析および埋込みパイプラインを構築することなく、ポリシー、製品ガイドおよびサポート記事を検索できます。概要は、ベクトル・ストアおよびセマンティック・ストアを参照してください。

このチュートリアルでは:

  • ベクトル・ストアを作成、取得およびリストします。
  • サンプル・ドキュメントをアップロードし、検索可能なチャンクに収集します。
  • ドキュメントを検索し、一致するパスを検査します。
  • ストアの名前を変更し、テスト・リソースを削除します。

番号付きの各タスクには、curlの例とPython (OpenAI SDK)の例があります。パスを1つ選択し、最初から最後まで続けます。curlの例では、BashからのHTTPリクエストを行います。Pythonの例では、OCIをコールするように構成されたOpenAI SDKを使用します。どちらのパスもOCI生成AI APIキーで認証されるため、OCI CLIセッションは必要ありません。

始める前に

このチュートリアルを完了するには、次のものが必要です。

例では、次のOCIベースURLを使用します。

https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/openai/v1

選択したリージョンのサービス・エンドポイントを使用します。チュートリアル全体を通して、同じエンドポイント、コンパートメントおよびプロジェクトを保持します。

サンプル・ドキュメントには、架空のショップ・ポリシーが含まれています。接続プレースホルダのみを独自の値に置き換えます。例では、APIキーを表示またはソース・コードに含めずに、APIキーの入力を求められます。

curlパスの設定

Bashターミナルで、コンパートメントおよびプロジェクトのプレースホルダを置き換え、次を実行します:

set -o pipefail
export GENAI_BASE_URL='https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/openai/v1'
export GENAI_COMPARTMENT_ID='<your-compartment-ocid>'
export GENAI_PROJECT_ID='<your-project-ocid>'

read -r -s -p 'OCI Generative AI API key: ' GENAI_API_KEY
printf '\n'
export GENAI_API_KEY

VECTOR_STORES_URL="$GENAI_BASE_URL/vector_stores"
FILES_URL="$GENAI_BASE_URL/files"

設定および返されたリソースIDが使用可能なままになるように、この端末で各curlの例を実行します。リクエストはBearer APIキーおよびopc-compartment-idを送信します。ファイルのアップロードおよびファイル削除では、OCIプロジェクトを識別するためにOpenAI-Projectも送信されます。ベースURLを末尾のスラッシュなしで設定します。

コマンドが失敗した場合は、エラーを解決してから続行します。クリーンアップの正常なリクエストによって返されたIDを保持します。成功した作成コマンドまたはアップロード・コマンドを再実行して、リソースのステータスを取得しないでください。

Pythonパスの設定

仮想環境を作成してアクティブ化し、OpenAI Python SDKをインストールします:

python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade openai

次の設定でvector_store_tutorial.pyを作成します。コンパートメントおよびプロジェクトのプレースホルダを置換します。次に、8つの番号付きタスクのそれぞれからPythonブロックを順番に追加します。すべてのブロックが同じクライアント変数とリソース変数を共有します。

import getpass
import time

from openai import OpenAI

BASE_URL = "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/openai/v1"
COMPARTMENT_ID = "<your-compartment-ocid>"
PROJECT_ID = "<your-project-ocid>"
API_KEY = getpass.getpass("OCI Generative AI API key: ")

client = OpenAI(
    api_key=API_KEY,
    base_url=BASE_URL.rstrip("/") + "/",
    default_headers={"opc-compartment-id": COMPARTMENT_ID},
    timeout=30,
)

サンプル・ドキュメントを保存し、すべてのPythonブロックをアセンブルした後、同じディレクトリから完了したスクリプトを実行します:

python vector_store_tutorial.py

完了したスクリプトによって、リソースが作成され、ドキュメントが検索され、ストアおよびアップロードされたファイルが削除されます。クリーンアップの前にさらに質問を試みるには、タスク6の後、削除ブロックの前に検索コールを追加します。スクリプトがエラーで停止した場合は、エラーの前に出力されたリソースIDを使用して、すでに作成されているリソースを検査およびクリーン・アップします。

サンプル・ドキュメントの準備

この架空のポリシーを、curlコマンドまたはPythonスクリプトを実行するディレクトリにsample-document.txtとして保存します:

Example shop policy

Returns
Customers can return unused purchases within 30 days of delivery.
Include the order number and keep the item in its original packaging.
Contact support before shipping a return.
Refunds go to the original payment method.

Delivery
Standard delivery usually takes 3 to 5 business days.
Express delivery usually takes 1 to 2 business days.

1. ベクトル・ストアの作成

認識可能な名前で空のストアを作成します。この例では、last_active_atに基づいて1日の有効期限ポリシーを設定します。ストアを作成しても、ドキュメントのアップロードや取込みは行われません。

選択したパスの例を実行します。

curl

STORE_RESPONSE=$(curl --fail-with-body --silent --show-error \
  --request POST "$VECTOR_STORES_URL" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  --header 'Content-Type: application/json' \
  --data '{"name":"document-search-demo","expires_after":{"anchor":"last_active_at","days":1}}')

printf '%s\n' "$STORE_RESPONSE" | jq '{id, name, status}'
VECTOR_STORE_ID=$(printf '%s' "$STORE_RESPONSE" | jq -er '.id')

Python(OpenAI SDK)

store = client.vector_stores.create(
    name="document-search-demo",
    expires_after={"anchor": "last_active_at", "days": 1},
)
print("Created store:", store.id, store.status)

返されたストアIDを保存します。作成は非同期にできます。次のタスクでステータスを確認します。

2. ストアの取得およびそのステータスの確認

ストアのメタデータを取得し、completedを待機してからドキュメントを取り込みます。

選択したパスの例を実行します。

curl

curl --fail-with-body --silent --show-error \
  "$VECTOR_STORES_URL/$VECTOR_STORE_ID" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  | jq '{id, name, status}'

ステータスがin_progressの場合は、2秒待ってから、取得コマンドを再度実行します。ステータスがcompletedの場合にのみ続行します。ストアの有効期限が切れているか、2分を超えて進行中かどうかを停止して調査します。

Python(OpenAI SDK)

store = client.vector_stores.retrieve(store.id)
deadline = time.monotonic() + 120
while store.status == "in_progress":
    if time.monotonic() >= deadline:
        raise TimeoutError(f"Store creation is still in progress: {store.id}")
    time.sleep(2)
    store = client.vector_stores.retrieve(store.id)

if store.status != "completed":
    raise RuntimeError(f"Store is not ready: {store.id}, {store.status}")
print("Store is ready:", store.id)

2分ポーリング・タイムアウトは、この例の制限であり、サービス完了保証ではありません。到達した場合は、ストアIDを保持し、ストアを検査してから再試行します。

その店は飲食の準備ができている。

3. ベクトルストアのリスト

ストアをリストして、すでに作成したリソースを検索します。この例では、最初のページに最大10個のエントリが表示されます。ストアは後のページにある可能性があります。特定の店舗をチェックするためのIDによる取得。

選択したパスの例を実行します。

curl

curl --fail-with-body --silent --show-error \
  "$VECTOR_STORES_URL?limit=10" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  | jq '.data[] | {id, name, status}'

Python(OpenAI SDK)

for item in client.vector_stores.list(limit=10).data:
    print(item.id, item.name, item.status)

出力には、返される各ストアのID、名前およびステータスが表示されます。

4. 文書のアップロード

サンプル・ドキュメントをアップロードして、ファイル・リソースを作成します。OpenAI-Projectヘッダーは、アップロードをOCI生成AIプロジェクトに関連付けます。次のタスクの取込み後に、ファイルが検索可能になります。

選択したパスの例を実行します。

curl

FILE_RESPONSE=$(curl --fail-with-body --silent --show-error \
  --request POST "$FILES_URL" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  --header "OpenAI-Project: $GENAI_PROJECT_ID" \
  --form 'purpose=assistants' \
  --form 'file=@sample-document.txt')

printf '%s\n' "$FILE_RESPONSE" | jq '{id, filename}'
FILE_ID=$(printf '%s' "$FILE_RESPONSE" | jq -er '.id')

Python(OpenAI SDK)

with open("sample-document.txt", "rb") as document:
    uploaded_file = client.files.create(
        file=document,
        purpose="assistants",
        extra_headers={"OpenAI-Project": PROJECT_ID},
    )
print("Uploaded file:", uploaded_file.id, uploaded_file.filename)

curlの場合は、マルチパート・コンテンツ・タイプと境界を自動的に設定します。

取り込みとクリーンアップのために返されたファイルIDを保存します。

5. 文書のストアへの取込み

取込みにより、ファイルがストアに関連付けられ、ドキュメントがチャンクに分割され、取得用の埋込みが作成されます。ファイル・バッチには、複数のファイルを含めることができます。この例では、1つのファイルとデフォルトのチャンク設定を使用します。

選択したパスの例を実行します。

curl

BATCH_RESPONSE=$(curl --fail-with-body --silent --show-error \
  --request POST "$VECTOR_STORES_URL/$VECTOR_STORE_ID/file_batches" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  --header 'Content-Type: application/json' \
  --data "$(jq -n --arg file_id "$FILE_ID" '{file_ids:[$file_id]}')")

printf '%s\n' "$BATCH_RESPONSE" | jq '{id, status, file_counts}'
BATCH_ID=$(printf '%s' "$BATCH_RESPONSE" | jq -er '.id')

バッチ・ステータスを確認します。

curl --fail-with-body --silent --show-error \
  "$VECTOR_STORES_URL/$VECTOR_STORE_ID/file_batches/$BATCH_ID" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  | jq '{id, status, file_counts}'

ステータスがin_progressの場合は、2秒待ってからバッチを再度取得します。ステータスがcompletedで、完了したファイル数が1で、失敗した数と取り消された数が0の場合、続行します。取込みが失敗したか、取り消されたか、または2分以上進行中かどうかを停止して調査します。

Python(OpenAI SDK)

batch = client.vector_stores.file_batches.create(
    vector_store_id=store.id,
    file_ids=[uploaded_file.id],
)
print("Ingestion batch:", batch.id)

deadline = time.monotonic() + 120
while batch.status == "in_progress":
    if time.monotonic() >= deadline:
        raise TimeoutError(f"Document ingestion is still in progress: {batch.id}")
    time.sleep(2)
    batch = client.vector_stores.file_batches.retrieve(
        batch.id, vector_store_id=store.id,
    )

counts = batch.file_counts
if (
    batch.status != "completed"
    or counts.completed != 1
    or counts.failed
    or counts.cancelled
):
    raise RuntimeError(
        f"Ingestion did not succeed: {batch.id}, {batch.status}, {counts}"
    )
print("Document is ready to search.")

正常に取り込まれた後、ドキュメントを検索する準備ができました。詳細は、「ベクトル・ストア・ファイル・バッチAPI」を参照してください。

6. 文書の検索

自然言語の質問をして、関連する通路を取り戻してください。検索コールはドキュメント・コンテンツを返します。言語モデルの回答は生成されません。

選択したパスの例を実行します。

curl

Python(OpenAI SDK)

サンプルポリシーの30日間の戻り期間を含むパスを探します。通過境界、順序付けおよびスコアは異なる場合があります。max_num_resultsは、ドキュメントではなくチャンクの一致を制限します。

速達度はどのくらいですか、返品には何を含める必要がありますかなど、別の質問をお試しください。ストアとファイルがまだ存在している間、検索コールのみを繰り返します。

7. ストアの名前変更

ストアの名前を更新します。名前を変更すると、ストアのメタデータが変更され、アップロードされたポリシー・テキストは変更されません。

選択したパスの例を実行します。

curl

curl --fail-with-body --silent --show-error \
  --request POST "$VECTOR_STORES_URL/$VECTOR_STORE_ID" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  --header 'Content-Type: application/json' \
  --data '{"name":"document-search-demo-updated"}' \
  | jq '{id, name, status}'

ステータスがin_progressの場合は、ステータスがcompletedになるまでタスク2から取得コマンドを使用します。例の2分ポーリング期間内に更新が完了していないかどうかを停止して調査します。

Python(OpenAI SDK)

store = client.vector_stores.update(
    store.id, name="document-search-demo-updated",
)
deadline = time.monotonic() + 120
while store.status == "in_progress":
    if time.monotonic() >= deadline:
        raise TimeoutError(f"Store update is still in progress: {store.id}")
    time.sleep(2)
    store = client.vector_stores.retrieve(store.id)

if store.status != "completed":
    raise RuntimeError(f"Store update did not complete: {store.id}, {store.status}")
print("Updated store:", store.id, store.name)

ストアには更新された名前があります。更新が完了するまで待ってから、削除します。

8. テスト・リソースの削除

このチュートリアルで作成したストアおよびアップロード済ファイルを削除します。これらは別個のリソースです。ストアを削除しても、ファイルの削除は置換されません。作成したテスト・リソースのIDのみを使用します。

以前のタスクが失敗した場合は、成功したタスクによって出力されたIDを使用して、存在するリソースのみをクリーンアップします。同じエンドポイント、コンパートメント、プロジェクトおよびAPIキー設定を保持します。Pythonの場合、削除ブロックを使用してセットアップ・ブロックを実行し、store.idおよびuploaded_file.idを引用符で囲まれた文字列として保存されたIDに置き換えます。作成されなかったリソースの削除を省略します。

選択したパスの例を実行します。

curl

curl --fail-with-body --silent --show-error \
  --request DELETE "$VECTOR_STORES_URL/$VECTOR_STORE_ID" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  | jq '{id, deleted}'

curl --fail-with-body --silent --show-error \
  --request DELETE "$FILES_URL/$FILE_ID" \
  --header "Authorization: Bearer $GENAI_API_KEY" \
  --header "opc-compartment-id: $GENAI_COMPARTMENT_ID" \
  --header "OpenAI-Project: $GENAI_PROJECT_ID" \
  | jq '{id, deleted}'

Python(OpenAI SDK)

deleted_store = client.vector_stores.delete(store.id)
print("Store deleted:", deleted_store.id, deleted_store.deleted)

deleted_file = client.files.delete(
    uploaded_file.id,
    extra_headers={"OpenAI-Project": PROJECT_ID},
)
print("File deleted:", deleted_file.id, deleted_file.deleted)
client.close()

正常な削除確認にはdeleted: trueが含まれます。両方のリソースのこの値を確認します。

トラブルシューティング

現象確認対象
認証エラーまたはHTTP 401OCI生成AI APIキー・シークレットが選択されたリージョンに対して有効であり、ベアラー・トークンとして送信されていることを確認します。
認可エラーまたはHTTP 403コンパートメントおよびプロジェクトのAPIキー権限およびファイルおよびベクトル・ストアの権限を確認してください。
リソースが見つかりませんファイル・リクエストのサービスURL、リージョン、コンパートメント、プロジェクト・ヘッダーおよびリソースIDを確認します。
アップロードが拒否されましたファイルAPIのトピックで、ファイル・タイプおよびアップロード制限を確認します。小さいサンプル・ドキュメントから開始します。
取込みに失敗しましたバッチを取得し、そのステータスおよびファイル数を検査します。エラーの詳細は、個々のベクトル・ストア・ファイル・レコードを取得してください。
検索の結果がありません取込みが正常に完了し、ドキュメントを含むストアを検索していることを確認します。
ポーリング・タイムアウトリソースを再度取得して、その現在のステータスを検査します。トラブルシューティングおよびクリーンアップのためにIDを保持します。
SDKには、vector_storesまたはsearchメソッドがありませんスクリプトで使用されるPython環境をアクティブ化し、openaiパッケージをアップグレードします。