How Signal found two hidden retry loops in our production agent Alyx

TL;DR · AI 摘要
Arize Signal工具通过分析生产跟踪发现Alyx代理中的隐藏重试循环,传统监控可能将其误判为正常运行。
核心要点
- Signal发现Alyx中227秒运行生成192个span的无效重试循环
- 传统监控将错误状态标记为OK导致问题被忽视
- 修复仅需代码微调但发现过程需要行为模式分析
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- Signal工具发现隐藏重试循环
- 核心功能
- 生产跟踪分析
- 行为模式分组
- 自动化调查生成
- Alyx案例
- Todo状态重试循环
- 空数据集ID重试
- 修复方案
- 规范化空值处理
- 状态更新去重
金句 / Highlights
值得收藏与分享的关键句。
Signal在227秒的运行中发现43次重复工具调用,根span仍标记为OK
传统监控将无效重试视为健康运行,Signal通过行为模式识别出问题
修复仅需代码微调,但发现过程需要分析跨生产跟踪的行为模式
Signal如何发现我们生产代理Alyx中的两个隐藏重试循环 - Arize AI
关键要点
- 在AI系统中,错误很少以错误的形式出现。它们表现为行为:看似有进展的循环、执行了错误操作的合法工具调用、状态仍标记为正常的根追踪。
- 手动发现这些行为效率低下。你无法像搜索异常那样搜索这些行为,逐条检查追踪也无法扩展。
- Signal会对生产追踪进行大规模分析,将重复行为归类为分级问题,并为每个问题生成包含证据、影响评估和后续步骤的调查。
- 我们在自己的生产代理Alyx上运行了Signal。它发现了一个待办事项循环和一个数据集查找重试,而传统监控系统会将这些视为正常运行。
- 代码修改量很小,但Signal完成了耗时的工作:发现模式并使修复路径显而易见。
当涉及到我们内置在Arize AX中的AI工程代理Alyx时,我们想知道它的生产追踪能揭示出哪些普通监控可能遗漏的信息。
因此我们使用了Arize AX新内置的托管代理Signal来分析Alyx。它很快在一个持续227秒、生成192个追踪点并调用同一工具43次的运行中发现了问题。根追踪点仍标记为正常。Alyx没有崩溃,但一个空的可选字段将其推入了错误的验证路径,导致错误信息不断将代理送回同一工具。
这是Signal在Alyx中发现的两个重试循环中的一个,乍看之下都像是合法的代理行为。在两种情况下,最终的代码修复都很小。但发现隐藏在生产追踪中的行为模式,是我们使用Signal之前未能做到的。
Arize Signal是什么?
Signal是Arize AX的一项功能,它会分析生产追踪中的重复代理行为,将相关模式归类为分级问题,并创建包含支持证据、预估影响和建议后续步骤的调查。
这些建议步骤可能涉及修改提示、代码、配置或评估。企业团队还可以连接GitHub仓库,使Signal能够将调查延伸至代码库,并创建拉取请求或范围限定的问题供审查。
我们使用Signal分析了内置在Arize AX中的AI工程代理Alyx。在30天的周期内,Signal发现了Alyx生产追踪中的34个问题,包括本文探讨的两个行为失败案例。
Signal在Alyx中发现的问题
这两个Alyx发现具有相同的本质:代理接收到一个表明操作失败的工具响应,然后重复执行一个永远无法改善状态的操作。
| 问题 | 监控显示 | 代理实际行为 | 修复方案 | |------|---------|-------------|---------| | 待办事项状态重试循环 | 重复的合法工具活动 | 重试已成功的状态转换 | 将重复的相同状态更新视为成功的无操作 | | 空数据集ID重试 | 根追踪点标记为正常 | 由于空的可选字段进入错误代码路径,重复执行 |
get_datasets43次 | 在工具边界将空的可选值标准化为
None这两个问题都不是从工程师搜索已知异常开始的。Signal发现了重复行为,归类了相关追踪,并提供了理解失败所需的关键证据。
发现1:如何一个todo_update错误将Alyx困在重试循环中
Alyx 使用任务列表来协调多步骤工作。它可以创建或恢复计划,将任务状态从待处理(pending)、已完成(completed)和已阻塞(blocked)等状态中移动,并在轮次准备关闭时调用 finish()。
正常流程大致如下:
- 恢复或创建待办事项计划。
- 选择当前任务。
- 调用完成该任务所需的工具。
- 使用 todo_update 更新任务状态。
- 在计划完成时调用 finish()。
在证据追踪中,finish() 被拒绝,因为计划中仍包含阻塞的工作。Alyx 随后尝试更新阻塞任务。
对 todo_update(id=0, status="blocked") 的重复调用返回了可恢复错误,而不是确认现有状态。由于每个工具响应都会附加到模型上下文中,代理将该错误解释为自身操作失败的证据。
它再次尝试状态转换。有时它在 todo_update 和 finish() 之间来回切换。由于这两个操作都没有改变底层状态,代理继续循环直到流被取消。
针对阻塞待办事项的 todo_update 重试循环发出信号,显示证据追踪、重复的 finish() 拒绝、重复的 todo_update(…, blocked) 调用以及关联的 PR 尝试。
代码更改非常直接。当请求的状态与当前状态一致时,todo_update 现在会将当前任务列表作为成功结果返回。对于真正无效的情况(如缺少任务列表或未知任务 ID),错误仍然保留。
已合并的 GitHub PR #77349 显示了 todo_update 重试循环的根本原因:重复的状态更新引发了 RecoverableException,将消息反馈给 LLM,导致重复的相同工具调用。
团队还添加了一个回归测试,覆盖了重复状态转换的情况。修复时间由发现和重建该行为所驱动。因此,一旦模式变得明显,补丁就变得简单。
发现 2:空数据集 ID 如何导致 43 次重复工具调用
第二个问题发生在 get_datasets 工具中,该工具具有两种操作模式:
- 当未提供 dataset_id 时,工具会列出当前空间中的数据集。
- 当提供 dataset_id 时,工具会预览所选数据集。
Alyx 的意图是列出可用数据集。但生产负载在可选的 dataset_id 字段中提供了一个空字符串。
在类型化工具边界处,空字符串仍被视为已提供的值。因此验证将其视为候选数据集 ID 并拒绝,显示以下消息:
数据集 ID 无效。请确保您从 get_datasets() 获取 ID。
恢复指导将 Alyx 送回它已经在调用的相同工具。由于没有更好的纠正措施可用,模型进行了重试。
受影响的运行包含:
- 192 个跨度
- 227 秒的运行时间
- 50 次编排器迭代
- 43 次重复的 get_datasets 调用
- 一个状态保持为 OK 的根跨度
Alyx 追踪显示在 one_alyx_agent 下,根状态健康但存在高延迟、重复的编排器迭代和重复的工具调用。
修复将空字符串规范化移到共享工具边界中。现在允许 None 的可选字段在进入工具特定验证之前会将空字符串转换为 None。
回归测试重现了生产负载并验证 get_datasets 进入列表模式而不是返回无效-ID 错误。
再次强调,代码修改的范围是有限的。困难的部分在于识别出一个看似健康的追踪记录中包含了可重复的行为性故障。
为什么行为调试会改变修复代理的成本
这些事件说明了一个常见的生产环境模式。代理的实现错误可能很小,但发现它需要对运行时行为有广泛的了解。
人工手动调查这些问题时需要:
- 发现一个长时间追踪记录中几乎没有实质性的进展。
- 重建模型决策和工具响应的序列。
- 确定该模式是否出现在其他追踪记录中。
- 识别出共享的机制。
- 定位负责该行为的代码边界。
- 创建可复现的测试用例。
Signal 在工程师开始调试之前就完成了大部分昂贵的发现工作。它会将相关追踪分组,描述重复出现的行为,并将证据打包成可审查的调查报告。
一些发现可以直接进入拉取请求。其他更适合作为附带相关追踪记录的GitHub问题进行记录。在这两种情况下,团队都会获得一个明确的起点,而不是需要维持一个全职的追踪审查轮班。
这也改变了团队使用可观测性数据的方式。追踪记录说明代理做了什么,而行为分析有助于判断这些操作是否使系统接近预期目标。
如何使用Signal监控生产环境AI代理
团队可以将Signal用作持续的生产反馈循环:
- 在生产项目中启用Signal。Signal将开始审查新追踪记录中的重复行为模式。
- 查看排名靠前的问题。每个问题都包含行为描述、受影响的追踪记录、影响范围和支撑证据。
- 检查完整轨迹。跟随导致问题的模型决策、工具调用、工具响应和状态转换。
- 选择适当的干预措施。发现可能指向提示词、代码、配置、工具模式或评估方式的更改。
- 创建回归测试用例。将生产环境的有效载荷或轨迹转换为防止该行为再次出现的测试。
- 将调查带入GitHub。企业团队可以连接仓库,将发现结果转化为拉取请求或范围限定的问题。
要实际查看工作流程,请遵循Signal教程或观看网络研讨会演示。
生产环境代理将继续产生在跨度级别看起来健康的故障。实际优势来自于将这些追踪记录转化为可重复的工程循环:检测模式、检查证据、推送更改、添加回归测试,并再次观察生产环境。
对于两个Alyx问题,修复都是微小的。Signal通过找到代理行为出错的位置,处理了昂贵的部分。