为 LLM 回答和其他流量配置流式传输

本文档介绍了如何在 API Gateway 中配置流式传输。

API Gateway 支持流式传输。通过流式传输,网关可以处理长时间运行的连接,并以块的形式传输数据,以实现请求和响应流式传输。

流式传输的常见用途是为大语言模型 (LLM) 提供服务。模型会一次发送一个令牌的回答,因此客户端可以在模型仍在生成文本时显示该文本。如需查看一个完整的示例,了解如何从 vLLM 在 Cloud Run 上部署的 Gemma 模型流式传输响应,请参阅从 LLM 流式传输响应。

支持的流式传输协议

启用后,API Gateway 支持以下流式传输方法:

  • 增量响应传送:HTTP/2 DATA 帧或 HTTP/1.1 分块传输编码,具体取决于客户端协商的结果。
  • 服务器发送的事件 (SSE):从服务器到客户端的单向流式传输。
  • WebSockets:通过单个 TCP 连接实现全双工通信通道。
  • gRPC 双向流式传输:使用 gRPC 进行全双工流式传输。

前提条件

在使用流式传输之前,请确保您的后端服务支持所需的协议(例如 HTTP/2 或 WebSockets),并且您的 API 配置已正确设置。

配置后端协议

如需支持流式传输流量,您必须根据流式传输类型为后端配置协议:

  • gRPC:您必须将后端配置为使用 HTTP/2 (h2)。
  • WebSockets:您必须使用 http/1.1。WebSocket 需要 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 字段用于控制请求(一元或流式)的运行时长。

下表显示了超时时间如何应用于每种类型的请求:

方法 空闲超时时间
(消息之间的最大间隔)
请求超时时间
(最长总请求时长)
非流式传输 不适用:空闲超时仅适用于流 默认值为 15 秒;设置 deadline 可更改此值,对于支持流式传输的网关,最长可设置为 3,600 秒
通过 HTTP 进行流式传输
(SSE、分块传输)
不适用:实际上是无限的;只有请求超时才会结束流 默认值为 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 字段,查看创建网关时使用的模式。
  • 不可变性:流式传输模式在创建时即已确定,之后无法修改。

如需在网关上指定流式传输,请将 --enable-streaming 标志与 gcloud api-gateway gateways create 命令结合使用:

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 部署了一个与 OpenAI 兼容的 API,该 API 以服务器发送事件 (SSE) 的形式流式传输响应。

在开始之前,请完成配置开发环境,包括配置用于创建 API 配置的服务账号。网关使用该服务账号来调用 Cloud Run 服务。

部署模型

按照使用 vLLM 容器部署 Gemma 4 模型中的说明部署 Gemma 模型。记下服务名称、服务网址、区域以及您部署的模型的名称,例如 google/gemma-4-E4B-it。

向网关授予对服务的访问权限

该指南使用 --no-allow-unauthenticated 部署服务。网关使用其服务账号的 ID 令牌调用服务,您可以在创建 API 配置时将该令牌作为 --backend-auth-service-account 传递。向该服务账号授予 Cloud Run Invoker 角色 (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 替换为您的服务网址:

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 令牌的目标对象,因此该示例会为您模拟的服务账号生成令牌。对于调用方,请使用现有服务账号或创建一个服务账号。如需了解详情,请参阅创建服务账号。向您自己授予该服务账号的 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator),gcloud CLI 需要该角色才能模拟该服务账号:

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 的对话补全请求,并在 Authorization 标头中包含调用方服务账号的 ID 令牌。-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 主机名可用之前创建的网关会永久保留此主机名,不会迁移到新模式。

    支持流式传输的新网关接收 Streaming 模式。前两个示例是同一项目中的同一网关:在流式模式下,项目编号以十进制而非 base36 显示,因此第一个标签的空间比非流式网关上的空间小。第一个标签是组合的 {gateway_id}-{project_number} 字符串,必须符合 63 个字符的 DNS 标签限制。49 个字符的网关 ID 限制可确保项目编号不超过 13 位数;如果项目编号更长,则需要更短的网关 ID。

  • Terraform:不支持使用 Terraform 启用流式传输(计划在未来版本中实现)。

  • 负载均衡和自定义网域:effectiveStreamingMode 为 EFFECTIVE_STREAMING_MODE_ENABLED 的网关与 API Gateway 的 HTTP(S) 负载均衡或无服务器 NEG 不兼容。您无法将此类网关放置在无服务器 NEG 或外部应用负载均衡器后面。因此,在公开预览版期间,这些网关不支持自定义网域(依赖于负载均衡)。

  • 截止时间行为:在网关上启用流式传输不会改变 deadline 字段在 SSE 或分块传输路径上的行为。截止时间仍然是完整响应的实际时间界限,因此一旦截止时间到期,无论流正在发送多少数据,都会被切断。默认值为 15 秒,最大值为 3,600 秒。在 WebSocket 上,deadline 会限制消息之间的间隔,连接会在 3,600 秒后终止。请参阅设置流截止时间。

  • Model Context Protocol (MCP):使用 --enable-streaming 创建网关不会生成 MCP 端点流。无论网关的流处理模式如何,MCP 响应始终是单个 application/json 正文。如需了解详情,请参阅 MCP 限制。