Skip to content

OpenClaw 的工具循环检测用于拦截 Agent 反复调用同一工具而不产生进展的情况。两个协作守卫:滚动历史检测器(默认关闭)和后压缩守卫(默认启用,除非总开关显式设为 false)。配置 tools.loopDetection 调整阈值、检测器类型和历史窗口大小;单 Agent 可独立覆盖。遇到 compaction_loop_persisted 错误时检查 postCompactionGuard.windowSize 或调高 criticalThreshold

OpenClaw 工具循环检测 — 配置 Agent 重复调用保护与后压缩守卫

OpenClaw 提供两个协作守卫来拦截重复工具调用模式:

  1. 循环检测tools.loopDetection.enabled)——默认关闭。监听滚动工具调用历史中的重复模式和未知工具重试。
  2. 后压缩守卫tools.loopDetection.postCompactionGuard)——默认启用,除非 tools.loopDetection.enabled 显式为 false。每次压缩重试后激活,在窗口内检测到相同的 (工具、参数、结果) 三元组时中止运行。

两者均在同一个 tools.loopDetection 配置块下管理,但后压缩守卫只要主开关未显式关闭就会运行。将 tools.loopDetection.enabled 设为 false 可同时关闭两个表面。

为什么需要这个功能

  • 检测没有进展的重复工具序列。
  • 检测高频无结果循环(同一工具、相同输入、重复错误)。
  • 检测已知轮询工具的特定重复调用模式。
  • 防止上下文溢出 → 压缩 → 再次相同循环的无限消耗。

配置块

全局默认值,包含所有文档字段:

json5
{
  tools: {
    loopDetection: {
      enabled: false, // 滚动历史检测器主开关
      historySize: 30,
      warningThreshold: 10,
      criticalThreshold: 20,
      unknownToolThreshold: 10,
      globalCircuitBreakerThreshold: 30,
      detectors: {
        genericRepeat: true,
        knownPollNoProgress: true,
        pingPong: true,
      },
      postCompactionGuard: {
        windowSize: 3, // 压缩重试后激活;除非 enabled 显式 false,否则运行
      },
    },
  },
}

可选:单 Agent 覆盖

json5
{
  agents: {
    list: [
      {
        id: "safe-runner",
        tools: {
          loopDetection: {
            enabled: true,
            warningThreshold: 8,
            criticalThreshold: 16,
          },
        },
      },
    ],
  },
}

字段行为

字段默认值作用
enabledfalse滚动历史检测器主开关。设为 false 也会禁用后压缩守卫。
historySize30保留用于分析的最近工具调用数量。
warningThreshold10模式被归类为仅警告的阈值。
criticalThreshold20阻断重复无进展循环模式的阈值。
unknownToolThreshold10同一不可用工具调用失败达到此次数后阻断。
globalCircuitBreakerThreshold30所有检测器的全局无进展熔断阈值。
detectors.genericRepeattrue警告相同工具+相同参数的模式;当调用返回相同结果时阻断。
detectors.knownPollNoProgresstrue检测已知类轮询模式且无状态变化。
detectors.pingPongtrue检测交替乒乓模式。
postCompactionGuard.windowSize3压缩后守卫保持激活的调用数,以及触发中止的相同三元组计数。

对于 exec,无进展检查会对比稳定命令结果,忽略运行时元数据(如耗时、PID、会话 ID、工作目录)。当有 run id 可用时,只评估该次运行内的工具调用历史,避免计划心跳周期和新运行继承旧运行的循环计数。

推荐设置

  • 对于较小模型,将 enabled 设为 true,保持默认阈值。旗舰模型很少需要滚动历史检测,可以保持主开关为 false,同时仍受益于后压缩守卫。
  • 保持阈值顺序:warningThreshold < criticalThreshold < globalCircuitBreakerThreshold
  • 如果出现误报:
    • 提高 warningThreshold 和/或 criticalThreshold
    • (可选)提高 globalCircuitBreakerThreshold
    • 仅禁用导致问题的检测器(detectors.<名称>: false
    • 降低 historySize 以放宽历史上下文严格度
  • 要完全关闭所有保护(包括后压缩守卫),显式设置 tools.loopDetection.enabled: false

后压缩守卫

当运行器在上下文溢出后完成压缩重试时,会激活一个短窗口守卫,监听接下来几次工具调用。如果 Agent 在窗口内多次发出相同的 (toolName, argsHash, resultHash) 三元组,守卫判断压缩未能打破循环,并以 compaction_loop_persisted 错误中止运行。

该守卫由主 tools.loopDetection.enabled 标志控制,但有一点不同:当标志未设置或为 true 时守卫启用,仅当标志显式为 false 时才停用。这是有意为之——守卫的存在是为了逃逸否则会无限消耗 token 的压缩循环,因此即使未做任何配置的用户也能获得保护。

json5
{
  tools: {
    loopDetection: {
      // 主开关;设为 false 可同时禁用守卫和滚动检测器
      enabled: true,
      postCompactionGuard: {
        windowSize: 3, // 默认
      },
    },
  },
}
  • 更低的 windowSize 更严格(更少尝试即中止)。
  • 更高的 windowSize 给 Agent 更多恢复尝试。
  • 只有当结果在整个窗口内字节完全相同时守卫才中止;结果有变化则不会中止。
  • 守卫故意窄化:只在压缩重试后立即生效。

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

日志与预期行为

检测到循环时,OpenClaw 上报循环事件并根据严重程度抑制或阻断下一个工具周期。这保护用户免受失控 token 消耗和死锁,同时保留正常工具访问。

  • 先发出警告。
  • 如果模式持续超出警告阈值则抑制。
  • 临界阈值会阻断下一个工具周期,并在运行记录中提供明确的循环检测原因。
  • 后压缩守卫会发出 compaction_loop_persisted 错误,包含违规工具名称和相同调用次数。

相关文档

Exec 审批

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

思考级别

推理努力级别及提供者策略交互。

子智能体

生成隔离智能体以限制失控行为。

配置参考

完整的 `tools.loopDetection` 模式与合并语义。

常见问题

Agent 一直重复调用同一个工具怎么解决?

首先检查工具返回的结果格式是否让 LLM 误以为需要重试。然后在配置中启用循环检测:设置 tools.loopDetection.enabled: true,必要时降低 warningThreshold(如改为 5)或开启所有检测器。如果误报,提高阈值或禁用特定检测器。

compaction_loop_persisted 错误是什么意思?

它表示后压缩守卫检测到 Agent 在上下文溢出压缩重试后,连续多次发出相同的工具调用(包括参数和结果完全相同)。守卫中止了运行以防止无限循环。调高 postCompactionGuard.windowSize 可以给 Agent 更多恢复机会,但更好的做法是修复导致重复调用的根源——通常是工具返回空结果或错误代码。

如何完全关闭 OpenClaw 的循环检测和后压缩守卫?

在配置中显式设置 tools.loopDetection.enabled: false。注意:如果只留空或注释掉该字段,后压缩守卫仍然会以默认的 windowSize: 3 启用。要确认守卫已关闭,检查网关日志中是否不再出现 post-compaction guard armed 信息。