プライベート(Private Service Connect)エンドポイントを使用したセマンティック キャッシュ保存

このページの内容は Apigee に適用されます。Apigee ハイブリッドには適用されません。

Apigee Edge のドキュメントを表示する。

このページでは、セマンティック類似性に基づいてレスポンスをインテリジェントに再利用できるようにするための、Apigee セマンティック キャッシング ポリシーの構成と使用方法について説明しています。この例では、ポリシーは プライベート(Private Service Connect)エンドポイントにデプロイされたベクトル検索インデックスに対して類似性検索を実行します。これらのポリシーを Apigee の API プロキシで使用することで、バックエンドでの API 呼び出しの冗長性を最小限に抑え、レイテンシを減らし、運用コストを削減できます。

始める前に

始める前に、次のタスクを完了します。

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. Enable the Compute Engine, AI Platform, and Cloud Storage APIs.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  4. Google Cloud プロジェクトで Vertex AI の Text embeddings API を有効にして構成します。
  5. プライベート(Private Service Connect)エンドポイントにデプロイされたベクトル検索インデックスを作成する(またはアクセス権がある)。このチュートリアルでは、ベクトル検索の設定手順は重複していません。SemanticCacheLookup 固有の要件とベクトル検索のドキュメントへのリンクについては、ベクトル検索インデックスの前提条件をご覧ください。
  6. Apigee インスタンスで中間環境または包括的環境が使用可能であることを確認します。セマンティック キャッシュ ポリシーは、中間環境または包括的環境にのみデプロイできます。
  7. API プロキシにリクエストを送信するために使用できるランタイム ホスト名を持つ環境グループがあることを確認します。

必要なロール

セマンティック キャッシュ ポリシーの作成と使用に必要な権限を取得するには、Apigee プロキシのデプロイに使用するサービス アカウントに対する AI Platform ユーザー roles/aiplatform.user)の IAM ロールを管理者に付与してもらってください。ロールの付与については、プロジェクト、フォルダ、組織に対するアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

環境変数を設定する

Apigee インスタンスを含む Google Cloud プロジェクトで、次のコマンドを使用して環境変数を設定します。

export PROJECT_ID=PROJECT_ID
export REGION=REGION
export RUNTIME_HOSTNAME=RUNTIME_HOSTNAME

ここで

  • PROJECT_ID: Apigee インスタンスを含むプロジェクトの ID。
  • REGION は Apigee インスタンスの Google Cloud リージョンです。
  • RUNTIME_HOSTNAME は Apigee ランタイムのホスト名です。

環境変数が正しく設定されていることを確認するには、次のコマンドを実行して出力を確認します。

echo $PROJECT_ID $REGION $RUNTIME_HOSTNAME

プロジェクトを設定する

開発環境で Google Cloud プロジェクトを設定します。

    gcloud auth login
    gcloud config set project $PROJECT_ID

ベクトル検索インデックスの前提条件

このチュートリアルでは、プライベート(Private Service Connect)エンドポイントにデプロイされたベクトル検索インデックスがすでに存在するか、作成されることを前提としています。ベクトル検索インデックスの作成、フォーマット、デプロイについては、ベクトル検索ガイドに記載されているため、このチュートリアルではこれらの手順を繰り返しません。ベクトル検索のドキュメントに沿って、次の操作を行います。

インデックスを作成する際は、次の SemanticCacheLookup 固有の要件を満たす必要があります。

  • SemanticCachePopulate ポリシーの upsertDatapoints 呼び出しがほぼリアルタイムでクエリ可能になるように、インデックスで STREAM_UPDATE"indexUpdateMethod": "STREAM_UPDATE")を使用する必要があります。
  • インデックス dimensions は、SemanticCacheLookup ポリシーで使用するエンベディング モデルの出力ディメンションと一致している必要があります。このチュートリアルでは gemini-embedding-001 を使用します。このモデルは、デフォルトで 3, 072 次元のエンベディングを生成します。出力をより低い次元(768 や 1,536 など)に切り捨てる場合は、dimensions を同じ値に設定します。
  • ポリシーの <DistanceMeasureType> に一致する距離測定(distanceMeasureType)を使用してインデックスを作成します。SemanticCacheLookup ポリシーの <SimilaritySearch><VertexAI><DistanceMeasureType> 要素は省略可能で、デフォルトは DOT_PRODUCT_DISTANCE です。COSINE_DISTANCE もサポートされています。インデックス距離測定とポリシー <DistanceMeasureType> は同じである必要があります。

次の最小限の例では、互換性のあるインデックスを作成します。リクエスト本文全体と使用可能なすべてのオプションについては、インデックスを作成して管理するをご覧ください。

ACCESS_TOKEN=$(gcloud auth print-access-token) && curl -X POST \
  "https://$REGION-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/indexes" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "semantic-cache-index",
    "metadata": {
      "config": {
        "dimensions": 3072,
        "distanceMeasureType": "DOT_PRODUCT_DISTANCE"
      }
    },
    "indexUpdateMethod": "STREAM_UPDATE"
  }'

レスポンスで返された数値の INDEX_ID をメモします。これは SemanticCachePopulate ポリシーで使用します。インデックスを作成したら、Private Service Connect インデックス エンドポイントを作成し、インデックスをデプロイします。

Private Service Connect インデックス エンドポイントを作成する場合は、次の SemanticCacheLookup 固有の要件を満たす必要があります。

  • projectAllowlist には、接続を開始する Apigee プロジェクトを含める必要があります
    • Apigee: Apigee テナント プロジェクトを使用します。Organizations APIapigeeProjectId フィールド)からテナント プロジェクト ID を取得します。
    インデックス エンドポイントの作成後に projectAllowlist を変更することはできません。間違ったプロジェクトを許可リストに登録した場合は、インデックス エンドポイントを削除して再作成する必要があります。

インデックス エンドポイントの数値 INDEX_ENDPOINT_ID をメモします。

Apigee プロキシのサービス アカウントを構成する

Apigee プロキシは、Vertex AI REST 呼び出しにサービス アカウントを使用します。SemanticCacheLookup ポリシーの Embeddings API、SemanticCachePopulate ポリシーの upsertDatapoints、モデル ターゲットです。そのサービス アカウントに AI Platform Userroles/aiplatform.user)ロールを付与します。

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:SERVICE_ACCOUNT" \
  --role="roles/aiplatform.user"

ここで、SERVICE_ACCOUNT はプロキシが使用するサービス アカウントのメールアドレスです。このサービス アカウントは、ステップ 4: API プロキシをインポートしてデプロイするでプロキシをデプロイするときに参照します。

概要

セマンティック キャッシュ ポリシーにより、LLM モデルを使用する Apigee ユーザーは、同一または意味的に類似したプロンプトを効率的に提供し、バックエンド API 呼び出しを最小限に抑えてリソース消費を削減できます。

SemanticCacheLookup ポリシーと SemanticCachePopulate ポリシーは、それぞれ Apigee API プロキシのリクエスト フローとレスポンス フローにアタッチされています。プロキシがリクエストを受信すると、SemanticCacheLookup ポリシーはそのリクエストからユーザー プロンプトを抽出し、Text embeddings API を使って数値表現に変換します。セマンティックな類似性検索は、ベクトル検索を使用して類似したプロンプトを見つけるために実行されます。類似したプロンプト データポイントが見つかった場合は、キャッシュ検索が実行されます。キャッシュに保存されているデータが見つかった場合、キャッシュに保存されているレスポンスがクライアントに返されます。

類似性検索で過去の類似したプロンプトが返されなかった場合、LLM モデルはユーザー プロンプトに対してコンテンツを生成し、そのレスポンスを Apigee キャッシュに保存します。フィードバック ループが作成され、今後のリクエストに備えてベクトル検索インデックス エントリが更新されます。

このシナリオでは、ベクトル検索インデックスは gRPC 経由でプライベート(Private Service Connect)エンドポイントにデプロイされます。ベクトル検索の Private Service Connect のサポートの詳細については、プライベート サービス アクセスまたは Private Service Connect インデックスをクエリするをご覧ください。

以降のセクションでは、セマンティック キャッシュ ポリシーを作成して構成するための手順をご案内します。

  1. リソースを確認し、Apigee が必要とする値を取得します。
  2. サービス アタッチメントに接続します。
  3. API プロキシ バンドルをビルドします。
  4. API プロキシをインポートしてデプロイします。
  5. セマンティック キャッシュ保存ポリシーをテストする。

ステップ 1: リソースを確認し、Apigee に必要な値を取得する

Apigee を構成する前に、ベクトル検索インデックス エンドポイントで Private Service Connect が有効になっており、インデックスがデプロイされていることを確認します。次に、Apigee プロキシが使用する 2 つの値(サービス アタッチメントと DEPLOYED_INDEX_ID)を読み取ります。

インデックスがデプロイされ、エンドポイントが Private Service Connect サービス アタッチメントを公開していることを確認します。

gcloud ai index-endpoints describe INDEX_ENDPOINT_ID \
  --project=$PROJECT_ID --region=$REGION \
  --format="value(deployedIndexes.privateEndpoints.serviceAttachment)"

このコマンドは、projects/TENANT_PROJECT/regions/REGION/serviceAttachments/SERVICE_ATTACHMENT_NAME 形式のサービス アタッチメント リソース名を返します。このガイドでは、この値を SERVICE_ATTACHMENT と呼びます。コマンドが空の値を返した場合、インデックスは Private Service Connect エンドポイントにまだデプロイされていません。ベクトル検索インデックスの前提条件に戻り、続行する前にインデックスのデプロイを完了します。

エンドポイントにデプロイされたインデックスの DEPLOYED_INDEX_ID を読み取ります。

gcloud ai index-endpoints describe INDEX_ENDPOINT_ID \
  --project=$PROJECT_ID --region=$REGION \
  --format="value(deployedIndexes.id)"

このガイドでは、この値を DEPLOYED_INDEX_ID と呼びます。これは、ステップ 3: API プロキシ バンドルをビルドするの SemanticCacheLookup ポリシーで使用します。

プライベート インデックス エンドポイントのデプロイとクエリの詳細については、Private Service Connect エンドポイントにインデックスをデプロイするPrivate Services Access または Private Service Connect インデックスをクエリするをご覧ください。

ステップ 2: サービス アタッチメントに接続する

このステップでは、プロキシの <GrpcEndpoint> が呼び出すプライベート ホストを取得します。Apigee で、Apigee エンドポイント アタッチメントを作成します。エンドポイント アタッチメントは、Apigee の Private Service Connect コンシューマー側です。ベクトル検索サービス アタッチメントに接続し、プロキシが呼び出すプライベート ホストを提供します。

curl -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{
        "location": "'"$REGION"'",
        "serviceAttachment": "SERVICE_ATTACHMENT"
      }' \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/endpointAttachments?endpointAttachmentId=ENDPOINT_ATTACHMENT"

アタッチメントの stateACTIVE になり、connectionStateACCEPTED になるまでポーリングし、ホストをメモします。

curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/endpointAttachments/ENDPOINT_ATTACHMENT"

レスポンスには、host フィールドにホストが含まれます。このガイドでは、この値を TARGET_HOST と呼びます。

プロキシからベクトル検索サービス アタッチメントに接続するには、次のいずれかを使用します。

  • IP アドレス: host フィールドで返された IP アドレスを TARGET_HOST(例: 7.0.3.4)として直接使用します。
  • プライベート DNS レコード: Apigee への DNS ピアリングを使用して Google Cloud プロジェクトで限定公開 Cloud DNS ゾーンを構成した場合は、エンドポイント アタッチメントの IP アドレスを参照する限定公開ゾーンに A レコードを作成し、そのドメイン名(vectorsearch.example.com など)を TARGET_HOST として使用できます。詳細については、DNS レコードを使用するプライベート DNS ピアリング ゾーンとの接続をご覧ください。

ステップ 3: API プロキシ バンドルをビルドする

プロキシ バンドルを作成する

次のディレクトリ レイアウトを作成します。

apiproxy/
├── PROXY_NAME.xml
├── proxies/default.xml
├── targets/default.xml
└── policies/
    ├── SCL-1.xml
    └── SCP-1.xml

policies/SCL-1.xml - SemanticCacheLookup ポリシー。<SimilaritySearch> ブロックは <PrivateServiceConnect><GrpcEndpoint><URL> なし)を使用します。

注: <GrpcEndpoint> ルール:

  • 形式は grpc://TARGET_HOST:PORT です。スキームは grpc:// にする必要があります。このバージョンでは grpcs://(TLS)はサポートされていません。
  • ベクトル検索のポートは 10000 です。Private Service Connect データプレーン エンドポイントはポート 10000 で gRPC を提供するため、エンドポイントは常に grpc://TARGET_HOST:10000 になります。
  • TARGET_HOST には、エンドポイント アタッチメントの IP アドレス(ステップ 2)またはプライベート DNS ゾーンに作成されたカスタム DNS レコードを指定できます。
  • gRPC ホップはプレーンテキストで認証されていません(ネットワーク分離によって保護されています)。
<SemanticCacheLookup async="false" continueOnError="false" enabled="true" name="SCL-1">
  <DisplayName>SCL-1</DisplayName>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <UserPromptSource>{jsonPath('$.contents[-1].parts[-1].text',request.content,true)}</UserPromptSource>
  <Embeddings>
    <VertexAI>
      <URL>https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/publishers/google/models/gemini-embedding-001:predict</URL>
    </VertexAI>
  </Embeddings>
  <SimilaritySearch>
    <VertexAI>
      <PrivateServiceConnect>
        <GrpcEndpoint>grpc://TARGET_HOST:10000</GrpcEndpoint>
      </PrivateServiceConnect>
      <DeployedIndexID>DEPLOYED_INDEX_ID</DeployedIndexID>
      <Threshold>0.95</Threshold>
    </VertexAI>
  </SimilaritySearch>
</SemanticCacheLookup>

policies/SCP-1.xml - SemanticCachePopulate ポリシー。Populate は REST 専用であり、<URL> を使用する必要があります(デプロイ時に <PrivateServiceConnect> を拒否します)。

<SemanticCachePopulate async="false" continueOnError="true" enabled="true" name="SCP-1">
  <DisplayName>SCP-1</DisplayName>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <SimilaritySearch>
    <VertexAI>
      <URL>https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/indexes/INDEX_ID:upsertDatapoints</URL>
    </VertexAI>
  </SimilaritySearch>
  <TTLInSeconds>3600</TTLInSeconds>
</SemanticCachePopulate>

targets/default.xml - モデルのターゲット。ターゲットは Google API を呼び出すため、トークンが必要です。<GoogleAccessToken> はデプロイのサービス アカウントを使用します。

<TargetEndpoint name="default">
  <PreFlow name="PreFlow"><Request/><Response/></PreFlow>
  <PostFlow name="PostFlow"><Request/><Response/></PostFlow>
  <HTTPTargetConnection>
    <Authentication>
      <GoogleAccessToken>
        <Scopes>
          <Scope>https://www.googleapis.com/auth/cloud-platform</Scope>
        </Scopes>
      </GoogleAccessToken>
    </Authentication>
    <URL>https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/publishers/google/models/gemini-2.5-flash:generateContent</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

proxies/default.xml - リクエストで SemanticCacheLookup ポリシーを実行し、レスポンスで SemanticCachePopulate ポリシーを実行します。

<ProxyEndpoint name="default">
  <PreFlow name="PreFlow">
    <Request><Step><Name>SCL-1</Name></Step></Request>
    <Response><Step><Name>SCP-1</Name></Step></Response>
  </PreFlow>
  <PostFlow name="PostFlow"><Request/><Response/></PostFlow>
  <HTTPProxyConnection>
    <BasePath>/PROXY_NAME</BasePath>
  </HTTPProxyConnection>
  <RouteRule name="default">
    <TargetEndpoint>default</TargetEndpoint>
  </RouteRule>
</ProxyEndpoint>

PROXY_NAME.xml - バンドル記述子:

<APIProxy name="PROXY_NAME">
  <BasePaths>/PROXY_NAME</BasePaths>
  <Policies><Policy>SCL-1</Policy><Policy>SCP-1</Policy></Policies>
  <ProxyEndpoints><ProxyEndpoint>default</ProxyEndpoint></ProxyEndpoints>
  <TargetEndpoints><TargetEndpoint>default</TargetEndpoint></TargetEndpoints>
</APIProxy>

ステップ 4: API プロキシをインポートしてデプロイする

バンドルを圧縮し、インポートして新しいリビジョンを作成し、サービス アカウントを使用してリビジョンをデプロイします。

TOKEN=$(gcloud auth print-access-token)
(cd BUNDLE_DIR && zip -r ../PROXY_NAME.zip apiproxy)
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -F "file=@PROXY_NAME.zip" \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/apis?action=import&name=PROXY_NAME"
curl -X POST -H "Authorization: Bearer $TOKEN" \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/environments/ENV/apis/PROXY_NAME/revisions/REVISION/deployments?override=true&serviceAccount=SERVICE_ACCOUNT"

ここで

  • BUNDLE_DIR は、apiproxy/ フォルダを含むディレクトリです。アーカイブのルートに apiproxy/ フォルダが含まれている必要があります。
  • ENV は、プロキシをデプロイする Apigee 環境です。環境は、中間環境または包括的環境である必要があります。
  • REVISION は、インポート呼び出しによって返されるリビジョン番号です。
  • SERVICE_ACCOUNT は、プロキシのデプロイに使用するサービス アカウントのメールアドレスです。

デプロイから READY が報告されるまで待ちます。

curl -s -H "Authorization: Bearer $TOKEN" \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/environments/ENV/apis/PROXY_NAME/revisions/REVISION/deployments" | jq .state

ステップ 5: セマンティック キャッシュ保存ポリシーをテストする

新しいプロンプトを送信します。これはキャッシュミスです。モデルが呼び出され、回答がキャッシュに保存されます。

curl -X POST "https://$RUNTIME_HOSTNAME/PROXY_NAME" \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"role":"user","parts":[{"text":"Explain in one sentence why the sky appears blue."}]}]}'

同じプロンプトをもう一度送信します。これはキャッシュ ヒットです。レスポンスはキャッシュから提供され、モデルは呼び出されません。

curl -i -X POST "https://$RUNTIME_HOSTNAME/PROXY_NAME" \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"role":"user","parts":[{"text":"Explain in one sentence why the sky appears blue."}]}]}'

ヒットの場合、レスポンスには Cached-content: true ヘッダー、同じ回答、大幅に低いレイテンシが含まれます。

デバッグ セッションでキャッシュ保存を確認することもできます。ヒットすると、SemanticCacheLookup ポリシーは次のフロー変数を設定します。

変数 ヒットの値
SemanticCacheLookup.SCL-1.dense_embeddings プロンプトのエンベディング ベクトル。
SemanticCacheLookup.SCL-1.is_nearest_neighbor_hit true
SemanticCacheLookup.SCL-1.cache_hit true
SemanticCacheLookup.SCL-1.cached_llm_response キャッシュに保存された回答。

ヒットすると、モデル ターゲットは呼び出されません。フローがショートサーキットし、キャッシュに保存されたレスポンスが返されます。

トラブルシューティング

エラー リファレンスの完全版については、SemanticCacheLookup ポリシーをご覧ください。

次のステップ