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 や WebSocket など)をサポートしていることと、API 構成が正しく設定されていることを確認してください。

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

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

  • gRPC: HTTP/2(h2)を使用するようにバックエンドを構成する必要があります。
  • WebSockets: http/1.1 を使用する必要があります。WebSockets には HTTP/1.1 Connection: Upgrade ハンドシェイクが必要です。
  • サーバー送信イベント(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 フィールドは、リクエスト(単項またはストリーミング)の実行時間を制御します。

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

メソッド アイドル タイムアウト
(メッセージ間の最大間隔)
リクエストのタイムアウト
(リクエストの最大合計時間)
非ストリーミング N/A: アイドル タイムアウトはストリームにのみ適用されます デフォルトは 15 秒です。deadline を設定して変更します。ストリーミング対応ゲートウェイの場合は最大 3,600 秒です。
HTTP 経由のストリーミング
(SSE、チャンク転送)
N/A: 事実上無限。リクエスト タイムアウトでのみストリームが終了します。 デフォルトは 15 秒です。deadline を設定して変更します。ストリーミング対応ゲートウェイの場合は最大 3,600 秒です。
gRPC または WebSocket 経由のストリーミング デフォルトは 300 秒です。deadline を設定して変更します。ストリーミング対応ゲートウェイの場合は最大 3,600 秒です。WebSocket では、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 文字列(変更不可、省略可)
  • 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

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

この例では、vLLM が Cloud Run で提供する Gemma モデルの前にストリーミング ゲートウェイを配置し、ゲートウェイを介してチャット補完をストリーミングします。vLLM は、レスポンスを Server-Sent Events(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.

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

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 を設定するチャット完了リクエストを送信します。このリクエストでは、呼び出し元のサービス アカウントの ID トークンが Authorization ヘッダーに設定されています。-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 ラベルの制限に収まる必要があります。49 文字のゲートウェイ ID の上限により、プロジェクト番号が 13 桁までの場合は上限内に収まります。プロジェクト番号が長い場合は、ゲートウェイ ID を短くする必要があります。

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

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

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

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