Tools

การตรวจจับลูปของเครื่องมือ

OpenClaw มี guardrail สองส่วนที่ทำงานร่วมกันสำหรับรูปแบบการเรียกเครื่องมือซ้ำ ๆ:

  1. การตรวจจับลูป (tools.loopDetection.enabled) — ปิดใช้งานโดยค่าเริ่มต้น เฝ้าดูประวัติการเรียกเครื่องมือแบบเลื่อนต่อเนื่องเพื่อหารูปแบบที่เกิดซ้ำและการลองซ้ำกับเครื่องมือที่ไม่รู้จัก
  2. ตัวป้องกันหลัง Compaction (tools.loopDetection.postCompactionGuard) — เปิดใช้งานโดยค่าเริ่มต้น เว้นแต่ tools.loopDetection.enabled จะถูกตั้งเป็น false อย่างชัดเจน จะเริ่มทำงานหลังการลองซ้ำหลัง Compaction ทุกครั้ง และยุติการรันเมื่อเอเจนต์ส่งสามค่า (tool, args, result) เดิมภายในหน้าต่างการตรวจสอบ

ทั้งสองส่วนกำหนดค่าอยู่ใต้บล็อก tools.loopDetection เดียวกัน แต่ตัวป้องกันหลัง Compaction จะทำงานเมื่อสวิตช์หลักไม่ได้ถูกปิดอย่างชัดเจน ตั้งค่า tools.loopDetection.enabled: false เพื่อปิดทั้งสองพื้นผิว

เหตุผลที่มีสิ่งนี้

  • ตรวจจับลำดับที่เกิดซ้ำซึ่งไม่เกิดความคืบหน้า
  • ตรวจจับลูปความถี่สูงที่ไม่มีผลลัพธ์ (เครื่องมือเดิม อินพุตเดิม ข้อผิดพลาดซ้ำ)
  • ตรวจจับรูปแบบการเรียกซ้ำเฉพาะสำหรับเครื่องมือ polling ที่รู้จัก
  • ป้องกันวงจรบริบทล้น จากนั้น Compaction จากนั้นกลับสู่ลูปเดิมไม่ให้ทำงานต่อไปไม่สิ้นสุด

บล็อกการกำหนดค่า

ค่าเริ่มต้นแบบทั่วระบบ พร้อมแสดงทุกฟิลด์ที่มีเอกสารกำกับ:

{
  tools: {
    loopDetection: {
      enabled: false, // master switch for the rolling-history detectors
      historySize: 30,
      warningThreshold: 10,
      criticalThreshold: 20,
      unknownToolThreshold: 10,
      globalCircuitBreakerThreshold: 30,
      detectors: {
        genericRepeat: true,
        knownPollNoProgress: true,
        pingPong: true,
      },
      postCompactionGuard: {
        windowSize: 3, // armed after compaction-retry; runs unless enabled is explicitly false
      },
    },
  },
}

การแทนที่ค่ารายเอเจนต์ (ไม่บังคับ):

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

พฤติกรรมของฟิลด์

ฟิลด์ ค่าเริ่มต้น ผลลัพธ์
enabled false สวิตช์หลักสำหรับตัวตรวจจับประวัติแบบเลื่อนต่อเนื่อง การตั้งเป็น false จะปิดตัวป้องกันหลัง Compaction ด้วย
historySize 30 จำนวนการเรียกเครื่องมือล่าสุดที่เก็บไว้สำหรับการวิเคราะห์
warningThreshold 10 เกณฑ์ก่อนที่รูปแบบจะถูกจัดประเภทเป็นคำเตือนเท่านั้น
criticalThreshold 20 เกณฑ์สำหรับบล็อกรูปแบบลูปที่เกิดซ้ำ
unknownToolThreshold 10 บล็อกการเรียกซ้ำไปยังเครื่องมือที่ไม่พร้อมใช้งานตัวเดิมหลังจากพลาดครบจำนวนนี้
globalCircuitBreakerThreshold 30 เกณฑ์ breaker แบบทั่วระบบสำหรับภาวะไม่คืบหน้าในทุกตัวตรวจจับ
detectors.genericRepeat true ตรวจจับรูปแบบเครื่องมือเดิม + พารามิเตอร์เดิมที่เกิดซ้ำ
detectors.knownPollNoProgress true ตรวจจับรูปแบบที่คล้าย polling ซึ่งรู้จักและไม่มีการเปลี่ยนแปลงสถานะ
detectors.pingPong true ตรวจจับรูปแบบ ping-pong แบบสลับไปมา
postCompactionGuard.windowSize 3 จำนวนการเรียกเครื่องมือหลัง Compaction ที่ตัวป้องกันยังคงทำงาน และจำนวนสามค่าที่เหมือนกันซึ่งจะทำให้ยุติการรัน

สำหรับ exec การตรวจสอบภาวะไม่คืบหน้าจะเปรียบเทียบผลลัพธ์ของคำสั่งที่เสถียร และละเว้นเมทาดาทารันไทม์ที่เปลี่ยนแปลงง่าย เช่น ระยะเวลา, PID, session ID และไดเรกทอรีทำงาน เมื่อมี run id ประวัติการเรียกเครื่องมือล่าสุดจะถูกประเมินเฉพาะภายในการรันนั้น เพื่อให้รอบ Heartbeat ตามกำหนดเวลาและการรันใหม่ไม่รับจำนวนลูปเก่าจากการรันก่อนหน้า

การตั้งค่าที่แนะนำ

  • สำหรับโมเดลขนาดเล็ก ให้ตั้ง enabled: true และคงค่าเกณฑ์ไว้ตามค่าเริ่มต้น โมเดลระดับ flagship แทบไม่ต้องใช้การตรวจจับประวัติแบบเลื่อนต่อเนื่อง และสามารถปล่อยสวิตช์หลักไว้ที่ false ขณะที่ยังได้ประโยชน์จากตัวป้องกันหลัง Compaction
  • คงลำดับเกณฑ์ไว้เป็น warningThreshold < criticalThreshold < globalCircuitBreakerThreshold
  • หากเกิด false positive:
    • เพิ่ม warningThreshold และ/หรือ criticalThreshold
    • อาจเพิ่ม globalCircuitBreakerThreshold
    • ปิดเฉพาะตัวตรวจจับที่ก่อปัญหา (detectors.<name>: false)
    • ลด historySize เพื่อให้บริบทประวัติเข้มงวดน้อยลง
  • หากต้องการปิดทุกอย่าง (รวมถึงตัวป้องกันหลัง Compaction) ให้ตั้ง tools.loopDetection.enabled: false อย่างชัดเจน

ตัวป้องกันหลัง Compaction

เมื่อ runner ทำ compaction-retry สำเร็จหลังบริบทล้น ระบบจะเริ่มตัวป้องกันหน้าต่างสั้น ๆ ที่เฝ้าดูการเรียกเครื่องมือไม่กี่ครั้งถัดไป หากเอเจนต์ส่งสามค่า (toolName, argsHash, resultHash) เดิมหลายครั้งภายในหน้าต่าง ตัวป้องกันจะสรุปว่า Compaction ไม่ได้ตัดลูป และยุติการรันด้วยข้อผิดพลาด compaction_loop_persisted

ตัวป้องกันถูกควบคุมด้วยแฟล็กหลัก tools.loopDetection.enabled แต่มีข้อยกเว้นหนึ่งอย่าง: ตัวป้องกันจะยัง เปิดใช้งานเมื่อไม่ได้ตั้งค่าแฟล็กหรือแฟล็กเป็น true และจะปิดเฉพาะเมื่อแฟล็กถูกตั้งเป็น false อย่างชัดเจน นี่เป็นพฤติกรรมที่ตั้งใจไว้ ตัวป้องกันนี้มีไว้เพื่อหลุดออกจากลูป Compaction ที่มิฉะนั้นจะใช้โทเค็นได้ไม่จำกัด ดังนั้นผู้ใช้ที่ไม่ได้กำหนดค่าก็ยังได้รับการป้องกัน

{
  tools: {
    loopDetection: {
      // master switch; set false to disable the guard along with the rolling detectors
      enabled: true,
      postCompactionGuard: {
        windowSize: 3, // default
      },
    },
  },
}
  • windowSize ที่ต่ำกว่าจะเข้มงวดกว่า (จำนวนครั้งที่ลองก่อนยุติน้อยกว่า)
  • windowSize ที่สูงกว่าจะให้เอเจนต์มีโอกาสกู้คืนมากขึ้น
  • ตัวป้องกันจะไม่ยุติการทำงานเมื่อผลลัพธ์กำลังเปลี่ยนแปลง จะยุติเฉพาะเมื่อผลลัพธ์เหมือนกันทุกไบต์ตลอดหน้าต่าง
  • ตั้งใจให้อยู่ในขอบเขตแคบ: ทำงานเฉพาะทันทีหลัง compaction-retry

ล็อกและพฤติกรรมที่คาดหวัง

เมื่อตรวจพบลูป OpenClaw จะรายงานเหตุการณ์ลูป และจะลดทอนหรือบล็อกรอบการใช้เครื่องมือถัดไปตามระดับความรุนแรง สิ่งนี้ช่วยปกป้องผู้ใช้จากการใช้โทเค็นที่บานปลายและการค้าง ขณะเดียวกันยังคงการเข้าถึงเครื่องมือตามปกติไว้

  • คำเตือนจะมาก่อน
  • การระงับจะตามมาเมื่อรูปแบบยังคงอยู่เกินเกณฑ์คำเตือน
  • เกณฑ์ระดับวิกฤตจะบล็อกรอบการใช้เครื่องมือถัดไป และแสดงเหตุผลการตรวจจับลูปอย่างชัดเจนในบันทึกการรัน
  • ตัวป้องกันหลัง Compaction จะส่งข้อผิดพลาด compaction_loop_persisted พร้อมชื่อเครื่องมือที่เป็นต้นเหตุและจำนวนการเรียกที่เหมือนกัน

ที่เกี่ยวข้อง