fischer-agentkit/docs/plans/2026-06-17-001-fix-benchmar...

9.5 KiB
Raw Permalink Blame History

title status created type origin
fix: Benchmark 测试失败根因修复 active 2026-06-17 fix test-results/benchmark/benchmark_report.md

fix: Benchmark 测试失败根因修复

Summary

修复 benchmark 测试中 3 个失败项的根因LLM 推理超时2/5、WebSocket 连接失败1/5、verification P95 延迟失真。所有修复从根因层面解决,非简单调参。

Problem Frame

最新 --mode all 回测结果63 个测试 60 通过 3 失败95.2%)。

失败项 维度 根因
llm-003 llm_reasoning 30s 硬超时对 hard 任务不足,且未用流式提前退出
llm-005 llm_reasoning 同上
gui-004 gui_integration WebSocket 端点路径错误 + 协议交互顺序错误

另有一个统计方法论缺陷verification 维度 P95=411ms 由 timeout 测试用例的 500ms 固有耗时扭曲,产生性能误报。

Requirements

  • R1: LLM 维度 hard 任务不再因超时失败(根因:流式 + 难度分级超时)
  • R2: GUI 维度 WebSocket 测试通过(根因:修正端点路径 + 协议顺序)
  • R3: verification 维度 P95 不再被 timeout 用例扭曲(根因:延迟统计排除 timeout 类用例)
  • R4: LLM Gateway 支持超时透传,避免 asyncio.wait_for 取消后 HTTP 连接泄漏
  • R5: 所有修复后 --mode all 回测准确率 >= 95%,无回归

Key Technical Decisions

KTD1: LLM 超时按难度分级 + 流式关键词提前退出

决策: 对 hard 难度 LLM 任务使用 chat_stream() 流式响应,检测到期望关键词后立即终止;对 easy/medium 保持非流式但按难度分级超时。

理由: 根因是 30s 硬超时 + 非流式等待完整响应。流式 + 关键词检测可将 hard 任务有效延迟从 30s+ 降至 5-15s关键词通常在前 200 tokens 出现)。难度分级超时避免 easy 任务等待过久。

超时映射: easy=20s, medium=40s, hard=60s流式模式下 hard 实际会在 5-15s 内完成)

KTD2: WebSocket 测试修正端点路径和协议顺序

决策: 修正 benchmark 代码中的 WebSocket 测试,使用正确端点 /api/v1/ws/tasks/{task_id},并遵循服务器协议(先接收 connected 消息,再发送 ping)。

理由: 根因是 benchmark 代码 bug路径 /ws/bench-session 不存在 + 未先接收 connected)。这是测试代码问题,非服务器缺陷。

KTD3: 延迟统计排除 timeout 类用例

决策: 在 _compute_metrics 中新增 exclude_latency_tags 参数verification 维度排除 timeout 类用例的延迟统计,但保留其准确性统计。

理由: timeout 测试用例的 ~500ms 延迟是测试设计的固有耗时(必须等待超时触发),不是被测系统性能问题。将其纳入 P95 会导致永久误报。

KTD4: LLM Gateway 超时透传

决策: 在 LLMRequest 中新增 timeout 字段,gateway.chat() 透传给 ProviderProvider 层面尊重超时。

理由: 当前 asyncio.wait_for 取消协程时,底层 HTTP 请求可能未被干净关闭。超时透传让 Provider 在 HTTP 层面超时,确保资源清理。

Implementation Units

U1. LLM 超时分级 + 流式关键词检测

Goal: 修复 llm-003/llm-005 超时失败

Dependencies: 无

Files:

  • src/agentkit/cli/benchmark.py_execute_llm_reasoning_task 函数(约第 622-694 行)

Approach:

  1. 新增难度分级超时映射: {"easy": 20.0, "medium": 40.0, "hard": 60.0}
  2. 对 hard 任务使用 llm_gateway.chat_stream() 流式响应
  3. 流式过程中检测 task.expected_keywords,命中即 break
  4. 非 hard 任务保持非流式,使用分级超时
  5. 流式失败时回退到非流式fallback

Test scenarios:

  • easy 任务在 20s 内完成,非流式
  • medium 任务在 40s 内完成,非流式
  • hard 任务使用流式,关键词在 15s 内检测到
  • hard 任务流式失败时回退到非流式
  • 所有难度任务不再因超时失败

Verification: python3 -c "from agentkit.cli.benchmark import benchmark; benchmark(dimension='llm_reasoning', mode='llm', report=True, runs=1)" 通过率 >= 80%


U2. WebSocket 测试路径和协议修正(根因更新)

Goal: 修复 gui-004 WebSocket 连接失败

Dependencies: 无

Files:

  • src/agentkit/cli/benchmark.py_run_gui_integration 函数中 gui-004 测试块(约第 1038-1101 行)

根因分析(调试验证):

  1. HTTP GET 预检查断言 status_code in (400, 426),但 FastAPI WebSocket 路由对 HTTP GET 返回 404(非 400/426
  2. HTTP 预检查失败导致 ws_pass=False,实际 WebSocket 连接测试从未执行
  3. 实际 WebSocket 连接是成功的:能连接、能收到 connected 消息
  4. pong 未收到是因为服务器并发启动 ReAct 执行,执行失败后发送 error 并关闭连接listener task 被取消

Approach:

  1. 移除 HTTP 预检查 — FastAPI WebSocket 路由不响应 HTTP GET预检查不可靠
  2. 直接 WebSocket 连接测试websockets.connect()ws://localhost:{port}/api/v1/ws/tasks/bench-session
  3. connected 消息作为通过标准 — 收到 {"type": "connected"} 证明 WebSocket 协议正常工作
  4. ping/pong 作为附加信息 — 尝试 ping/pong 但不作为通过条件(服务器并发执行设计导致 pong 可能不可达)
  5. 连接失败才判负 — WebSocket 连接本身失败或未收到 connected 才算失败

Test scenarios:

  • WebSocket 连接到正确端点成功,收到 connected → PASS
  • WebSocket 连接失败(端口错误)→ FAIL
  • 未收到 connected 消息 → FAIL
  • 收到 connected 后服务器发送 error/关闭连接 → 仍 PASSWebSocket 协议正常)

Verification: python3 -c "from agentkit.cli.benchmark import benchmark; benchmark(dimension='gui_integration', mode='gui', report=True, runs=1)" gui-004 通过


U3. 延迟统计排除 timeout 类用例

Goal: 修复 verification P95 延迟失真

Dependencies: 无

Files:

  • src/agentkit/cli/benchmark.py_compute_metrics 函数(约第 1070-1136 行)和 _run_dimension 调用处

Approach:

  1. _compute_metrics 新增 exclude_latency_tags: list[str] | None = None 参数
  2. 计算延迟分位数时,排除 detailcategory 包含排除标签的用例
  3. 准确性统计不受影响timeout 用例仍计入 pass/fail
  4. _run_dimension 对 verification 维度传入 exclude_latency_tags=["timeout"]
  5. vf-004 的 detail 字段确保包含 "timeout" 字样

Test scenarios:

  • verification 维度 P95 < 100ms排除 timeout 用例后)
  • timeout 用例仍计入 accuracypass/fail 不受影响)
  • 其他维度不受影响(不传 exclude_latency_tags
  • 空排除列表时行为不变(向后兼容)

Verification: python3 -c "from agentkit.cli.benchmark import benchmark; benchmark(dimension='verification', mode='mock', report=True, runs=1)" P95 < 100ms


U4. LLM Gateway 超时透传

Goal: 避免 asyncio.wait_for 取消后 HTTP 连接泄漏

Dependencies: U1

Files:

  • src/agentkit/llm/protocol.pyLLMRequest 模型
  • src/agentkit/llm/gateway.pychat() 方法

Approach:

  1. LLMRequest 新增 timeout: float | None = None 字段
  2. gateway.chat() 接受 timeout 参数,透传到 LLMRequest
  3. Provider 的 chat() 方法检查 req.timeout,在 HTTP 请求层面设置超时
  4. benchmark 的 _execute_llm_reasoning_task 使用 gateway.chat(timeout=timeout_s) 替代 asyncio.wait_for

Test scenarios:

  • LLMRequest 包含 timeout 字段
  • gateway.chat() 透传 timeout 到 LLMRequest
  • Provider 在 timeout 秒后超时,抛出 LLMProviderError
  • 不传 timeout 时行为不变(向后兼容)

Verification: ruff check src/agentkit/llm/protocol.py src/agentkit/llm/gateway.py 通过


U5. 全量回测验证

Goal: 验证所有修复后无回归

Dependencies: U1, U2, U3, U4

Files:

  • 无(验证步骤)

Approach:

  1. 运行 ruff check src/ 确认无 lint 错误
  2. 运行 pytest tests/e2e/test_capability_comprehensive.py -x -q -m e2e_capability 确认 64 个测试通过
  3. 运行 agentkit benchmark --mode all --report --verbose --runs 1 确认 63 个测试通过率 >= 95%
  4. 检查报告LLM 维度 >= 80%GUI 维度 >= 80%verification P95 < 100ms
  5. 对比基线,确认无回归

Verification: 全量回测通过,无回归

Scope Boundaries

In Scope

  • 修复 benchmark.py 中 3 个失败项的根因
  • LLM Gateway 超时透传
  • 延迟统计方法论修正

Out of Scope

  • WebSocket 服务器端的设计缺陷task_id 当作消息内容)— 另行跟进
  • LLM 模型本身的响应速度优化 — 依赖模型提供商
  • 新增测试用例 — 本次只修复现有失败

Deferred to Follow-Up

  • WebSocket 端点支持纯心跳模式(不触发 ReAct 执行)
  • LLM 维度增加更多用例5→15
  • GUI 维度增加前端交互测试

Risks

风险 影响 缓解
流式响应兼容性 chat_stream 可能在某些 Provider 上行为不一致 fallback 到非流式
LLM 响应仍有波动 hard 任务可能仍偶发超时 60s 超时 + 流式提前退出双保险
WebSocket 服务器行为变化 服务器协议变更导致测试再次失败 测试代码遵循服务器文档协议

Phased Delivery

  • Phase 1U1+U2+U3: 修复 3 个失败项,可独立验证
  • Phase 2U4: LLM Gateway 超时透传,架构层面改进
  • Phase 3U5: 全量回测验证