LLM レスポンスとその他のトラフィックのストリーミングを構成する

このドキュメントでは、API Gateway でストリーミングを構成する方法について説明します。

API Gateway はストリーミングをサポートしています。ストリーミングにより、ゲートウェイは長時間実行される接続を処理し、リクエスト ストリーミングとレスポンス ストリーミングの両方でデータをチャンクで送信できます。

ストリーミングの一般的な用途は、大規模言語モデル(LLM)のサービングです。モデルは回答を 1 トークンずつ送信するため、クライアントはモデルがテキストを生成している間にテキストを表示できます。vLLM が Cloud Run でサービングする Gemma モデルからレスポンスをストリーミングする実証済みの例については、LLM からレスポンスをストリーミングするをご覧ください。

サポートされているストリーミング プロトコル

有効にすると、API Gateway は次のストリーミング メソッドをサポートします。

  • 増分レスポンス配信: クライアントがネゴシエートする内容に応じて、HTTP/2 DATA フレームまたは HTTP/1.1 チャンク転送エンコード。
  • サーバー送信イベント(SSE): サーバーからクライアントへの単方向ストリーミング。
  • WebSockets: 単一の TCP 接続を介した全二重通信チャネル。
  • gRPC 双方向ストリーミング: gRPC を使用した全二重ストリーミング。

前提条件

ストリーミングを使用する前に、バックエンド サービスが必要なプロトコル(HTTP/2 や WebSockets など)をサポートしていること、API 構成が正しく設定されていることを確認してください。

バックエンド プロトコルを構成する

ストリーミング トラフィックをサポートするには、ストリーミングのタイプに基づいてバックエンドのプロトコルを構成する必要があります。

  • gRPC: HTTP/2(h2)を使用するようにバックエンドを構成する必要があります。
  • WebSockets: http/1.1 を使用する必要があります。WebSocket には HTTP/1.1 Connection: Upgrade handshake が必要です。
  • Server-Sent Events(SSE)と増分レスポンス配信: バックエンドは HTTP/1.1 または HTTP/2(h2)を使用できます。パフォーマンスを向上させるには、HTTP/2(h2)をおすすめします。

OpenAPI 仕様で、バックエンド プロトコルを次のように構成します。

例(OpenAPI 3.x)

x-google-api-management.backends オブジェクト内の名前付きバックエンド定義で protocol フィールドを設定します。また、ルートレベルまたはオペレーション レベルで x-google-backend を使用して、このバックエンドを参照する必要があります。

x-google-api-management:
  backends:
    gemma:
      address: https://my-gemma-service.run.app
      protocol: h2 # Use 'http/1.1' for WebSockets
x-google-backend: gemma

例(OpenAPI 2.0)

x-google-backend 拡張機能の protocol フィールドを設定します。

x-google-backend:
  address: https://my-gemma-service.run.app
  protocol: h2 # Use 'http/1.1' for WebSockets

ストリームの期限を設定する

deadline フィールドは、リクエスト(単項またはストリーミング)の実行時間を制御します。

次の表に、各種類のリクエストにタイムアウトがどのように適用されるかを示します。

メソッド アイドル タイムアウト
(メッセージ間の最大間隔)
リクエストのタイムアウト
(リクエストの最大合計時間)
非ストリーミング 該当なし: アイドル タイムアウトはストリームにのみ適用されます デフォルトは 15 秒です。変更するには deadline を設定します。ストリーミング対応ゲートウェイの場合は最大 3,600 秒です。
HTTP 経由のストリーミング
(SSE、チャンク転送)
該当なし: 実質的に無限。リクエスト タイムアウトのみがストリームを終了します デフォルトは 15 秒です。変更するには deadline を設定します。ストリーミング対応ゲートウェイの場合は最大 3,600 秒です。
gRPC または WebSocket を介したストリーミング デフォルトは 300 秒です。変更するには deadline を設定します。ストリーミング対応ゲートウェイの場合は最大 3,600 秒です。WebSockets では、300 秒未満の deadline は無視され、最小値の 300 秒が適用されます。 ストリーミング対応ゲートウェイの場合は常に 3,600 秒(構成不可)

例(OpenAPI 3.x)

名前付きバックエンド定義で deadline フィールドを設定します。

x-google-api-management:
  backends:
    gemma:
      address: https://my-gemma-service.run.app
      protocol: h2
      deadline: 3600.0
x-google-backend: gemma

例(OpenAPI 2.0)

x-google-backend 拡張機能の deadline フィールドを設定します。

x-google-backend:
  address: https://my-gemma-service.run.app
  protocol: h2
  deadline: 3600.0

ストリーミング接続に適用されるその他の上限については、制限事項をご覧ください。

ゲートウェイでストリーミングを有効にする

ストリーミングは、ゲートウェイの作成時に指定します。次の動作に注意してください。

  • 明示的な無効化なし: ストリーミングを明示的に無効にするフラグはありません。--enable-streaming フラグを省略すると、API Gateway は作成時に API 構成とプラットフォームのデフォルトからモードを解決します。モデルルーターを構成する API 構成は、常にストリーミング ゲートウェイを生成します。ゲートウェイの出力専用 effectiveStreamingMode フィールドを読み取り、作成されたモードを確認します。
  • 不変性: ストリーミング モードは作成時に固定され、後で変更することはできません。

ゲートウェイでストリーミングを指定するには、gcloud api-gateway gateways create コマンドで --enable-streaming フラグを使用します。

gcloud api-gateway gateways create GATEWAY_ID \
    --api=API_ID \
    --api-config=CONFIG_ID \
    --location=GCP_REGION \
    --enable-streaming

ゲートウェイのデプロイ オプションの詳細については、API をゲートウェイにデプロイするをご覧ください。

ゲートウェイのストリーミング プロパティ

Gateway リソースの次のフィールドで、ストリーミング動作を制御します。

フィールド 属性 値
streamingMode 文字列(IMMUTABLE、OPTIONAL)
  • STREAMING_MODE_UNSPECIFIED(デフォルト: サービスがモードを選択)
  • STREAMING_MODE_ENABLED
effectiveStreamingMode 文字列(OUTPUT_ONLY)
  • EFFECTIVE_STREAMING_MODE_DISABLED
  • EFFECTIVE_STREAMING_MODE_ENABLED

REST API を使用してゲートウェイを作成する場合は、リクエスト本文でストリーミングを指定できます。

{
  "apiConfig": "projects/...",
  "streamingMode": "STREAMING_MODE_ENABLED"
}

ストリーミングが有効になっていることを確認する

ゲートウェイでストリーミングが有効になっているかどうかを確認するには、gcloud CLI を使用してゲートウェイを記述します。

gcloud api-gateway gateways describe GATEWAY_ID \
    --location=GCP_REGION

出力で effectiveStreamingMode フィールドを探します。ストリーミングが有効になっている場合、出力には次のものが含まれます。

effectiveStreamingMode: EFFECTIVE_STREAMING_MODE_ENABLED

Google Cloud API を呼び出す

ストリーミング ゲートウェイは aiplatform.googleapis.com などの Google Cloud API を呼び出すことができるため、ゲートウェイを介して Agent Platform の Gemini モデルからレスポンスをストリーミングできます。ゲートウェイは、ID トークンではなくアクセス トークンを使用してこれらのバックエンドを認証します。詳細については、バックエンド サービスの保護をご覧ください。

LLM からのレスポンスをストリーミングする

この例では、vLLM が Cloud Run でサービングする Gemma モデルの前にストリーミング ゲートウェイを配置し、ゲートウェイを介してチャット補完をストリーミングします。vLLM は、サーバー送信イベント(SSE)としてレスポンスをストリーミングする OpenAI 互換の API を提供します。

始める前に、API 構成の作成に使用するサービス アカウントの構成を含む開発環境の構成を完了します。ゲートウェイは、そのサービス アカウントを使用して Cloud Run サービスを呼び出します。

モデルをデプロイする

vLLM コンテナを使用して Gemma 4 モデルをデプロイするの手順に沿って、Gemma モデルをデプロイします。サービス名、サービス URL、リージョン、デプロイするモデルの名前(google/gemma-4-E4B-it など)をメモします。

ゲートウェイにサービスへのアクセス権を付与する

このガイドでは、--no-allow-unauthenticated を使用してサービスをデプロイします。ゲートウェイは、サービス アカウントの ID トークンを使用してサービスを呼び出します。このトークンは、API 構成の作成時に --backend-auth-service-account として渡します。サービス アカウントに、サービスに対する Cloud Run 起動元ロール(roles/run.invoker)を付与します。

gcloud run services add-iam-policy-binding SERVICE_NAME \
    --region=REGION \
    --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
    --role=roles/run.invoker

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

  • SERVICE_NAME: Cloud Run サービスの名前
  • REGION: サービスをデプロイしたリージョン
  • SERVICE_ACCOUNT_EMAIL: ゲートウェイのサービス アカウントのメールアドレス

API 構成を作成する

次の OpenAPI 仕様を gemma-api.yaml として保存します。https://my-gemma-service.run.app はサービス URL に置き換えます。

openapi: 3.0.3
info:
  title: Gemma API
  version: 1.0.0
x-google-api-management:
  backends:
    gemma:
      address: https://my-gemma-service.run.app
      protocol: h2
      deadline: 570.0
x-google-backend: gemma
components:
  securitySchemes:
    google_id_token:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: ""
          scopes: {}
      x-google-auth:
        issuer: https://accounts.google.com
        jwksUri: https://www.googleapis.com/oauth2/v3/certs
        audiences:
          - gemma-api
security:
  - google_id_token: []
paths:
  /v1/chat/completions:
    post:
      operationId: createChatCompletion
      responses:
        '200':
          description: A chat completion, streamed as SSE when the request sets "stream" to true.

deadline の 570 秒は、Gemma ガイドがサービスに設定する --timeout 600 よりも 30 秒短くなっています。その結果、サービスのタイムアウトではなく、ゲートウェイの deadline によって、実行時間が長すぎるストリームが終了します。最上位の x-google-backend のデフォルトは pathTranslation: APPEND_PATH_TO_ADDRESS です。ゲートウェイはリクエストパスをバックエンド アドレスに追加するため、/v1/chat/completions へのリクエストは vLLM チャット補完エンドポイントに到達します。

security 要件により、ゲートウェイは、オーディエンス gemma-api を含む Google 署名付き ID トークンを持たないリクエストを拒否します。呼び出し元がトークンを生成するときに同じ文字列をリクエストする限り、別のオーディエンス文字列を選択できます。詳細については、ユーザーを認証するための Google ID トークンの使用をご覧ください。

API 構成を作成します。

gcloud api-gateway api-configs create CONFIG_ID \
    --api=API_ID \
    --openapi-spec=gemma-api.yaml \
    --backend-auth-service-account=SERVICE_ACCOUNT_EMAIL

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

  • CONFIG_ID: API 構成の ID
  • API_ID: API の ID。API が存在しない場合は、このコマンドによって作成されます。

ゲートウェイを作成する

API 構成からストリーミング ゲートウェイを作成します。

gcloud api-gateway gateways create GATEWAY_ID \
    --api=API_ID \
    --api-config=CONFIG_ID \
    --location=GCP_REGION \
    --enable-streaming

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

  • GATEWAY_ID: ゲートウェイの ID
  • GCP_REGION: ゲートウェイのリージョン。REGION とは異なる場合があります。使用可能な値については、API をゲートウェイにデプロイするをご覧ください。

ゲートウェイの準備ができたら、そのホスト名を取得します。

gcloud api-gateway gateways describe GATEWAY_ID \
    --location=GCP_REGION \
    --format="value(defaultHostname)"

呼び出し元の ID トークンを取得する

ユーザー アカウントは ID トークンの対象を選択できないため、この例では、権限を借用するサービス アカウントのトークンを生成します。呼び出し元には、既存のサービス アカウントを使用するか、新しいサービス アカウントを作成します。詳細については、サービス アカウントの作成をご覧ください。そのサービス アカウントに対するサービス アカウント トークン作成者ロール(roles/iam.serviceAccountTokenCreator)を自分自身に付与します。このロールは、gcloud CLI がサービス アカウントの権限を借用するために必要です。

gcloud iam service-accounts add-iam-policy-binding CALLER_SERVICE_ACCOUNT_EMAIL \
    --member=user:USER_EMAIL \
    --role=roles/iam.serviceAccountTokenCreator

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

  • CALLER_SERVICE_ACCOUNT_EMAIL: ゲートウェイを呼び出すサービス アカウントのメールアドレス
  • USER_EMAIL: メールアドレス

ストリーミング リクエストを送信する

"stream": true を設定するチャット完了リクエストを送信します。このリクエストには、Authorization ヘッダーに呼び出し元のサービス アカウントの ID トークンが含まれています。-N フラグは curl の出力バッファリングをオフにするため、各イベントは到着時に出力されます。

curl -N https://DEFAULT_HOSTNAME/v1/chat/completions \
    -H "Authorization: Bearer $(gcloud auth print-identity-token \
        --impersonate-service-account=CALLER_SERVICE_ACCOUNT_EMAIL \
        --audiences=gemma-api)" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "MODEL_NAME",
      "messages": [{"role": "user", "content": "Why is the sky blue?"}],
      "stream": true
    }'

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

  • DEFAULT_HOSTNAME: ゲートウェイのホスト名
  • CALLER_SERVICE_ACCOUNT_EMAIL: 前のステップのサービス アカウント
  • MODEL_NAME: デプロイしたモデル(google/gemma-4-E4B-it など)

レスポンスは SSE ストリームです。最初のイベントは assistant ロールを保持し、それ以降の各イベントは回答の次の部分を保持します。data: [DONE] の前の最後のイベントは finish_reason を設定します。出力は次のようになります。

data: {"id":"chatcmpl-7bcd57ad-1c3c-4779-91be-2973b875e517","object":"chat.completion.chunk","created":1790099706,"model":"google/gemma-4-E4B-it","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],"prompt_token_ids":null}

data: {"id":"chatcmpl-7bcd57ad-1c3c-4779-91be-2973b875e517","object":"chat.completion.chunk","created":1790099706,"model":"google/gemma-4-E4B-it","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null,"token_ids":null}]}

...

data: {"id":"chatcmpl-7bcd57ad-1c3c-4779-91be-2973b875e517","object":"chat.completion.chunk","created":1790099706,"model":"google/gemma-4-E4B-it","choices":[{"index":0,"delta":{"content":""},"logprobs":null,"finish_reason":"stop","stop_reason":106,"token_ids":null}]}

data: [DONE]

クリーンアップ

この例で使用したリソースについて Google Cloud アカウントに課金されないようにするには、ゲートウェイと API 構成を削除します。

gcloud api-gateway gateways delete GATEWAY_ID \
    --location=GCP_REGION
gcloud api-gateway api-configs delete CONFIG_ID \
    --api=API_ID

この例のために API を作成した場合は、それを削除します。

gcloud api-gateway apis delete API_ID

Cloud Run サービスを削除します。

gcloud run services delete SERVICE_NAME \
    --region=REGION

料金

ストリーミングのパブリック プレビュー期間中は、ストリーミング対応ゲートウェイでのネットワーク下り(外向き)料金は発生しません。ただし、Service Control の課金は、リリース フェーズに関係なく、API レベルで適用されます。

制限事項

公開プレビュー期間中、API Gateway でのストリーミングには次の制限が適用されます。

  • 不変性: 既存のゲートウェイを更新してストリーミングを有効または無効にすることはできません。新しいゲートウェイを作成する必要があります。ストリーミング対応のゲートウェイは、異なるホスト名シェイプを受け取るため、クライアントまたは DNS レコードを更新する必要があります。新しい形式を使用するようにゲートウェイ レコードを更新する場合は、サポートにお問い合わせください。API Gateway では、次のホスト名パターンが使用されます。

    • 非ストリーミング: {gateway_id}-{base36_project_number}.{shard_hash}.gateway.dev(例: test-gateway-4jcaz8x.uc.gateway.dev)
    • ストリーミング: {gateway_id}-{project_number}.{region}.gateway.dev(例: test-gateway-9876654321.us-central1.gateway.dev)
    • ストリーミング(レガシー): {service}-{tenant_project_number}.{region}.run.app(例: test-gateway-834512064953.us-central1.run.app)。リージョン *.gateway.dev ホスト名が利用可能になる前に作成された Gateway は、このホスト名を永続的に保持し、新しいパターンに移行されません。

    新しいストリーミング対応ゲートウェイは、ストリーミング パターンを受信します。最初の 2 つの例は、同じプロジェクト内の同じゲートウェイです。ストリーミング パターンでは、プロジェクト番号が base36 ではなく 10 進数で表示されるため、最初のラベルのスペースは、ストリーミング以外のゲートウェイよりも少なくなります。最初のラベルは、結合された {gateway_id}-{project_number} 文字列です。これは、63 文字の DNS ラベルの上限に収まる必要があります。ゲートウェイ ID の 49 文字の上限により、最大 13 桁のプロジェクト番号がこの上限内に収まります。プロジェクト番号が長い場合は、ゲートウェイ ID を短くする必要があります。

  • Terraform: Terraform を使用したストリーミングの有効化はサポートされていません(今後のリリースで予定されています)。

  • ロード バランシングとカスタム ドメイン: effectiveStreamingMode が EFFECTIVE_STREAMING_MODE_ENABLED のゲートウェイは、API Gateway またはサーバーレス NEG の HTTP(S) ロード バランシングと互換性がありません。このようなゲートウェイをサーバーレス NEG または外部アプリケーション ロードバランサの背後に配置することはできません。そのため、パブリック プレビュー期間中は、これらのゲートウェイでカスタム ドメイン(ロード バランシングに依存)はサポートされません。

  • 期限の動作: ゲートウェイでストリーミングを有効にしても、SSE またはチャンク転送パスでの deadline フィールドの動作は変更されません。期限は、完全なレスポンスに対する実時間の制限として残ります。そのため、送信されるデータの量に関係なく、期限が経過するとストリームは切断されます。デフォルトは 15 秒、最大値は 3,600 秒です。WebSocket では、deadline はメッセージ間のギャップを制限し、接続は 3,600 秒後に終了します。ストリームの期限を設定するをご覧ください。

  • Model Context Protocol(MCP): --enable-streaming を使用してゲートウェイを作成しても、MCP エンドポイント ストリームは作成されません。MCP レスポンスは、ゲートウェイのストリーミング モードに関係なく、単一の application/json 本文のままです。詳細については、MCP の制限事項をご覧ください。