# R2.2.1 客户可见错误溯源与调优建议

## 范围与数据源

- 运行目标：PK01 host-Docker，Sub2API `0.1.153`。
- 原生 API：`dashboard/overview`、`upstream-errors`、`account-availability`、`concurrency`、`requests`、`system-logs/health`。
- 原生 `system-logs` 未索引策略事件，按既定 CLI 规则回退读取 runtime 日志。
- 观察窗口：连续 20 分钟快照与 60 分钟汇总。
- 本轮只分析，没有修改 YAML、runtime 配置或 Sub2API 代码。

## 客户错误率

- 20 分钟窗口：335 次请求，4 次客户错误，客户错误率 1.19%，上游错误率 2.99%。
- 60 分钟窗口：907 次请求，8 次客户错误，客户错误率 0.88%，上游错误率 3.64%。
- 60 分钟内发生 7 次 `account_select_failed`，几乎覆盖全部客户可见错误。
- 组并发快照为 9/218，负载 4.13%，排队 0；全池并发不是主因。
- system-log sink 的 queue、drop 和 write failure 均为 0；日志落库不是业务错误来源。

## 请求级根因

### 模型候选为零

- 三个 `gpt-5.4-nano` 流式请求分别在 5ms、10ms、28ms 内未选中账号并返回 404。
- 请求 ID：`21e5d449-3b0d-4a70-a798-1dc0af0ba110`、`55f7eb2a-b469-4d90-9ec9-3d20d278aef7`、`e90dfd63-22c1-419b-a479-53f860d4151a`。
- 官方源码会在组内存在账号但没有任何 `model_mapping` 支持请求模型时返回 `404 model_not_found`。
- 这不是瞬时容量问题，重试、临时不可调度和提高切号次数均无效。

### 多账号连续失败后候选耗尽

- `8150234d-eee2-4a08-a43e-e47a22274609`：`gpt-5.4`，account 28 返回 503、account 27 返回 429、account 31 返回 429，约 6.1 秒后无候选，最终 429。
- `bf9aea0a-869a-4ee0-a99c-3b0ceb553822`：`gpt-5.6-luna`，account 28 返回 503、account 27 返回 429，约 67 秒后上下文取消且无候选，最终 429。
- `03a94444-ff26-4038-b1b9-67e249ce7f59`：`gpt-5.6-sol`，account 33 返回 524、account 31 返回 502，约 180 秒后上下文取消且无候选，最终 502。
- `5d8f05ff-9cbc-4040-b6eb-4b262ab85f39`：`gpt-5.6-sol`，account 33 返回 524，约 126 秒后上下文取消且无候选，最终 502。
- `max_account_switches=10` 只是上限。官方实现会排除已失败账号并重新选号；剩余账号不满足模型或运行状态时，会在只切 1 至 3 次后结束。

### 流式提交后错误

- 成功样本证明自动 failover 正常工作：account 27 的 502 可切到 account 33，account 28 的 503 可切到 account 31。
- 存在 `forward_failed + HTTP 200`，例如 account 31 返回 `Concurrency limit exceeded`，但下游已经提交流式响应。
- 官方 `v0.1.153` 在检测到已写入语义响应后明确禁止换号，以免拼接两个上游流。
- 此类错误不能靠临时不可调度透明恢复，只能减少上游发生率，或由客户端在流中断后重试或恢复。

## 上游账号主因

- 60 分钟上游记录共 72 条：rate-limit 24、overload 15、concurrency 12、generic upstream failure 11、status-only 6、model-route-unavailable 4。
- account 28：10 次 overload，当前高频触发 503 临时不可调度。
- account 27：rate-limit 为主，同时有 502 generic failure；现有规则只覆盖 502，不覆盖真实 429 文本。
- account 31：13 次 rate-limit 为主，另有 concurrency 和一次 `GROUP_DISABLED`；模板未匹配 `Upstream rate limit exceeded`。
- account 19：7 次 504，其中 2 次明确 concurrency、1 次 upstream unavailable、4 次只有状态；另有 3 次 `No available channel for model`。
- account 32：2 次 429 rate-limit、1 次 502 concurrency。
- account 29、30：余额不足导致 403，已处于 `status=error`、`schedulable=false`，不会继续被调度，但减少了候选容量。

## 官方版本判断

- PK01 运行 `v0.1.153`。
- `v0.1.152..v0.1.153` 的相关变更是 WebSocket ingress 生命周期限制，不改变当前 HTTP 模型选号、failover 或临时不可调度匹配。
- `v0.1.149` 已包含无账号支持模型时返回 404 的实现，因此回退不会消除 `gpt-5.4-nano` 404。
- `v0.1.153` 已包含 compact 心跳不阻断 failover 的官方 #3887 修复。没有证据表明回退能降低当前错误率，不建议回退。

## 调优建议

### P0：修正模型目录与映射

- 查明 `gpt-5.4-nano` 是客户端误配、错误广告模型还是预期别名。
- 若没有真实上游支持，从客户可见模型目录和调用配置中移除。
- 若业务确实需要，只映射到已经实测支持的真实模型，不能为消除 404 添加虚假映射。

### P1：扩展保守临时不可调度模板

- 在 429 规则增加真实关键词 `upstream rate limit exceeded`，保持 1 分钟冷却。
- 新增 504 规则时只加入实测关键词 `concurrency limit exceeded` 和 `upstream service temporarily unavailable`，保持 1 分钟冷却。
- 不增加任意 504 规则；4 次 504 只有状态码，不能推断真实原因。
- 不把 `No available channel for model` 放入通用账号级模板；这是模型级缺口，账号级摘除会误伤其他模型。
- `lyon9801` 继续保持例外，不绑定临时不可调度规则。

### P1：账号级并发对照调优

- 不降低组级并发。
- account 31 有最强直接并发证据，可先做单账号对照，例如从 30 降到 20，观察 30 至 60 分钟的错误和吞吐。
- account 19、27、32 也有信号，但没有错误时刻并发历史；不要一次性全降。
- 手工账号属于 runtime 管理面，后续通过 runtime CRUD 调整，不纳入 YAML managed profile 自动同步。

### P1：降低慢失败对客户时间预算的吞噬

- 524 请求分别在约 126 秒和 180 秒后穿透，第一个慢上游已消耗大部分客户超时预算。
- 官方默认 `gateway.response_header_timeout=600s`，明显长于当前客户或边缘上下文。
- 建议先确认运行实际值，再受控收紧 OpenAI 响应头超时，为一次 failover 预留预算；不能直接照抄固定值。
- 对照指标应包含首 token 延迟、超时型上游错误、failover 成功率和客户错误率。

### P2：恢复候选容量与调度偏好

- account 29、30 只有补足余额并通过真实请求验证后才能恢复，不能直接改为 schedulable。
- account 28、27、31 当前优先级高且错误集中，可在确认模型覆盖后降低调度偏好，让更稳定账号先承担请求。
- Ops system-log 未索引策略事件，60 分钟有 144 条事件依赖 runtime fallback；这不造成业务错误，但限制长期归因，由 R2.3 跟踪。

## 不建议的措施

- 不建议回退到 `v0.1.149`。
- 不建议提高 `max_account_switches`。
- 不建议降低全池并发。
- 不建议启用 `pool_mode` 做同账号重试。
- 不建议对所有 4xx/5xx 做无关键词临时不可调度。

## 后续验收

- 按 20 分钟和 60 分钟双窗口继续观察客户错误率、upstream error rate、`account_select_failed`、模型 404、failover 成功率、`forward_failed + 200` 和每账号根因。
- 每次只改变一个变量并保留前后窗口；R2.2 继续保持进行中。
