跳转至

工具循环检测

OpenClaw 具有两个协作的保护机制,用于应对重复的工具调用模式,两者都配置在 tools.loopDetection 下:

  1. 循环检测(enabled)- 默认禁用。监视滚动工具调用历史中的重复模式和未知工具重试。
  2. 压缩后保护 - 只要 enabled 未显式设为 false 就启用。在每次压缩重试后启用,如果代理在窗口内重复相同的 (tool, args, result) 三元组,则中止运行。

设置 tools.loopDetection.enabled: false 以禁用两个保护机制。

为什么存在此功能

  • 检测没有进展的重复序列。
  • 检测高频无结果循环(相同工具、相同输入、重复错误)。
  • 检测已知轮询工具的特定重复调用模式。
  • 打破“上下文溢出 -> 压缩 -> 相同循环”的循环,而不是让它们无限期运行。

配置块

全局设置:

{
  tools: {
    loopDetection: {
      enabled: false, // master switch for the rolling-history detectors
    },
  },
}

按代理覆盖(可选,位于 agents.entries.*.tools.loopDetection):

{
  agents: {
    entries: {
      "safe-runner": {
        default: true,
        tools: {
          loopDetection: {
            enabled: true,
          },
        },
      },
    },
  },
}

按代理设置会覆盖全局设置。

您还可以在 Control UI 的 设置 → 代理默认值 → 工具 中启用全局滚动历史检测器。将该设置重置为默认值可禁用滚动检测器,同时保留压缩后保护;显式关闭则会禁用两者。

字段行为

字段 默认值 效果
enabled false 滚动历史检测器的主开关。false 同时禁用压缩后保护。

执行标题不会区分其他方面相同的 exec 调用。Code Mode 还提供私有结果标识:记账计数器和续传 ID 不计为进展。自动保留的值使用其原始值标识,而不是新的结果引用 ID。待处理工作按其操作和参数进行比较,而输出变化、返回值和错误仍然有意义。显示的回执和来宾数据保持不变,包括名为 telemetry 或 pendingToolCalls 的来宾字段。这不会检测任意语义等效的 JavaScript 重写,也不会让后台进程在 Gateway 重启后存活。

对于 exec,无进展哈希比较稳定的命令结果(状态、退出码、超时标志、输出),并忽略易变的运行时元数据,例如持续时间、PID、会话 ID 和工作目录。对于类型化终端失败,它还会忽略诊断时间戳、显式尝试或重试计数器、已用时长以及带标签的进程 ID。其他文本和数字仍然重要,因此新的失败原因会重置连续计数。出站消息发送结果在哈希时会剥离易变的每次调用 ID(消息 ID、文件 ID、时间戳),因此仅凭投递 ID 不会让重复的等效发送看起来像进展。当存在运行 ID 时,历史仅在该运行内评估,因此计划的心跳周期和新的运行不会从早期运行继承过期的循环计数。

成功的 progress_card 调用使用已保存的 Markdown 和计划进行比较,而不是使用其写入修订版本或回执措辞。已保存的修订版本和已投递的回执保持不变,因此即使卡片内容未变化,请求刷新仍会获得更新的已保存修订版本。错误以及没有该工具私有语义结果的结果保持完整结果比较。

来自 computer get_window_state 的窗口观察在比较时不包含新的观察和元素引用。像素、元素标签、值、边界以及其他观察数据仍计为变化。面向模型的结果保留新引用,而过期引用对后续输入仍然无效。

结果比较还会忽略新的外部内容包装器 nonce,包括包装的错误和 JSON 结果。已投递的安全标记保持不变;负载文本、状态、时间戳和持续时间仍用于区分网络结果。这是语法比较:与完整包装格式匹配的逐字或复制文本也会忽略仅 nonce 的变化。它不会验证内容、更改授权或修改已投递的工具结果。

  • 对于较小的模型,设置 enabled: true。旗舰模型很少需要滚动历史检测,可以保持主开关未设置,同时仍受益于压缩后保护。
  • 要禁用所有内容(包括压缩后保护),请显式设置 tools.loopDetection.enabled: false。

压缩后保护

在上下文溢出后的压缩重试之后,运行器会在接下来的几次工具调用上启用一个短窗口保护。如果代理在该窗口内足够多次发出相同的 (toolName, argsHash, resultHash) 三元组,保护机制会判定压缩未能打破循环,并以 compaction_loop_persisted 错误中止运行。

该保护由主标志 tools.loopDetection.enabled 控制,但有一个例外:它保持启用(当标志未设置或为 true 时),只有当标志显式为 false 时才会关闭。这是有意为之——该保护旨在逃离压缩循环,否则这些循环会消耗无限制的 token,因此未配置用户也能获得保护。

{
  tools: {
    loopDetection: {
      // master switch; set false to disable the guard along with the rolling detectors
      enabled: true,
    },
  },
}
  • 该保护比较规范化结果哈希,而不是原始结果字节。有意义的变化会阻止其中止;仅新的包装器 nonce 不计为进展。
  • 它只在压缩重试后的紧接阶段启用,而不是在运行中的其他点启用。

Note

压缩后守卫只要主标志未显式设置为 false 就会运行,即使你从未编写过 tools.loopDetection 块。要验证,请在压缩事件后立即在网关日志中查找 post-compaction guard armed for N attempts。

日志与预期行为

当检测到循环时,OpenClaw 会记录一个循环事件,并根据严重程度警告或阻止下一个工具周期,从而防止失控的 Token 消耗和锁死,同时保留正常的工具访问。

  • 警告优先。对于由 OpenClaw 执行的工具调用,会在受影响的工具结果后追加一条简短的系统备注,以便模型在关键阻止前改变方法。警告共享诊断日志的速率限制,而不是在每次重复调用时都出现。原始结果在添加备注之前记录,因此警告文本不计为进展。
  • 一旦模式持续超过警告阈值,就会触发阻止。
  • 使用相同参数和结果重复 wait 十次会阻止下一次等待。结果变化会重置连续次数。这使用下文描述的相同恢复响应和终端处理;它不会取消仍在执行的工具调用。
  • 在嵌入式代理循环中,第一个关键循环会在该批次中的任何工具运行之前阻止整个工具批次。然后模型会获得一次额外的响应,并带有其正常工具。
  • 在该响应期间,模型可以回答、提出问题,或使用不同的工具或不同参数继续。
  • 同一次运行中的另一个关键循环会阻止其整个批次并结束运行。新的用户运行将以新的恢复额度开始。
  • 压缩后守卫会发出 compaction_loop_persisted 错误,指出问题工具和相同调用次数。

执行审批

Shell 执行的允许/拒绝策略。

思考级别

推理力度级别与提供商策略的交互。

子代理

生成隔离代理以限制失控行为。

配置参考

完整的 tools.loopDetection 架构和合并语义。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw