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

Ce document explique comment configurer le streaming dans API Gateway.

API Gateway est compatible avec le streaming. Le streaming permet aux passerelles de gérer les connexions de longue durée et de transmettre les données par blocs pour le streaming des requêtes et des réponses.

Le streaming est souvent utilisé pour 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 en flux continu des réponses d'un modèle Gemma que vLLM diffuse sur Cloud Run, consultez Diffuser les réponses d'un LLM en flux continu.

Protocoles de streaming compatibles

Lorsqu'il est activé, API Gateway est compatible avec les méthodes de streaming suivantes :

  • Diffusion incrémentielle des réponses : trames DATA HTTP/2 ou encodage par transfert segmenté HTTP/1.1, selon ce que le client négocie.
  • Événements envoyés par le serveur (SSE) : flux unidirectionnel du serveur vers le client.
  • WebSockets : canaux de communication en duplex intégral sur une seule connexion TCP.
  • Streaming bidirectionnel gRPC : streaming en duplex intégral à 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 la configuration de votre API est correcte.

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é au sein de l'objet x-google-api-management.backends. Vous devez également faire référence à ce backend à l'aide de x-google-backend au niveau 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 régit la durée d'exécution d'une requête (unaire ou de streaming).

Le tableau suivant indique comment les délais 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 par blocs)
N/A : durée infinie. Seul le délai d'expiration de la requête met fin au flux. 15 secondes par défaut. Définissez deadline pour le modifier (jusqu'à 3 600 secondes pour les passerelles compatibles avec le streaming).
Streaming sur 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 de 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 :

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

Pour spécifier le streaming sur une passerelle, utilisez le flag --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 du streaming :

Champ Attributs Valeurs
streamingMode Chaîne (IMMUTABLE, 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 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

Diffuser des 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 sous forme d'événements envoyés par le serveur (SSE).

Avant de commencer, suivez la procédure 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 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'identité pour son compte de service, que vous transmettez en tant que --backend-auth-service-account lorsque vous créez la configuration de l'API. Accordez à 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 de l'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.

Le deadline de 570 secondes est 30 secondes plus court que le --timeout 600 défini par le guide Gemma 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 trop long. Un x-google-backend de premier niveau est défini par défaut sur pathTranslation: APPEND_PATH_TO_ADDRESS. L'application de passerelle ajoute le chemin d'accès à la requête à l'adresse du backend. Par conséquent, une requête adressée à /v1/chat/completions atteint le point de terminaison de complétion de chat vLLM.

L'exigence security permet à la passerelle de refuser 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 génèrent un jeton. Pour en savoir plus, consultez Utiliser des jetons d'identité 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 de l'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, récupérez son nom d'hôte :

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

Obtenir un jeton d'identification pour l'appelant

Un compte utilisateur ne peut pas choisir l'audience de son jeton d'identité. 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 l'emprunter :

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 demande de streaming

Envoyez une requête de complétion de conversation qui définit "stream": true, avec un jeton d'identité pour le compte de service de l'appelant dans l'en-tête Authorization. L'indicateur -N désactive la mise en mémoire tampon de la sortie dans curl. Chaque événement est donc imprimé à son arrivée :

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é, tel que google/gemma-4-E4B-it

La réponse est un flux SSE. Le premier événement porte le rôle assistant, chaque événement ultérieur 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 ne 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 Service Control s'applique toujours au niveau de l'API, quelle que soit la phase de publication.

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 un nom d'hôte différent, 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 noms 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 (ancienne) : {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 *.gateway.dev régionaux 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 en décimal plutôt qu'en base36. Le premier libellé dispose donc de moins d'espace que sur une passerelle non associée au streaming. Le premier libellé est la chaîne {gateway_id}-{project_number} combinée, qui doit respecter la limite de 63 caractères pour les libellés 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. Si le numéro de projet est plus long, l'ID de passerelle doit être plus court.

  • Terraform : l'activation du streaming à l'aide de Terraform n'est pas prise en charge (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 ni avec 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 du délai : l'activation du streaming sur une passerelle ne modifie pas le comportement du champ deadline sur un chemin SSE ou de transfert segmenté. Le délai reste une limite de temps pour la réponse complète. Un flux est donc interrompu 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 plutôt l'écart entre les messages, et la connexion se termine après 3 600 secondes. Consultez Définir le délai de la 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 corps application/json unique, quel que soit le mode de traitement en flux continu de la passerelle. Pour en savoir plus, consultez Limites du MCP.