[business-logic] false_premise 检测器:工具错误记录在成功重跑后不清除——"失败→修复→重跑→如实报告"核心工作流被诬告 confabulation
问题
internal/agent/false_premise_check.go 的 recordToolResult()(L74-77)只在 isError=true 时追加错误记录,成功结果直接 return——同工具成功重跑不会清除/失效旧错误记录。错误记录只有三条出路:被标记 matched、turnsAgo > 2(falsePremiseFreshnessTurns)过期、或 5 条环形溢出。L106 仅凭 turnsAgo <= 2 判断"新鲜",完全无视期间同工具是否已成功重跑。
触发场景(独立复核已实测复现)
编码 agent 的核心正确循环:
- 迭代 N:
run_command 构建 → 失败(exit 1)→ 记录 {toolName: "run_command", turnsAgo: 0}
- 迭代 N+1:修复代码,同工具重跑 → 成功。
recordToolResult(..., false) 直接 return,旧错误仍在
- 迭代 N+1/N+2/N+3 的 assistant 文本如实报告 "build passed and all tests pass"
- L110:
fpIsBuildTestTool("run_command") ✓ && matchesBuildSuccessClaim ✓ && turnsAgo≤2 → 误报注入 "[False Premise Warning] Your recent success claim(s) contradict tool error results ... do not confabulate positive results"
调用序(agent.go L2273 checkFalsePremise 每迭代文本检查 → L3331 recordToolResult 工具执行后)保证错误记录可跨 3 次文本检查触发,即使中间已成功重跑。
复现还证实:文本明确提及旧错误("the earlier build error is fixed")仍误报——branch 1(L110)没有 branch 4 才有的 acknowledgesError 守卫。对照组(未重跑即宣称成功)正确检出,证明是特异性缺陷而非全坏。
预期 vs 实际
- 预期(文件头 L19-20 自述):检测 success claims 与 "most recent tool error results" 的事实矛盾
- 实际:重跑成功后旧错误已被新事实推翻,声明与最新证据无矛盾,却仍被惩罚。等于训练信号惩罚正确行为(诚实报告),还消耗 2 次警告配额、触发
recordUncertainty("false_premise")
次级发现(复核实测确认)
- branch 4(L131)泛化分支无工具类别限制:无关 grep 语法错误 + "I updated the config file. Done." → 误报(Low-Medium)
- branch 1 缺
acknowledgesError 守卫扩大主 bug 触发面
acknowledgesErrorRe 宽词漏报为保守取舍,不建议报
严重程度
Medium — 核心工作流高频触发,但非阻塞(指导注入、每 run 上限 2 次、3 迭代窗口),典型代价是 agent 被错误警告后浪费 1-2 个迭代重新验证。
修复建议
recordToolResult 在 !isError 时删除 recentErrors 中同 toolName 的未过期记录(更精确可存参数指纹,成功时只清指纹匹配的记录)
- branch 1(L110)补
&& !acknowledgesError(lowered),与 branch 4 对齐
- branch 4 限定为非 search/read 类工具(这些已有专属分支)
相关文件
- internal/agent/false_premise_check.go:74-89(recordToolResult 无清除路径)
- internal/agent/false_premise_check.go:106-136(新鲜度判定与四个分支)
- internal/agent/agent.go:2273, 3331(接线与调用序)
[business-logic] false_premise 检测器:工具错误记录在成功重跑后不清除——"失败→修复→重跑→如实报告"核心工作流被诬告 confabulation
问题
internal/agent/false_premise_check.go的recordToolResult()(L74-77)只在isError=true时追加错误记录,成功结果直接 return——同工具成功重跑不会清除/失效旧错误记录。错误记录只有三条出路:被标记matched、turnsAgo > 2(falsePremiseFreshnessTurns)过期、或 5 条环形溢出。L106 仅凭turnsAgo <= 2判断"新鲜",完全无视期间同工具是否已成功重跑。触发场景(独立复核已实测复现)
编码 agent 的核心正确循环:
run_command构建 → 失败(exit 1)→ 记录 {toolName: "run_command", turnsAgo: 0}recordToolResult(..., false)直接 return,旧错误仍在fpIsBuildTestTool("run_command")✓ &&matchesBuildSuccessClaim✓ && turnsAgo≤2 → 误报注入 "[False Premise Warning] Your recent success claim(s) contradict tool error results ... do not confabulate positive results"调用序(agent.go L2273 checkFalsePremise 每迭代文本检查 → L3331 recordToolResult 工具执行后)保证错误记录可跨 3 次文本检查触发,即使中间已成功重跑。
复现还证实:文本明确提及旧错误("the earlier build error is fixed")仍误报——branch 1(L110)没有 branch 4 才有的
acknowledgesError守卫。对照组(未重跑即宣称成功)正确检出,证明是特异性缺陷而非全坏。预期 vs 实际
recordUncertainty("false_premise")次级发现(复核实测确认)
acknowledgesError守卫扩大主 bug 触发面acknowledgesErrorRe宽词漏报为保守取舍,不建议报严重程度
Medium — 核心工作流高频触发,但非阻塞(指导注入、每 run 上限 2 次、3 迭代窗口),典型代价是 agent 被错误警告后浪费 1-2 个迭代重新验证。
修复建议
recordToolResult在!isError时删除recentErrors中同toolName的未过期记录(更精确可存参数指纹,成功时只清指纹匹配的记录)&& !acknowledgesError(lowered),与 branch 4 对齐相关文件