在 UniRoute 排查 Claude 流式中断与空闲超时
通过 UniRoute 用量记录与诊断摘要排查 Claude 部分响应中断,核对费用和工具执行结果,再决定如何恢复任务。
UniRoute ·
使用 UniRoute 的 Claude Code 出现 claude api error: stream idle timeout - partial response received 时,先保留已收到的内容,在 UniRoute 控制台找到对应请求,再决定是否重新提交。本教程介绍如何定位记录、复制诊断摘要、区分流式中断与请求完成,以及如何恢复任务。
仅凭这条错误,无法确定是客户端、网络、网关还是上游停止了进展。超时也不能证明零消费。先核对已经发出的请求,收集下列信息无需再发起一次付费调用。
1. 在 UniRoute 找到中断的请求
打开 UniRoute 控制台,登录 Claude Code 所用 Key 对应的账户。在用量记录中选择覆盖事发时间的日期范围,寻找时间与模型匹配的请求。成功和失败记录都应核对:终端里的一次操作可能产生多次请求。
打开对应记录的查看详情,逐项比较:
| 字段 | 如何使用 |
|---|---|
| 时间与模型 | 按所在时区匹配事发时间,并核对客户端选择的完整模型 ID。 |
| 接口地址与可用的请求 ID | 确认请求路径,保留标识以供私有支持查询;区分网关与上游的不同 ID。 |
| 结果、HTTP 状态与脱敏错误响应 | 记录服务端已观测的信息,不要根据终端提示补造缺失状态码。 |
| 可用的首 token 时间与耗时 | 与终端停止时间比较;这些字段不是完整的 SSE 事件轨迹。 |
| 可用的输入、输出、缓存与实际费用 | 逐条核对原请求及重试;缺失字段保持未知。 |
若未找到匹配记录,检查账户、Key、日期范围、模型,以及 Claude Code 实际配置的服务地址。直接发往 Anthropic 或其他网关的请求不会出现在您的 UniRoute 账户中。缺少记录不能证明没有到达某个服务,也不能证明免费。
在请求详情点击复制诊断摘要。摘要只复制可安全识别的时间、模型、请求 ID、已记录 HTTP 状态与可用消费记录等字段,不包含 Key、提示词、响应原文、作品链接或余额。缺失或无法安全提供的字段记为 null;摘要不代表钱包结算确认。检查复制内容后,仅保留给私有支持使用。
2. 确认客户端与输出停止的位置
记录 claude --version、模型 ID 与实际服务地址。UniRoute 用户可对照Claude Code 接入参考检查本地配置。在 Claude Code 内运行 /doctor 可检查本地设置,相关行为见官方排错文档。本地检查成功不代表中断的请求已经完成。
然后记录终端中实际出现的现象:
| 现象 | 接下来核对 |
|---|---|
| 完全没有输出 | 区分连接或首响应等待,与收到内容后的流式中断。 |
| 出现部分文字后停止 | 保留内容,比较客户端时间、对应请求记录与可用网络日志。 |
| 出现工具调用或结果 | 先核对文件变更或外部操作结果,再要求代理重复工作。 |
| 文字看似完整,随后报错 | 检查是否开始了下一轮请求;报错可能属于后续轮次。 |
| 只有长任务失败 | 比较上下文长度、输出量、工具轮次和已观测限制,每次只改变一个因素。 |
不要把凭据或整份配置贴到公开 issue。网络代理与 API 供应商是两项设置:前者传输流量,后者决定接口地址和认证。实际地址不明确时,查看UniRoute 接口地址参考。
3. 区分空闲时间与总耗时
如果您维护自己的接入程序并能观测事件,应分别记录:收到响应头或首事件之前的等待、距上次收到数据的间隔,以及总耗时。客户端所谓的“空闲”可能按字节、完整事件或可见文字计算,三种时钟可能不同。
例如,0.10 秒收到响应头,0.45 秒出现文字,1.00 秒收到最后事件,1.25 秒客户端停止。这些是假设数值,用于说明测量方式,并非 UniRoute 或 Claude Code 默认值。控制台的首 token 时间与总耗时无法还原全部事件轨迹。
按照 Messages 流式协议,message_stop 标记消息结束;ping 不代表新的回答文字。API 错误说明指出,HTTP 成功后仍可能出现 SSE 错误。未收到预期终止事件就发生 EOF,应视为流未完成;消息完成也可能仍需工具步骤才能完成用户任务。
自建解析器应跨网络分片组装完整 SSE 帧,不要执行尚未完整的工具参数片段。调整超时前,先确认当前客户端或中间层确实读取该设置,并确认观测时间支持这一修改。增加限制不能解决所有网络或上游故障。
4. 恢复前核对执行结果与费用
将 UniRoute 请求记录与本地任务状态一起检查,单独一方都不能确定代理已经修改了什么。
| 当前状态 | 继续前应做的事 |
|---|---|
| 输出前已被拒绝 | 阅读拒绝原因,处理认证、权限、限流或服务问题,并检查是否还有其他尝试。 |
| 只有部分文字,未观测到工具 | 保留回答;新回答属于新请求,应限制范围与预算。 |
| 出现工具参数或结果 | 检查文件变更、命令日志与操作标识,先核对已经完成的动作。 |
| 可能执行了部署、付款、发消息或其他外部写入 | 用稳定标识查询结果;状态未知时保持未知,不要直接重放。 |
| 缺少最终用量或实际费用 | 等待记录或联系私有支持核查;缺少最终 usage 不等于零消费。 |
检查客户端、SDK、包装脚本与网关各自是否重试。确认是临时失败后,恢复过程应由一个执行方负责,并限制次数和总耗时。不要给本来就可能重试的操作再套无限循环。
再次付费调用前,查看UniRoute 当前模型与渠道价格。Claude Code 费用指南介绍输入、输出与缓存成本。多请求同时运行时,客户端估算或钱包余额差不能归因某一笔费用。若问题是开始流式输出前的 HTTP 500,可使用UniRoute 500 错误排查流程;若遇到 HTTP 529 或流式中途 overloaded_error,请参阅 Claude API 529 Overloaded 排查指南;若需核对 OpenRouter 会话配置或切换供应商,请参阅Claude Code 接入 OpenRouter 与切换供应商指南。
核对原请求后,若仍需要小请求对照,可在可信空目录中手动测试。先检查实际供应商、模型、权限与 hooks,使用简短且不含敏感信息的提示词,只运行一次,再核对用量。此类测试属于真实请求,可能产生费用及客户端重试;简短成功不能验证长任务。
5. 通过私有支持发送 UniRoute 诊断摘要
使用详情中的通过邮件联系私有支持,或将检查后的摘要发给 support@uniroute.app。复制的服务端字段不能说明终端中的全部情况,请补充:
- 客户端版本、带时区的事发时间、服务主机名与完整模型 ID。
- 是完全无输出、部分文字、工具调用,还是看似完整的回答。
- 已知尝试次数、观测时间,以及是否确实见到 SSE 错误或终止事件。
- 已核对的工具执行结果,以及已经做过的单变量对照。
缺失信息明确标为未知。不要包含 Key、Authorization 请求头、Cookie、提示词、私人代码、完整响应、账户余额或无关记录。请求 ID 仅通过私有支持分享,勿公开发布。由其他供应商处理的请求,应使用该服务的记录与支持渠道。
可选附录:在本地理解流式边界
若想在不使用 API Key、不产生模型费用的条件下观察时间差异,下载并检查 Python 3 本地流式探针,然后运行:
curl --fail --silent --show-error --proto '=https' \
--output claude-stream-probe.py \
https://uniroute.app/examples/claude-stream-probe.py
python3 claude-stream-probe.py --scenario all
下载使用公开网站。随后程序启动 127.0.0.1 临时服务,仅向该回环服务发送模拟请求。它不接受真实 Key 或远程 API 地址,不调用模型。它展示流式边界,不能诊断生产事故或验证 UniRoute 账户。
| 场景 | 展示内容 |
|---|---|
normal | 流到达终止事件。 |
sse-error | HTTP 成功后出现 SSE 错误。 |
truncated | 连接在完成前结束。 |
idle-gap | 响应体数据暂停,超过探针的空闲限制。 |
delayed-first-event | 响应头早于首个完整事件。 |
ping-deadline | 心跳持续到总截止时间,仍未出现回答文字。 |
fragmented-multiline | 网络分片与多行数据需要组装完整帧。 |
可用 python3 claude-stream-probe.py --scenario idle-gap 查看单一场景。可选的 --idle-timeout 0.2 --total-timeout 0.6 以模拟秒数计,并非 Claude Code 配置。探针按未收到响应体字节的间隔计算空闲;ttfb_ms 近似表示收到完整响应头的时间,first_event_ms 记录首个完整 SSE 帧。在首事件延迟场景中,空闲限制先到,因此该字段为 null。结合结果与时间阅读;探针不打印响应内容,也不重试失败。

