ปัญหาและแนวทางแก้ไขสำหรับฟีเจอร์ Compact ของ Claude Code

@u1
ญี่ปุ่น3 วันที่ผ่านมา · 04 ก.ค. 2569
717K
1.6K
180
11
3.3K

TL;DR

บทความนี้อธิบายรายละเอียดการแก้ไขเชิงโครงสร้างสำหรับการบีบอัดบริบทของ Claude Code โดยใช้ทักษะและ Hook แบบกำหนดเองเพื่อบันทึกสถานะเซสชันและตรรกะการตัดสินใจ ก่อนที่จะถูกลบออกไปในระหว่างการสรุปผล

ภายหลังฉันสร้างปลั๊กอินที่สามารถรวมเนื้อหาต่อไปนี้ได้โดยอัตโนมัติ และช่วยเสริมฟีเจอร์ Compact ให้ดียิ่งขึ้น

https://x.com/u1/status/2073742408555343968

การทำงานจริงของ Claude Code's Compact

โดยพื้นฐานแล้ว ฟีเจอร์ Compact ของ Claude Code จะทำงานผ่านสองเส้นทาง:

  • Compact แบบแมนนวล (/compact): ถูกเรียกใช้โดยผู้ใช้อย่างชัดเจน สามารถสั่งงานได้ทุกเมื่อ
  • Compact อัตโนมัติ: ทำงานโดยอัตโนมัติเมื่อการใช้ context ของเซสชันใกล้ถึงขีดจำกัด (ในทางปฏิบัติคือประมาณ 90-95%) มันจะไม่ทำงาน ณ เวลาที่ผู้ใช้ต้องการโดยตรง แต่จะทำงานในช่วงเปลี่ยนเทิร์นที่คุณรู้สึกทันทีว่าข้อมูลถูกบีบอัดไปแล้ว

ในทั้งสองเส้นทาง เนื้อหาจะเหมือนกัน: ประวัติการสนทนาก่อนหน้านี้จะถูกส่งไปยัง LLM เพื่อสร้างสรุปด้วยภาษาธรรมชาติ จากนั้นสรุป + การสนทนาล่าสุด + system prompt จะถูกประกอบขึ้นเป็น context ใหม่ สรุปจะกลายเป็นคำอธิบายรูปแบบเรื่องเล่าเกี่ยวกับ "สิ่งที่ทำลงไป" และผลที่ตามมาคือ โครงสร้างการตัดสินใจ เช่น "เหตุใดจึงเลือกตัวเลือกนั้น" "แผนไหนที่ถูกปฏิเสธ" และ "เราอยู่ในเฟสใดขณะนี้" จะอ่อนลง ยิ่งไปกว่านั้น เมื่อการบีบอัดเกิดขึ้นแล้ว มันเป็นการดำเนินการที่ไม่สามารถย้อนกลับได้ คุณไม่สามารถกลับไปยัง logs ดิบก่อนการบีบอัดได้

จากมุมมองของ hook การบีบอัดสามารถตรวจจับได้ผ่านอีเวนต์ PostCompact อย่างไรก็ตาม hook ของ PostCompact ไม่สามารถคืนค่า additionalContext ได้ ดังนั้นจึงไม่มีช่องทางในการฉีดคำสั่งไปยังเอเยนต์โดยตรงหลังจากการบีบอัด ในการแทรกคำสั่ง คุณต้องผ่านอีเวนต์ UserPromptSubmit ที่ตามมา ข้อจำกัดนี้กำหนดการออกแบบ hook ในบทความนี้

อะไรที่ผิดพลาดกับ Compact มาตรฐาน

/compact ของ Claude Code จะสรุปประวัติการสนทนา โดยวางผลลัพธ์เป็น context เริ่มต้นของเซสชันใหม่ แม้ว่าสรุปนั้นจะสมเหตุสมผล แต่มันคือ "บันทึกการทำงานในอดีต" มากกว่า "คำแนะนำสำหรับสิ่งที่จะทำต่อไป" ส่งผลให้เอเยนต์หลังการบีบอัดมีแนวโน้มที่จะเกิดความเข้าใจผิดดังต่อไปนี้:

  • สูญเสียขอบเขตระหว่าง "คำสั่งทำงาน" และ "บันทึกการทำงาน" หากสรุปบอกว่า "แผน A ถูกพิจารณา" เอเยนต์อาจเริ่มดำเนินการตามแผน A แทนที่จะเป็นแผน B ที่ได้นำมาใช้จริง
  • สับสนระหว่างเฟสการตรวจสอบกับเฟสการนำไปใช้ ข้อสมมติฐาน "ต้องตรวจสอบบนเครื่องจริงก่อนนำไปใช้" หลุดออกจากสรุป และเอเยนต์อาจกระโดดเข้าสู่การดำเนินการปรับใช้ที่ทำลายล้างในเทิร์นถัดไป
  • เสนอแนวทางที่ไม่ถูกต้องซึ่งถูกปฏิเสธไปแล้วซ้ำอีก สรุปอาจบันทึกว่าแนวทางหนึ่ง "ถูกทดลอง" แต่ไม่ได้บันทึก "สาเหตุที่ถูกปฏิเสธ"
  • สูญเสีย "สถานะของเซสชัน" เช่น โหมดแผน (plan mode), การมอบหมายงานให้ worker, หรือ task tree เอเยนต์อาจทำงานต่อไปโดยไม่ได้อยู่ในโหมดแผน หรือลืมการมีอยู่ของ workers ที่ทำงานใน tmux และเริ่มทำงานนั้นด้วยตัวเอง

อุบัติเหตุประเภทใดที่เกิดขึ้นจริง

ย้อนดูเซสชันของฉันในสัปดาห์ที่ผ่านมา ฉันสังเกตเห็นอย่างน้อยสี่รูปแบบทันทีหลังจาก compact ทั้งหมดดูเหมือนมีสาเหตุมาจากการแยก "คำสั่งทำงาน" ออกจาก "บันทึกการทำงาน" ไม่สำเร็จ:

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

สิ่งเหล่านี้เกิดขึ้นหลายครั้งในเซสชันเดียวกัน โดยมีความเข้าใจผิดประเภทต่างๆ เกิดขึ้นหลังจากทุกครั้งที่มี compact ฉันมองว่าสิ่งเหล่านี้เป็นความล้มเหลวเชิงโครงสร้างของข้อกำหนด compact มาตรฐาน มากกว่าที่จะเป็นอุบัติเหตุเดี่ยวๆ

สิ่งที่ฉันสร้างขึ้น

(1) สกิล compact-prep

สกิลที่ถูกใช้งานเป็นคำสั่ง slash ซึ่งผู้ใช้เรียกใช้ก่อนพิมพ์ /compact อย่างชัดเจน มันจะดึง "โครงสร้างการตัดสินใจ" และ "สถานะของเซสชัน" ที่มีแนวโน้มจะไม่ถูกบรรจุในสรุปออกมา และบันทึกลงในไฟล์สถานะที่พาธคงที่ (${TMPDIR}/claude-compact-state/<session_id>.md) ในรูปแบบเฉพาะ

รายการที่บันทึก รวมถึงสิ่งที่ยากจะจับในสรุป:

  • แผนที่กำลังดำเนินการ (Active Plan) (พาธของไฟล์แผนและเฟสปัจจุบัน)
  • สรุป TaskList (งานที่กำลังดำเนินการและส่วนเสริม)
  • การตัดสินใจของเซสชัน (Session Decisions) (แผนที่นำมาใช้ / แผนที่ถูกปฏิเสธ / เหตุผลที่ปฏิเสธ)
  • ข้อจำกัดและอุปสรรค (Constraints and Blockers)
  • โครงสร้าง Worker (Worker Topology) (tmux-bridge panes / บทบาท / การมอบหมาย)
  • ไฟล์ที่กำลังแก้ไข (Editing Files) (หมายเหตุเกี่ยวกับการเปลี่ยนแปลงที่ยังไม่ได้บันทึกหรือยังไม่ได้ตรวจสอบ)
  • หมายเหตุการกู้คืน (Recovery Notes) (จดหมายถึงตัวเองหลังการบีบอัด)

จุดออกแบบที่สำคัญคือ "การบังคับใช้เชิงกลไก" (mechanical enforcement) มันใช้ hard gate เพื่อป้องกันการสร้างไฟล์หากไม่พบ session_id, ฟังก์ชันบังคับ (forcing function) ด้วยหัวข้อคงที่เพื่อตรวจจับการละเว้น และจำกัดเครื่องมือที่อนุญาต (allowed-tools) เพื่อป้องกันสถานะเสียหาย

(2) Hook สองขั้นตอน: PostCompact + UserPromptSubmit

แม้ว่า (1) จะเขียนไฟล์สถานะ มันก็ไร้ความหมายถ้าเอเยนต์หลังการบีบอัดไม่อ่านไฟล์นั้น เนื่องจาก PostCompact ไม่สามารถคืนค่า additionalContext ได้ ฉันจึงใช้การกำหนดค่าสองขั้นตอน:

  1. Hook PostCompact เขียนไฟล์ marker ที่มี session_id (ไม่มีคำสั่ง แค่บันทึกว่ามีการบีบอัดเกิดขึ้น)
  2. เมื่อ Hook UserPromptSubmit ถัดไปตรวจพบ marker มันจะฉีดคำสั่งผ่าน additionalContext: "อ่านไฟล์แผน / อ่านไฟล์สถานะ / ตรวจสอบ TaskList / ถือว่าขั้นตอนถัดไปในสรุปเป็นสมมติฐาน / ยืนยันการเข้าสู่ระบบอีกครั้งหากโหมดแผนถูกปิดใช้งาน" จากนั้นลบ marker

เนื่องจาก Claude Code ไม่มีกลไกสถานะร่วมระหว่าง hooks ไฟล์ marker ในระบบไฟล์จึงเป็นช่องทางการสื่อสารเพียงช่องทางเดียว สิ่งนี้ทำให้แต่ละ hook มีความบางและรับผิดชอบเดียว ในเทิร์นปกติ ภาระเพิ่มเติมคือแค่การตรวจสอบ test -f หนึ่งครั้ง

(3) การแจ้งเตือน 60% (เพื่อหลีกเลี่ยง Compact อัตโนมัติ)

เครื่องมือก่อนหน้านี้สมมติว่าผู้ใช้รัน /compact-prep → /compact ด้วยตนเอง อย่างไรก็ตาม Compact อัตโนมัติทำงานโดยไม่มีการเตือน ข้ามโฟลว์นี้ไป หาก Compact อัตโนมัติเกิดขึ้นก่อน ไฟล์สถานะจะไม่ถูกบันทึก และ logs ดิบจะถูกบดเป็นสรุป ทำให้สูญเสียวัสดุสำหรับการกู้คืน

แนวทางแก้ไขคือการสร้างสถานะที่ผู้ใช้สามารถรัน prep ด้วยตนเองก่อนที่ Compact อัตโนมัติจะเริ่มทำงาน นี่คือจุดประสงค์ของการแจ้งเตือน 60%

ทำไมต้อง 60%?

  • เวลาเหลือเฟือ: Compact อัตโนมัติเริ่มทำงานประมาณ 90-95% 60% ให้ส่วนต่าง 30% ทำให้แน่ใจว่าผู้ใช้เห็นคำเตือนก่อนที่เทิร์นถัดไปจะทำให้เกิด Compact อัตโนมัติ
  • พื้นที่ในการหยุดงาน: ที่ 60% ยังมีความจุเหลือ 30% ที่จะทำงานย่อยให้เสร็จก่อนบันทึกสถานะ
  • ตัวกระตุ้นเชิงกลไก: มันทำหน้าที่เป็นฟังก์ชันบังคับเมื่อคุณจดจ่อเกินไปจนไม่สังเกตว่ากำลังใช้ context ไปเท่าไร
  • สมมติฐาน Context 1M: ด้วย context 200K, 60% น้อยเกินไป ฉันใช้ context 1M (Opus 4.7) ซึ่ง 60% เหลือประมาณ 600K tokens — มีพื้นที่เหลือเฟือในการทำงานให้เสร็จและรัน prep

การนำไปใช้เกี่ยวข้องกับ statusline hook ที่เขียน marker เตือนที่เกณฑ์ดังกล่าว และ UserPromptSubmit hook ที่ตรวจจับมันเพื่อแนะนำให้รัน /compact-prep

ผลลัพธ์

ตอนนี้เซสชันมีความเสถียรแม้จะผ่านการ compact ประมาณ 10 ครั้ง โดยไม่มีการพังทลายทางตรรกะ!

  • การสูญเสียงานเนื่องจากการบีบอัดใกล้เป็นศูนย์
  • การเสนอแนวคิดที่ถูกปฏิเสธซ้ำ ๆ หายไป
  • โหมดแผน (Plan mode) ถูกรักษาไว้
  • ไม่มีการลืมโครงสร้าง worker เมื่อรันหลาย workers ใน tmux

อ้างอิง: โค้ดการนำไปใช้

ด้านล่างคือโค้ดสกิลและ hooks จริง พวกมันทำงานโดยการคัดลอกไปยังไดเรกทอรีมาตรฐานของ Claude Code (~/.claude/)

A: เนื้อหาสกิล compact-prep

วางใน ~/.claude/skills/compact-prep/SKILL.md

markdown
1---
2name: compact-prep
3description: |
4 ก่อนดำเนินการ /compact ใน Claude Code ให้บันทึกสถานะเซสชันปัจจุบันไปยังไฟล์สถานะชั่วคราว
5 ทริกเกอร์บังคับ: /compact-prep, compact-prep, การเตรียมการบีบอัด
6 ห้ามทริกเกอร์: การกู้คืนหลัง compact, รายงานความคืบหน้าปกติ, การสร้างแผน
7strict_procedure: true
8argument-hint: "[บันทึกการกู้คืน]"
9allowed-tools: Read Write Bash(~/.claude/scripts/get-session-id.sh *) Bash(mkdir *) Bash(date *) Bash(pwd)
10---
11
12# compact-prep
13
14บันทึกสถานะเซสชันที่ยากจะเก็บไว้ในสรุปการบีบอัด ไปที่
15`${TMPDIR}/claude-compact-state/${SESSION_ID}.md` ก่อน `/compact`
16
17## โปรไฟล์ขั้นตอนที่เข้มงวด
18
19- ความเข้มงวด: strict-procedure
20- Hard gates: หยุดหากไม่สามารถดึง session_id ได้
21- ฟังก์ชันบังคับ: ตรวจสอบพาธคงที่และหัวข้อบังคับหลังจากบันทึก
22- ใบเสร็จรับเงินเมื่อเสร็จสิ้น: รายงานพาธไฟล์, รายการที่บันทึก, และคำแนะนำให้รัน `/compact`
23
24## ขั้นตอน
25
261. รับ session_id ผ่าน `~/.claude/scripts/get-session-id.sh`
272. ตั้งค่าเส้นทางเป็น `${TMPDIR:-/tmp}/claude-compact-state/${SESSION_ID}.md`
283. ตรวจสอบ TaskList, แผนที่กำลังดำเนินการ, tmux-bridge, และไฟล์ที่กำลังแก้ไข
294. บันทึกหัวข้อตามลำดับ: # Compact Prep State, ## Active Plan, ## Current Phase, ## TaskList Summary, ## Session Decisions, ## Constraints and Blockers, ## Worker Topology, ## Editing Files, ## Recovery Notes
305. ตรวจสอบว่าทุกหัวข้อมีอยู่
316. บอกผู้ใช้: "การเตรียมการเสร็จสมบูรณ์ กรุณาดำเนินการ `/compact`"

B: Recovery hooks (2 ขั้นตอน)

B-1: PostCompact hook

~/.claude/hooks/compaction-recovery.sh

B-2: UserPromptSubmit hook (การฉีด)

~/.claude/hooks/userpromptsubmit-compaction-recovery.sh

C: การแจ้งเตือน 60%

C-1: statusline hook สาขา threshold

เพิ่มใน ~/.claude/hooks/statusline.sh

C-2: UserPromptSubmit hook (การเตือนความจำ)

~/.claude/hooks/userpromptsubmit-compact-prep-reminder.sh

D: การลงทะเบียนใน settings.json

เพิ่ม hooks ใน ~/.claude/settings.json.

บันทึกในคลิกเดียว

อ่านบทความไวรัลเชิงลึกด้วย AI ใน YouMind

Save the source, ask focused questions, summarize the argument, and turn a viral article into reusable notes in one AI workspace.

Explore YouMind
สำหรับครีเอเตอร์

เปลี่ยน Markdown ของคุณให้เป็นบทความ 𝕏 ที่สะอาดตา

เวลาคุณเผยแพร่งานเขียนยาวของตัวเอง การจัดรูปแบบรูปภาพ ตาราง และบล็อกโค้ดให้เข้ากับ 𝕏 นั้นน่าปวดหัว YouMind เปลี่ยนร่าง Markdown ทั้งฉบับให้เป็นบทความ 𝕏 ที่สะอาดตาและพร้อมโพสต์ทันที

ลอง Markdown เป็น 𝕏

แพตเทิร์นให้ถอดรหัสเพิ่มเติม

บทความไวรัลล่าสุด

สำรวจบทความไวรัลเพิ่มเติม