For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
メインナビゲーション
Theme

データ検索

意味の類似度をもとにデータを検索します。

Retrieval API を使うと、自分のデータに対してセマンティック検索を実行できます。セマンティック検索は、一致するキーワードが少ない場合やまったくない場合でも、意味の近い結果を見つける手法です。検索だけでも役立ちますが、OpenAI のモデルと組み合わせると、検索結果をもとに回答を生成できます。

Retrieval API による検索の概念図

Retrieval API は、データのインデックスとして機能するベクトルストアを使って検索します。このガイドでは、セマンティック検索の実行方法と、ベクトルストアの仕組みや操作方法を解説します。

クイックスタート

  • ベクトルストアを作成し、ファイルをアップロードします。

  • ファイルを含むベクトルストアの作成
    from openai import OpenAI
    
    client = OpenAI()
    
    vector_store = client.vector_stores.create(        # Create vector store
        name="Support FAQ",
    )
    
    client.vector_stores.files.upload_and_poll(        # Upload file
        vector_store_id=vector_store.id,
        file=open("customer_policies.txt", "rb")
    )
  • 検索クエリを送信し、関連する結果を取得します。

  • 検索クエリ
    user_query = "What is the return policy?"
    
    results = client.vector_stores.search(
        vector_store_id=vector_store.id,
        query=user_query,
    )

    OpenAI のモデルで検索結果を活用する方法は、「検索結果に基づく回答の生成」を参照してください。

    セマンティック検索

    セマンティック検索は、ベクトル埋め込みを使って、クエリと意味的に関連する結果を見つける手法です。クエリと共通するキーワードが少ない、あるいはまったくないために従来の検索手法では見逃しやすい結果も見つけられます。

    たとえば、"When did we go to the moon?"(人類が月に行ったのはいつですか?)というクエリで得られる結果を見てみましょう。

    テキスト キーワードの類似度 意味の類似度
    初の月面着陸は 1969 年 7 月でした。 0% 65%
    初めて月面に降り立ったのはニール・アームストロング氏です。 27% 43%
    月餅を食べたら、おいしかったです。 40% 28%

    (英語の原文でのキーワードの類似度には積集合と和集合の比を、意味の類似度にはコサイン類似度を使っています。埋め込みモデルは text-embedding-3-small です。)

    最も関連性の高い結果の原文には、検索クエリに含まれる単語が一つもありません。このように単語が一致しなくても検索できるため、セマンティック検索は規模を問わずナレッジベースの検索に有効です。

    セマンティック検索にはベクトルストアを使います。ベクトルストアについては、このガイドの後半で詳しく説明します。ここでは、セマンティック検索の具体的な使い方を説明します。

    セマンティック検索の実行

    search 関数で query を自然言語で指定すると、ベクトルストアを検索できます。結果はリストで返され、各結果には該当するチャンク、類似度スコア、元のファイルが含まれます。

    検索クエリ
    results = client.vector_stores.search(
        vector_store_id=vector_store.id,
        query="How many woodchucks are allowed per passenger?",
    )
    検索結果
    {
      "object": "vector_store.search_results.page",
      "search_query": "How many woodchucks are allowed per passenger?",
      "data": [
        {
          "file_id": "file-12345",
          "filename": "woodchuck_policy.txt",
          "score": 0.85,
          "attributes": {
            "region": "North America",
            "author": "Wildlife Department"
          },
          "content": [
            {
              "type": "text",
              "text": "According to the latest regulations, each passenger is allowed to carry up to two woodchucks."
            },
            {
              "type": "text",
              "text": "Ensure that the woodchucks are properly contained during transport."
            }
          ]
        },
        {
          "file_id": "file-67890",
          "filename": "transport_guidelines.txt",
          "score": 0.75,
          "attributes": {
            "region": "North America",
            "author": "Transport Authority"
          },
          "content": [
            {
              "type": "text",
              "text": "Passengers must adhere to the guidelines set forth by the Transport Authority regarding the transport of woodchucks."
            }
          ]
        }
      ],
      "has_more": false,
      "next_page": null
    }

    デフォルトでは 1 回のレスポンスに含まれる結果は最大 10 件ですが、max_num_results パラメーターで上限を 50 件まで設定できます。

    クエリの書き換え

    クエリの表現によって検索精度が変わるため、検索に適した表現に自動で書き換える設定を用意しています。rewrite_query=true を指定して search を実行すると、この機能が有効になります。

    書き換え後のクエリは、検索結果の search_query フィールドで確認できます。

    元のクエリ 書き換え後
    本社ビルの高さを知りたいです。 本社ビル 高さ
    危険物の輸送にはどのような安全規則が適用されますか? 危険物 安全規則
    サービスの問題について苦情を申し立てるにはどうすればよいですか? サービス 苦情 申し立て手順

    属性による絞り込み

    属性を使うと、特定の期間に検索対象を限定するなど、条件を指定して結果を絞り込めます。filters に条件を定義し、必要に応じて組み合わせることで、セマンティック検索を実行する前にファイルの属性に基づいて検索対象を絞り込めます。

    比較フィルターは、指定した key に対応するファイルの attributes 内の値を、指定した value と比較します。複合フィルターは、複数のフィルターを and や or で組み合わせます。

    比較フィルター
    {
      "type": "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "in" | "nin",  // comparison operators
      "key": "attributes_key",                           // attributes key
      "value": "target_value"                             // value to compare against
    }
    複合フィルター
    {
      "type": "and" | "or",                                // logical operators
      "filters": [...]
    }

    以下にフィルターの例を示します。

    ファイル名で絞り込む例では、カスタム属性 filename の値を照合します。ベクトルストアの各ファイルに {"filename": "example.txt"} のように明示的に設定してください。アップロードしたファイルの名前が自動で照合に使われることはありません。

    地域で絞り込むフィルター
    {
      "type": "eq",
      "key": "region",
      "value": "us"
    }

    ランキング

    ファイル検索で十分に関連性の高い結果が得られない場合は、ranking_options を調整して回答の質を改善できます。たとえば、ranker に auto や default-2024-08-21 を指定し、score_threshold を 0.0 から 1.0 の範囲で設定できます。score_threshold を高くすると、関連性の高いチャンクに結果を絞れますが、有用なチャンクが除外されることもあります。ranking_options.hybrid_search を指定した場合は、hybrid_search.embedding_weight(rrf_embedding_weight)と hybrid_search.text_weight(rrf_text_weight)も調整できます。これらの重みは、逆順位融合で、埋め込みによる意味の一致とスパース検索によるキーワードの一致をそれぞれどの程度重視するかを決めます。意味の類似度を重視する場合は前者を、テキストに共通する語句を重視する場合は後者を大きくしてください。少なくとも一方の重みを 0 より大きくする必要があります。

    ベクトルストア

    ベクトルストアは、Retrieval API とファイル検索ツールでセマンティック検索を行うためのコンテナです。ベクトルストアにファイルを追加すると、自動的にチャンクに分割され、各チャンクの埋め込みが生成されてインデックスに登録されます。

    ベクトルストアには vector_store_file オブジェクトが格納されます。それぞれの元となるのが file オブジェクトです。

    オブジェクトの種類
    説明
    file Files API を通じてアップロードしたコンテンツを表します。ベクトルストアでよく使われるほか、ファインチューニングなどにも使われます。
    vector_store 検索対象のファイルを格納するコンテナです。
    vector_store.file チャンク分割と埋め込みの生成を終えた file を、特定の vector_store に関連付けた状態で表すラッパー型です。
    絞り込みに使う attributes マップを含みます。

    料金

    料金は、すべてのベクトルストアの合計ストレージ使用量に基づきます。使用量は、ファイルの解析で得られたチャンクと、それぞれに対応する埋め込みのサイズで決まります。

    ストレージ使用量 料金
    1 GB まで(全ストアの合計) 無料
    1 GB を超える分 1 GB あたり 1 日 0.10 ドル

    コストを抑えるための設定は、「有効期限ポリシー」を参照してください。

    ベクトルストアの操作

    ベクトルストアの作成
    client.vector_stores.create(
        name="Support FAQ",
        file_ids=["file_123"]
    )

    ベクトルストアのファイル操作

    一部の操作は非同期で実行され、完了までに時間がかかることがあります。たとえば、create で vector_store.file を作成する場合がこれにあたります。操作の完了を待ってから次の処理に進むには、create_and_poll などのヘルパー関数を使ってください。ステータスを個別に確認することもできます。ベクトルストアからのファイル削除には結果整合性が適用されるため、削除後もしばらくはそのファイルの内容が検索結果に含まれることがあります。

    ファイル追加のレート制限は、ベクトルストア ID ごとに適用されます。/vector_stores/{vector_store_id}/files と /vector_stores/{vector_store_id}/file_batches へのリクエストには共通の上限があり、ベクトルストアごとに合計で毎分 300 リクエストまでです。

    ベクトルストアのファイルの作成
    client.vector_stores.files.create_and_poll(
        vector_store_id="vs_123",
        file_id="file_123"
    )

    バッチ操作

    バッチの作成
    client.vector_stores.file_batches.create_and_poll(
        vector_store_id="vs_123",
        files=[
            {
                "file_id": "file_123",
                "attributes": {"department": "finance"}
            },
            {
                "file_id": "file_456",
                "chunking_strategy": {
                    "type": "static",
                    "static": {
                        "max_chunk_size_tokens": 1200,
                        "chunk_overlap_tokens": 200
                    }
                }
            }
        ]
    )

    バッチを作成する方法は 2 通りあります。すべてのファイルに同じ設定を適用する場合は file_ids を渡し、必要に応じて attributes と chunking_strategy の一方または両方を指定します。ファイルごとに設定を変える場合は、files 配列でファイルごとのオブジェクトを渡します。各オブジェクトには file_id を含め、必要に応じて attributes と chunking_strategy を指定します。この 2 つの方法は併用できません。

    単一のベクトルストアにファイルを取り込む際のスループットを高めるには、可能な限りバッチ作成を使うことをおすすめします。バッチでは 1 回のリクエストで最大 500 ファイルを追加できます。通常、ファイルごとに作成リクエストを多数送る場合よりも競合が減り、処理全体にかかる時間が短くなります。

    属性

    各 vector_store.file には、属性値を格納する辞書 attributes を関連付けられます。セマンティック検索で属性による絞り込みを行う際に、この辞書の値を参照できます。辞書には最大 16 個のキーを設定でき、各キーの長さは最大 256 文字です。

    属性を指定したベクトルストアのファイルの作成
    client.vector_stores.files.create(
        vector_store_id="<vector_store_id>",
        file_id="file_123",
        attributes={
            "region": "US",
            "category": "Marketing",
            "date": 1672531200      # Jan 1, 2023
        }
    )

    有効期限ポリシー

    vector_store オブジェクトには、expires_after で有効期限ポリシーを設定できます。ベクトルストアの有効期限が切れると、関連付けられたすべての vector_store.file オブジェクトが削除され、以降はそれらに対する料金は発生しません。

    ベクトルストアの有効期限ポリシーの設定
    client.vector_stores.update(
        vector_store_id="vs_123",
        expires_after={
            "anchor": "last_active_at",
            "days": 7
        }
    )

    上限

    ファイルサイズの上限は 512 MB です。各ファイルのトークン数は 5,000,000 以下にしてください。トークン数はファイルを追加するときに自動で計算されます。

    チャンク分割

    デフォルトでは max_chunk_size_tokens は 800、chunk_overlap_tokens は 400 に設定されています。各ファイルは 800 トークンずつのチャンクに分割され、隣り合うチャンクが 400 トークンずつ重なる形でインデックスに登録されます。

    分割方法は、ベクトルストアにファイルを追加するときに chunking_strategy で調整できます。設定には以下の制約があります。

    • max_chunk_size_tokens は 100 以上 4096 以下である必要があります。
    • chunk_overlap_tokens は 0 以上である必要があり、max_chunk_size_tokens / 2 を超えないようにしてください。

    検索結果に基づく回答の生成

    検索を実行した後は、その結果をもとに回答を生成できます。検索結果と元のクエリを OpenAI のモデルに渡すと、検索結果を根拠とした回答が得られます。

    検索クエリの実行と結果の取得
    from openai import OpenAI
    
    client = OpenAI()
    
    user_query = "What is the return policy?"
    
    results = client.vector_stores.search(
        vector_store_id=vector_store.id,
        query=user_query,
    )
    検索結果に基づく回答の生成
    # Use results and user_query from the preceding search step.
    formatted_results = format_results(results.data)
    
    "\n".join("\n".join(c.text for c in result.content) for result in results.data)
    
    completion = client.chat.completions.create(
        model="gpt-6-astra",
        messages=[
            {
                "role": "developer",
                "content": "Produce a concise answer to the query based on the provided sources.",
            },
            {
                "role": "user",
                "content": f"Sources: {formatted_results}\n\nQuery: '{user_query}'",
            },
        ],
    )
    
    print(completion.choices[0].message.content)
    "Our return policy allows returns within 30 days of purchase."

    この例で使っている format_results 関数は、以下のように実装できます。

    検索結果を整形する関数の例
    def format_results(results):
        formatted_results = ""
        for result in results.data:
            formatted_result = (
                f"<result file_id='{result.file_id}' file_name='{result.filename}'>"
            )
            for part in result.content:
                formatted_result += f"<content>{part.text}</content>"
            formatted_results += formatted_result + "</result>"
        return f"<sources>{formatted_results}</sources>"