type, node_id, title, date
| type |
node_id |
title |
date |
| finding |
finding:2026-09-10-24-hedged-requests-validation |
issue #24 长尾对冲请求与裸生成时间验证报告 |
2026-09-10 |
issue #24 长尾对冲请求与裸生成时间验证报告
计划:research-wiki/plans/2026-09-10-24-hedged-requests.md;设计:research-wiki/designs/2026-09-10-24-hedged-requests-design.md(H1–H8 全数获批)。
分支 feature/1.3.7-hedged-requests;基线 main 166b286(1.3.6);代码提交 0a6d622(T1)/463eca3(T2)/adc0694(T3),文档提交见本文件 git 历史。
所有命令在 PolyGateway conda 环境执行,未接管道(退出码不失真)。
1. 红绿证据索引
证据目录 tests/outputs/137/{t1,t2,t3}(不提交,本地留存);每份日志末尾带 EXIT_CODE= 行。
| 任务 |
相位 |
证据文件 |
退出码 |
结果与失败形态 |
| T1 端口事件 |
红(批次 A) |
t1/red-batch-a.log |
1 |
4 failed,143 deselected——失败均为 TypeError(端口签名无 first_token_event 必填 kw),非断言值不符 |
| T1 |
绿(批次 A) |
t1/green-batch-a.log |
0 |
147 passed |
| T1 |
绿(unit 全套) |
t1/green-unit-full.log |
0 |
1550 passed,既有断言一行未改 |
| T2 CallStats 三字段 |
红(批次 B–F) |
t2/red-batch-b-f.log |
1 |
10 failed,373 deselected——字段不存在(TypeError/AttributeError)与计时字段恒 0 |
| T2 |
绿(批次 B–F) |
t2/green-batch-b-f.log |
0 |
10 passed,373 deselected |
| T2 |
绿(unit+contracts) |
t2/green-unit-contracts.log |
0 |
1621 passed,17 skipped |
| T3 对冲编排 |
红(编排+配置守卫,计划批次 G/H) |
t3/red_batches_d_h.txt |
1 |
25 failed——14×RetryMW 缺 hedge_after_s、2×GatewayClient 缺参、4×GatewaySettings 缺属性、4×守卫未抛 ValueError、1×client 缺属性,均为未实现形态 |
| T3 |
绿(同上 25 用例) |
t3/green_batches_d_h_run1.txt |
0 |
25 passed,2.55s |
| T3 |
绿(批次 I 默认关闭回归) |
t3/green_full_unit_contracts.txt |
0 |
1646 passed = 基线 1621 + 新增 25,17 skipped,48s;既有断言一行未改 |
| T3 |
lint |
t3/lint.txt |
0 |
make lint(ruff --fix + import-linter)通过,Contracts: 1 kept,0 broken |
T3 各相位命令原文与退出码另见 t3/commands.md(该文件表头"批次 D–H"为执行批次流水号,对应计划 §5 的批次 G 对冲编排 + H 配置守卫,25 用例 = 15 编排 + 8 配置 + 2 client 入口校验)。
2. 批次与提交映射
| 提交 |
计划任务 |
覆盖批次(计划 §5) |
关键断言 |
0a6d622 |
T1 端口事件(H2) |
A |
流式首 token 置位事件;非流式永不置位;None 不观测行为不变;漏传必填 kw 即 TypeError |
463eca3 |
T2 三字段与计时(H3+H8) |
B–F |
三字段默认 0/0/False;chat 计时排除退避与准入;结构化重问取最后一轮;embedding 批次累加;OCR 单次;缓存命中恒 0 |
adc0694 |
T3 对冲编排(H1/H4/H5/H6) |
G、H、I |
触发两形态;异源排除;准入失败静默;赢家 settle 实际/输家 settle est;hedge_cancelled 标签;输家不喂熔断;attempts==2 无任务泄漏;外部取消两路穿透;deadline 切断对冲树;原路后发先至;两败计一次预算;两 429 免预算退 stall;混合失败计一次;配置守卫四路 |
3. 实测核对(文档承诺 vs 运行实测,本文件交付时复核)
| 承诺 |
核对方式 |
实测结果 |
CallStats 三字段默认值 |
CallStats(logical_call_id='x', attempts=1, total_latency_ms=5) 仅旧三参构造 |
hedges=0、generation_ms=0、hedge_won=False,构造不炸 |
hedge_won 语义 |
现读 middleware/retry.py:498-578 |
赢家裁定后 hedge_won=winner is hedge;两败轮次照登 hedge_won=False 且裸生成时间无归属不记;触发但准入失败不计 hedges |
| 两键 env 解析 |
GatewaySettings.from_env(env=...) 注入两源 + LLM__HEDGE__AFTER_S=8/MAX_EXTRA=2 |
解析出 hedge_after_s=8.0/hedge_max_extra=2,两源照常加载(3 段键未被当源字段);MAX_EXTRA=2 触发装配期 warning「v1 仅单路对冲生效」;不设两键时 None/1 |
| 版本号不动 |
pyproject.toml 与 src/polygateway/__init__.py |
两处均 1.3.6,本计划不 bump、不 tag、不发布 |
| 文档行号 |
README/CHANGELOG/.env.example 接入点 |
均按交付时现读行号接入,未沿用计划旧行号 |
4. 豁免索引(未跑项与去向)
| 未跑项 |
理由 |
去向 |
tests/e2e/(slow) |
本计划不新增、不跑真实网关用例;tests/e2e/conftest.py 包装 transport 已同步转发 first_token_event |
发布清单第 4 步按 diff 交集选子集(本 diff 触及公开入口与 e2e 设施,e2e 冒烟届时在交集内) |
| Redis 契约/integration(slow) |
T1–T3 未触碰限流 Lua、Permit 端口、backends/** 与 tests/contracts/**(计划 §2 不改清单);对冲结算复用既有 settle_and_release 路径,无新 Lua 行为可测 |
同按发布交集规则判断;diff 已触及 retry/限流结算路径,Redis 时间语义变体届时在交集内(计划 §5 末句已登记) |
test_thinking_live.py 全模型矩阵 |
未动 thinking.py/能力注册表 |
不在交集,复用最近一次有效矩阵证据 |
5. 残余复述(设计 §10 与计划 §6 的已批准口径)
| 项 |
口径 |
| 非流式「挂起 vs 慢生成」 |
物理不可分(无中途信号),只能靠阈值取值(建议源 p50 数倍)与 hedge_max_extra 上限控制误对冲;分位数触发为未来扩展 |
| 输家取消止不住上游计费 |
est 保留只是闸内保守记账,不是上游真实计量的计量;文档只写「可能已计费」,不写「浪费上限 = est」 |
| 竞速误贴标签 |
外部取消与对冲取消同时到达时,输家行可能误贴 cancelled/hedge_cancelled;两任务同消、记账方向一致(est 保留),不造成结算或熔断错误,可接受 |
hedge_max_extra v1 单路 |
值域 [1,3] 接受,>1 仅装配期 warning,运行期恒单路(对冲任务恒传 first_token_event=None,不再触发梯次);若未来审定应为 ValueError,改 check_hedge_assembly 一处 + 批次 H 一条断言 |
| 挂起源不喂熔断的反向代价 |
持续挂起的源不会因对冲输家被熔断标记;「挂起率」只能靠 hedge_cancelled 遥测行统计(同 logical_call_id join 还原) |
6. 结论
T1–T3 全部行为变更具备先红后绿证据(§1),默认关闭回归门成立(1646 passed 且既有断言一行未改),lint 与 import-linter 契约通过。文档承诺经运行实测核对(§3)。版本 bump、tag、发布与 slow/e2e 交集子集不在本计划内,按 CLAUDE.md §4.4.1 另行执行。