AgentEvalTool/docs/adr/0011-intelligent-eval-terminal-state-discipline.md
sinohqb eb4944a8bd feat(intelligent-eval): terminal-state discipline watchdogs (ADR-0011)
常见故障自愈有上限,超限收敛终态且可见:任务 attempts 上限、会话过期、
planning 双闸、executing 超窗兜底、触发失败计数判死、孤儿 agent 双管、
fire-and-forget 触发;open_session 预算硬闸门、settle 按终态区分、报告
scores 归一化;cron 池遗留面全删。
2026-08-20 14:34:17 +08:00

4.4 KiB
Raw Blame History

ADR-0011: 智能评估容错收敛——终态纪律与失败可见性

状态: 已接受 日期: 2026-08-19 决策者: 架构团队 相关: ADR-0009触发式执行、ADR-0010独立 session、ADR-0007已被取代、CONTEXT.md智能评估会话、触发式执行

Context

v1.1.1 将触发式执行在 t480 跑通后,对智能评估模块做容错盘点,发现一批"无声卡死"类缺口:评估级无 watchdogworker 不关闭会话 → 报告永远 409 → 评估永久卡 executing、任务与 planner 触发无限重试、子进程触发失败只写日志不落库、600s 超时杀不掉容器内 agent 形成孤儿、会话数无平台侧上限、串行 await 触发使 60s 扫描周期漂移、已删除前端页面的 Cron 池 API 面仍挂载。

根本问题不是单点 bug而是缺少一条容错纪律故障发生后系统该自愈到什么程度、什么时候必须放弃并让人知道。

Decision

确立终态纪律常见故障自愈有上限超限或结构性失败收敛到终态completed/failed/cancelled且用户可见绝不无声卡死。具体机制

  1. planning 双闸planner 触发满 5 次或进入 planning 满 30 分钟仍未提交粗计划(触发失败计入次数),置 failed 并落原因 + 决策日志。
  2. 会话过期running 会话 60 分钟无新轮次由平台置 expired(启用既有 EXPIRED 枚举);submit_report 校验从"全部 completed"放宽为"全部终态"expired 会话在报告中标注为不完整证据——不把超时会话伪装成 completed证据链保持诚实。
  3. executing 兜底:最后一个会话到达终态后 10 分钟平台自动触发 analyst上限 3 次;仍无报告或 executing 总时长超 time_window_hours + 2h,置 failed
  4. 任务重试上限:任务表加 attemptsstale requeue 上限 3 次,超限置 failed
  5. 触发失败可见:子进程缺失/超时/非零退出记入决策日志(cron_id=platform)并计入对应闸;同一评估连续 3 次触发失败直接判 failed(结构性故障不等自然到期)。
  6. 孤儿 agent 双管:触发命令容器内包 timeout 灭杀 agent 进程;平台侧 per-eval 触发冷却 10 分钟,兜住重启丢句柄留下的残余孤儿。
  7. 预算硬闸门open_session 校验会话数 < 粗计划审批的虚拟用户数,超出 409。用户审批粗计划 = 审批预算,平台执行审批过的数字。
  8. 扫描节奏恢复:触发改 fire-and-forgetasyncio task结果在回调中持久化扫描循环恢复准确 60s保住时段分布。
  9. Cron 池遗留面全删:摘除 /api/openclaw/cron-pool router 挂载,删除 openclaw_cron_pool / alerts / fault_tolerance / cron_pool 模块AlertManager 无后台 tickduration 告警永远不会触发,是假装在工作的死代码)。
  10. settle 语义诚实化:评估 cancelled/failed 时遗留任务置 failedcompleted 时才置 completed任务队列监控统计口径随之诚实。
  11. 报告边界归一化submit_report 将 scores 归一到单一规范结构落库,前端与 markdown 渲染删除双兼容分支。

Considered Options已拒绝

  • 全自动自愈:任何故障都自行恢复。对单实例内部工具是过度工程,且"明确失败"本身是重要信号。
  • 任务/触发不设上限,靠评估级超时兜底:确定性失败的任会在兜底期内被重试约 24 次、触发约 24 个子进程,烧资源并刷垃圾数据。
  • 超时会话强置 completed:会让报告消费者(人和 AI无法分辨完整证据与不完整证据污染证据链。
  • 预算软约束(自然语言指令):对会幻觉的 agent 不是约束;预算失控完全无声。

Consequences

  • 新增 schema 变更:IntelligentEvalTaskQueueDB.attemptsAlembic 迁移 + 全新库 parity 测试)。
  • EXPIRED 会话状态从死代码变为真实终态CONTEXT.md 已同步;报告校验口径变化需要前后端一起改。
  • 冷却期把触发频率从"每 60s"降为"每评估每 10 分钟",时段推进节奏相应放缓,与 stale requeue 的 10 分钟对齐。
  • 部署拓扑假设不变单进程单实例SQLite + StaticPool多实例部署需另行复审触发/扫描的分布式互斥。
  • 不变更OpenClaw 三角色职责划分、时间窗口语义、报告业务 schema仅归一化 scores 结构)。