SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-28

ทำไม Coding Agents ถึงไม่ทำตามคำสั่งที่คุณตั้งไว้

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

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

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

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

ขออธิบายสองคำศัพท์ก่อน 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/ ซึ่งมีฟิลด์ frontmatter เป็น paths: กฎเหล่านี้จะเข้าสู่บริบทเมื่อมีการอ่านไฟล์ที่ตรงกับเงื่อนไข ไม่ใช่ในทุกรอบการทำงาน

ความแตกต่างเพียงจุดเดียวนี้อธิบายถึงสาเหตุของความล้มเหลวที่ได้รับรายงานส่วนใหญ่ คุณใส่กฎไว้ใน 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 มองเห็นไฟล์นั้นแล้ว การตรวจสอบมี 2 ขั้นตอน โดยเริ่มจากวิธีที่ง่ายที่สุดก่อน

ให้รัน /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 และกฎที่ไม่มีขอบเขต (unscoped rules) จะถูกนำกลับเข้ามาจากดิสก์ใหม่หลังจากการบีบอัด หน่วยความจำอัตโนมัติ (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 โดยตรง บริบทจึงมีประโยคที่เป็นนามธรรมอยู่ฝั่งหนึ่ง และมีตัวอย่างที่เป็นรูปธรรม ทันสมัย และตรงกับงานอยู่อีกฝั่งหนึ่ง การคัดลอกรูปแบบในพื้นที่มักเป็นพฤติกรรมที่ถูกต้อง แต่มันผิดในกรณีนี้เพียงเพราะคุณรู้บางสิ่งที่บริบทไม่รู้ นั่นคือไฟล์เหล่านั้นเป็น legacy code

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

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

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

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

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

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

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

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

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

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

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

  1. ยืนยันว่าโหลดไฟล์แล้ว รัน /context และอ่านรายการไฟล์ใน Memory หากไม่พบไฟล์ดังกล่าว ให้แก้ไขตำแหน่งที่ตั้งของไฟล์แล้วหยุดขั้นตอนอื่นไว้ก่อน เพราะขั้นตอนที่เหลือในรายการนี้ยังไม่มีผล
  2. จำลองปัญหาในเซสชันใหม่ เริ่มเซสชันใหม่และทดสอบด้วยงานที่เล็กที่สุดที่ควรจะกระตุ้นให้กฎทำงาน หากผ่านในขั้นตอนนี้แต่ล้มเหลวในเซสชันที่ยาวนาน แสดงว่าปัญหาเกิดจากระยะห่างหรือการบีบอัดข้อมูล แต่หากล้มเหลวตั้งแต่ขั้นตอนนี้ แสดงว่าตัวกฎเองนั่นแหละที่เป็นปัญหา
  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 จะบล็อกการเรียกใช้เครื่องมือก่อนที่จะเริ่มทำงาน และข้อความใน stderr ของคุณจะถูกส่งไปยังโมเดลในฐานะข้อความแจ้งเตือนการบล็อก ${CLAUDE_PROJECT_DIR} จะชี้ไปยัง root ของโปรเจกต์ ดังนั้น hook จะทำงานได้ไม่ว่า agent จะอยู่ใน directory ใดก็ตาม agent ไม่จำเป็นต้องเห็นด้วยกับกฎ จำกฎได้ หรือมีกฎนั้นอยู่ใน context การแก้ไขจึงไม่เกิดขึ้น

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

สิ่งที่คุณไม่สามารถสั่งให้หายไปได้

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

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

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

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

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

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

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