Appearance
OpenClaw 的工具循环检测用于拦截 Agent 反复调用同一工具而不产生进展的情况。两个协作守卫:滚动历史检测器(默认关闭)和后压缩守卫(默认启用,除非总开关显式设为 false)。配置 tools.loopDetection 调整阈值、检测器类型和历史窗口大小;单 Agent 可独立覆盖。遇到 compaction_loop_persisted 错误时检查 postCompactionGuard.windowSize 或调高 criticalThreshold。
OpenClaw 工具循环检测 — 配置 Agent 重复调用保护与后压缩守卫
OpenClaw 提供两个协作守卫来拦截重复工具调用模式:
- 循环检测(
tools.loopDetection.enabled)——默认关闭。监听滚动工具调用历史中的重复模式和未知工具重试。 - 后压缩守卫(
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,
},
},
},
],
},
}字段行为
| 字段 | 默认值 | 作用 |
|---|---|---|
enabled | false | 滚动历史检测器主开关。设为 false 也会禁用后压缩守卫。 |
historySize | 30 | 保留用于分析的最近工具调用数量。 |
warningThreshold | 10 | 模式被归类为仅警告的阈值。 |
criticalThreshold | 20 | 阻断重复无进展循环模式的阈值。 |
unknownToolThreshold | 10 | 同一不可用工具调用失败达到此次数后阻断。 |
globalCircuitBreakerThreshold | 30 | 所有检测器的全局无进展熔断阈值。 |
detectors.genericRepeat | true | 警告相同工具+相同参数的模式;当调用返回相同结果时阻断。 |
detectors.knownPollNoProgress | true | 检测已知类轮询模式且无状态变化。 |
detectors.pingPong | true | 检测交替乒乓模式。 |
postCompactionGuard.windowSize | 3 | 压缩后守卫保持激活的调用数,以及触发中止的相同三元组计数。 |
对于 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 信息。