-
released this
2026-08-17 11:36:32 +08:00 | 148 commits to main since this release网关拒绝一次调用时,它说的话不再丢失(issue #10)。下游一轮 1050 张医学影像的批处理里,1 张在读表格这一步收到 400、被判确定性失败而放弃;事后想知道"这张图到底哪里不合规",无从查起——响应体在 transport 翻译层之后就不存在于进程任何位置了。
根因是三条留存通道同时为空:
_status_to_error手上握着body_text却只用于 429 的类型细分,该模块没有任何 logger 调用,异常类也没有承载响应体的字段。而库的逐次遥测写的是str(exc),即 message——所以只给异常加字段并不能让它进遥测表,必须两者都做。新增
- 四分类错误新增
body_text字段(加在PolyGatewayError基类): 非 2xx 响应体的摘要。与ResultInvalidError.raw_text分工明确——前者是"对方拒绝的理由"(非 2xx),后者是"2xx 但内容不可解析时的模型输出"。scope 级错误(GatewayUnavailableError一族)恒为空串: 它们没有单一响应体可言。 - 同一份摘要同时进入异常 message,故 SQLite/Postgres 遥测的
error列里直接可查,下游不必为此单独埋点。
行为变更
- 非 2xx 的 message 末尾追加
| {响应体摘要},覆盖两个 transport 的全部分支: chat 的 400 / 401·403 / 4xx 兜底 / 5xx / 429 两支(含insufficient_quota),以及 OCR 的全部分支。issue 只报告了 chat 的 400,但 401 会force_open整个源、OCR 侧 message 原本只有一个状态码,是同一个缺陷的其余分支。 - 摘要口径: 先折叠空白(错误体常是缩进 JSON,原样拼进 message 会把一行日志炸成多行),再限长 2048 字符(对齐 Kubernetes client-go 同场景的
maxUnstructuredResponseTextBytes)。超长时保留头 1400 + 尾 600并记下省略字数——JSON 错误体的code/request_id收在尾部,头部硬切正好会切掉向网关方追查时唯一有用的那部分。 - 遥测
error列因此变长: 纯 ASCII 约 2KB/条,最坏(5xx 重试 3 次)一次调用约 6KB。
不变
- 状态码 → 错误分类的映射逐条未动(ARCHITECTURE §6.2 表),
retry_after_s解析、429 免重试预算、insufficient_quota细分全部保持——429 的类型判定仍解析未截断的原文,若改用摘要,超长 body 的配额耗尽会退化成普通限速、该源不再force_open。 - 异常类型树、
str(exc)之外的字段、遥测 22 字段与列序、DDL 全部未变。错误面零变更,下游except写法不受影响。 - 400 仍按确定性失败处理(不重试不换源)。但请注意: 经第三方中转部署时,中转自身抖动也会回 400,从状态码上与"你的输入有问题"分不开(下游实测: 同一份字节 sha256 一致、重发 15 次全部成功,失败那次
prompt_tokens=0且耗时远低于任何成功调用)。库不改默认语义——直连供应商时重试只会白烧配额——但body_text现在给了下游自行区分的判据。
升级提示
README 的安装 pin 由
==1.1.*改为>=1.2,<2。仍按==1.1.*安装的下游会静默停在 1.1.2,拿不到本次修复且没有任何报错,请同步改自己的依赖约束。- 打包元数据补齐:
readme与[project.urls]。1.1.2 及之前的包在 registry 页面上没有任何说明正文(缺readme时 twine 只警告不阻塞),也没有仓库链接。代码零变更,自本版生效。
Downloads
- 四分类错误新增