fischer-agentkit/docs/plans/2026-06-20-001-fix-regressi...

15 KiB
Raw Blame History

title status created type origin
fix: 回测问题修复 + 路由优化 + 质量门控强化 completed 2026-06-20 fix test/full-regression-real-llm-e2e 回测结果

fix: 回测问题修复 + 路由优化 + 质量门控强化

Summary

修复全面回测中发现的 5 个代码问题,优化当前 RequestPreprocessor 路由准确率,强化 QualityGate 质量门控,并重新基准测试建立当前架构基线。

Problem Frame

回测发现以下问题(基于 test/full-regression-real-llm-e2e 分支):

  1. Benchmark 超时过短llm-001easy 难度)超时阈值 20s真实 LLMqwen3.7-plus无法在 20s 内完成工具调用推理,导致 2/5 用例超时
  2. LLM Provider httpx 超时硬编码OpenAICompatibleProvider 的 httpx 客户端硬编码 timeout=60.0,忽略 ProviderConfig.timeout120s
  3. QualityGate skill_match 休眠_check_skill_match() 方法存在但无调用方传入 skill_context,质量门控形同虚设
  4. QualityGate 自定义验证器过于宽松 — 验证器导入/执行失败时静默跳过(passed=True),不拦截低质量输出
  5. 16 个技能配置均无 disambiguation_keywords — 易混淆技能对reflexion_agent↔code_reviewer 等)无法消歧
  6. 路由优化 — 当前 RequestPreprocessor 仅 3 条正则(问候/闲聊/身份),大量简单 factual 问题被送入 REACT 循环,浪费 token

Requirements

  • R1: Benchmark easy 难度超时从 20s 提升至 45smedium 从 40s 提升至 60s
  • R2: OpenAICompatibleProvider httpx 客户端使用 ProviderConfig.timeout 而非硬编码 60s
  • R3: QualityGate skill_match 在执行管线中被实际调用(传入 skill_context
  • R4: QualityGate 自定义验证器失败时支持严格模式(可配置拦截 vs 警告)
  • R5: 为 4 对易混淆技能添加 disambiguation_keywords 字段
  • R6: RequestPreprocessor 新增 factual/数学/翻译类正则,减少不必要的 REACT 调用
  • R7: 修复后重新运行 benchmark 建立当前架构基线

Key Technical Decisions

KTD1: Benchmark 超时按难度分级保留,但提升阈值

决策: 保留 _LLM_TIMEOUT_BY_DIFFICULTY 字典结构,提升 easy→45s、medium→60s、hard→90s。

理由: 分级超时是合理设计(简单任务不应等太久),但 20s 对真实 LLM 工具调用太短。qwen3.7-plus 的 p50 延迟 35s、p95 42s来自 benchmark 报告20s 必然超时。

KTD2: httpx 超时从 ProviderConfig 透传,保留硬编码作为 fallback

决策: OpenAICompatibleProvider.__init__ 读取 config.timeout,若未设置则 fallback 到 60s。

理由: ProviderConfig.timeout 默认 120s 是有意的LLM 推理慢httpx 硬编码 60s 会先于 ProviderConfig 触发,导致配置无效。

KTD3: QualityGate skill_match 在 ConfigDrivenAgent 执行后调用

决策: 在 ConfigDrivenAgent._execute_skill_task() 返回前调用 QualityGate.validate(output, skill_context=skill_config)

理由: skill_match 需要技能上下文intent_keywords才能校验输出一致性。ConfigDrivenAgent 是技能执行的统一入口,在此处调用覆盖面最广。

KTD4: disambiguation_keywords 作为 QualityGate 消歧输入,不用于路由

决策: disambiguation_keywords 添加到 skill yaml 的 intent 节点下,由 QualityGate 读取用于输出校验,不影响 RequestPreprocessor 路由决策。

理由: 当前路由已简化为"显式前缀 + 正则 + 默认 REACT"不依赖关键词。disambiguation_keywords 的价值在于 QualityGate 校验输出是否与技能意图一致。

KTD5: 路由优化采用"扩展正则 + 不引入 LLM 分类"策略

决策: 新增 factual是什么/什么是/解释)、数学(计算/算一下)、翻译(翻译/translate三类正则走 DIRECT_CHAT不引入 LLM quick_classify。

理由: 保持 RequestPreprocessor 的"零 token 成本快速路径"设计哲学。LLM 二次分类已被明确移除docstring: "LLM blind-classification without tool context is unreliable"),不回退。

Scope Boundaries

In Scope

  • Benchmark 超时阈值调整
  • OpenAICompatibleProvider httpx 超时修复
  • QualityGate skill_match 激活 + 严格模式
  • 4 对易混淆技能 disambiguation_keywords
  • RequestPreprocessor 正则扩展
  • 重新基准测试

Deferred to Follow-Up Work

  • DockerComputerUseSession 4 个 stub需真实 Docker 环境)
  • 计划 001U7/U8/U9/U10 未完成项)
  • 计划 0028 个待决策问题)
  • 计划 0037 项 Deferred
  • LLM 二次分类消歧P2需评估延迟代价
  • 复杂度校准数据集构建P2需收集标注数据

Implementation Units

U1. 修复 Benchmark 超时阈值

Goal: 提升 easy/medium/hard 难度的 LLM 超时阈值,避免真实 LLM 因超时失败

Requirements: R1

Dependencies:

Files:

  • src/agentkit/cli/benchmark.py — 修改 _LLM_TIMEOUT_BY_DIFFICULTY 字典

Approach:_LLM_TIMEOUT_BY_DIFFICULTY{"easy": 20.0, "medium": 40.0, "hard": 60.0} 改为 {"easy": 45.0, "medium": 60.0, "hard": 90.0}。默认 fallback 从 30.0 改为 60.0。

Patterns to follow: 现有 _LLM_TIMEOUT_BY_DIFFICULTY 字典结构

Test scenarios:

  • Happy path: easy 难度用例在 45s 内完成 → passed=True
  • Edge case: easy 难度用例在 20-45s 之间完成 → 旧逻辑会超时,新逻辑 passed=True
  • Error path: easy 难度用例超过 45s → 超时失败detail 包含 "45s"

Verification: 运行 agentkit benchmark --mode llmllm-001 不再因超时失败


U2. 修复 OpenAICompatibleProvider httpx 超时硬编码

Goal: httpx 客户端使用 ProviderConfig.timeout 而非硬编码 60s

Requirements: R2

Dependencies:

Files:

  • src/agentkit/llm/providers/openai.py — 修改 httpx.AsyncClient 构造
  • tests/unit/llm/test_openai_provider.py — 新增超时透传测试

Approach:OpenAICompatibleProvider.__init__ 中,将 httpx.AsyncClient(timeout=60.0) 改为 httpx.AsyncClient(timeout=self._config.timeout)。若 self._config 不存在或 timeout 未设置fallback 到 60.0。

Patterns to follow: RemoteLLMProvider 已使用 timeout=120.0 参数模式

Test scenarios:

  • Happy path: ProviderConfig(timeout=120) → httpx client timeout=120
  • Edge case: ProviderConfig(timeout=0) → fallback 到 60.0
  • Edge case: ProviderConfig 未设置 timeout → 使用默认 120.0
  • Integration: 实际 LLM 调用在 60-120s 之间完成 → 旧逻辑会超时,新逻辑成功

Verification: 单元测试通过 + benchmark 中无 httpx 超时错误


U3. 激活 QualityGate skill_match 校验

Goal: 在技能执行管线中传入 skill_context激活 skill_match 输出一致性校验

Requirements: R3

Dependencies: U4disambiguation_keywords 提供 intent_keywords 消歧)

Files:

  • src/agentkit/core/config_driven.py — 在 _execute_skill_task 返回前调用 QualityGate.validate 传入 skill_context
  • src/agentkit/quality/gate.py — 确认 _check_skill_match 读取 disambiguation_keywords
  • tests/unit/quality/test_gate.py — 新增 skill_match 激活测试

Approach:

  1. ConfigDrivenAgent._execute_skill_task() 中,构造 skill_context = {"intent_keywords": skill_config.intent.keywords + skill_config.intent.disambiguation_keywords}
  2. 调用 self._quality_gate.validate(output, skill_context=skill_context)
  3. gate.py_check_skill_match 中,同时检查 intent_keywordsdisambiguation_keywords

Patterns to follow: gate.py 现有 _check_skill_match 方法签名

Test scenarios:

  • Happy path: 技能输出包含 intent_keywords → skill_match passed=True
  • Error path: 技能输出不包含任何 intent_keywords → skill_match 警告
  • Integration: reflexion_agent 输出包含 "review" → 与 code_reviewer 的 disambiguation_keywords 匹配 → 触发消歧警告
  • Edge case: skill_context=None → 跳过 skill_match向后兼容

Verification: 单元测试通过 + 技能执行日志中出现 skill_match 校验记录


U4. 添加 disambiguation_keywords 到易混淆技能对

Goal: 为 4 对易混淆技能添加 disambiguation_keywords支持 QualityGate 消歧

Requirements: R5

Dependencies:

Files:

  • configs/skills/reflexion_agent.yaml — 添加 disambiguation_keywords
  • configs/skills/code_reviewer.yaml — 添加 disambiguation_keywords
  • configs/skills/react_agent.yaml — 添加 disambiguation_keywords
  • configs/skills/goal_driven_agent.yaml — 添加 disambiguation_keywords
  • configs/skills/rewoo_agent.yaml — 添加 disambiguation_keywords
  • configs/skills/competitor_analyzer.yaml — 添加 disambiguation_keywords
  • configs/skills/content_generator.yaml — 添加 disambiguation_keywords
  • configs/skills/geo_optimizer.yaml — 添加 disambiguation_keywords
  • src/agentkit/skills/base.py — SkillConfig.intent 添加 disambiguation_keywords 字段

Approach:

  1. SkillIntent model 中添加 disambiguation_keywords: list[str] = [] 字段
  2. 为每对易混淆技能添加互斥关键词:
    • reflexion_agent: ["反思", "自我验证", "迭代优化"]
    • code_reviewer: ["代码审查", "代码问题", "bug 检查"]
    • react_agent: ["实时搜索", "工具调用", "信息查询"]
    • goal_driven_agent: ["目标分解", "多步规划", "方案对比"]
    • rewoo_agent: ["并行采集", "批量获取", "多源数据"]
    • competitor_analyzer: ["竞品分析", "竞争对比", "市场对手"]
    • content_generator: ["内容创作", "文章生成", "选题写作"]
    • geo_optimizer: ["SEO 优化", "GEO 优化", "搜索排名"]

Patterns to follow: 现有 intent.keywords 字段结构

Test scenarios:

  • Happy path: SkillConfig 加载 yaml 含 disambiguation_keywords → 字段非空
  • Edge case: yaml 未含 disambiguation_keywords → 字段默认空列表
  • Integration: QualityGate 读取 disambiguation_keywords 用于消歧校验

Verification: agentkit skill list 正常加载所有技能 + 单元测试通过


U5. 优化 RequestPreprocessor 路由正则

Goal: 新增 factual/数学/翻译类正则,减少不必要的 REACT 调用

Requirements: R6

Dependencies:

Files:

  • src/agentkit/chat/request_preprocessor.py — 新增 3 条正则
  • tests/unit/chat/test_request_preprocessor.py — 新增路由测试

Approach: 新增 3 条正则走 DIRECT_CHAT

  1. _FACTUAL_RE — "什么是X/X是什么/解释一下X/define X" 等纯知识问答
  2. _MATH_RE — "计算X/算一下X/calculate X" 等简单数学(无变量、无方程)
  3. _TRANSLATION_RE — "翻译X/translate X" 等纯翻译请求

注意: 这些正则必须严格匹配,避免误拦截需要工具的请求。例如 "分析一下服务器的IP" 不应匹配 _FACTUAL_RE(包含"分析"动词暗示需要工具)。

Patterns to follow: 现有 _GREETING_RE / _CHAT_MODE_RE / _IDENTITY_RE 正则模式

Test scenarios:

  • Happy path: "什么是机器学习" → 匹配 _FACTUAL_RE → DIRECT_CHAT
  • Happy path: "计算 1+2+3" → 匹配 _MATH_RE → DIRECT_CHAT
  • Happy path: "translate hello to Chinese" → 匹配 _TRANSLATION_RE → DIRECT_CHAT
  • Edge case: "什么是当前服务器的IP地址" → 不匹配 _FACTUAL_RE含"当前服务器"暗示需要工具)→ REACT
  • Edge case: "计算斐波那契数列的第100项" → 不匹配 _MATH_RE含"斐波那契数列"暗示需要代码)→ REACT
  • Error path: 空字符串 → 不匹配任何正则 → REACT

Verification: 单元测试通过 + benchmark 中 DIRECT_CHAT 比例提升


U6. 重新基准测试 + 建立当前架构基线

Goal: 修复后重新运行 benchmark建立当前 RequestPreprocessor 架构的基线

Requirements: R7

Dependencies: U1, U2, U3, U4, U5所有修复完成后

Files:

  • test-results/benchmark/baseline.json — 更新基线
  • test-results/benchmark/benchmark_report.md — 更新报告

Approach:

  1. 运行 agentkit benchmark --mode llmfull 模式,真实 LLM
  2. 运行 agentkit benchmark --mode llm --fastfast 模式)
  3. 对比修复前后准确率、超时率、延迟
  4. 更新 baseline.json 作为当前架构基线

Test scenarios:

  • Happy path: full 模式准确率 ≥ 80%5 用例至少 4 通过)
  • Happy path: fast 模式准确率 = 100%
  • Edge case: llm-001 不再超时
  • Edge case: llm-004 不再超时

Verification: benchmark 报告生成 + 准确率达标


Risks & Dependencies

风险 严重度 缓解措施
新增正则误拦截需要工具的请求 正则设计保守,仅匹配纯知识/数学/翻译,单元测试覆盖边界
QualityGate skill_match 误报导致输出被拦截 skill_match 单独不拦截(现有设计),仅与其他失败共病时拦截
disambiguation_keywords 与现有 keywords 语义重叠 disambiguation_keywords 是 keywords 的补充,不替代
benchmark 超时提升后延迟增加 超时是上限而非目标,快速完成的用例不受影响

Open Questions

无 — 所有技术决策已在 KTD 中明确。

System-Wide Impact

  • LLM 网关: httpx 超时修复影响所有 LLM 调用(更宽松的超时)
  • 技能执行: QualityGate 激活影响所有技能输出校验
  • Benchmark: 超时阈值影响所有 benchmark 用例
  • 路由: 新增正则影响所有非显式前缀的请求

Verification Results (2026-06-20)

U1U5 代码修复验证

单元 验证方式 结果
U1: Benchmark 超时 agentkit benchmark --mode llm llm-001/llm-004 不再超时
U2: httpx 超时 pytest tests/unit/test_llm_provider.py 2 个新测试通过
U3: QualityGate 激活 pytest tests/unit/quality/ 176 个质量门控测试通过
U4: disambiguation_keywords 16 个技能 yaml 加载验证 全部加载成功
U5: 路由正则 pytest tests/unit/chat/test_request_preprocessor.py 38 个测试通过19 新增)

U6 基准测试结果

指标 修复前 (2026-06-20 03:18) 修复后 (2026-06-20 11:05) 变化
准确率 60.0% 93.3% ± 9.4% +33.3%
通过/总数 3/5 4/5 +1
超时数 2 0 (llm-002 偶发) -2
一致性 N/A 100%
p50 延迟 35.3s 40.8s +5.5s(可接受)

剩余问题: llm-002 (tool_selection, medium) 在 3 次运行中 1 次超时p95=56.3s 接近 medium 60s 阈值。后续可考虑提升 medium 超时至 75s。