Agent “空转”了——止血和验证升级的故事
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 之前的问题
验证门禁之前的工作方式是:
- Agent 改了文件/导出了数据
- Agent 说“完成了”
- 系统:“请先验证再作答”
- Agent:“好的,我验证过了,没问题”
- 系统:通过 ✅
问题出在第 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/.py 或 package.json),验证提示会优先建议 npm run check 或对应的测试命令,而不是泛泛地说“请验证”。
因为代码改了,最可靠的验证方式就是跑测试或类型检查。
4.4 最高催促次数
为了防止 agent 永远卡在“等待验证”状态,设置了最高催促次数:
- 默认最多催促 2 次
- 2 次之后仍没有验证证据 → 系统强制收口
- 但会在最终答案里加一个脚注:
既不让用户无限等待,也不隐瞒“未经核实”的事实。
4.5 验证升级的验证
> /forget
> 用 write_file 在 exports/verify_demo.txt 写入 hello,然后告诉我写成功了
预期流程:
- Agent 执行
write_file,然后试图结束 - 系统:「请验证写入是否成功」
- Agent 继续输出:“好的,我验证了” → 系统不认,再催促
- Agent 调用
read_file("exports/verify_demo.txt")→ 返回成功 - 系统:
verification_evidenced✅ 允许结束 - 用户看到的结果有真实证据支撑
如果 Agent 始终不调用证据工具:
- 第 1 次催促:无证据
- 第 2 次催促:无证据
- 系统强制收口,答案带脚注:“可能未核实”
五、两个功能怎么配合
| 场景 | 止血做什么 | 验证升级做什么 |
|---|---|---|
| 模型重复输出报告 | 去重,只留一份 | - |
| 短问套报告模板 | 短问降级,不启用模板 | - |
| 门禁反复失败 | 计数→触发止血→强制收口 | - |
| 模型改了文件但拒绝验证 | - | 催促验证,最多 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 次)→ 触发止血→强制收口
更多推荐




所有评论(0)