GoogleドライブをデータソースとするVertex AI SearchアプリでPythonからの検索結果がゼロになる場合の対処法

記事タイトルとURLをコピーする

G-gen の堂原です。当記事では、Google ドライブをデータソースとする Vertex AI Search アプリに対して、Python から検索を行う際に検索結果が0件になってしまう場合の対処法について紹介します。

はじめに

当記事では、Google Cloud(旧称 GCP)が提供する検索エンジンサービスである Vertex AI Search において、Google ドライブをデータソースとする Vertex AI Search アプリに対して、Python から検索を行う方法について紹介します。

Vertex AI Search アプリを Python から検索するには、次の 2 つの方法があります。

  1. Python Client を用いる方法
  2. Requests ライブラリを用いて直接 Google Cloud APIs にアクセスする方法

しかし実装方法によっては、検索結果が0件になってしまう場合があります。

検索が失敗するケース

Google Cloud APIs のチャンネルが v1alpha 以外の場合

当記事を執筆した2024年12月現在、Google ドライブをデータソースとする Vertex AI Search アプリへの検索は、「Python Client を用いる方法」「直接 Google Cloud APIs にアクセスする方法」の両方とも、v1alpha でのみ期待通り動作します。一方で、v1 または v1beta を用いた場合は、検索結果が0件になります。

Google Cloud APIs において v1alpha とは、API のバージョンを示すチャンネルの1つです。Google Cloud APIs は基本的に、v1alpha、v1beta、v1 という順で開発が進みます。v1alpha の機能は予告なく削除される可能性があるため、本番環境での利用は非推奨です。

サービスアカウントを用いる場合

Google Cloud APIs には通常、Google アカウントまたはサービスアカウントの認証情報を使用してアクセスします。

ただし、2024年12月現在では、サービスアカウントを用いて Google ドライブをデータソースとする Vertex AI Search アプリへの検索を行った場合、サーバ側のエラー(500 Internal Server Error)が発生します。

対処法

当事象に対する2024年12月現在の対処法は、以下のとおりです。

  1. v1alpha チャンネルのクライアントライブラリを使用する
  2. サービスアカウントではなく、Google アカウントの認証情報を使用する

Python Client

サンプルコード

Python Client を使用する場合のサンプルコードは次のとおりです。

from google.cloud.discoveryengine_v1alpha import SearchServiceClient, SearchRequest
from google.protobuf.json_format import MessageToDict
 
PROJECT_ID = "xxx" # Google Cloud プロジェクト ID
VERTEX_AI_APP_ID = "xxx" # Vertex AI Search アプリの ID
 
client = SearchServiceClient(credentials=credentials)
 
serving_config = f"projects/{PROJECT_ID}/locations/global/collections/default_collection/engines/{VERTEX_AI_APP_ID}/servingConfigs/default_serving_config"
 
content_search_spec = SearchRequest.ContentSearchSpec(
    # スニペットを出力させない
    snippet_spec=SearchRequest.ContentSearchSpec().SnippetSpec(
        return_snippet=False
    ),
    # 要約文を出力させる
    summary_spec=SearchRequest.ContentSearchSpec().SummarySpec(
        summary_result_count=3,
        include_citations=False,

        # Gemini Proを用いるように指定
        model_spec=SearchRequest.ContentSearchSpec().SummarySpec().ModelSpec(
            version="gemini-1.5-flash-001/answer_gen/v1"
        )
    )
)
 
# Vertex AI Searchにクエリを投げる
response = client.search(
    SearchRequest(
        serving_config=serving_config,
        query="G-genとは?",
        page_size=3,
        content_search_spec=content_search_spec
    )
)
 
# 要約文を標準出力
print(response.summary.summary_text)
 
# 検索結果を標準出力
for r in response.results:
    r_dct = MessageToDict(r._pb)
    print(r_dct)

ポイント

ライブラリのチャンネル指定

from google.cloud.discoveryengine_v1alpha import SearchServiceClient, SearchRequest

上記のように、google-cloud-discoveryengine をインポートする際のチャンネル指定は _v1alpha を明示的に指定する必要があります。チャンネルを指定しない以下のようなインポート文だと、検索が失敗するケースに記載の通り、検索結果が0件になります。

# 未指定
from google.cloud.discoveryengine import SearchServiceClient, SearchRequest
 
# v1 指定
from google.cloud.discoveryengine_v1 import SearchServiceClient, SearchRequest
 
# v1beta 指定
from google.cloud.discoveryengine_v1beta import SearchServiceClient, SearchRequest

credentials

client = SearchServiceClient(credentials=credentials) でパラメータとして与える認証情報はサービスアカウントのものではなく、Google アカウントのものにする必要があります。

Google アカウントの認証情報の場合は変数の型が google.oauth2.credentials.Credentials に、サービスアカウントの認証情報の場合は変数の型が google.oauth2.service_account.Credentials になります。

Requests ライブラリを用いての直接アクセス

サンプルコード

Requests ライブラリを使用して Google Cloud APIs に直接アクセスする場合のサンプルコードは次のとおりです。

import requests
 
PROJECT_NUMBER = "xxx" # Google Cloud プロジェクト番号
VERTEX_AI_APP_ID = "xxx" # Vertex AI Search アプリの ID
 
# APIのURL
url = f"https://discoveryengine.googleapis.com/v1alpha/projects/{PROJECT_NUMBER}/locations/global/collections/default_collection/engines/{VERTEX_AI_APP_ID}/servingConfigs/default_search"
 
# リクエストヘッダ
headers = {
    "Authorization": "Bearer " + credentials.token,
    "Content-Type": "application/json",
}
 
# リクエストボディ
session = f"projects/{PROJECT_NUMBER}/locations/global/collections/default_collection/engines/{VERTEX_AI_APP_ID}/sessions/-"
data = {
    "query": "G-genとは?",
    "pageSize": 3,
    "contentSearchSpec": {
        "snippetSpec": {
            "returnSnippet": False
        },
        "extractiveContentSpec": {
            "maxExtractiveAnswerCount": 1
        }
    },
    "session": session
}
 
# 検索リクエスト送信
response = requests.post(f"{url}:search", headers=headers, json=data)
 
# 検索結果を標準出力
for r in response.json().get("results"):
    print(r)
 
data = {
    "query": {
        "text": "G-genとは?",
        "queryId": response.json().get("sessionInfo").get("queryId")
    },
    "session": response.json().get("sessionInfo").get("name"),
    "answerGenerationSpec": {
        "modelSpec": {
            "modelVersion": "gemini-1.5-flash-001/answer_gen/v1"
        }
    }
}
 
# 要約リクエスト送信
response = requests.post(f"{url}:answer", headers=headers, json=data)
 
# 要約文を標準出力
print(response.json().get("answer").get("answerText"))

ポイント

Requests ライブラリを用いて直接 Google Cloud APIs にアクセスパターンでも、重要なポイントは Python Client を用いる場合と変わりません。

  • API の URL のチャンネル指定を v1alpha にする
  • ヘッダの Authorization に含むトークンは Google アカウントのアクセストークンとする

堂原 竜希(記事一覧)

クラウドソリューション部データアナリティクス課。2023年4月より、G-genにジョイン。

Google Cloud Partner Top Engineer 2023, 2024, 2025に選出 (2024年はRookie of the year、2025年はFellowにも選出)。休みの日はだいたいゲームをしているか、時々自転車で遠出をしています。