Các vấn đề và giải pháp cho tính năng nén (Compact) của Claude Code

@u1
TIẾNG NHẬT3 ngày trước · 04 thg 7, 2026
717K
1.6K
180
11
3.3K

TL;DR

Bài viết này trình bày chi tiết về giải pháp cấu trúc cho việc nén ngữ cảnh của Claude Code, sử dụng các kỹ năng và hook tùy chỉnh để lưu trạng thái phiên làm việc và logic quyết định trước khi các bản tóm tắt xóa chúng.

Sau đó, tôi đã tạo một plugin có thể tự động bao gồm nội dung sau và nâng cao tính năng nhỏ gọn một cách minh bạch.

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

Cách Tính Năng Compact Của Claude Code Thực Sự Hoạt Động

Về cơ bản, tính năng compact của Claude Code chạy qua hai luồng:

  • Compact thủ công (/compact): Được kích hoạt trực tiếp bởi người dùng. Có thể thực hiện bất kỳ lúc nào.
  • Compact tự động: Tự động chạy khi dung lượng ngữ cảnh của phiên gần đạt đến giới hạn (thực tế là khoảng 90-95%). Nó không chạy ngay tại thời điểm người dùng muốn, mà thường chạy ở ranh giới giữa các lượt tương tác, khi bạn chợt nhận ra nó đã được nén.

Trong cả hai luồng, nội dung đều giống nhau: lịch sử hội thoại trước đó được gửi đến LLM để tạo một bản tóm tắt bằng ngôn ngữ tự nhiên, và bản tóm tắt này cùng với các lượt gần đây và prompt hệ thống được tái cấu trúc thành một ngữ cảnh mới. Bản tóm tắt trở thành một mô tả dạng tường thuật về "những gì đã được thực hiện", và kết quả là, cấu trúc quyết định—chẳng hạn như "tại sao lựa chọn đó được đưa ra", "kế hoạch nào đã bị từ chối", và "chúng ta đang ở giai đoạn nào"—bị suy yếu. Hơn nữa, một khi quá trình nén đã chạy, đó là một thao tác không thể đảo ngược; bạn không thể quay lại các nhật ký thô trước khi nén.

Từ góc nhìn hook, quá trình nén có thể được bắt bởi sự kiện PostCompact. Tuy nhiên, hook PostCompact không thể trả về additionalContext, vì vậy không có cách nào để trực tiếp tiêm chỉ thị vào agent ngay sau khi nén. Để chèn chỉ thị, bạn phải đi qua sự kiện UserPromptSubmit tiếp theo. Ràng buộc này định hình thiết kế hook trong bài viết này.

Vấn Đề Với Compact Tiêu Chuẩn

/compact của Claude Code tóm tắt lịch sử hội thoại, đặt kết quả làm ngữ cảnh ban đầu cho một phiên mới. Mặc dù bản tóm tắt hợp lý, nhưng nó là một "nhật ký công việc trong quá khứ" chứ không phải là "chỉ thị cho việc cần làm tiếp theo". Do đó, agent sau khi nén dễ mắc phải những hiểu lầm sau:

  • Mất ranh giới giữa "chỉ thị công việc" và "nhật ký công việc". Nếu bản tóm tắt nói "Kế hoạch A đã được xem xét", agent có thể bắt đầu triển khai Kế hoạch A thay vì Kế hoạch B đã được chấp nhận.
  • Nhầm lẫn giữa giai đoạn xác minh và giai đoạn triển khai. Tiền đề "xác minh trên máy thật trước khi triển khai" bị loại khỏi bản tóm tắt, và agent có thể lao vào các thao tác triển khai phá hoại trong lượt tiếp theo.
  • Đề xuất lại các cách tiếp cận sai lầm đã bị loại bỏ. Bản tóm tắt có thể ghi lại rằng một cách tiếp cận đã được "thử" nhưng không ghi lại "lý do tại sao nó bị từ chối".
  • Mất "trạng thái phiên" như chế độ kế hoạch, ủy quyền worker, hoặc cây nhiệm vụ. Agent có thể tiếp tục công việc khi không ở chế độ kế hoạch hoặc quên mất sự tồn tại của các worker đang chạy trong tmux và tự mình bắt đầu làm việc đó.

Những Loại Sự Cố Nào Đã Thực Sự Xảy Ra

Nhìn lại các phiên làm việc của tôi trong tuần qua, tôi đã quan sát thấy ít nhất bốn mẫu hình ngay sau một lần compact. Tất cả dường như bắt nguồn từ việc không phân tách được "chỉ thị công việc" khỏi "nhật ký công việc":

  • Triển khai trước khi xác minh: Mặc dù đã đồng ý "xác minh hành vi trên máy trước khi đặt tệp", agent chỉ thấy hình ảnh hoàn thành trong bản tóm tắt sau khi nén, bỏ qua bước xác minh và ghi đè lên đích đến.
  • Thực thi lại các lối tắt đã bị từ chối: Vì bản tóm tắt ghi lại một cách tiếp cận lối tắt thất bại như một "quy trình đã thử", agent đã thực thi lại nó và lại gặp phải thất bại tương tự.
  • Quên các nguyên tắc thiết kế: Các nguyên tắc được thiết lập trong phiên, như "chỉnh sửa kho lưu trữ nguồn thay vì đích đến", đã bị loại khỏi bản tóm tắt, khiến agent thực hiện các chỉnh sửa trực tiếp có hiệu quả ngắn hạn nhưng không thể tái tạo.
  • Hiểu sai mục tiêu nhiệm vụ: Mục đích cụ thể của một bài kiểm tra được sửa chữa trước khi nén đã bị mất, khiến agent đi lạc vào các cuộc điều tra ngoại vi và bắt đầu công việc theo một hướng hoàn toàn khác.

Những điều này đã xảy ra nhiều lần trong cùng một phiên, với các loại hiểu lầm khác nhau xảy ra sau mỗi lần compact. Tôi coi đây là những thất bại có cấu trúc của đặc tả compact tiêu chuẩn chứ không phải là những tai nạn cá biệt.

Những Gì Tôi Đã Xây Dựng

(1) Kỹ năng compact-prep

Một kỹ năng được triển khai dưới dạng lệnh gạch chéo mà người dùng chủ động gõ trước khi gõ /compact. Nó trích xuất "cấu trúc quyết định" và "trạng thái phiên" mà có khả năng sẽ không nằm gọn trong bản tóm tắt và lưu chúng vào một tệp trạng thái tại một đường dẫn cố định (${TMPDIR}/claude-compact-state/<session_id>.md) theo một định dạng cụ thể.

Các mục được lưu bao gồm những thứ khó nắm bắt trong các bản tóm tắt:

  • Kế hoạch Hoạt động (đường dẫn tệp kế hoạch và giai đoạn hiện tại)
  • Tóm tắt Danh sách Nhiệm vụ (các nhiệm vụ đang thực hiện và bổ sung)
  • Quyết định Phiên (các kế hoạch được chấp nhận / kế hoạch bị từ chối / lý do từ chối)
  • Các Ràng buộc và Vật cản
  • Cấu trúc liên kết Worker (các ngăn tmux-bridge / vai trò / phân công)
  • Các Tệp đang Chỉnh sửa (ghi chú về các thay đổi chưa lưu hoặc chưa xác minh)
  • Ghi chú Phục hồi (một lá thư gửi cho bản thân sau khi nén)

Điểm thiết kế chính là "thực thi một cách máy móc". Nó sử dụng một cổng chặn cứng để ngăn việc tạo tệp nếu không tìm thấy session_id, một chức năng thúc đẩy với các tiêu đề cố định để phát hiện thiếu sót, và các công cụ được phép hạn chế để ngăn hỏng trạng thái.

(2) Hook hai giai đoạn: PostCompact + UserPromptSubmit

Ngay cả khi (1) ghi một tệp trạng thái, nó cũng vô nghĩa nếu agent sau khi nén không đọc nó. Vì PostCompact không thể trả về additionalContext, tôi đã sử dụng cấu hình hai giai đoạn:

  1. Hook PostCompact ghi một tệp đánh dấu với session_id (không có chỉ thị, chỉ ghi lại rằng quá trình nén đã xảy ra).
  2. Khi hook UserPromptSubmit tiếp theo phát hiện tệp đánh dấu, nó sẽ tiêm các chỉ thị thông qua additionalContext: "Đọc tệp kế hoạch / Đọc tệp trạng thái / Kiểm tra Danh sách Nhiệm vụ / Coi các bước tiếp theo của bản tóm tắt là giả thuyết / Xác nhận tái nhập nếu chế độ kế hoạch bị vô hiệu hóa", sau đó xóa tệp đánh dấu.

Vì Claude Code thiếu cơ chế trạng thái chia sẻ giữa các hook, một tệp đánh dấu trên hệ thống tệp là con đường giao tiếp duy nhất. Điều này giữ cho mỗi hook gọn nhẹ với một trách nhiệm duy nhất. Trong các lượt bình thường, chi phí chỉ là một lần kiểm tra test -f.

(3) Thông báo 60% (Để tránh compact tự động)

Các công cụ trước đây giả định người dùng chạy thủ công /compact-prep → /compact. Tuy nhiên, compact tự động chạy mà không báo trước, bỏ qua luồng này. Nếu compact tự động xảy ra trước, tệp trạng thái sẽ không được lưu và các nhật ký thô bị nghiền nát thành một bản tóm tắt, làm mất tài liệu phục hồi.

Giải pháp là tạo ra một trạng thái nơi người dùng có thể chạy thủ công bước chuẩn bị trước khi compact tự động kích hoạt. Đây là mục đích của thông báo 60%.

Tại sao là 60%?

  • Đủ thời gian dẫn trước: Compact tự động kích hoạt ở khoảng 90-95%. 60% cung cấp một khoảng đệm 30%, đảm bảo người dùng nhìn thấy cảnh báo trước khi lượt tiếp theo kích hoạt compact tự động.
  • Chỗ để đạt đến điểm dừng: Ở mức 60%, vẫn còn 30% dung lượng để hoàn thành một nhiệm vụ phụ trước khi lưu trạng thái.
  • Kích hoạt máy móc: Nó hoạt động như một chức năng thúc đẩy khi bạn quá tập trung để nhận thấy mức tiêu thụ ngữ cảnh.
  • Giả định Ngữ cảnh 1M: Với ngữ cảnh 200K, 60% là quá nhỏ. Tôi sử dụng ngữ cảnh 1M (Opus 4.7), nơi 60% để lại khoảng 600K token—đủ chỗ để hoàn thành công việc và chạy bước chuẩn bị.

Việc triển khai liên quan đến một hook statusline ghi một tệp đánh dấu cảnh báo tại ngưỡng, và một hook UserPromptSubmit phát hiện nó để đề xuất chạy /compact-prep.

Kết Quả

Các phiên làm việc hiện đã ổn định ngay cả sau khoảng 10 lần nén mà không bị đổ vỡ logic!

  • Mất mát công việc do nén gần như bằng không.
  • Các đề xuất lại ý tưởng đã bị từ chối đã biến mất.
  • Chế độ kế hoạch được duy trì.
  • Không còn quên cấu trúc liên kết khi chạy nhiều worker trong tmux.

Tham Khảo: Mã Triển Khai

Dưới đây là mã kỹ năng và hook thực tế. Chúng hoạt động bằng cách sao chép chúng vào thư mục Claude Code tiêu chuẩn (~/.claude/).

A: Nội dung kỹ năng compact-prep

Đặt tại ~/.claude/skills/compact-prep/SKILL.md.

markdown
1---
2name: compact-prep
3description: |
4 Trước khi thực thi /compact trong Claude Code, lưu trạng thái phiên hiện tại vào một tệp trạng thái tạm thời.
5 KÍCH HOẠT BẮT BUỘC: /compact-prep, compact-prep, chuẩn bị nén.
6 KHÔNG KÍCH HOẠT: phục hồi sau nén, báo cáo tiến độ bình thường, tạo kế hoạch.
7strict_procedure: true
8argument-hint: "[ghi chú phục hồi]"
9allowed-tools: Read Write Bash(~/.claude/scripts/get-session-id.sh *) Bash(mkdir *) Bash(date *) Bash(pwd)
10---
11
12# compact-prep
13
14Lưu trạng thái phiên khó giữ trong các bản tóm tắt nén vào
15`${TMPDIR}/claude-compact-state/${SESSION_ID}.md` trước `/compact`.
16
17## Hồ sơ quy trình nghiêm ngặt
18
19- Mức độ nghiêm ngặt: quy trình nghiêm ngặt.
20- Cổng chặn cứng: Dừng nếu không thể lấy session_id.
21- Chức năng thúc đẩy: Đường dẫn cố định và kiểm tra tiêu đề bắt buộc sau khi lưu.
22- Biên nhận hoàn thành: Báo cáo đường dẫn tệp, các mục đã lưu và hướng dẫn chạy `/compact`.
23
24## Quy trình
25
261. Lấy session_id qua `~/.claude/scripts/get-session-id.sh`.
272. Đặt đường dẫn đến `${TMPDIR:-/tmp}/claude-compact-state/${SESSION_ID}.md`.
283. Kiểm tra TaskList, kế hoạch hoạt động, tmux-bridge và các tệp đang chỉnh sửa.
294. Lưu các tiêu đề theo thứ tự: # Compact Prep State, ## Active Plan, ## Current Phase, ## TaskList Summary, ## Session Decisions, ## Constraints and Blockers, ## Worker Topology, ## Editing Files, ## Recovery Notes.
305. Xác minh tất cả các tiêu đề tồn tại.
316. Nói với người dùng: "Quá trình chuẩn bị hoàn tất. Vui lòng thực thi `/compact`."

B: Hook phục hồi (2 giai đoạn)

B-1: Hook PostCompact

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

B-2: Hook UserPromptSubmit (Tiêm)

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

C: Thông báo 60%

C-1: Nhánh ngưỡng hook statusline

Được thêm vào ~/.claude/hooks/statusline.sh.

C-2: Hook UserPromptSubmit (Nhắc nhở)

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

D: Đăng ký settings.json

Thêm các hook vào ~/.claude/settings.json.

Lưu một chạm

Đọc sâu bài viết viral bằng AI trong YouMind

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

Explore YouMind
Dành cho nhà sáng tạo

Biến Markdown của bạn thành bài viết 𝕏 gọn gàng

Khi bạn đăng bài viết dài của riêng mình, việc định dạng hình ảnh, bảng và khối mã cho 𝕏 rất mệt mỏi. YouMind biến cả bản nháp Markdown thành một bài viết 𝕏 gọn gàng, sẵn sàng để đăng.

Thử Markdown sang 𝕏

Thêm pattern để giải mã

Bài viết viral gần đây

Khám phá thêm bài viết viral