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 transmisiones. La transmisión permite que las puertas de enlace atiendan 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 la publicación de un modelo de lenguaje grande (LLM). El modelo envía su respuesta de a un token por 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á habilitado, API Gateway admite los siguientes métodos de transmisión:

  • Entrega de respuestas incrementales: Se utilizan tramas 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 completos a través de una sola conexión TCP.
  • Transmisión bidireccional de gRPC: 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 la API esté configurada 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. WebSockets requiere el protocolo de enlace Connection: Upgrade HTTP/1.1.
  • Eventos enviados por el servidor (SSE) y entrega de respuestas incrementales: 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 del backend con nombre dentro del objeto x-google-api-management.backends. También debes hacer referencia a este backend con x-google-backend a nivel de la raíz o de la 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

Cómo establecer la fecha límite de la transmisión

El campo deadline rige la duración de 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 por inactividad solo se aplica a las transmisiones. El valor predeterminado es de 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 de 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 es de 3,600 segundos para las puertas de enlace habilitadas para la transmisión, no se puede configurar.

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 una marca para inhabilitar explícitamente la transmisión. Si omites la marca --enable-streaming, API Gateway resuelve el modo en 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 de Gateway controlan el comportamiento de transmisión:

Campo Atributos Valores
streamingMode Cadena (INMUTABLE, OPCIONAL)
  • STREAMING_MODE_UNSPECIFIED (predeterminado: el servicio selecciona el modo)
  • STREAMING_MODE_ENABLED
effectiveStreamingMode Cadena (solo salida)
  • 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

Transmite respuestas desde 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 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 la sección Configura el entorno de desarrollo, incluida la sección Configura la cuenta de servicio que se usa para crear configuraciones de 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 los pasos 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: La dirección de correo electrónico de la cuenta de servicio de la puerta de enlace

Crea la configuración de 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 establece la guía de Gemma 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 tiene el valor predeterminado pathTranslation: APPEND_PATH_TO_ADDRESS. La puerta de enlace agrega la ruta 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 incluya un token de ID firmado por Google con el público gemma-api. Puedes elegir una cadena de público diferente, siempre y cuando los llamantes soliciten la misma cuando generen un token. Para obtener más información, consulta Cómo usar tokens de ID de Google para autenticar usuarios.

Crea la configuración de 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: Es 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 diferir 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 la persona que llama

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

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: 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 llamador 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: Es 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 tiene el rol assistant, cada evento posterior contiene 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, a los clientes no se les cobra la salida de red en las puertas de enlace habilitadas para la transmisión. Sin embargo, la facturación de Control de servicios sigue aplicándose 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 diferente de nombre de host, por lo que debes actualizar tus clientes o registros DNS. Si quieres que actualicemos tu registro de puerta de enlace para que use el nuevo formato, comunícate con el equipo de asistencia al cliente. API Gateway usa los siguientes patrones de nombres 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 nuevo patrón.

    Una nueva puerta de enlace compatible con la transmisión recibe el patrón Streaming. Los dos primeros ejemplos son la misma puerta de enlace en el mismo proyecto: en el patrón Streaming, 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 requiere 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 ni con los 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 fecha límite: Habilitar la transmisión en una puerta de enlace no cambia el comportamiento del campo deadline en una ruta de transferencia fragmentada o de SSE. La fecha límite sigue siendo un límite de tiempo real para la respuesta completa, por lo que se corta una transmisión una vez que vence la fecha límite, independientemente de la cantidad de datos que esté enviando. El valor predeterminado es de 15 segundos y el máximo es de 3,600 segundos. En un WebSocket, deadline limita la brecha entre los mensajes, y la conexión finaliza después de 3,600 segundos. Consulta Cómo establecer la fecha límite de la transmisión.

  • Protocolo de contexto del modelo (MCP): La creación de la puerta de enlace con --enable-streaming no genera una transmisión de extremo 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 información, consulta Limitaciones de MCP.