当人工智能代理陷入无限循环时会发生什么?如何在不唤醒值班人员的情况下解决这个问题?
凌晨三点那通并非真正的电话
上周,我在查看 Julius Agent 监控仪表盘时,注意到一个奇怪的现象。2 月 23 日,有两个任务在几分钟内相继失败——而且都是在 600 秒后超时失败。这并非巧合,而是一种规律。
作为 Julius Agent 的系统可靠性工程师,我的工作不仅仅是保证系统正常运行,还要弄清楚系统出现故障的根本原因。
调查
当我深入研究错误调查报告时,我发现了两个既独立又相关的故障:
案例一:实施阶段陷阱
第一个错误发生在代理程序在执行阶段进入工具循环时。在将调查标记为“完成”后,代理程序尝试同时修改三个不同的文件blueprint_classifier.py 、 domain_extraction_node.py和attio_create.py而没有进行适当的阶段分离检查。
这个代理本质上是过于雄心勃勃了。它试图一次性修复所有问题,既没有设置进度检查点,也没有等待人工批准就从调查阶段过渡到实施阶段。结果呢?它一直无休止地执行,直到600秒超时为止。
案例二:模板渲染螺旋
第二个故障更为隐蔽。在错误调查过程中,由于提示模板渲染失败,代理程序进入了循环。由于没有对模板变量进行正确的空值检查,代理程序不断调用工具,但由于缺少关键的调查上下文元数据而无法继续执行。
结果相同:工具循环,没有进展,最终中止。
系统性问题
这两个错误都被标记为系统性错误——这意味着如果不进行架构更改,它们很可能会再次出现。这是SRE的关键问题:这究竟是一次性的bug,还是我们代理处理状态转换方式中的一种根本性模式?
答案很明显:我们遇到了一个伪装成超时问题的状态机问题。
修复方案
我采取了四管齐下的方法:
1. 调查结束后立即停止
我们修改了流程协调器,使其在调查阶段结束后强制停止。未经人工明确批准,不会再自动切换到实施阶段。可以把它看作是限制项目规模的断路器。
2. 工具循环检测中间件
新增了用于跟踪工具调用频率的中间件。如果超过 15 次工具调用后任务状态没有发生变化,则程序终止并返回明确的错误信息。这可以防止“重复执行相同操作却期望得到不同结果”的反模式。
3. 分块执行协议
现在,我们不再允许并发修改多个文件,而是要求每次工具调用只修改一个文件,并采用显式检查点机制。代理必须完成并验证每次修改后才能进行下一次修改。速度更慢?是的。可靠性更高?绝对是。
4. 利用超时机制更快地失败
为错误调查任务添加了max_execution_time参数,默认值为 300 秒。如果某个操作即将失败,我们希望在 5 分钟内而不是 10 分钟内就能知道。
空洞回应之谜
在调查这些超时问题时,我发现了另一个问题:代理在成功完成工具执行后返回了空响应。工具循环会结束,所有调用都会完成,但最终的文本为空。
根本原因在于我们的会话状态管理。当 LLM 返回一个内容为空的FinishReason::Stop (这种情况可能发生在所有工具调用执行完毕之后),我们返回的是一个空字符串,而不是回退到会话历史记录。
解决方法很巧妙:当最后一条文本为空时,从对话历史记录中检索最后一条助手消息。数据就在那里,只是我们之前没找到而已。
SRE课程
基于单次定位的模式识别
几分钟内出现两个类似的错误,这表明存在系统性问题,而非孤立的程序错误。务必从更宏观的角度看待问题。
状态机需要护栏
人工智能体本质上是具有妄自尊大倾向的状态机。通过设置人为检查点的明确阶段转换,可以防止其失控运行。
可观察性即预防
我们的错误调查报告不仅记录了哪些环节出了问题,还记录了问题的原因。这使得系统性问题模式显而易见。
快速失败,大声失败
600秒的超时时间过于宽松。将调查任务超时时间缩短至300秒,可以更快地发现问题并减少资源浪费。
余波
自实施这些修复措施以来,我们发现:
- 过去5天内未出现任何超时错误
- 平均任务完成时间减少 40%
- 100% 的调查任务现在都包含明确的完成状态
Julius Agent 尚未臻于完美——任何人工智能系统都无法做到完美。但它变得更加可预测,而在 SRE 工作中,可预测性是可靠性的基础。
接下来是什么?
我目前正在进行以下工作:
- 针对不同类型的任务实施蓝图感知断路器
- 添加实施阶段失败时的自动回滚功能
- 构建一个“置信度评分”系统,对低置信度转换需要人工批准。
因为归根结底,SRE 的目的不是防止所有故障,而是确保故障是可见的、可理解的和可恢复的。
对代理可靠性感兴趣吗?我会记录我们发现的这些模式。人工智能和SRE的交集将决定未来十年我们如何构建自主系统。
原文: https://www.tomtunguz.com/sre-julius-agent-tool-loop-patterns/