Configurer le streaming pour les réponses des LLM et d'autres types de trafic

Ce document explique comment configurer le streaming dans API Gateway.

API Gateway accepte le streaming. Le streaming permet aux passerelles de diffuser des connexions de longue durée et de transmettre des données par fragments pour le streaming des requêtes et des réponses.

Une utilisation courante du streaming consiste à diffuser un grand modèle de langage (LLM). Le modèle envoie sa réponse un jeton à la fois, ce qui permet à un client d'afficher le texte pendant que le modèle le génère. Pour obtenir un exemple complet de diffusion de réponses à partir d'un modèle Gemma que vLLM diffuse sur Cloud Run, consultez Diffuser les réponses d'un LLM.

Protocoles de streaming compatibles

Lorsqu'elle est activée, API Gateway accepte les méthodes de streaming suivantes :

  • Diffusion incrémentielle des réponses : frames DATA HTTP/2 ou encodage de transfert fragmenté HTTP/1.1, selon ce que le client négocie.
  • Événements envoyés par le serveur (SSE) : streaming unidirectionnel du serveur vers le client.
  • WebSockets : canaux de communication full-duplex sur une seule connexion TCP.
  • Streaming bidirectionnel gRPC : streaming full-duplex à l'aide de gRPC.

Prérequis

Avant de pouvoir utiliser le streaming, assurez-vous que votre service de backend est compatible avec le protocole requis (par exemple, HTTP/2 ou WebSockets) et que votre configuration d'API est correctement configurée.

Configurer le protocole de backend

Pour accepter le trafic de streaming, vous devez configurer le protocole de votre backend en fonction du type de streaming :

  • gRPC : vous devez configurer votre backend pour qu'il utilise HTTP/2 (h2).
  • WebSockets : vous devez utiliser http/1.1. Les WebSockets nécessitent le handshake HTTP/1.1 Connection: Upgrade.
  • Événements envoyés par le serveur (SSE) et diffusion incrémentielle des réponses : votre backend peut utiliser HTTP/1.1 ou HTTP/2 (h2). Nous vous recommandons d'utiliser HTTP/2 (h2) pour améliorer les performances.

Dans votre spécification OpenAPI, configurez le protocole de backend comme suit :

Exemple (OpenAPI 3.x)

Définissez le champ protocol dans la définition du backend nommé dans l'objet x-google-api-management.backends. Vous devez également référencer ce backend à l'aide de x-google-backend au niveau de la racine ou de l'opération.

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

Exemple (OpenAPI 2.0)

Définissez le champ protocol dans l'extension x-google-backend.

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

Définir le délai de diffusion

Le champ deadline détermine la durée d'exécution d'une requête (unaire ou en streaming).

Le tableau suivant montre comment les délais avant expiration s'appliquent à chaque type de requête :

Méthode Délai d'inactivité
(écart maximal entre les messages)
Délai avant expiration de la requête
(durée totale maximale de la requête)
Sans streaming N/A : le délai d'inactivité ne s'applique qu'aux flux La valeur par défaut est de 15 secondes. Définissez deadline pour la modifier, jusqu'à 3 600 secondes pour les passerelles compatibles avec le streaming.
Streaming sur HTTP
(SSE, transfert fragmenté)
N/A : effectivement infini ; seul le délai avant expiration de la requête met fin au flux La valeur par défaut est de 15 secondes. Définissez deadline pour la modifier, jusqu'à 3 600 secondes pour les passerelles compatibles avec le streaming.
Streaming via gRPC ou WebSockets La valeur par défaut est de 300 secondes. Définissez deadline pour la modifier, jusqu'à 3 600 secondes pour les passerelles compatibles avec le streaming. Sur WebSockets, un deadline inférieur à 300 secondes est ignoré, et un minimum de 300 secondes s'applique. Toujours 3 600 secondes pour les passerelles compatibles avec le streaming, non configurable

Exemple (OpenAPI 3.x)

Définissez le champ deadline dans la définition du backend nommé.

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

Exemple (OpenAPI 2.0)

Définissez le champ deadline dans l'extension x-google-backend.

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

Pour connaître les autres limites qui s'appliquent aux connexions en streaming, consultez Limites.

Activer le streaming sur une passerelle

Le streaming est spécifié au moment de la création de la passerelle. Notez le comportement suivant :

  • Pas de désactivation explicite : il n'existe pas d'option permettant de désactiver explicitement le streaming. Si vous omettez l'option --enable-streaming, API Gateway détermine le mode lors de la création à partir de la configuration de l'API et de la valeur par défaut de la plate-forme : une configuration d'API qui configure un routeur de modèle produit toujours une passerelle de streaming. Lisez le champ effectiveStreamingMode de la passerelle (en sortie uniquement) pour voir le mode avec lequel elle a été créée.
  • Immuabilité : le mode de diffusion est fixé lors de la création et ne peut pas être modifié ultérieurement.

Pour spécifier le streaming sur une passerelle, utilisez l'option --enable-streaming avec la commande gcloud api-gateway gateways create :

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

Pour en savoir plus sur les options de déploiement de passerelle, consultez Déployer une API sur une passerelle.

Propriétés de streaming de la passerelle

Les champs suivants de la ressource Gateway contrôlent le comportement de streaming :

Champs Attributs Valeurs
streamingMode Chaîne (IMMUABLE, FACULTATIF)
  • STREAMING_MODE_UNSPECIFIED (par défaut : le service sélectionne le mode)
  • STREAMING_MODE_ENABLED
effectiveStreamingMode Chaîne (OUTPUT_ONLY)
  • EFFECTIVE_STREAMING_MODE_DISABLED
  • EFFECTIVE_STREAMING_MODE_ENABLED

Lorsque vous utilisez l'API REST pour créer une passerelle, vous pouvez spécifier le streaming dans le corps de la requête :

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

Vérifier que le streaming est activé

Pour vérifier si le streaming est actif sur votre passerelle, décrivez-la à l'aide de la gcloud CLI :

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

Recherchez le champ effectiveStreamingMode dans le résultat. Si le streaming est activé, le résultat inclut les éléments suivants :

effectiveStreamingMode: EFFECTIVE_STREAMING_MODE_ENABLED

Appeler les API Google Cloud

Une passerelle de streaming peut appeler des API Google Cloud telles que aiplatform.googleapis.com, ce qui vous permet de diffuser des réponses d'un modèle Gemini sur Agent Platform via la passerelle. La passerelle s'authentifie auprès de ces backends à l'aide d'un jeton d'accès au lieu d'un jeton d'ID. Pour en savoir plus, consultez Sécuriser les services de backend.

Diffuser un flux de réponses à partir d'un LLM

Cet exemple place une passerelle de streaming devant un modèle Gemma que vLLM diffuse sur Cloud Run, et diffuse une complétion de chat via la passerelle. vLLM diffuse une API compatible avec OpenAI qui diffuse les réponses en tant qu'événements envoyés par le serveur (SSE).

Avant de commencer, suivez les étapes de la section Configurer l'environnement de développement, y compris Configurer le compte de service utilisé pour créer des configurations d'API. La passerelle utilise ce compte de service pour appeler le service Cloud Run.

Déployer le modèle

Déployez un modèle Gemma en suivant les instructions de la section Déployer un modèle Gemma 4 avec un conteneur vLLM. Notez le nom du service, l'URL du service, la région et le nom du modèle que vous déployez, par exemple google/gemma-4-E4B-it.

Accorder à la passerelle l'accès au service

Le guide déploie le service avec --no-allow-unauthenticated. La passerelle appelle le service avec un jeton d'ID pour son compte de service, que vous transmettez en tant que --backend-auth-service-account lorsque vous créez la configuration de l'API. Attribuez à ce compte de service le rôle Demandeur Cloud Run (roles/run.invoker) sur le service :

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

Remplacez les éléments suivants :

  • SERVICE_NAME : nom du service Cloud Run.
  • REGION : région dans laquelle vous avez déployé le service
  • SERVICE_ACCOUNT_EMAIL : adresse e-mail du compte de service de la passerelle

Créer la configuration d'API

Enregistrez la spécification OpenAPI suivante sous le nom gemma-api.yaml, en remplaçant https://my-gemma-service.run.app par l'URL de votre service :

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.

La valeur deadline de 570 secondes est inférieure de 30 secondes à la valeur --timeout 600 que le guide Gemma définit sur le service. Par conséquent, c'est le deadline de la passerelle, et non le délai avant expiration du service, qui met fin à un flux qui s'exécute trop longtemps. Un x-google-backend de premier niveau est défini par défaut sur pathTranslation: APPEND_PATH_TO_ADDRESS. La passerelle ajoute le chemin de la requête à l'adresse du backend. Ainsi, une requête envoyée à /v1/chat/completions atteint le point de terminaison de complétion de chat vLLM.

L'exigence security fait que la passerelle rejette toute requête qui ne comporte pas de jeton d'ID signé par Google avec l'audience gemma-api. Vous pouvez choisir une autre chaîne d'audience, à condition que les appelants demandent la même lorsqu'ils créent un jeton. Pour en savoir plus, consultez Utiliser des jetons d'ID Google pour authentifier les utilisateurs.

Créez la configuration de l'API :

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

Remplacez les éléments suivants :

  • CONFIG_ID : ID de la configuration d'API.
  • API_ID : ID de l'API. Si l'API n'existe pas, la commande la crée.

Créer la passerelle

Créez une passerelle de streaming à partir de la configuration de l'API :

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

Remplacez les éléments suivants :

  • GATEWAY_ID : ID de la passerelle
  • GCP_REGION : région de la passerelle, qui peut être différente de REGION. Pour connaître les valeurs autorisées, consultez Déployer une API sur une passerelle.

Lorsque la passerelle est prête, obtenez son nom d'hôte :

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

Obtenir un jeton d'ID pour l'appelant

Un compte utilisateur ne peut pas choisir l'audience de son jeton d'ID. L'exemple crée donc le jeton pour un compte de service dont vous empruntez l'identité. Pour l'appelant, utilisez un compte de service existant ou créez-en un. Pour en savoir plus, consultez la section Créer des comptes de service. Attribuez-vous le rôle Créateur de jetons du compte de service (roles/iam.serviceAccountTokenCreator) sur ce compte de service, dont la gcloud CLI a besoin pour emprunter son identité :

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

Remplacez les éléments suivants :

  • CALLER_SERVICE_ACCOUNT_EMAIL : adresse e-mail du compte de service qui appelle la passerelle.
  • USER_EMAIL : votre adresse e-mail.

Envoyer une requête de streaming

Envoyez une requête de complétion de chat qui définit "stream": true, avec un jeton d'ID pour le compte de service de l'appelant dans l'en-tête Authorization. L'option -N désactive la mise en mémoire tampon de la sortie dans curl, de sorte que chaque événement s'affiche lorsqu'il arrive :

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
    }'

Remplacez les éléments suivants :

  • DEFAULT_HOSTNAME : nom d'hôte de la passerelle
  • CALLER_SERVICE_ACCOUNT_EMAIL : compte de service de l'étape précédente.
  • MODEL_NAME : modèle que vous avez déployé, par exemple google/gemma-4-E4B-it

La réponse est un flux SSE. Le premier événement porte le rôle assistant, chaque événement suivant porte la partie suivante de la réponse, et le dernier événement avant data: [DONE] définit finish_reason. Le résultat ressemble à ce qui suit :

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]

Effectuer un nettoyage

Pour éviter que les ressources utilisées dans cet exemple soient facturées sur votre compte Google Cloud , supprimez la passerelle et la configuration de l'API :

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

Si vous avez créé l'API pour cet exemple, supprimez-la :

gcloud api-gateway apis delete API_ID

Supprimez le service Cloud Run :

gcloud run services delete SERVICE_NAME \
    --region=REGION

Tarifs

Pendant la version Preview publique du streaming, les clients ne sont pas facturés pour la sortie réseau sur les passerelles compatibles avec le streaming. Toutefois, la facturation de Service Control s'applique toujours au niveau de l'API, quelle que soit la phase de lancement.

Limites

Les limites suivantes s'appliquent au streaming dans API Gateway pendant la version Preview publique :

  • Immuabilité : vous ne pouvez pas mettre à jour une passerelle existante pour activer ou désactiver le streaming. Vous devez créer une passerelle. Notez qu'une passerelle compatible avec le streaming reçoit une forme de nom d'hôte différente, ce qui vous oblige à mettre à jour vos clients ou vos enregistrements DNS. Si vous souhaitez que nous mettions à jour votre enregistrement de passerelle pour utiliser le nouveau format, contactez l'assistance. API Gateway utilise les modèles de nom d'hôte suivants :

    • Non-streaming : {gateway_id}-{base36_project_number}.{shard_hash}.gateway.dev, par exemple test-gateway-4jcaz8x.uc.gateway.dev
    • Streaming : {gateway_id}-{project_number}.{region}.gateway.dev, par exemple test-gateway-9876654321.us-central1.gateway.dev
    • Streaming (ancien) : {service}-{tenant_project_number}.{region}.run.app, par exemple test-gateway-834512064953.us-central1.run.app. Les passerelles créées avant que les noms d'hôte régionaux *.gateway.dev ne soient disponibles conservent ce nom d'hôte de manière permanente et ne sont pas migrées vers le nouveau modèle.

    Une nouvelle passerelle compatible avec le streaming reçoit le modèle Streaming. Les deux premiers exemples correspondent à la même passerelle dans le même projet : dans le modèle Streaming, le numéro de projet apparaît au format décimal plutôt qu'en base 36. La première étiquette dispose donc de moins d'espace que sur une passerelle non diffusée en streaming. Le premier libellé est la chaîne {gateway_id}-{project_number} combinée, qui doit respecter la limite de 63 caractères du libellé DNS. La limite de 49 caractères pour l'ID de passerelle permet de respecter cette limite pour les numéros de projet comportant jusqu'à 13 chiffres. Un numéro de projet plus long nécessite un ID de passerelle plus court.

  • Terraform : l'activation du streaming à l'aide de Terraform n'est pas possible (prévue pour une prochaine version).

  • Équilibrage de charge et domaines personnalisés : les passerelles avec un effectiveStreamingMode de EFFECTIVE_STREAMING_MODE_ENABLED ne sont pas compatibles avec l'équilibrage de charge HTTP(S) pour API Gateway ou les NEG sans serveur. Vous ne pouvez pas placer une telle passerelle derrière un NEG sans serveur ni un équilibreur de charge d'application externe. Par conséquent, les domaines personnalisés (qui reposent sur l'équilibrage de charge) ne sont pas compatibles avec ces passerelles pendant la version Preview publique.

  • Comportement de l'échéance : l'activation du streaming sur une passerelle ne modifie pas le comportement du champ deadline sur un chemin d'accès SSE ou de transfert fragmenté. Le délai reste une limite de temps réel sur la réponse complète. Un flux est donc coupé une fois le délai écoulé, quelle que soit la quantité de données qu'il envoie. La valeur par défaut est de 15 secondes et la valeur maximale est de 3 600 secondes. Sur un WebSocket, deadline limite l'écart entre les messages, et la connexion se termine après 3 600 secondes. Consultez Définir le délai de diffusion.

  • Protocole MCP (Model Context Protocol) : la création de la passerelle avec --enable-streaming ne crée pas de flux de point de terminaison MCP. Les réponses MCP restent un seul corps application/json, quel que soit le mode de streaming de la passerelle. Pour en savoir plus, consultez Limites de MCP.