Agent “空转”了——止血和验证升级的故事

门禁是好事,但门禁空转不是

一、一个让我哭笑不得的循环

之前我加了一堆门禁——假工具检测、必须调工具才能结束、验证门禁、子任务追踪、观察事实拦截、报告模板守门员……

每一个门禁单独看都是好事:它们让 Agent 不能作弊、不能偷懒、不能瞎编。

但当我全部串在一起之后,出现了一个我没预料到的问题。

事情是这样的。

用户问了一个很简单的短问题:

“这个文件有多少行?”

Agent 回答:

## 数据概况
- 文件:sample_data.xlsx
- 行数:120
## 关键发现
- 数据量适中
## 导出与产出
- 无
## 建议下一步
- 可以按列做进一步分析

看起来还行,对吧?

但问题是——用户只问“多少行”,Agent 却自动套了四段报告模板(概况、发现、导出、建议),输出了一整篇“微型报告”。

而且更离谱的是,门禁系统检测到“报告模板已启用但格式不够标准”,于是又 Nudge 了一次,Agent 重新生成了一份几乎一样的报告。然后又 Nudge 了一次,又来一份。

同一份报告,连续输出了三次。

用户看到的是:

## 数据概况
...
## 关键发现
...
## 导出与产出
...
## 建议下一步
...

## 数据概况
...
## 关键发现
...
## 导出与产出
...
## 建议下一步
...

## 数据概况
...
## 关键发现
...
## 导出与产出
...
## 建议下一步
...

三份一模一样的报告糊脸。

这就是我说的“门禁空转”——每道门禁都在“刷卡”,但刷完了门没开,Agent 原地转圈,重复输出同样的东西。

今天这两个更新,就是解决这个问题的。

第一个(止血):门禁空转多了,强制收口,不让无限循环。顺便短问答不再套报告模板。
第二个(验证升级):验证门禁不再只是“提醒一下”,而是要有真凭实据才放行。

二、先解释概念

2.1 什么是“门禁空转”?

概念解释:门禁空转就是 Agent 在门口反复“刷卡”,但始终没通过,于是在原地不停重试。

想象一个场景:你要进一栋楼,每层都有一道门禁。

  • 第一道门:刷了卡,红灯,没开。
  • 你退回起点,重新来。
  • 又刷了一遍,还是红灯。
  • 再退回去,再来……

你一直在“进门”这件事上打转,永远进不去。

Agent 也一样:

用户问题
  → 假工具检测 → 通过
  → 必须调工具门禁 → 没调?打回
  → 重试,调了工具
  → 验证门禁 → 没验证?打回
  → 重试,验证了
  → 报告模板守门员 → 格式不对?打回
  → 重写报告,格式对了
  → 终于通过 → 但用户已经在屏幕前等了很久

每道门禁都是好事,但它们串联在一起时,任一道失败就会让 Agent 重试。如果 Agent 不知道“怎么做才能通过”,它就会反复输出同样的错误答案——这就是空转。

2.2 什么是“验证证据”?

概念解释:验证证据就是 Agent 做验证时,必须真正调用验证工具并拿到结果,才算通过验证。口头说“我验证了”不算。

之前的验证门禁(Verification Gate)是这样的:Agent 改了文件之后,系统会说“请先验证再作答”。然后 Agent 说“好的,我验证过了,没问题”,就直接通过了。

这跟没验证有什么区别? Agent 完全可以骗人说“我验证了”,实际上啥也没做。

现在的验证门禁升级为:必须真正调用 read_file / list_files / run_script 等工具,并且返回成功,才算“有证据”。 口头说“我验证了”不算。

三、止血:门禁空转计数器

3.1 怎么止住空转?

新增了一个“空转计数器”:

  • 同一种门禁失败原因,连续失败 超过 3 次 → 触发止血
  • 所有门禁失败原因累计 超过 6 次 → 触发止血

止血后,Agent 不再继续循环,而是强制收口

“经过多次尝试,任务未能完成。以下是已执行的操作:……建议您检查后重新尝试。”

不再烧满轮次上限,而是提前结束并给出明确的停止原因。

3.2 短问不再套报告模板

另一个让人哭笑不得的问题是:用户问“多少行”,Agent 却输出四段报告(概况、发现、导出、建议)。

报告模板本来是好的——它让数据分析的输出更结构化。但它不应该用在“短问”上。

所以这次加了一个判断:短问降级

  • “多少行”、“多少列”、“有没有空值”这类短事实查询
  • 不再启用四段报告模板
  • 直接回答:“120 行,8 列。”

用户省时间,Agent 省 token。

3.3 报告去重

如果 Agent 还是被 Nudge 了两次,生成了三份报告怎么办?

去重机制:如果检测到连续出现多个 ## 数据概况 标题,只保留第一份,其余删除。

三份报告 → 去重 → 只留一份

这样用户看到的永远是一份报告,不是三份。

3.4 止血的验证

> /forget
> 帮我分析一下这个文件

如果 Agent 在门禁上反复失败:

  • 第 1-2 次失败:记录,继续尝试
  • 第 3 次失败(同原因):触发止血,强制收口
  • 终端出现 [gate] stop ... 强制收口

不会烧满硬轮次上限,不会让用户等半天。

四、验证升级:从“提醒”到“有证据”

4.1 之前的问题

验证门禁之前的工作方式是:

  1. Agent 改了文件/导出了数据
  2. Agent 说“完成了”
  3. 系统:“请先验证再作答”
  4. Agent:“好的,我验证过了,没问题”
  5. 系统:通过 ✅

问题出在第 4 步——Agent 说“验证过了”,但它可能根本没调任何工具。

这就像学生说“我检查了作业”,但其实只是扫了一眼,根本没检查。

4.2 解决方案:验证证据状态机

升级后的验证是一个状态机:

idle(空闲)
  ↓ 有变更操作且试图结束
pending(验证待处理)→ 系统催促验证
  ↓ 有证据工具成功
evidenced(有证据)→ 允许结束
  ↓ 始终无证据
skipped(跳过)→ 答案带脚注:“未核实”

证据工具包括:

  • 读文件:read_file / read_csv / read_excel
  • 预览数据:profile_dataset
  • 列举文件:list_files
  • 搜索内容:grep
  • 执行命令:run_shell / run_script(且返回成功)

重点: 只有这些工具被调用并成功返回,才算“有证据”。口头说“我验证了”没有任何作用。

4.3 代码变更的特殊处理

如果 Agent 改了代码文件(.ts/.js/.pypackage.json),验证提示会优先建议 npm run check 或对应的测试命令,而不是泛泛地说“请验证”。

因为代码改了,最可靠的验证方式就是跑测试或类型检查。

4.4 最高催促次数

为了防止 agent 永远卡在“等待验证”状态,设置了最高催促次数:

  • 默认最多催促 2 次
  • 2 次之后仍没有验证证据 → 系统强制收口
  • 但会在最终答案里加一个脚注:

既不让用户无限等待,也不隐瞒“未经核实”的事实。

4.5 验证升级的验证

> /forget
> 用 write_file 在 exports/verify_demo.txt 写入 hello,然后告诉我写成功了

预期流程:

  1. Agent 执行 write_file,然后试图结束
  2. 系统:「请验证写入是否成功」
  3. Agent 继续输出:“好的,我验证了” → 系统不认,再催促
  4. Agent 调用 read_file("exports/verify_demo.txt") → 返回成功
  5. 系统:verification_evidenced ✅ 允许结束
  6. 用户看到的结果有真实证据支撑

如果 Agent 始终不调用证据工具:

  1. 第 1 次催促:无证据
  2. 第 2 次催促:无证据
  3. 系统强制收口,答案带脚注:“可能未核实”

五、两个功能怎么配合

场景 止血做什么 验证升级做什么
模型重复输出报告 去重,只留一份 -
短问套报告模板 短问降级,不启用模板 -
门禁反复失败 计数→触发止血→强制收口 -
模型改了文件但拒绝验证 - 催促验证,最多 2 次
模型口头说“验证了” - 不认,必须调证据工具
模型始终不验证 - 强制收口+脚注“未核实”

止血关“别转圈”,验证关“真核实”。

六、完整链路

两个功能加进去之后,最终执行的决策链路变成了这样:

用户话
  ↓
澄清门禁(信息够不够?)
  ↓
任务拆解(分类 + 选档位)
  ↓
工具环(执行)
  ├── 每道门禁失败 → 记录到空转计数器
  ├── 同原因失败 ≥ 3 次 → 触发止血,强制收口
  ├── 有变更操作 → 验证门禁
  │   ├── 催促验证(最多 2 次)
  │   ├── 有证据工具成功 → 放行
  │   └── 始终无证据 → 脚注 + 收口
  └── 最终回答
  ├── 短问 → 不套报告模板
  ├── 长分析 → 套报告模板
  └── 重复报告 → 去重

七、以前 vs 现在

场景 1:短问“多少行”

以前

Agent:输出四段报告(概况、发现、导出、建议)→ 用户只问了多少行,被信息淹没

现在

Agent:“120 行,8 列。”→ 干净利落

场景 2:改了文件,试图蒙混过关

以前

Agent:“我验证了,没问题。” → 系统放行 → 实际文件可能没写进去

现在

Agent:“我验证了,没问题。” → 系统:不认,请调 read_file
Agent:调 read_file → 返回内容 → 系统:有证据 ✅ 放行

场景 3:门禁反复失败,原地转圈

以前

门禁1→失败→重试→门禁2→失败→重试→门禁1→失败→……烧满 30 轮才停

现在

门禁1→失败→重试→门禁1→失败(同原因第 3 次)→ 触发止血→强制收口
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐