Configura la transmisión para las respuestas de LLM y otro tráfico

En este documento, se describe cómo configurar la transmisión en API Gateway.

API Gateway admite la transmisión. La transmisión permite que las puertas de enlace entreguen conexiones de larga duración y transmitan datos en fragmentos para la transmisión de solicitudes y respuestas.

Un uso común de la transmisión es entregar un modelo de lenguaje grande (LLM). El modelo envía su respuesta un token a la vez, por lo que un cliente puede mostrar el texto mientras el modelo aún lo está generando. Para ver un ejemplo completo que transmita respuestas de un modelo de Gemma que vLLM entrega en Cloud Run, consulta Transmite respuestas desde un LLM.

Protocolos de transmisión compatibles

Cuando está habilitada, API Gateway admite los siguientes métodos de transmisión:

  • Entrega de respuestas incremental: marcos DATA de HTTP/2 o codificación de transferencia fragmentada de HTTP/1.1, según lo que negocie el cliente.
  • Eventos enviados por el servidor (SSE): Transmisión unidireccional del servidor al cliente.
  • WebSockets: Canales de comunicación dúplex completo a través de una sola conexión TCP.
  • Transmisión bidireccional de gRPC: Es la transmisión dúplex completa con gRPC.

Requisitos previos

Antes de usar la transmisión, asegúrate de que tu servicio de backend admita el protocolo requerido (por ejemplo, HTTP/2 o WebSockets) y de que la configuración de tu API esté establecida correctamente.

Configura el protocolo de backend

Para admitir el tráfico de transmisión, debes configurar el protocolo de tu backend según el tipo de transmisión:

  • gRPC: Debes configurar tu backend para que use HTTP/2 (h2).
  • WebSockets: Debes usar http/1.1. Los WebSockets requieren el protocolo de enlace HTTP/1.1 Connection: Upgrade.
  • Eventos enviados por el servidor (SSE) y entrega de respuestas incremental: Tu backend puede usar HTTP/1.1 o HTTP/2 (h2). Recomendamos HTTP/2 (h2) para mejorar el rendimiento.

En tu especificación de OpenAPI, configura el protocolo de backend de la siguiente manera:

Ejemplo (OpenAPI 3.x)

Configura el campo protocol en la definición de backend con nombre dentro del objeto x-google-api-management.backends. También debes hacer referencia a este backend con x-google-backend en el nivel raíz o de operación.

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

Ejemplo (OpenAPI 2.0)

Configura el campo protocol en la extensión x-google-backend.

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

Establece la fecha límite de la transmisión

El campo deadline rige el tiempo que puede ejecutarse una solicitud (unaria o de transmisión).

En la siguiente tabla, se muestra cómo se aplican los tiempos de espera a cada tipo de solicitud:

Método Tiempo de espera de inactividad
(intervalo máximo entre mensajes)
Tiempo de espera de la solicitud
(duración total máxima de la solicitud)
Sin transmisión N/A: El tiempo de espera de inactividad solo se aplica a las transmisiones El valor predeterminado es 15 segundos; establece deadline para cambiarlo, hasta 3,600 segundos para las puertas de enlace habilitadas para la transmisión
Transmisión por HTTP
(SSE, transferencia fragmentada)
N/A: efectivamente infinito; solo el tiempo de espera de la solicitud finaliza la transmisión El valor predeterminado es 15 segundos; establece deadline para cambiarlo, hasta 3,600 segundos para las puertas de enlace habilitadas para la transmisión
Transmisión a través de gRPC o WebSockets El valor predeterminado es de 300 segundos. Establece deadline para cambiarlo, hasta 3,600 segundos para las puertas de enlace habilitadas para la transmisión. En WebSockets, se ignora un deadline de menos de 300 segundos y se aplica un mínimo de 300 segundos Siempre 3,600 segundos para las puertas de enlace habilitadas para la transmisión, no configurable

Ejemplo (OpenAPI 3.x)

Establece el campo deadline en la definición del backend con nombre.

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

Ejemplo (OpenAPI 2.0)

Configura el campo deadline en la extensión x-google-backend.

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

Para conocer los otros límites que se aplican a las conexiones de transmisión, consulta Limitaciones.

Habilita la transmisión en una puerta de enlace

La transmisión se especifica en el momento de la creación de la puerta de enlace. Ten en cuenta el siguiente comportamiento:

  • No hay inhabilitación explícita: No hay ninguna marca para inhabilitar la transmisión de forma explícita. Si omites la marca --enable-streaming, API Gateway resuelve el modo en el momento de la creación a partir de la configuración de la API y el valor predeterminado de la plataforma: una configuración de API que configura un Model Router siempre produce una puerta de enlace de transmisión. Lee el campo effectiveStreamingMode de solo salida de la puerta de enlace para ver el modo con el que se creó.
  • Inmutabilidad: El modo de transmisión se fija en el momento de la creación y no se puede modificar más adelante.

Para especificar la transmisión en una puerta de enlace, usa la marca --enable-streaming con el comando gcloud api-gateway gateways create:

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

Para obtener más información sobre las opciones de implementación de la puerta de enlace, consulta Implementa una API en una puerta de enlace.

Propiedades de transmisión de la puerta de enlace

Los siguientes campos del recurso Gateway controlan el comportamiento de la transmisión:

Campo Atributos Valores
streamingMode Cadena (INMUTABLE, OPCIONAL)
  • STREAMING_MODE_UNSPECIFIED (predeterminado: el servicio selecciona el modo)
  • STREAMING_MODE_ENABLED
effectiveStreamingMode String (OUTPUT_ONLY)
  • EFFECTIVE_STREAMING_MODE_DISABLED
  • EFFECTIVE_STREAMING_MODE_ENABLED

Cuando usas la API de REST para crear una puerta de enlace, puedes especificar la transmisión en el cuerpo de la solicitud:

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

Verifica que la transmisión esté habilitada

Para confirmar si la transmisión está activa en tu puerta de enlace, descríbela con gcloud CLI:

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

Busca el campo effectiveStreamingMode en el resultado. Si la transmisión está habilitada, el resultado incluye lo siguiente:

effectiveStreamingMode: EFFECTIVE_STREAMING_MODE_ENABLED

Llama a las APIs de Google Cloud

Una puerta de enlace de transmisión puede llamar a las APIs de Google Cloud , como aiplatform.googleapis.com, para que puedas transmitir respuestas desde un modelo de Gemini en Agent Platform a través de la puerta de enlace. La puerta de enlace se autentica en estos backends con un token de acceso en lugar de un token de ID. Para obtener más información, consulta Protege los servicios de backend.

Transmite respuestas de un LLM

En este ejemplo, se coloca una puerta de enlace de transmisión frente a un modelo de Gemma que vLLM entrega en Cloud Run y se transmite una finalización de chat a través de la puerta de enlace. vLLM entrega una API compatible con OpenAI que transmite respuestas como eventos enviados por el servidor (SSE).

Antes de comenzar, completa el paso Configura el entorno de desarrollo, incluido Configura la cuenta de servicio que se usa para crear parámetros de configuración de la API. La puerta de enlace usa esa cuenta de servicio para llamar al servicio de Cloud Run.

Implementa el modelo

Implementa un modelo de Gemma siguiendo las instrucciones de Implementa un modelo de Gemma 4 con un contenedor de vLLM. Toma nota del nombre del servicio, la URL del servicio, la región y el nombre del modelo que implementas, como google/gemma-4-E4B-it.

Otorga acceso a la puerta de enlace al servicio

En la guía, se implementa el servicio con --no-allow-unauthenticated. La puerta de enlace llama al servicio con un token de ID para su cuenta de servicio, que pasas como --backend-auth-service-account cuando creas la configuración de la API. Otorga a esa cuenta de servicio el rol de Invocador de Cloud Run (roles/run.invoker) en el servicio:

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

Reemplaza lo siguiente:

  • SERVICE_NAME: Es el nombre del servicio de Cloud Run.
  • REGION: Es la región en la que implementaste el servicio.
  • SERVICE_ACCOUNT_EMAIL: Es la dirección de correo electrónico de la cuenta de servicio de la puerta de enlace.

Crea la configuración de la API

Guarda la siguiente especificación de OpenAPI como gemma-api.yaml y reemplaza https://my-gemma-service.run.app por la URL de tu servicio:

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.

El deadline de 570 segundos es 30 segundos más corto que el --timeout 600 que la guía de Gemma establece en el servicio. Como resultado, el deadline de la puerta de enlace, no el tiempo de espera del servicio, finaliza una transmisión que se ejecuta durante demasiado tiempo. Un x-google-backend de nivel superior se establece de forma predeterminada en pathTranslation: APPEND_PATH_TO_ADDRESS. La puerta de enlace agrega la ruta de acceso de la solicitud a la dirección de backend, por lo que una solicitud a /v1/chat/completions llega al extremo de finalización de chat de vLLM.

El requisito security hace que la puerta de enlace rechace cualquier solicitud que no tenga un token de ID firmado por Google con el público gemma-api. Puedes elegir una cadena de público diferente, siempre que los emisores soliciten la misma cuando creen un token. Para obtener más información, consulta Usa tokens de ID de Google para autenticar usuarios.

Crea la configuración de la API:

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

Reemplaza lo siguiente:

  • CONFIG_ID: un ID para la configuración de la API
  • API_ID: Es el ID de la API. Si la API no existe, el comando la crea.

Crea la puerta de enlace

Crea una puerta de enlace de transmisión a partir de la configuración de la API:

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

Reemplaza lo siguiente:

  • GATEWAY_ID: Es un ID para la puerta de enlace.
  • GCP_REGION: Es la región de la puerta de enlace, que puede ser diferente de REGION. Para obtener los valores permitidos, consulta Implementa una API en una puerta de enlace.

Cuando la puerta de enlace esté lista, obtén su nombre de host:

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

Obtén un token de ID para el emisor

Una cuenta de usuario no puede elegir el público de su token de ID, por lo que el ejemplo genera el token para una cuenta de servicio cuya identidad suplantas. Para el emisor, usa una cuenta de servicio existente o crea una. Para obtener más información, consulta Crea cuentas de servicio. Otórgate el rol de creador de tokens de cuenta de servicio (roles/iam.serviceAccountTokenCreator) en esa cuenta de servicio, que gcloud CLI necesita para actuar en su nombre:

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

Reemplaza lo siguiente:

  • CALLER_SERVICE_ACCOUNT_EMAIL: Es la dirección de correo electrónico de la cuenta de servicio que llama a la puerta de enlace.
  • USER_EMAIL: tu dirección de correo electrónico

Envía una solicitud de transmisión

Envía una solicitud de finalización de chat que establezca "stream": true, con un token de ID para la cuenta de servicio del emisor en el encabezado Authorization. La marca -N desactiva el almacenamiento en búfer de salida en curl, por lo que cada evento se imprime cuando llega:

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

Reemplaza lo siguiente:

  • DEFAULT_HOSTNAME: el nombre de host de la puerta de enlace
  • CALLER_SERVICE_ACCOUNT_EMAIL: la cuenta de servicio del paso anterior
  • MODEL_NAME: Es el modelo que implementaste, como google/gemma-4-E4B-it.

La respuesta es una transmisión de SSE. El primer evento lleva el rol assistant, cada evento posterior lleva la siguiente parte de la respuesta y el último evento antes de data: [DONE] establece finish_reason. El resultado es similar a lo siguiente:

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]

Realiza una limpieza

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en este ejemplo, borra la puerta de enlace y la configuración de la API:

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

Si creaste la API para este ejemplo, bórrala:

gcloud api-gateway apis delete API_ID

Borra el servicio de Cloud Run:

gcloud run services delete SERVICE_NAME \
    --region=REGION

Precios

Durante la versión preliminar pública de la transmisión, no se les cobra a los clientes por la salida de red en las puertas de enlace habilitadas para la transmisión. Sin embargo, la facturación de Control de servicios se sigue aplicando a nivel de API, independientemente de la fase de lanzamiento.

Limitaciones

Las siguientes limitaciones se aplican a la transmisión en API Gateway durante la versión preliminar pública:

  • Inmutabilidad: No puedes actualizar una puerta de enlace existente para habilitar o inhabilitar la transmisión. Debes crear una puerta de enlace nueva. Ten en cuenta que una puerta de enlace habilitada para la transmisión recibe una forma de nombre de host diferente, lo que requiere que actualices tus clientes o registros DNS. Si quieres que actualicemos tu registro de puerta de enlace para usar el formato nuevo, comunícate con el equipo de asistencia. API Gateway usa los siguientes patrones de nombre de host:

    • Sin transmisión: {gateway_id}-{base36_project_number}.{shard_hash}.gateway.dev, por ejemplo, test-gateway-4jcaz8x.uc.gateway.dev
    • Transmisión: {gateway_id}-{project_number}.{region}.gateway.dev, por ejemplo, test-gateway-9876654321.us-central1.gateway.dev
    • Transmisión (heredada): {service}-{tenant_project_number}.{region}.run.app, por ejemplo, test-gateway-834512064953.us-central1.run.app. Las puertas de enlace creadas antes de que estuvieran disponibles los nombres de host regionales de *.gateway.dev conservan este nombre de host de forma permanente y no se migran al patrón nuevo.

    Una nueva puerta de enlace habilitada para la transmisión recibe el patrón Transmisión. Los primeros dos ejemplos son la misma puerta de enlace en el mismo proyecto: en el patrón Transmisión, el número de proyecto aparece en decimal en lugar de base36, por lo que la primera etiqueta tiene menos espacio que en una puerta de enlace que no es de transmisión. La primera etiqueta es la cadena {gateway_id}-{project_number} combinada, que debe ajustarse al límite de 63 caracteres de la etiqueta de DNS. El límite de 49 caracteres para el ID de la puerta de enlace lo mantiene dentro de ese límite para los números de proyecto de hasta 13 dígitos. Un número de proyecto más largo necesita un ID de puerta de enlace más corto.

  • Terraform: No se admite la habilitación de la transmisión con Terraform (se planea para una versión futura).

  • Balanceo de cargas y dominios personalizados: Las puertas de enlace con un effectiveStreamingMode de EFFECTIVE_STREAMING_MODE_ENABLED no son compatibles con el balanceo de cargas de HTTP(S) para API Gateway o NEG sin servidores. No puedes colocar una puerta de enlace de este tipo detrás de un NEG sin servidores o un balanceador de cargas de aplicaciones externo. Por lo tanto, los dominios personalizados (que dependen del balanceo de cargas) no son compatibles con estas puertas de enlace durante la versión preliminar pública.

  • Comportamiento de la fecha límite: Habilitar la transmisión en una puerta de enlace no cambia el comportamiento del campo deadline en una ruta de acceso de SSE o de transferencia fragmentada. La fecha límite sigue siendo un límite de tiempo real para la respuesta completa, por lo que una transmisión se corta una vez que transcurre la fecha límite, independientemente de la cantidad de datos que envíe. El valor predeterminado es 15 segundos y el máximo es 3,600 segundos. En un WebSocket, deadline limita el intervalo entre mensajes y la conexión finaliza después de 3,600 segundos. Consulta Establece la fecha límite de la transmisión.

  • Protocolo de contexto del modelo (MCP): Crear la puerta de enlace con --enable-streaming no genera un flujo de extremos de MCP. Las respuestas de MCP siguen siendo un solo cuerpo de application/json, independientemente del modo de transmisión de la puerta de enlace. Para obtener más detalles, consulta Limitaciones de MCP.