Files
Video-Tree-TRM5/research-wiki/designs/2026-07-11-agent-runtime-fixes-design.md

4.4 KiB
Raw Permalink Blame History

Spec-1:Agent 执行环境修复(解析容错 + 步级重试 + 摘要附实体)

  • 日期: 2026-07-11
  • 状态: 已批准(用户确认,步级重试退避改为 20s/40s)
  • 依据: research-wiki/findings/2026-07-11-benchmark-failure-taxonomy.md §四(T85 题)与 §二 M1view_node 摘要吞 entities
  • 系列: Spec-1/2/3 三件套之一,见 [2026-07-11-batch-tree-build-design.md]、[2026-07-11-question-gen-v2-design.md]

1. 问题

# 缺陷 证据 影响
A1 _parse_responsecore/agent/loop.py:265-300)只接受 action.args 嵌套结构;deepseek 稳定输出变体(args 平铺 + ```json 围栏)解析三连拒 → 0 步阵亡 637-3、615-3 整题报废,且 json_repair 修不了结构错位
A2 LLM 调用异常(loop.py:118-129)直接整题终止,无步级重试 796-3SSL BAD_RECORD_MAC 废掉 13 步上下文) 一次网络抖动损失全部已积累推理
B summarize_nodeapp/search/summarizer.py)两轮按题摘要后 entities/visible_text 不保证幸存 786-2、872-3、750-1Agent 站在证据节点上漏读实体) M1 负证据幻觉的恶化因素

2. 设计

A1 解析容错(结构归一化层)

在现有 repair_json → json.loads → 校验 之后、返回 None 之前,增加确定性归一化:

  1. 围栏剥除repair_json 前先剥 json / 围栏(正则,幂等)。
  2. args 收拢:若 action 为 dict 且含 tool 但缺 args,把 action 下除 tool 外的所有平铺键收拢为 args 嵌套。
  3. 归一化成功 → 照常执行;失败 → 走现有 retry 追问路径(行为不变)。

纯函数实现,用 637-3/615-3 的真实坏输出作单测样本。

A2 步级重试

_call_llm 异常处理改为步级重试循环:

参数 说明
重试次数 2 第 3 次失败才整题终止(stop_reason=error 不变)
退避 20s / 40s 用户指定
可重试异常 显式类型元组,默认 (TimeoutError, OSError)ssl.SSLError/ConnectionError 均为 OSError 子类,覆盖实测穿透案例);作为构造参数可注入扩展 遵循 CLAUDE.md P5(不做全 Exception 兜底);core/ 不依赖 openai SDK——API 类异常由 GovernedLLMClient 内部重试栈负责;asyncio.CancelledError 绝不吞;未知异常 fail-fast 整题终止(现状行为)
上下文 原样保留 messages 不回滚,重试即重发
遥测 失败尝试的 error 记录由 GovernedLLMClient 内部负责(已有);AgentLoop 侧只以 loguru 记录步级重试事件(不注入 TelemetryRecorder AgentLoop 无遥测端口,不越层补写

B 摘要附带实体原文

dispatcher 侧SearchToolDispatcher._handle_view_node)由确定性代码(非 LLM)在摘要结果末尾追加节点 card 的字段原文:

[实体] <entities + visible_entities 原文>
[画面文字] <visible_text 原文>
  • 调用链改动Codex 审查修正):summarize_node 只收 raw_text: str、无结构化 card 访问,且 _node_full_text 递归收值不保留字段名——因此在 TreeEnvironment 新增结构化字段提取方法(如 node_entity_fields(node_id) -> dict[str, str]),dispatcher 调用它并把区块拼接到 summarize_node 返回值之后;summarize_node 本体不改
  • 摘要后追加 → LLM 无法吞掉;字段为空则不加对应区块
  • 对 anchor / 非 anchor 两种模式一致生效

3. 不做什么(YAGNI

  • 不改 GovernedLLMClient 的内部重试栈(已有四层治理)
  • 不改判分协议、不动 prompt 版本化内容
  • 不做异常分型重试策略(统一兜底已覆盖已知案例)

4. 验证

  1. 单测:坏输出样本(围栏/平铺/两者叠加)归一化正确;空 content、缺 tool 仍拒
  2. 单测:步级重试计数与退避(mock LLM 抛错)
  3. 单测:summarize_node 追加区块(有/无实体字段两种节点)
  4. 集成:抽 10 道 T2/T8 错题重跑(637-3、615-3、786-2、872-3、750-1 必含),对比修复前后
  5. make test 全绿 + 覆盖率不降

5. 被否方案

  • prompt 层要求 LLM 修正输出格式:治标,deepseek 变体是稳定行为,代码归一化是确定性修复
  • 重试时区分异常类型(仅网络类重试):已知案例全是穿透型异常,分型收益低且易漏