SSD Nodes Learn 🎉 VPS เริ่ม $5.50/เดือน
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-13

ทำไม Coding Agents ถึงไม่ทำตามคำสั่ง และวิธีแก้ไขปัญหา

พบกับ 4 สาเหตุหลักที่ทำให้ Coding Agents เพิกเฉยต่อคำสั่งของคุณ ตั้งแต่ปัญหา Context Window ไปจนถึงข้อมูลขัดแย้ง พร้อมวิธีวินิจฉัยและแก้ไขปัญหาอย่างเป็นระบบเพื่อผลลัพธ์ที่แม่นยำ

เหตุใด coding agents ถึงเพิกเฉยต่อคำสั่งของคุณ

Coding agents เพิกเฉยต่อคำสั่งของคุณด้วย 4 สาเหตุหลัก และไม่มีสาเหตุใดเลยที่เกิดจากการที่คุณสุภาพเกินไป สาเหตุแรกคือ กฎดังกล่าวไม่ได้อยู่ใน context window สาเหตุที่สองคือ กฎนั้นคลุมเครือเกินกว่าจะนำไปตรวจสอบการกระทำได้ สาเหตุที่สามคือ มีข้อมูลอื่นใน context ขัดแย้งกับคำสั่งนั้น ซึ่งมักจะเป็นโค้ดที่ agent เพิ่งอ่านไป และสาเหตุสุดท้ายคือ กฎยังคงถูกโหลดอยู่แต่ถูกผลักไปอยู่ไกลจากลำดับการสนทนาปัจจุบัน ทำให้ agent เลือกทำงานจากข้อมูลที่อยู่ใกล้ตัวมากกว่า

แต่ละสาเหตุมีวิธีแก้ไขเฉพาะตัว ดังนั้นงานแรกของคุณคือการแยกแยะให้ออกว่าเกิดจากอะไร การใช้ตัวพิมพ์ใหญ่หรือคำว่า IMPORTANT ไม่ใช่การวินิจฉัยปัญหา กลไกที่อธิบายด้านล่างนี้ใช้ Claude Code เป็นตัวอย่างประกอบ เนื่องจากพฤติกรรมการโหลดและการบีบอัดข้อมูลของเครื่องมือนี้มีการบันทึกไว้อย่างละเอียด ณ เดือนสิงหาคม 2026 เครื่องมืออื่นอาจมีรายละเอียดที่แตกต่างกันออกไป แต่โดยภาพรวมแล้วจะมีพฤติกรรมในลักษณะเดียวกัน

ก่อนอื่นต้องทำความเข้าใจ 2 คำศัพท์นี้ก่อน context window คือบล็อกของข้อความที่โมเดลมองเห็นในแต่ละรอบการสนทนา ซึ่งประกอบด้วย system prompt, ไฟล์คำสั่งของคุณ, ประวัติการสนทนา และทุกไฟล์ที่ agent ได้อ่านไป ส่วน harness คือโปรแกรมที่ครอบตัวโมเดลไว้อีกที ซึ่งทำหน้าที่อ่านไฟล์จากดิสก์และรวบรวมข้อมูลเหล่านั้นเข้าเป็นบล็อก เกือบทุกข้อร้องเรียนในบทความนี้ แท้จริงแล้วเป็นการร้องเรียนเกี่ยวกับตัว harness ไม่ใช่ตัวโมเดลเอง

ไฟล์คำสั่งของคุณคือข้อความ ไม่ใช่การตั้งค่า

ไฟล์คำสั่งไม่ใช่การตั้งค่าคอนฟิกูเรชัน ไม่มีส่วนใดในรันไทม์ที่อ่าน CLAUDE.md แล้วบังคับใช้กฎดังกล่าว ระบบจะอ่านไฟล์จากดิสก์แล้วนำข้อความไปวางในบทสนทนา ใน Claude Code เนื้อหานี้จะถูกส่งเป็นข้อความของผู้ใช้ที่วางไว้หลัง system prompt ซึ่งหมายความว่าโมเดลจะมองเห็นกฎของคุณในลักษณะเดียวกับข้อความอื่นๆ ที่คุณพิมพ์

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

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

ไฟล์คำสั่งใดถูกโหลดบ้าง และโหลดเมื่อใด

Claude Code จะไล่ลำดับขึ้นไปตามโครงสร้างไดเรกทอรีจากไดเรกทอรีที่คุณเริ่มใช้งาน ทุกไฟล์ CLAUDE.md และ CLAUDE.local.md ตั้งแต่ root ของระบบไฟล์ลงมาจนถึงไดเรกทอรีทำงานของคุณจะถูกโหลดทั้งหมดเมื่อเริ่มโปรแกรม ไฟล์เหล่านี้จะถูกนำมาต่อกันตามลำดับดังกล่าว ดังนั้นไฟล์ที่อยู่ใกล้กับตำแหน่งที่คุณเริ่มใช้งานมากที่สุดจะถูกอ่านเป็นลำดับสุดท้าย และภายในไดเรกทอรีเดียวกัน ไฟล์ .local จะถูกต่อท้ายหลังจากไฟล์หลัก

ไฟล์ในไดเรกทอรีย่อยที่อยู่ ต่ำกว่า ไดเรกทอรีทำงานของคุณจะมีพฤติกรรมที่ต่างออกไป ไฟล์เหล่านี้จะไม่ถูกโหลดเมื่อเริ่มโปรแกรม แต่จะถูกโหลดเมื่อเอเจนต์อ่านไฟล์ในไดเรกทอรีนั้นๆ เช่นเดียวกับกฎที่กำหนดขอบเขตตาม path ใน .claude/rules/ ซึ่งมีฟิลด์ paths: ในส่วน frontmatter กฎเหล่านี้จะเข้าสู่บริบทเมื่อมีการอ่านไฟล์ที่ตรงกับเงื่อนไข ไม่ใช่ทุกครั้งที่มีการโต้ตอบ

ความแตกต่างเพียงจุดเดียวนี้อธิบายถึงสาเหตุส่วนใหญ่ของความล้มเหลวที่มีการรายงานเข้ามา คุณใส่กฎไว้ใน packages/api/CLAUDE.md แล้วถามคำถามเกี่ยวกับ API แต่เอเจนต์กลับตอบโดยไม่เคยเปิดไฟล์ใดๆ ภายใต้ packages/api/ เลย กฎนั้นไม่ได้ถูกเพิกเฉย แต่กฎนั้นไม่เคยถูกโหลดเข้ามาตั้งแต่แรก หาก repository ของคุณมีการแยกคำแนะนำไว้ตาม ไฟล์คำสั่งแยกตามแพ็กเกจใน monorepo นี่คือสิ่งแรกที่คุณต้องตรวจสอบทุกครั้ง

กับดักอีกประการหนึ่งในการโหลด ซึ่งเป็นสาเหตุที่พบบ่อยที่สุดของปัญหา "เอเจนต์เพิกเฉยต่อคำสั่งของฉัน" คือ Claude Code อ่านไฟล์ CLAUDE.md ไม่ใช่ AGENTS.md ดังนั้น repository ที่ใช้มาตรฐาน AGENTS.md และไม่มีไฟล์ CLAUDE.md จะทำให้ Claude Code ไม่มีข้อมูลใดๆ ให้โหลดเลย วิธีเชื่อมต่อที่รองรับคือการใช้ไฟล์ CLAUDE.md ซึ่งบรรทัดแรกต้องเป็น @AGENTS.md เพื่อนำเข้าไฟล์ดังกล่าวเมื่อเริ่มโปรแกรม พร้อมกับบันทึกเฉพาะสำหรับ Claude ที่อยู่ด้านล่าง การใช้ symlink ก็สามารถทำได้เช่นกันหากคุณไม่มีข้อมูลอื่นที่ต้องการเพิ่ม ส่วนการตัดสินใจว่าข้อมูลใดควรอยู่ในไฟล์นั้นแต่แรกเป็นอีกประเด็นหนึ่ง ซึ่งครอบคลุมอยู่ใน การแยกคำสั่งสำหรับเอเจนต์ออกจากเอกสารสำหรับมนุษย์

ยืนยันว่าไฟล์ถูกโหลดก่อนทำการแก้ไขใหม่

ห้ามปรับเปลี่ยนเนื้อหาจนกว่าคุณจะมีหลักฐานว่า agent มองเห็นไฟล์นั้น การตรวจสอบมีสองขั้นตอน โดยเริ่มจากวิธีที่ง่ายที่สุดก่อน

ให้รัน /context ภายในเซสชัน คำสั่งนี้จะแสดงรายการหน้าต่างปัจจุบันแยกตามหมวดหมู่ และรายการ Memory files จะระบุชื่อไฟล์คำสั่งทุกไฟล์ที่ถูกโหลดเข้าสู่ระบบจริง หากไฟล์ใดไม่อยู่ในรายการนั้น แสดงว่าไฟล์ดังกล่าวไม่ได้อยู่ในบทสนทนา ดังนั้นสิ่งที่คุณเขียนลงไปในไฟล์นั้นจะไม่มีผลใดๆ ทั้งสิ้น /memory จะแสดงตำแหน่งของไฟล์และเปิดไฟล์เหล่านั้นเพื่อแก้ไข รวมถึงไฟล์ที่ยังไม่มีอยู่จริงด้วย

สำหรับการตรวจสอบที่ละเอียดขึ้น ให้บันทึกการโหลดไฟล์ เหตุการณ์ hook InstructionsLoaded จะทำงานทุกครั้งที่มี CLAUDE.md หรือไฟล์กฎ (rules file) เข้าสู่บริบท และตัวจับคู่ (matcher) จะบอกคุณว่าเหตุใดการโหลดจึงเกิดขึ้น ได้แก่ session_start, nested_traversal, path_glob_match, include หรือ compact ให้ใส่คำสั่งนี้ลงใน .claude/settings.json:

{
  "hooks": {
    "InstructionsLoaded": [
      {
        "matcher": "nested_traversal",
        "hooks": [
          {
            "type": "command",
            "command": "cat >> /tmp/instructions-loaded.log"
          }
        ]
      }
    ]
  }
}

hook จะรับข้อมูล payload ในรูปแบบ JSON ผ่านทาง standard input ดังนั้น cat จะทำการต่อท้ายบันทึกทั้งหมดลงไป ให้ตรวจสอบด้วย tail -f /tmp/instructions-loaded.log ในขณะที่คุณทำงาน สถานะการจบการทำงาน (exit status) ของเหตุการณ์นี้จะถูกละเว้น ดังนั้น hook จึงทำได้เพียงเฝ้าสังเกตเท่านั้น ไม่สามารถบล็อกการทำงานได้ หากไฟล์ที่คุณซ้อนไว้ไม่ปรากฏใน log นั้นระหว่างเซสชันที่คุณคาดหวัง ให้หยุดการแก้ไขเนื้อหา ปัญหาอยู่ที่ตำแหน่งการวางไฟล์

ผลกระทบของเซสชันที่ยาวนานต่อกฎของคุณ

มีผลกระทบสองประการที่เกิดขึ้นแยกกัน และจำเป็นต้องใช้วิธีรับมือที่แตกต่างกัน

ระยะห่าง (Distance) กฎที่ระบุไว้ในเทิร์นที่ 1 จะยังคงอยู่ในหน้าต่างบริบทจนถึงเทิร์นที่ 90 ซึ่งในขณะนี้ต้องแข่งขันกับข้อความอีก 90 เทิร์นที่ใหม่กว่าและเฉพาะเจาะจงกับสิ่งที่คุณกำลังทำอยู่ คุณไม่สามารถตั้งค่าเพื่อแก้ไขปัญหานี้ได้ แต่คุณสามารถวัดผลได้ ให้ลองรันงานเดิมในเซสชันใหม่ หากกฎนั้นยังคงทำงานได้ปกติแต่กลับล้มเหลวเมื่ออยู่ในเซสชันที่ยาวนาน แสดงว่าระยะห่างคือสาเหตุของปัญหา

การบีบอัด (Compaction) เมื่อหน้าต่างบริบทเต็ม ระบบจะสรุปบทสนทนาที่ผ่านมาและดำเนินการต่อจากบทสรุปนั้น สิ่งที่ยังคงอยู่คือสิ่งที่ตัวสรุปตัดสินว่าสำคัญ ซึ่งอาจไม่ตรงกับสิ่งที่คุณให้ความสำคัญ Claude Code มีการบันทึกผลลัพธ์แยกตามกลไก และมีความแตกต่างกันอย่างมาก โดยไฟล์ project root CLAUDE.md และกฎที่ไม่มีขอบเขตจะถูกโหลดใหม่จากดิสก์หลังจากการบีบอัด หน่วยความจำอัตโนมัติ (Auto memory) จะถูกโหลดใหม่จากดิสก์เช่นกัน กฎที่มี frontmatter แบบ paths: จะสูญหายไปจนกว่าจะมีการอ่านไฟล์ที่ตรงกันอีกครั้ง ส่วนไฟล์ CLAUDE.md ที่ซ้อนอยู่ในไดเรกทอรีย่อยจะสูญหายไปจนกว่าจะมีการอ่านไฟล์ในไดเรกทอรีย่อยนั้นอีกครั้ง

หากคุณจัดลำดับความสำคัญของคำสั่งตามตารางดังกล่าว คุณจะเห็นลำดับความเปราะบางของกฎ กฎที่คุณพิมพ์ลงในแชทเพียงอย่างเดียวคือสิ่งที่เปราะบางที่สุดในเซสชัน เพราะจะคงอยู่ก็ต่อเมื่อบทสรุปเก็บมันไว้เท่านั้น กฎใน packages/api/CLAUDE.md มีความสำคัญรองลงมา เพราะถูกโหลดเพียงครั้งเดียว ถูกสรุปทิ้งไป และจะกลับมาอีกครั้งก็ต่อเมื่อมีการอ่านไฟล์ในไดเรกทอรีนั้นอีกครั้ง กฎที่อยู่ในไฟล์ project root มีความทนทานที่สุด เพราะจะถูกอ่านใหม่จากดิสก์ทุกครั้ง

ดังนั้น หากคำสั่งใดจำเป็นต้องคงอยู่ตลอดทั้งเซสชัน ควรใส่ไว้ในไฟล์ project root โดยไม่มี frontmatter แบบ paths: ส่วนคำสั่งอื่นๆ เป็นการแลกเปลี่ยนที่คุณควรตัดสินใจอย่างตั้งใจ การจัดการสิ่งที่คงอยู่ในหน้าต่างบริบท ครอบคลุมถึง /compact ด้วยอาร์กิวเมนต์ focus และ /clear ระหว่างงานที่ไม่เกี่ยวข้องกัน ซึ่งทั้งสองอย่างนี้ส่งผลต่อความถี่ที่ตัวสรุปจะตัดสินว่ากฎของคุณคืออะไร

เหตุผลที่โค้ดที่มีอยู่จริงมีน้ำหนักเหนือกว่ากฎที่ตั้งไว้

นี่คือความล้มเหลวที่ผู้คนมักกล่าวถึงบ่อยที่สุด แต่กลับวินิจฉัยหาสาเหตุได้น้อยที่สุด ไฟล์ของคุณระบุว่าการเข้าถึงฐานข้อมูลต้องผ่านชั้น repository แต่ตัว agent กลับเขียน handler ที่เรียกใช้ ORM (object relational mapper) โดยตรง คุณไม่ได้ถูกเพิกเฉยด้วยเหตุผลด้านสไตล์ แต่คุณถูกหักล้างด้วยหลักฐานที่ปรากฏจริง

กฎเป็นเพียงการอธิบายความชอบส่วนบุคคล แต่โค้ดคือสิ่งที่แสดงให้เห็นถึงการใช้งานจริง เมื่อ agent เปิดไฟล์ 3 ไฟล์ในโมดูลที่กำลังจะแก้ไข แล้วพบว่าทั้ง 3 ไฟล์เรียกใช้ ORM โดยตรง บริบทในขณะนั้นจะมีประโยคนามธรรมหนึ่งประโยคอยู่ฝั่งหนึ่ง และมีตัวอย่างที่เป็นรูปธรรม ทันสมัย และตรงกับงานอีก 3 ตัวอย่างอยู่อีกฝั่งหนึ่ง การคัดลอกรูปแบบที่มีอยู่เดิมในพื้นที่นั้นมักเป็นพฤติกรรมที่ถูกต้อง แต่ในกรณีนี้มันผิดเพียงเพราะคุณรู้ในสิ่งที่บริบทไม่รู้ นั่นคือไฟล์เหล่านั้นเป็นโค้ดเก่า (legacy)

ดังนั้น ให้เขียนสิ่งนั้นลงไปในกฎ กฎที่ระบุถึงหลักฐานที่ขัดแย้งกับตัวมันเองจะสามารถคงอยู่ได้เมื่อต้องเผชิญกับ repository จริงๆ ส่วนกฎที่ระบุเพียงแค่ความชอบแบบลอยๆ จะไม่สามารถคงอยู่ได้

การเข้าถึงฐานข้อมูลใหม่ต้องผ่าน app/repositories/ ไฟล์ที่อยู่ภายใต้ app/legacy/ ยังคงเรียกใช้ ORM โดยตรง นั่นเป็นโค้ดเก่า ไม่ใช่รูปแบบที่ควรทำตาม ห้ามคัดลอกรูปแบบดังกล่าว

ประโยคที่สองคือส่วนที่สำคัญที่สุด มันบอกให้ agent ทราบว่าจะต้องพบกับอะไรและควรตีความอย่างไรก่อนที่มันจะไปพบเจอด้วยตัวเอง การแก้ไขแบบเดียวกันนี้สามารถใช้ได้กับกฎทุกข้อที่ขัดแย้งกับสิ่งที่มีอยู่ใน repository ของคุณอย่างชัดเจน เช่น สไตล์การ commit ที่ประวัติของคุณไม่ได้ทำตาม, โครงสร้างการทดสอบที่ชุดทดสอบครึ่งหนึ่งของคุณไม่ได้ใช้, หรือธรรมเนียมการ import ที่ใช้ได้เฉพาะในโค้ดใหม่เท่านั้น ไม่ว่าที่ใดที่โค้ดขัดแย้งกับไฟล์กฎ ให้ระบุความขัดแย้งนั้นลงไปในไฟล์กฎด้วย

กฎที่คลุมเครือไม่สามารถตรวจสอบได้ จึงไม่สามารถปฏิบัติตามได้

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

นี่คือแบบทดสอบที่ใช้กับทุกบรรทัดในไฟล์ของคุณ ให้เขียนคำสั่ง shell ที่จะ exit ด้วยค่าที่ไม่ใช่ศูนย์เมื่อกฎถูกละเมิด หากคุณไม่สามารถเขียนคำสั่งนั้นได้ แสดงว่ากฎนั้นตรวจสอบไม่ได้ ให้เปรียบเทียบตัวอย่างเหล่านี้:

  • ตรวจสอบไม่ได้: "เขียนฟังก์ชันให้สั้น" ตรวจสอบได้: "ฟังก์ชันที่มีความยาวเกิน 60 บรรทัดต้องมีคอมเมนต์กำกับไว้ด้านบนเพื่ออธิบายเหตุผล"
  • ตรวจสอบไม่ได้: "ทดสอบการเปลี่ยนแปลงของคุณ" ตรวจสอบได้: "รัน npm test และวางจำนวนความผิดพลาดก่อนที่จะถือว่างานเสร็จสิ้น"
  • ตรวจสอบไม่ได้: "จัดระเบียบไฟล์ให้ดี" ตรวจสอบได้: "HTTP handlers ต้องอยู่ใน src/api/handlers/ เท่านั้น ห้ามมีไฟล์อื่นอยู่ในไดเรกทอรีนั้น"
  • ตรวจสอบไม่ได้: "จัดรูปแบบโค้ดให้เหมาะสม" ตรวจสอบได้: "ใช้การเยื้อง 2 ช่องว่างในไฟล์ .ts"

"อย่าทำอะไรที่ซับซ้อนเกินความจำเป็น" เป็นกฎข้อแรกที่ผู้คนมักจะเลิกใช้ เพราะวิธีแก้ไขไม่ใช่การทำให้ประโยคสั้นลง แต่เป็นการทำให้ยาวขึ้น: การระบุรายละเอียดว่าการเปลี่ยนแปลงที่เล็กที่สุดที่ใช้งานได้จริงหมายถึงอะไร จะทำให้ agent มีเกณฑ์ที่สามารถนำไปตรวจสอบกับ diff ของตัวเองได้

ขนาดของไฟล์ก็เป็นปัญหาเดียวกันในรูปแบบที่ต่างออกไป คำแนะนำของ Claude Code กำหนดเป้าหมายไว้ที่ไฟล์คำสั่งละไม่เกิน 200 บรรทัด และระบุโดยตรงว่าไฟล์ที่ยาวขึ้นจะลดความสามารถในการปฏิบัติตามกฎ ไฟล์ขนาด 700 บรรทัดไม่ใช่คำสั่งที่แน่นหนาขึ้น แต่มันคือ 700 บรรทัดของข้อเรียกร้องที่มีโอกาสขัดแย้งกันเองมากขึ้น และยังถูกนำไปคำนวณกับ context window ของคุณในทุกๆ รอบ ซึ่ง ปรากฏให้เห็นโดยตรงในการใช้ token ของคุณ การจัดโครงสร้างไฟล์โดยให้กฎแต่ละข้ออยู่ภายใต้หัวข้อที่ผู้อ่านสามารถกวาดสายตาดูได้นั้น ได้อธิบายไว้ใน การเขียนไฟล์คำสั่งที่ agent สามารถปฏิบัติตามได้

วิธีวินิจฉัยปัญหาภายในสิบนาที

ให้รันคำสั่งตามลำดับนี้ การข้ามไปขั้นตอนสุดท้ายเป็นสาเหตุที่ทำให้ผู้ใช้งานต้องลงเอยด้วยการเขียนกฎจำนวนมากที่ตะโกนใส่ระบบแต่ก็ยังใช้งานไม่ได้

  1. ยืนยันว่าโหลดไฟล์แล้ว รัน /context แล้วอ่านรายการ Memory files หากไม่พบไฟล์ดังกล่าว ให้แก้ไขตำแหน่งที่ตั้งแล้วหยุดทันที ขั้นตอนอื่นในรายการนี้ยังไม่มีผล
  2. จำลองปัญหาในเซสชันใหม่ เริ่มเซสชันใหม่แล้วทดสอบด้วยงานที่เล็กที่สุดที่ควรจะกระตุ้นให้กฎทำงาน หากผ่านในขั้นตอนนี้แต่ล้มเหลวในเซสชันที่ยาวนาน แสดงว่าปัญหาเกิดจากระยะห่างหรือการบีบอัด (compaction) แต่หากล้มเหลวตั้งแต่ขั้นตอนนี้ แสดงว่าตัวกฎเองนั่นแหละที่เป็นปัญหา
  3. กำจัดปัจจัยรบกวน ลองใช้การเปลี่ยนแปลงเดียวกันในไดเรกทอรีที่โค้ดเดิมปฏิบัติตามกฎนั้นอยู่แล้ว หากผลลัพธ์กลับมาเป็นไปตามกฎ แสดงว่าโค้ดโดยรอบเป็นตัวขัดขวางกฎของคุณ
  4. ค้นหาความขัดแย้ง การมีไฟล์สองไฟล์ที่ให้คำแนะนำต่างกันสำหรับพฤติกรรมเดียวกันถือเป็นความล้มเหลวที่ระบุไว้ชัดเจน โมเดลอาจเลือกไฟล์ใดไฟล์หนึ่งโดยสุ่มและจะไม่แจ้งให้คุณทราบ
  5. ทำให้ตรวจสอบได้และทดสอบซ้ำ เขียนกฎใหม่โดยระบุ path และเงื่อนไขที่ชัดเจน หากอัตราการปฏิบัติตามกฎเพิ่มขึ้นอย่างมาก แสดงว่าสาเหตุมาจากวิธีการใช้ถ้อยคำของคุณ

ขั้นตอนที่ 4 ใช้เพียงหนึ่งคำสั่ง ให้ใช้ grep ค้นหาแหล่งคำสั่งทั้งหมดในหัวข้อนั้น ไม่ใช่แค่ไฟล์ที่คุณกำลังแก้ไขอยู่:

grep -rni "migration" --include="CLAUDE.md" --include="CLAUDE.local.md" .
grep -rni "migration" .claude/rules/ ~/.claude/CLAUDE.md ~/.claude/rules/ 2>/dev/null

หากพบข้อมูลในสองไฟล์ที่ระบุไม่เหมือนกัน นั่นคือบั๊กของคุณ ให้ลบออกหนึ่งไฟล์ อย่าพยายามจัดลำดับความสำคัญด้วยการใช้ถ้อยคำที่รุนแรงขึ้น เพราะไม่มีกลไกการจัดลำดับให้คุณอุทธรณ์ได้

ลำดับการแก้ไขตามระดับผลกระทบ

แต่ละขั้นตอนด้านล่างนี้มีผลกระทบมากกว่าขั้นตอนก่อนหน้า แต่ต้องใช้การตั้งค่าที่ซับซ้อนกว่า ให้เริ่มจากด้านบนเมื่อกฎนั้นสามารถปรับแก้ได้ง่าย และขยับลงมาเมื่อกฎมีความสำคัญจนไม่สามารถยอมรับความผิดพลาดที่เกิดขึ้นเป็นครั้งคราวได้

  1. ทำให้กฎมีความชัดเจน: ระบุ path, command หรือเงื่อนไขให้ชัดเจน เพิ่มหลักฐานคัดค้านที่ agent จะพบใน repository ดังที่แสดงไว้ก่อนหน้านี้ วิธีนี้ไม่มีค่าใช้จ่ายและสามารถแก้ไขปัญหาได้จำนวนมากอย่างน่าประหลาดใจ
  2. ย้ายกฎไปไว้ใกล้กับสิ่งที่ควบคุม: ใช้ CLAUDE.md แบบซ้อนกัน, กฎที่กำหนดขอบเขตตาม path ใน .claude/rules/ หรือใส่ comment ไว้ที่ส่วนบนสุดของไฟล์ กฎจะถูกอ่านพร้อมกับโค้ดที่กฎนั้นบังคับใช้ ยอมรับข้อแลกเปลี่ยนที่ว่า: สิ่งใดก็ตามที่โหลดด้วยวิธีนี้จะถูกลบออกเมื่อมีการบีบอัด (compaction) ครั้งถัดไป และจะกลับมาอีกครั้งเมื่อมีการอ่านที่ตรงกับเงื่อนไข
  3. ย้ายการบังคับใช้ไปไว้ใน hook: ข้อความที่เป็นคำบรรยายคือการร้องขอ แต่ hook คือการตัดสินใจ hook จะทำงานเป็นโค้ดในเหตุการณ์ lifecycle ที่กำหนดไว้ และจะมีผลบังคับใช้โดยไม่คำนึงถึงสิ่งที่โมเดลสรุป
  4. มอบกฎให้เครื่องมือที่เป็น deterministic และลบคำบรรยายทิ้ง: เช่น การจัดรูปแบบ, ลำดับการ import, ความยาวบรรทัด, การห้าม import บางรายการ, รูปแบบของ commit message ใช้ ruff format, prettier --write, eslint หรือ hook ของ pre-commit เครื่องมือจัดรูปแบบจะทำงานถูกต้องเสมอและไม่เสีย token ในขณะที่ประโยคคำสั่งอาจถูกต้องเป็นส่วนใหญ่แต่ต้องเสีย token ในทุกครั้งที่เรียกใช้

ขั้นตอนที่ 3 โดยละเอียด: สมมติว่าไฟล์ migration ต้องไม่ถูกแก้ไขโดย agent ให้ใส่สิ่งนี้ลงใน .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-migrations.sh"
          }
        ]
      }
    ]
  }
}

และใส่สิ่งนี้ลงใน .claude/hooks/guard-migrations.sh:

#!/usr/bin/env bash
set -euo pipefail

path=$(jq -r '.tool_input.file_path // empty')

case "$path" in
  */migrations/*)
    echo "Files under migrations/ are written by hand. Stop and ask first." >&2
    exit 2
    ;;
esac

exit 0

รัน chmod +x .claude/hooks/guard-migrations.sh จากนั้นเริ่ม session ใหม่และสั่งให้ agent แก้ไขไฟล์ภายใต้ migrations/ การแก้ไขจะถูกปฏิเสธและข้อความของคุณจะถูกส่งกลับมาเป็นเหตุผล สถานะ exit status 2 บน PreToolUse จะบล็อกการเรียกใช้เครื่องมือ (tool call) ก่อนที่จะเริ่มทำงาน และข้อความ stderr ของคุณจะถูกส่งไปยังโมเดลในฐานะข้อความแจ้งเตือนการบล็อก ${CLAUDE_PROJECT_DIR} จะชี้ไปยัง root ของโปรเจกต์ ดังนั้น hook จะทำงานได้ไม่ว่า agent จะอยู่ใน directory ใดก็ตาม agent ไม่จำเป็นต้องเห็นด้วยกับกฎ จำกฎได้ หรือมีกฎอยู่ในบริบท และการแก้ไขจะไม่เกิดขึ้น

สำหรับการห้ามโดยเด็ดขาดที่ไม่มีตรรกะซับซ้อน permissions.deny ในการตั้งค่าของคุณสามารถทำหน้าที่เดียวกันได้โดยไม่ต้องดูแลสคริปต์ และ โหมดสิทธิ์ (permission modes) จะเป็นตัวตัดสินว่าสิ่งใดทำงานได้โดยไม่ต้องถามคุณก่อน หากคำสั่งจำเป็นต้องอยู่ในระดับ system prompt แทนที่จะเป็นข้อความของผู้ใช้ --append-system-prompt จะทำหน้าที่นั้น แม้ว่าจะต้องส่งผ่านในทุกการเรียกใช้ ซึ่งเหมาะกับสคริปต์มากกว่าการทำงานแบบโต้ตอบ

สิ่งที่คุณไม่สามารถสั่งให้เลิกทำได้

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

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

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

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

ไฟล์คำสั่งไม่ใช่ขอบเขตความปลอดภัย มันเป็นเพียงสิ่งที่กำหนดพฤติกรรมแต่ไม่ได้บังคับใช้ สิ่งใดก็ตามที่หากพลาดไปแล้วมีราคาที่ต้องจ่ายสูง เช่น ข้อมูลประจำตัว (credentials) หรือคำสั่งที่ทำลายข้อมูล ควรจัดการด้วยสิทธิ์การเข้าถึง (permissions) หรือ hook การเก็บความลับให้พ้นมือเอเจนต์ ใช้หลักการเดียวกันกับข้อมูล คืออย่าขอให้เอเจนต์อย่าอ่านไฟล์ แต่จงจัดการไม่ให้ไฟล์นั้นสามารถอ่านได้ตั้งแต่ต้น

สรุปสั้นๆ คือ พิสูจน์ว่าไฟล์ถูกโหลดแล้ว ทำให้กฎสามารถตรวจสอบได้ วางกฎไว้ใกล้กับสิ่งที่กฎนั้นควบคุม และเมื่ออัตราความผิดพลาดยังคงเป็นเรื่องสำคัญ ให้ย้ายกฎนั้นออกจากรูปแบบข้อความบรรยาย กฎที่เอเจนต์ไม่สามารถเพิกเฉยได้คือกฎที่ไม่เคยถูกร้องขอจากเอเจนต์เลย

FAQ

ทำไม Claude Code ถึงเพิกเฉยต่อไฟล์ CLAUDE.md ของฉัน

ตรวจสอบให้แน่ใจว่าระบบได้โหลดไฟล์นั้นแล้วก่อนจะสรุปว่าถูกเพิกเฉย ให้รันคำสั่ง /context แล้วดูที่รายการ Memory files หากไม่มีชื่อไฟล์ปรากฏอยู่ในนั้น แสดงว่าไฟล์ดังกล่าวไม่ได้อยู่ในบทสนทนา ไฟล์คำสั่งจะถูกส่งเป็นข้อความของผู้ใช้หลังจาก system prompt และถูกปฏิบัติเสมือนเป็นบริบท (context) มากกว่าจะเป็นการตั้งค่าที่บังคับใช้ ดังนั้นจึงไม่มีการรับประกันว่าจะปฏิบัติตามอย่างเคร่งครัด กรณีที่พบบ่อยที่สุดมี 4 ประการ: ไฟล์อยู่ในไดเรกทอรีย่อยที่เอเจนต์ไม่เคยอ่าน, ไฟล์สองไฟล์มีเนื้อหาขัดแย้งกันและโมเดลเลือกใช้ไฟล์ใดไฟล์หนึ่งโดยสุ่ม, กฎมีความคลุมเครือเกินกว่าจะตรวจสอบการกระทำได้ หรือโค้ดโดยรอบแสดงผลลัพธ์ที่ตรงกันข้ามกับสิ่งที่กฎระบุไว้

การแก้ไขไฟล์คำสั่งระหว่างเซสชันส่งผลอะไรหรือไม่

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

ไฟล์ใดจะมีผลหาก CLAUDE.md ที่ root และที่อยู่ในโฟลเดอร์ย่อยมีเนื้อหาขัดแย้งกัน

ไม่มีไฟล์ใดที่เชื่อถือได้ ไฟล์ที่ถูกค้นพบจะถูกนำมาต่อกัน (concatenate) ในบริบทแทนที่จะเขียนทับกัน โดยเรียงลำดับจาก root ของระบบไฟล์ลงมาจนถึงไดเรกทอรีทำงานของคุณ ดังนั้นไฟล์ที่อยู่ใกล้ที่สุดจะถูกอ่านเป็นลำดับสุดท้าย ไม่มีกลไกกำหนดลำดับความสำคัญเพื่อแก้ไขข้อขัดแย้ง และเอกสารของ Claude Code ระบุว่ากฎที่ขัดแย้งกันอาจถูกตัดสินโดยสุ่ม ให้เขียนไฟล์ในโฟลเดอร์ย่อยเป็นส่วนเสริมที่ระบุ path ที่ต้องการควบคุม และลบส่วนที่ขัดแย้งออกแทนที่จะพยายามเขียนให้มีลำดับความสำคัญสูงกว่า

คำสั่งของฉันจะยังคงอยู่หรือไม่หลังจากใช้ /compact

ขึ้นอยู่กับวิธีการโหลดไฟล์นั้น ไฟล์ CLAUDE.md ที่ root ของโปรเจกต์, กฎที่ไม่ได้กำหนดขอบเขต (unscoped) และ auto memory จะถูกนำกลับเข้ามาจากดิสก์หลังการ compaction ส่วนกฎที่มี frontmatter แบบ paths: และไฟล์ CLAUDE.md ที่อยู่ในไดเรกทอรีย่อยจะสูญหายไปจนกว่าไฟล์นั้นจะถูกอ่านอีกครั้ง สิ่งใดก็ตามที่คุณพิมพ์ลงในแชทจะคงอยู่ก็ต่อเมื่อตัวสรุปผล (summariser) เก็บข้อมูลนั้นไว้ หากกฎใดจำเป็นต้องคงอยู่ตลอดทั้งเซสชัน ให้ใส่ไว้ในไฟล์ที่ root ของโปรเจกต์โดยไม่มี frontmatter แบบ paths:

เมื่อใดที่ควรเปลี่ยนกฎให้เป็น hook แทนการเขียนเป็นข้อความ

เมื่อการตรวจสอบนั้นเป็นแบบกำหนดผลลัพธ์ได้ชัดเจน (deterministic) และต้นทุนของการตรวจสอบพลาดสูงกว่าต้นทุนในการเขียนสคริปต์ขนาดเล็ก ข้อจำกัดด้าน path ของไฟล์, คำสั่งที่จำเป็นต้องรันก่อนการ commit และการเรียกใช้เครื่องมือที่ถูกห้าม ทั้งหมดนี้เข้าข่ายดังกล่าว Hook แบบ PreToolUse ที่จบการทำงานด้วยสถานะ 2 จะบล็อกการเรียกใช้เครื่องมือนั้นทันทีและส่งข้อความ stderr กลับไปยังโมเดลเพื่อแจ้งเหตุผล ดังนั้นกฎนี้จะมีผลไม่ว่ากฎนั้นจะยังอยู่ในบริบทหรือไม่ก็ตาม สิ่งใดก็ตามที่ formatter หรือ linter สามารถตัดสินได้ ควรให้เครื่องมือเหล่านั้นเป็นผู้จัดการและลบออกจากไฟล์คำสั่งทั้งหมดทิ้งไป