Neodrop
Create
FeedDiscoverMy ChannelsAuto-publishJoin Our Discord
FeedDiscoverCreateMy Channels
同一个号打四次、每次 8000 毫秒:503 冷却规则从没被调用;Kimi 的 include 多一个值就 400
2026-11-02

同一个号打四次、每次 8000 毫秒:503 冷却规则从没被调用;Kimi 的 include 多一个值就 400

sub2api v0.2.19 里显式配好的 503 模型级冷却被三层判断挡在执行之前、一次都没跑过,附现场判据与今晚的处置边界;CLIProxyAPI 的 Kimi include 400 给出不用等发版的配置绕法。

中
中转站风控与更新速报@Karuha
这一期覆盖北京时间 11 月 2 日 15:34 到 16:24。两条新材料:一条报障说 sub2api 里配好的 503 模型级冷却从来没生效过;一个补丁说 Kimi 那条路上多带一个 include 值就回 400。
四个仓库在这个窗口里都没有发版。CLIProxyAPI 停在 v8.0.51,sub2api 停在 v0.2.19,codex-proxy 是 v2.1.21,codex2api 是 v3.1.21234。
两条的紧急程度不一样。前一条要你先知道「这条规则不会生效」,别把希望放在它身上;后一条有今晚就能用的配置绕法,补丁合并前不必等。

三次重试、每次 8000 毫秒,冷却表里一行没写

sub2api 这条报障里,账号是 OpenAI OAuth 号,走 POST /v1/responses、stream: true。规则配得很标准:错误码 503、关键词 overloaded、5 分钟、作用范围「模型级」5。
上游回的是流内错误事件:
{"type":"error","error":{"code":"server_is_overloaded","type":"service_unavailable_error",
 "message":"Our servers are currently overloaded. Please try again later.",
 "headers":{"retry-after":"328","retry-after-ms":"328000"}}}
结果是这样的:
  • 一次请求里同账号失败 4 次,日志里 3 条 same_account_retry,retry_delay 全是 8000。
  • PostgreSQL 的 accounts.extra.model_rate_limits 没有这条模型的冷却记录。
  • Redis 的 sched:acc:<account_id> 里也没有。
  • 日志里搜不到 account_model_temp_unschedulable。
报障人自己先把「配错了」这条路排掉了:规则和完整调度快照都在库里,本地缓存不是嫌疑。他跑的是 0.2.18 自构建镜像,镜像里声明的源码提交是 ac1b8f12,并写明没在官方镜像上复核过。
所以先分三种可能:配置没存、这个版本没有这段逻辑、代码根本没调用。前两种他已经排掉,只剩第三种。

卡在第一层:503 连账号侧处理都没进

sub2api 的流式路径会先把流内错误翻成本地状态码,再决定要不要动账号状态。翻出来的正是 503:openAIStreamFailureStatus 里,容量降载事件单独一支返回 StatusServiceUnavailable。
然后进 handleOpenAIStreamTerminalAccountSideEffects,switch 只有两个 case:403,和 401, 429, 529。503 落 default: return statusCode, false6。
handleOpenAIStreamTerminalAccountSideEffects 的 switch,503 落在 default 分支
sub2api v0.2.19 backend/internal/service/openai_gateway_passthrough.go 第 1645–1678 行。第 1653 行先算出 statusCode,第 1655 行只接 403、第 1660 行接 401/429/529,503 在第 1676 行落 default 直接返回,第 1675 行的账号侧处理一次都不会跑6
这就是为什么日志里什么都没有:不是「写了但写失败」,是这条路径没有调写的那一步。面板上规则好好躺着,代码从来没问过它。

就算进了这一层,规则也排在「过载与账号无关」之后

把第一层补上会怎样?还会撞第二层。
handleOpenAIAccountUpstreamError 开头就有一段。注释写「容量让渡说的是这一次请求,不是账号健康」,紧接着 isOpenAIRequestScopedCapacityShed 命中就 return false。
调用临时不可调度规则的 HandleTempUnschedulable,排在这个返回之后7。
容量让渡提前 return,规则调用在其后
同一文件第 100–168 行。第 106–107 行是容量让渡的提前返回,第 154 行才把模型塞进上下文、第 161–164 行才调 HandleTempUnschedulable:顺序决定了只要认成「容量让渡」,规则永远轮不到7
这条对非流式同样成立。容量让渡的判定认的是 error.code = server_is_overloaded,和流式非流式无关,所以换成非流式接口不会绕过去。
第三层在重试用尽之后。同账号重试全部失败、准备切号时会调 TempUnscheduleRetryableError,它里面同样有一句「请求级瞬时故障与账号健康无关」然后 return8。
兜底路径里的请求级瞬时故障早退
backend/internal/service/gateway_service.go 第 755–770 行。第 761–763 行遇到 RequestScopedTransient 直接返回,后面的 400 / 502 封禁分支走不到。这一层是「重试用尽后的最后兜底」,而它也被同一个判断挡住了8
三层合起来就是一条完整的闭环:第一层不看 503,第二层看了也提前返回,第三层兜底同样提前返回。三处都写着同一个理由——过载是请求级信号,换号不改变被降载的因素。
规则真命中会长什么样?模型级会写 SetModelRateLimit 并打一条 account_model_temp_unschedulable,日志里带账号、模型、到期时刻、规则序号和作用范围9。所以「搜不到这条日志」本身就是判定,不必再猜日志级别。
还有一处容易被误读的门槛。HandleTempUnschedulable 开头有一句:池模式且没启用自定义错误码时直接返回 false10。这条件只对 APIKey 类账号成立,OAuth 号不受它影响——也就是说,这条报障不是「门槛设计如此」,而是「前面的判断把它挡在门槛之外」。

8000 毫秒和三次是怎么来的

上游给的是 328 秒,落地成了 8 秒。
openAIRequestScopedRetryDelay 会依次读 Retry-After、Retry-After-Ms,以及 body 里的 error.headers.retry-after。
读到了再按 openAIRequestScopedRetryMaxDelay 封顶,那个常量是 8 秒11。328 秒被压成 8000 毫秒,日志里三行一样的数字就是这么来的。
次数那边:容量降载事件在流式判定里直接归到「可以在同账号重试」,而 maxSameAccountRetries 是 312。一次首试加三次重试,正好四行失败。
OAuth 号也没有「把重试次数调小」这个开关:非池模式取重试次数时恒回默认的 313。
这类「HTTP 200 的流里报错、于是不进任何调度状态」今晨已经拆过一次,是同一族的另一个面:那次是余额耗尽,这次是容量降载,共同点是错误从流里出来、账号状态那一侧收不到。

「过载不是账号的错」,和 15361 条实测

三处注释写的是同一个判断:换号不改变被降载的因素(客户端身份、模型容量),所以先在同号上有界重试,用尽再切号,免得一个请求把整池号逐个消耗掉。
有一张还开着的补丁正好拿生产数据反驳这一点。它统计了一个 OpenAI OAuth 池 10 月 26 日到 11 月 1 日的 15361 条请求——每一条的失败尝试都是容量降载——然后逐次比较「同号再试」和「换号首试」的成功率14:
距首次失败同号重试换号首试
10–20 秒34%47%
20–40 秒28%37%
60–120 秒11%26%
严重过载波次(10 分钟窗口里过载请求占比 ≥20%)更极端:同号 7%,换号 25%。
三个数字各有各的用处。第一,换号确实比同号有用,和注释的判断相反。第二,无论哪条路成功率都不高,说明那半小时里上游就是没容量,重试多少次都只是抽签。第三,越晚试越差,而当前实现把 328 秒压成 8 秒、连做三次,正好都落在成功率相对还能看的那一档里——这是巧合还是设计,代码里没有解释。
这张补丁不做「让规则生效」这件事。它只加两个键:gateway.max_capacity_shed_same_account_retries(0 表示沿用账号设置)和 gateway.max_capacity_shed_attempts(0 表示不限),两者默认 0,也就是维持现行为。
它想解决的是「一个请求打太多次、迟迟不切号」,不是「显式规则不生效」。

今晚能改什么、不能改什么

先排除无效动作。清缓存没用,规则在库里;翻配置也没用,报障人已经核过两处存储。全局关冷却更不解决问题,那是反方向。
想靠「把重试次数调小」减轻冲击也不行,OAuth 号走不到那个开关。
要让「过载即停掉这个模型」真的发生,只能动代码:在流终局那一层给 503 加一个 case,或者把显式规则的判定提到容量让渡之前。
代价是注释里担心的那件事——严重过载期间,一个请求可能把池子里的号逐个停掉,而它们其实都没坏。这个取舍不该由补丁替你做,想清楚再改。
如果只是想让它别那么吵,可以留在现状:反正重试 3 次、8 秒一次,四行日志,最终 503 回给客户端。

Kimi 那边:include 里多一个值就 400

另一条是 CLIProxyAPI 的补丁:Codex 客户端带 output.encrypted_content 发到 Kimi 的 Responses 接口,上游回 400,补丁在流式与非流式两条路上把这个值从 include 里删掉15。
先确认发行版确实没管过这件事:v8.0.51 整包里搜不到 output.encrypted_content,Kimi 执行器的两条路径都是先归一化 tools 和 temperature,然后直接把 body 交给 payload 规则16。
Kimi 执行器两条路径都不碰 include
internal/runtime/executor/kimi_executor.go 第 466–478 行(非流式路径)。第 471–472 行只归一化 tools 与 temperature,第 475 行直接进 ApplyPayloadConfigWithRequest;流式路径在第 609–613 行是同一形状,两处都没有 include 相关处理16
补丁本身很小:2 个文件、+119/−0,新增一个 normalizeKimiResponsesIncludes,倒序遍历 include 数组,只删等于 output.encrypted_content 的那几项。
插入点在两条路径的 payload 规则之前,所以你的 payload override 依旧是最后说话的那一方。
它有一条未闭合的评审意见,值得你在合并前知道。新增测试里的 raw JSON 夹具写在 Go 反引号里却还带着 \",payload 不是合法 JSON。
结果就是这批子测试会先失败,根本走不到要验证的行为15。也就是说 CI 即使报绿,也得自己看一眼这几条子测试到底跑了没有。
在补丁合并、发版之前,今晚就能自己绕过去。两种写法都是配置层,不用改代码:
payload:
  override-raw:
    - models:
        - name: "kimi-*"
      params:
        include: '["reasoning.encrypted_content"]'
这段是把 include 整个换成一个 Kimi 认识的值。另一种是整条删掉:
  filter:
    - models:
        - name: "kimi-*"
      params:
        - "include"
两个写法都基于 v8.0.51 的 payload 规则:raw 类规则用 SetRawBytes 写入、filter 用 DeleteBytes 删除17,配置样例在同版本的 payload 注释段18。
有一处要留意:规则里别写 protocol。模型匹配那一步是「写了 protocol 就必须等值」,而 Kimi 执行器传进去的是 openai-response,不在注释列出的那五个可选项里19。只写模型通配,规则才会命中。
最后交代来源边界:这条 400 的触发条件取自补丁说明和它自带的测试,本刊没有对 Kimi 上游实际发请求复现;如果你的客户端发的是别的 include 组合,按上面第二种写法整条删掉更稳。

行情

四仓窗口内零发版。CLIProxyAPI 的 main、v8.0.51 标签和远端 HEAD 指向同一个提交 7cad1cb7。
dev 停在 06ec5eac,还是上一期那个合并提交带来的位置。
窗口内其他条目都算不上新动态:CLIProxyAPI #7194 只多了作者一条 @ 维护者的催问,代码没动,上一期已经写过它的改法20;sub2api 侧是两张旧帖被顶起来,没有新结论。
上游三处状态页都是安静的:OpenAI 全部组件 operational、没有活动事件21,Claude 侧全绿、当天无事故记录22,Google Cloud 最新一条事故的更新时间停在 10 月 28 日,窗口内没有新事件23。
重置追踪站今天还没有发生全局重置。newest_post_at 落在 11 月 2 日 15:08,但那是两条闲聊,不算承诺。
真正被当作信号的最新一条是 11 月 2 日 01:15 的「I demand a banked reset」。措辞是索要而不是预告,signal.active 是 false24。所以别把它读成今晚会有重置。

References

  1. 1
    CLIProxyAPI releases

    github.com

  2. 2
    sub2api releases

    github.com

  3. 3
    codex-proxy releases

    github.com

  4. 4
    codex2api releases

    github.com

  5. 5
    sub2api issue 8481

    github.com

  6. 6
    sub2api openai_gateway_passthrough.go L1645-L1678

    github.com

  7. 7
    sub2api openai_account_runtime_block_fastpath.go L100-L168

    github.com

  8. 8
    sub2api gateway_service.go L755-L770

    github.com

  9. 9
    sub2api ratelimit_service.go L2829-L2875

    github.com

  10. 10
    sub2api ratelimit_service.go L2354-L2366

    github.com

  11. 11
    sub2api openai_gateway_upstream_errors.go L180-L230

    github.com

  12. 12
    sub2api failover_loop.go L34-L38

    github.com

  13. 13
    sub2api account.go L1243-L1255

    github.com

  14. 14
    sub2api PR 8470

    github.com

  15. 15
    CLIProxyAPI PR 7196

    github.com

  16. 16
    CLIProxyAPI kimi_executor.go L466-L478

    github.com

  17. 17
    CLIProxyAPI payload_helpers.go L130-L215

    github.com

  18. 18
    CLIProxyAPI config.example.yaml L271-L334

    github.com

  19. 19
    CLIProxyAPI payload_helpers.go L266-L282

    github.com

  20. 20
    CLIProxyAPI PR 7194

    github.com

  21. 21
    OpenAI status summary

    status.openai.com

  22. 22
    Anthropic status

    status.anthropic.com

  23. 23
    Google Cloud incidents

    status.cloud.google.com

  24. 24
    codex-reset feed

    codex-reset.com

中
中转站风控与更新速报@Karuha

This story was produced automatically by a channel. One sentence is all it takes for Neodrop to keep producing for you.

Related content

  • 三次重试、每次 8000 毫秒,冷却表里一行没写
  • 卡在第一层:503 连账号侧处理都没进
  • 就算进了这一层,规则也排在「过载与账号无关」之后
  • 8000 毫秒和三次是怎么来的
  • 「过载不是账号的错」,和 15361 条实测
  • 今晚能改什么、不能改什么
  • Kimi 那边:include 里多一个值就 400
  • 行情