ルーティング、Model Armor、セマンティック キャッシュを使用して AI ゲートウェイを構築する

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

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

このチュートリアルでは、Apigee を AI ゲートウェイとして構成して使用し、ポリシーベースの柔軟なルーティング ルールに基づいて、大規模言語モデル(LLM)リクエストをさまざまなバックエンド モデルにルーティングする方法について説明します。AI ゲートウェイは、モデル トラフィックの保護、管理、最適化に役立ち、費用を管理してモデルの乱立を防ぎます。

チュートリアルの各ステージでは、再利用可能な Apigee Feature Template(AFT)ファイルを使用して特定の機能を追加することで、前の構成をベースに構築します。

  • ステージ 1: 単一の LLM プロバイダをフロントエンドとする最小限の API プロキシをデプロイします。
  • ステージ 2: Model Armor のプロンプトとレスポンスのサニタイズを追加して、悪意のある入力をフィルタし、機密データの漏洩を防ぎます。
  • ステージ 3: クロス プロバイダ モデル ルーティングと、Agent Platform ベクトル検索に基づくセマンティック キャッシュを追加します。
  • ステージ 4: プライマリ ターゲットが 4xx または 5xx HTTP ステータス コードを返した場合に、セカンダリ プロバイダに対してリクエストを自動的に再試行するように、プロバイダ間のフォールバックを構成します。

機能を追加するには、テンプレートの features ブロックに 1 行追加します。AFT ファイルやヘルパー スクリプトなど、サンプル ファイルの完全なセットを表示またはダウンロードするには、GitHub の Apigee テンプレート リポジトリをご覧ください。

始める前に

このチュートリアルを最後まで進めるには、次のものが必要です。

  • 課金が有効になっているアクティブな Google Cloud プロジェクト。
  • Apigee インスタンスで包括的な環境が使用可能であること。Model Armor、SemanticCacheLookup、SemanticCachePopulate のポリシーは、包括的環境でのみデプロイできます。
  • Google Cloud CLI(gcloud)がインストールされ、アプリケーションのデフォルト認証情報(ADC)で構成されている。認証情報を生成するには、gcloud auth application-default login を実行します。
  • 次の IAM ロールを持つランタイム サービス アカウント。
    • roles/aiplatform.user
    • roles/modelarmor.user
    サービス アカウントには、プロバイダ固有の認証情報へのアクセス権も必要です。
  • ステージ 2、3、4 では、Model Armor テンプレートのリソースパスを指定します。たとえば、projects/YOUR_PROJECT/locations/us-central1/templates/apigee-aft-demo-ma のようになります。
  • ステージ 3 と 4 の場合: 有効な OpenAI API キーを含む api-key エントリを含む、環境内の openai-credentials という名前の Apigee Key-Value マップ(KVM)。
  • ステージ 3 と 4 の場合: セマンティック キャッシュ用にデプロイされた Vertex AI ベクトル検索インデックス エンドポイント。インデックス設定の手順については、GitHub の Apigee テンプレート リポジトリの README をご覧ください。

概要

4 つのステージはすべて、/v1/chat/completions[-stageN] で OpenAI Chat Completions リクエストの形式を受け入れるため、同じクライアント SDK がすべてのステージで機能します。model フィールドの接頭辞によってモデル ルーティングが決定されます。google/* モデルのリクエストは Agent Platform の Gemini にルーティングされ、他のすべてのリクエストは OpenAI にルーティングされます。このデフォルトの反転により、o1-*、o3-*、chatgpt-* などの新しい OpenAI モデル ファミリーが、gpt-* 接頭辞の一致がサイレントに欠落するのではなく、正しくルーティングされます。

ステージ 機能を追加しました Base path
1 Hello LLM(Agent Platform での Gemini への OpenAI 形式のリクエスト) /v1/chat/completions
2 Model Armor(プロンプト インジェクション、責任ある AI、Sensitive Data Protection のフィルタ) /v1/chat/completions-stage2
3 プロバイダ間のルーティングと Agent Platform ベクトル検索セマンティック キャッシュ /v1/chat/completions-stage3
4 クロスプロバイダ フォールバック(完全な AI ゲートウェイ) /v1/chat/completions-stage4

ステージ 1: LLM の概要

最小限のプロキシは、OpenAI 互換のエンドポイントを介して単一の Gemini ターゲットをフロントエンドします。2 つの小さな機能ファイルが、ベース プロキシのスケルトンと JSON エクストラクタを提供します。抽出ツールは、$.model と $.messages[-1].content を llm.model と llm.prompt のフロー変数にコピーし、後続のステージで一貫した入力が得られるようにします。

llm-base.yaml は、ベース プロキシ スケルトンを定義します。

gateway: apigee
schemaVersion: 1.0.0
name: llm-base
type: feature
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions
endpoints:
  - name: default
    basePath: "{BASE_PATH}"
    routes:
      - name: primary
        target: gemini-target

llm-openai-format.yaml は、OpenAI 形式のリクエスト フィールドを抽出します。

gateway: apigee
schemaVersion: 1.0.0
name: llm-openai-format
type: feature
defaultEndpoint:
  name: default
  flows:
    - name: PreFlow
      mode: Request
      steps:
        - name: EV-ExtractOpenAIRequest
policies:
  - name: EV-ExtractOpenAIRequest
    type: ExtractVariables
    content:
      ExtractVariables:
        metadata:
          name: EV-ExtractOpenAIRequest
          continueOnError: "true"
        Source:
          _text: request
        JSONPayload:
          Variable:
            - metadata:
                name: model
              JSONPath:
                _text: "$.model"
            - metadata:
                name: prompt
              JSONPath:
                _text: "$.messages[-1].content"
        VariablePrefix:
          _text: llm

target-vertex-gemini.yaml は、OpenAI 互換エンドポイントを使用する Agent Platform ターゲットを定義します。

gateway: apigee
schemaVersion: 1.0.0
name: target-vertex-gemini
type: feature
targets:
  - name: gemini-target
    httpTargetConnection:
      URL: https://aiplatform.googleapis.com/v1/projects/{organization.name}/locations/global/endpoints/openapi/chat/completions
      Authentication:
        GoogleAccessToken:
          Scopes:
            Scope: https://www.googleapis.com/auth/cloud-platform

機能ファイルをステージ 1 テンプレート 01-hello-llm.yaml に作成します。

gateway: apigee
schemaVersion: 1.0.0
name: aft-demo-01-hello-llm
features:
  - llm-base.yaml
  - llm-openai-format.yaml
  - target-vertex-gemini.yaml

テンプレートをデプロイします。

gcloud beta apigee apis import aft-demo-01-hello-llm \
  --from-template=01-hello-llm.yaml \
  --organization=APIGEE_ORG

プロキシをテストします。

curl -X POST https://APIGEE_HOSTNAME/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"google/gemini-2.5-flash",
       "messages":[{"role":"user","content":"Explain how AI works in a few words"}]}'

次のように置き換えます。

  • APIGEE_ORG: Apigee の組織名。
  • APIGEE_HOSTNAME: Apigee 環境グループのホスト名(通常はロードバランサ)。 Google Cloud

ステージ 2: Model Armor を追加する

Model Armor は、ターゲット呼び出しの前に、受信したプロンプトを検査して、プロンプト インジェクション、許可されていないコンテンツ、センシティブ データが含まれているかどうかを確認します。次に、レスポンスがクライアントに到達する前にモデルのレスポンスをスキャンします。

テンプレート llm-model-armor.yaml に 1 つの機能ファイルを追加します。

gateway: apigee
schemaVersion: 1.0.0
name: llm-model-armor
type: feature
parameters:
  - name: MA_TEMPLATE_PATH
    default: projects/{organization.name}/locations/us-central1/templates/apigee-aft-demo-ma
defaultEndpoint:
  name: default
  flows:
    - name: PreFlow
      mode: Request
      steps:
        - name: MA-SanitizeUserPrompt
    - name: PostFlow
      mode: Response
      steps:
        - name: MA-SanitizeModelResponse
policies:
  - name: MA-SanitizeUserPrompt
    type: SanitizeUserPrompt
    content:
      SanitizeUserPrompt:
        metadata:
          name: MA-SanitizeUserPrompt
        ModelArmor:
          TemplateName:
            _text: "{MA_TEMPLATE_PATH}"
        UserPromptSource:
          _text: "{llm.prompt}"
  - name: MA-SanitizeModelResponse
    type: SanitizeModelResponse
    content:
      SanitizeModelResponse:
        metadata:
          name: MA-SanitizeModelResponse
        ModelArmor:
          TemplateName:
            _text: "{MA_TEMPLATE_PATH}"
        UserPromptSource:
          _text: "{llm.prompt}"
        LLMResponseSource:
          _text: "{jsonPath('$.choices[-1].message.content',response.content,true)}"

ステージ 2 のテンプレート 02-add-model-armor.yaml では、1 行が追加されます。

gateway: apigee
schemaVersion: 1.0.0
name: aft-demo-02-add-model-armor
features:
  - llm-base.yaml
  - llm-openai-format.yaml
  - target-vertex-gemini.yaml
  - llm-model-armor.yaml           # <-- the change from Stage 1
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions-stage2

MA_TEMPLATE_PATH パラメータのデフォルトは、us-central1 の apigee-aft-demo-ma という名前のテンプレートです。独自の Model Armor テンプレートを使用するには、テンプレートの parameters ブロックでパラメータをオーバーライドします。

ステージ 3: クロス プロバイダ ルーティングとセマンティック キャッシュを追加する

ステージ 3 では、2 つ目のターゲット(OpenAI)を追加し、単一ルートルールをモデルベースのルーティングに置き換え、両方のターゲットの前に Agent Platform ベクトル検索を基盤とするセマンティック キャッシュを構成します。

ステージ 3 を構成するには、テンプレートの features ブロックに 3 つの機能ファイルを追加します。

  • target-openai-gpt.yaml: OpenAI をセカンダリ ターゲット エンドポイントとして追加します。
  • llm-routing.yaml: リクエストされたモデル名に基づいてリクエストを動的にルーティングします。
  • llm-semantic-cache.yaml: 両方のプロバイダの前にセマンティック キャッシュを追加します。

次の例は、llm-routing.yaml 機能ファイルでルーティング ロジックを定義する方法を示しています。

gateway: apigee
schemaVersion: 1.0.0
name: llm-routing
type: feature
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions
endpoints:
  - name: default
    basePath: "{BASE_PATH}"
    routes:
      - name: gemini
        condition: llm.model StartsWith "google/"
        target: gemini-target
      - name: openai
        target: openai-target      # default when the condition is false

セマンティック キャッシュは、キャッシュミスの場合にのみ、リクエスト PreFlow で SemanticCacheLookup を実行し、レスポンス PostFlow で SemanticCachePopulate を実行します。どちらのポリシーも、個別にプロビジョニングする Agent Platform ベクトル検索インデックス エンドポイントを使用します。次の抜粋は、ポリシー定義の重要な部分を示しています。

policies:
  - name: SCLLookup
    type: SemanticCacheLookup
    content:
      SemanticCacheLookup:
        UserPromptSource:
          _text: "{llm.prompt}"
        Embeddings:
          VertexAI:
            URL:
              _text: "https://{EMBEDDINGS_LOCATION}-aiplatform.googleapis.com/v1/projects/{organization.name}/locations/{EMBEDDINGS_LOCATION}/publishers/google/models/{EMBEDDINGS_MODEL}:predict"
        SimilaritySearch:
          VertexAI:
            URL:
              _text: "https://{VECTOR_INDEX_ENDPOINT_SUBDOMAIN}.{EMBEDDINGS_LOCATION}-{PROJECT_NUMBER}.vdb.vertexai.goog/v1/projects/{organization.name}/locations/{EMBEDDINGS_LOCATION}/indexEndpoints/{VECTOR_INDEX_ENDPOINT_ID}:findNeighbors"
            DeployedIndexID:
              _text: "{DEPLOYED_INDEX_ID}"
            Threshold:
              _text: "{THRESHOLD}"
  - name: SCPPopulate
    type: SemanticCachePopulate
    # ... (see the GitHub repository for the full definition)

ステージ 3 のテンプレートは、すべての特徴ファイルを作成します。

gateway: apigee
schemaVersion: 1.0.0
name: aft-demo-03-add-routing-and-cache
features:
  - llm-base.yaml
  - llm-openai-format.yaml
  - target-vertex-gemini.yaml
  - llm-model-armor.yaml
  - target-openai-gpt.yaml         # <-- add OpenAI target
  - llm-routing.yaml               # <-- add model-name routing
  - llm-semantic-cache.yaml        # <-- add semantic cache
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions-stage3
  - name: VECTOR_INDEX_ENDPOINT_ID
    default: "YOUR_INDEX_ENDPOINT_ID"
  - name: VECTOR_INDEX_ID
    default: "YOUR_INDEX_ID"
  - name: VECTOR_INDEX_ENDPOINT_SUBDOMAIN
    default: "YOUR_SUBDOMAIN"
  - name: PROJECT_NUMBER
    default: "YOUR_PROJECT_NUMBER"
  - name: DEPLOYED_INDEX_ID
    default: "YOUR_DEPLOYED_INDEX_ID"

ステージ 1 で使用したのと同じ gcloud beta apigee apis import コマンドと --from-template フラグを使用して、テンプレートをデプロイします。

ステージ 4: プロバイダ間のフォールバックを追加する

ステージ 4 では、両方のターゲットに DefaultFaultRule をアタッチします。プライマリ ターゲットが 4xx または 5xx ステータスを返すと、障害ルールは同じプロンプトを含む ServiceCallout を他のプロバイダに送信し、そのレスポンスをクライアントに返します。クライアントは、正常に完了した 200 レスポンスを受け取ります。独自の再試行ロジックやエラー処理は必要ありません。

この動作は、llm-fallback.yaml 機能ファイルによって追加されます。次の例は省略されています。完全なファイルについては、GitHub リポジトリをご覧ください。

gateway: apigee
schemaVersion: 1.0.0
name: llm-fallback
type: feature
targets:
  # Vertex primary; on 4xx/5xx, fall back to OpenAI.
  - name: gemini-target
    httpTargetConnection:
      Properties:
        Property:
          metadata:
            name: success.codes
          _text: "2XX"
      URL: https://aiplatform.googleapis.com/v1/projects/{organization.name}/locations/global/endpoints/openapi/chat/completions
      Authentication:
        GoogleAccessToken:
          Scopes:
            Scope: https://www.googleapis.com/auth/cloud-platform
    flows:
      - name: PostFlow
        mode: Response
        steps:
          - name: RF-TargetErrorToFault
            condition: response.status.code >= 400
    defaultFaultRule:
      name: FallbackToOpenAI
      steps:
        - name: KVM-GetOpenAIKey
        - name: AM-BuildOpenAIFallbackRequest
        - name: SC-FallbackToOpenAI
        - name: AM-CopyOpenAIFallbackResponse
  # OpenAI primary; on 4xx/5xx, fall back to Vertex.
  - name: openai-target
    httpTargetConnection:
      Properties:
        Property:
          metadata:
            name: success.codes
          _text: "2XX"
      URL: https://api.openai.com/v1/chat/completions
    flows:
      - name: PreFlow
        mode: Request
        steps:
          - name: JS-StripOpenAIModelPrefix
          - name: KVM-GetOpenAIKey
          - name: AM-SetOpenAIAuth
      - name: PostFlow
        mode: Response
        steps:
          - name: RF-TargetErrorToFault
            condition: response.status.code >= 400
    defaultFaultRule:
      name: FallbackToVertex
      steps:
        - name: AM-BuildVertexFallbackRequest
        - name: SC-FallbackToVertex
        - name: AM-CopyVertexFallbackResponse
policies:
  # RaiseFault converts a target 4xx/5xx into a fault so DefaultFaultRule fires.
  - name: RF-TargetErrorToFault
    type: RaiseFault
    content:
      RaiseFault:
        IgnoreUnresolvedVariables: "true"
        # empty FaultResponse -- DefaultFaultRule builds the real response
  # ... AM-Build*, SC-Fallback*, AM-Copy* policies -- see GitHub repository

フォールバックは次の 2 つの設定に依存します。

  • 両方の httpTargetConnection ブロックで success.codes: 2XX を使用します。Apigee は、2xx 以外のターゲット レスポンスをターゲット エラーとして扱い、障害フローに直接移行します。
  • 各ターゲットのレスポンス PostFlow の RaiseFault ポリシー。response.status.code >= 400 でゲートされます。このポリシーにより、すべてのエラー レスポンスに対して DefaultFaultRule が実行されます。

ステージ 4 のテンプレートを作成します。これにより、ステージ 3 のテンプレートに 1 行追加されます。

gateway: apigee
schemaVersion: 1.0.0
name: aft-demo-04-add-fallback
features:
  - llm-base.yaml
  - llm-openai-format.yaml
  - target-vertex-gemini.yaml
  - llm-model-armor.yaml
  - target-openai-gpt.yaml
  - llm-routing.yaml
  - llm-semantic-cache.yaml
  - llm-fallback.yaml              # <-- the change from Stage 3
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions-stage4
  # ... Model Armor and Vector Search parameters as in Stage 3

テンプレートをデプロイします。

gcloud beta apigee apis import aft-demo-04-add-fallback \
  --from-template=04-add-fallback.yaml \
  --organization=APIGEE_ORG

エンドツーエンドの動作を確認する

GitHub リポジトリには、トピックが多様なプロンプトを使用して、すべてのルーティング パスとフォールバック パスをテストする routing-diagnostic.sh スクリプトが含まれています。セマンティック キャッシュは類似したプロンプトをショートサーキットするため、各テストプロンプトは明確に異なる表現にする必要があります。

STAGE=4 ./routing-diagnostic.sh

このスクリプトは、ステージ 4 プロキシを介して 5 つのリクエストを送信します。

  • 正規の OpenAI モデル
  • google/ 接頭辞が付いた Gemini モデル
  • 接頭辞のない Gemini モデル名。反転したデフォルトで OpenAI にルーティングされます
  • OpenAI の推論モデル
  • openai/ 接頭辞が付いたモデル名

スクリプトは、リクエストごとに、レスポンスを配信したアップストリーム プロバイダと、フォールバックが発生したかどうかを報告します。

単一のリクエストのすべてのポリシー ステップ、ターゲット呼び出し、障害ルール遷移を確認するには、デプロイされたリビジョンに対して Apigee デバッグ セッションを作成します。

DEBUG_URL="https://apigee.googleapis.com/v1/organizations/APIGEE_ORG/environments/APIGEE_ENV/apis/aft-demo-04-add-fallback/revisions/REVISION/debugsessions"
curl -X POST -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{"filter":"","count":10,"timeout":"600","validity":600}' \
  "$DEBUG_URL"

次のように置き換えます。

  • APIGEE_ORG: Apigee の組織名。
  • APIGEE_ENV: プロキシをデプロイした環境。
  • REVISION: aft-demo-04-add-fallback プロキシのデプロイされたリビジョン番号。

次に、フォールバックを実行するリクエストを送信します。

curl -X POST https://APIGEE_HOSTNAME/v1/chat/completions-stage4 \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini",
       "messages":[{"role":"user","content":"Describe nuclear fusion in stars in two sentences."}]}'

Apigee API を使用して、キャプチャされたデバッグ セッション メッセージを取得すると、トレースに次の実行フローが表示されます。

  1. リクエスト変数を抽出する: Apigee は、受信ペイロードから llm.model 変数と llm.prompt 変数を抽出します。
  2. 安全性ポリシーを評価する: リクエストは Model Armor セキュリティ フィルタリングを通過します。
  3. セマンティック キャッシュを確認する: ルックアップでセマンティック キャッシュが見つからないため、リクエストはターゲットに続行されます。
  4. ルーティング条件を評価する: 条件 llm.model StartsWith "google/" は false と評価されます。
  5. プライマリ ターゲットへのルート: Apigee はリクエストを openai-target に転送します。
  6. ターゲット エラーを処理する: OpenAI ターゲットが 2xx 以外の HTTP ステータス コードを返すと、Apigee はターゲット エラーを発生させます。
  7. 障害ルールを実行する: DefaultFaultRule は、AM-BuildVertexFallbackRequest、SC-FallbackToVertex、AM-CopyVertexFallbackResponse を実行してフォールバック シーケンスをトリガーします。
  8. レスポンスを返す: クライアントは、Agent Platform の Gemini によって生成されたペイロードを含む HTTP 200 レスポンスを受信します。

次のステップ

  • 認証を構成する: プロキシの前にフェデレーション JWT、OpenID Connect(OIDC)、または Apigee API キーを実装して、テナント固有のトークン割り当てとプロバイダ アクセス制御を適用します。
  • 費用とレイテンシをモニタリングする: Apigee 分析ダッシュボードを API プロキシに接続して、モデルごとにレイテンシと運用コストを追跡します。
  • テナント固有の安全ポリシーを適用する: MA_TEMPLATE_PATH パラメータを使用してテナントごとの Model Armor テンプレートを構成し、エンタープライズ、デベロッパー、パブリック トラフィックにカスタマイズされたサニタイズ ルールを適用します。
  • サンプル構成を確認する: llm-fallback.yaml テンプレート、8 つの機能ファイル、routing-diagnostic.sh スクリプト、KVM、Model Armor、Agent Platform Vector Search のプロビジョニング スクリプトを含む完全なサンプルセットをダウンロードするには、GitHub の Apigee 進化型 AI ゲートウェイ リポジトリをご覧ください。