200 OK 返回时什么都没带、一个流在工具调用进行到一半时停止。本页是针对这些情况的约定:调用方会收到什么、GoModel 是否重试或进行故障转移,以及该事件会出现在您监控中的什么位置。
关于控制重试和熔断器的配置项,请参阅
弹性与容错。关于如何选择备用模型,请参阅
故障转移。
Schema 漂移
提供商改变响应结构,是网关通常避而不谈的故障,因为要应对它,就必须对“响应应该是什么样子”有自己的立场。GoModel 的立场是 OpenAI Schema,并以宽松的方式应用:未知成员予以保留,已知成员进行规范化,只有完全无法读取的响应才会变成错误。
透传端点不受上述所有规则约束:
/p/{provider}/... 直接转发提供商返回的字节,不施加 GoModel 的任何处理,因此希望自行处理漂移的客户端可以这样做。
看似成功的空响应
没有可用内容的200 是披着成功外衣的失败。问题在于是否值得为它进行故障转移——对于 Chat Completions,答案是肯定的。
每一行都会记录一条警告,注明提供商、模型和原因,并递增
gomodel_empty_responses_total。由于 gomodel_requests_total
将正常返回的那些行计为成功,因此该计数器是那些不会失败的行唯一出现的地方。
后台运行或进行中的
/v1/responses 调用本来就既没有输出也没有用量,因此永远不会被报告为空响应。流式传输故障
已经发送过字节的流无法重试——客户端已经拿到了部分回答。因此 GoModel 的规则是:能在第一个字节之前做出判断的,就在之前判断;无法做到时,则明确告知截断。
等待第一个字节的时间永远不计入空闲超时,因此在提供商发送任何内容之前,慢速推理模型都是安全的。此后,任何字节都会启动计时器——包括 keep-alive 注释——之后的每个字节都会重新计时,因此该限制约束的是两次读取之间的间隔,而不是响应的总长度。一旦第一个字节发出,响应就已确定为
200,这就是为什么此后的停滞只能在带内报告,而无法作为状态码返回。详情参见:
流完成、
空闲超时、
流启动时的故障转移。
传输和状态码故障
为完整起见,列出常规情况。
流式请求一旦发出就永远不会重试;透传请求仅在可安全重放时才会重试(
GET、HEAD、OPTIONS、PUT,或任何携带 Idempotency-Key 的请求)。
捕获静默故障
上面那些不会触发故障转移的行,正是需要设置告警的情况,因为按定义,不会有其他任何地方报错:gomodel.client.empty_responses,
其中原因以 error.type 而非 reason 的形式提供,同时附带
gomodel.provider.name 和 gen_ai.request.model。参见
Prometheus 指标和
OpenTelemetry。
控制台读取的是同样的信号:如果某个模型的近期请求持续失败,即使模型发现仍然成功,其提供商也会被标记为 Degraded——这正可以发现那些能正常列出模型、但实际调用失败的上游。
模型发现中断
提供商的/models 列表可能失败,而推理仍然正常。此时 GoModel 会按以下顺序继续路由:
- 上一次获取或从缓存加载的模型清单。
- 已配置的模型(
<PROVIDER>_MODELS,参见CONFIGURED_PROVIDER_MODELS_MODE)。 - 对于使用默认基础 URL 的提供商,使用 模型目录中该提供商类型的模型列表。
PROVIDER_RECHECK_INTERVAL 秒(默认 60)重新检查一次,一旦列表获取成功,实时列表就会替换临时列表。如果没有任何可用模型,请求会返回 503,以便客户端重试;
/health/ready 会报告 degraded 并带有 "models": "down",而实例仍保留在轮转中。
如果要完全不依赖模型发现,请自行列出模型并设置
CONFIGURED_PROVIDER_MODELS_MODE=allowlist:
如果 GoModel 本身宕机
在请求路径中加入网关,是用网关风险换取提供商风险,因此如实的数据比安慰性的说法更重要。 GoModel 的故障是显性的,而不是静默的:宕机的实例会返回连接被拒绝,或由其前置组件返回502,绝不会给出看似合理的错误答案。
它是单个静态二进制文件,请求路径无状态,提供 /health 和
/health/ready 探针,并在收到 SIGTERM 时进行 10 秒的优雅排空,因此滚动重启以及在负载均衡器后部署多个副本,现在就能正常工作。
这次排空是一个截止时间,而不是完成保证:它针对的是能在十秒内真正完成的请求,超过时间仍未结束的请求——尤其是进行中的流——连接会被切断。对于长时间运行的流量,请在负载均衡器上排空连接,让新旧副本重叠运行足够长的时间以覆盖一次生成,并让客户端进行重试。
以下状态按实例保存,因此不会在副本之间共享:熔断器状态、速率限制计数器、请求健康窗口以及会话保持。生产环境指南介绍了这对您的拓扑意味着什么。
如果 GoModel 宕机,而您需要立即恢复流量,可以将
base_url 直接指回提供商——API 在两个方向上都兼容 OpenAI。在 GoModel 恢复之前,您将失去路由、故障转移和日志记录——而且,由于速率限制和预算检查运行在 GoModel 的请求路径中而非提供商的请求路径中,它们将完全不再起任何拦截作用。