Files
PolyGateway/research-wiki/findings/2026-09-10-24-hedged-requests-validation.md
T

6.6 KiB
Raw Blame History

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(H1H8 全数获批)。 分支 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 三字段 红(批次 BF) t2/red-batch-b-f.log 1 10 failed,373 deselected——字段不存在(TypeError/AttributeError)与计时字段恒 0
T2 绿(批次 BF) 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) BF 三字段默认 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=0generation_ms=0hedge_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.tomlsrc/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) T1T3 未触碰限流 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 另行执行。