Giữ context cho coding agent qua nhiều session
Cách nhận ra agent đang mất context, viết bản bàn giao gọn và chuyển session mà không phải kể lại mọi thứ từ đầu.
18 min read

Ở bài trước, mình đã đi từ một feature còn mơ hồ tới spec và các task nhỏ có thể kiểm tra riêng.
Nhưng task nhỏ không có nghĩa là lúc nào cũng làm xong trong một session.
Có task mình phải dừng để chờ API. Có task tìm hiểu buổi sáng, làm buổi chiều, hôm sau mới chạy được integration test. Cũng có lúc đang sửa auth thì một bug production chen ngang, vài tiếng sau quay lại mình còn không nhớ chính mình đã chốt gì.
Coding agent cũng gặp đúng vấn đề đó, chỉ nhanh hơn mình một chút.
Đầu session nó đọc đúng file, nhắc lại đúng giới hạn và đưa ra kế hoạch khá ổn. Sau một loạt command, log dài, diff, feedback và vài lần đổi hướng, nó bắt đầu hỏi lại những thứ đã nói. Tệ hơn là nó không hỏi. Nó âm thầm dùng giả định cũ và tiếp tục code.
Lúc này viết prompt dài hơn thường không cứu được nhiều.
Thứ mình cần là đặt đúng loại thông tin vào đúng chỗ, biết khi nào context bắt đầu “lụt nghề”, và có cách chuyển việc sang session tiếp theo mà không dựa vào trí nhớ của đoạn chat.
Task nhỏ vẫn có thể tạo ra context rất lớn
Ở bài đầu tiên của series, mình đã giải thích context window là gì. Bài này mình không lặp lại định nghĩa đó nữa.
Điểm quan trọng cần nhớ là context của coding agent không chỉ có prompt mình vừa gõ.
Nó còn có hướng dẫn hệ thống, AGENTS.md hoặc CLAUDE.md, lịch sử hội thoại, file agent đã đọc, đầu ra của câu lệnh, log lỗi, diff, nội dung từ công cụ và cả câu trả lời do chính agent tạo ra.
Mỗi thứ nhìn riêng có vẻ không nhiều. Cộng lại qua một session dài thì khác.
Ví dụ một task sửa login redirect có thể bắt đầu rất gọn:
Sau đó agent đọc middleware, route handler, session service, test cũ và config cookie. Nó chạy test ba lần, mỗi lần trả về vài trăm dòng log. Mình sửa lại requirement. Agent thử một hướng rồi revert. Cuối cùng task chỉ đổi mười dòng code, nhưng context đã chứa cả một buổi làm việc.
Độ lớn của diff và độ lớn của context là hai chuyện khác nhau.

Nhiều context hơn chưa chắc tốt hơn
Mình từng nghĩ context càng nhiều thì agent càng ít đoán.
Điều đó chỉ đúng khi phần lớn context còn liên quan và không mâu thuẫn nhau.
Một session dài thường giữ lại cả những thứ đã hết hạn:
- Requirement cũ trước khi mình đổi ý
- Error log của hướng triển khai đã bỏ
- File agent đọc trong lúc tìm hiểu nhưng cuối cùng không liên quan
- Một plan cũ không còn khớp với diff hiện tại
- Feedback tạm thời chỉ đúng ở một bước
- Những câu trả lời dài do agent tự tạo ra
Agent không nhìn context như mình nhìn một folder đã được sắp xếp. Nó nhận một khối thông tin và phải suy ra phần nào còn quan trọng cho token tiếp theo.
Nếu trong đó có ba phiên bản của cùng một quyết định, mình đang bắt model tự đoán phiên bản nào là mới nhất.
Context tốt không phải context chứa nhiều nhất. Nó là context có đủ thông tin đúng, ít mâu thuẫn và có một nguồn chuẩn rõ ràng.
Dấu hiệu agent đang mất context
Context đầy không phải lúc nào cũng hiện ra bằng một thông báo rõ ràng.
Mình thường nhìn vào chất lượng hành vi của agent hơn là chỉ nhìn số token.
Một vài dấu hiệu khá dễ thấy:
- Agent hỏi lại constraint vừa được xác nhận
- Nó mở lại cùng một file nhiều lần nhưng vẫn hiểu sai flow
- Plan ở đầu session nói một kiểu, diff cuối session đi theo kiểu khác
- Nó sửa ra ngoài phạm vi dù ranh giới đã được nhắc rõ
- Một bug vừa fix xong lại xuất hiện ở bước sau
- Agent bắt đầu trả lời chung chung thay vì chỉ vào file và cách hoạt động cụ thể
- Nó nhầm một giả định cũ thành quyết định đã được chốt
- Sau , nó nhớ mục tiêu lớn nhưng mất chi tiết quan trọng
Một dấu hiệu riêng lẻ chưa đủ kết luận model đã "quên". Có thể instruction viết mơ hồ, hai rule mâu thuẫn, hoặc codebase vừa thay đổi.
Nhưng nếu nhiều dấu hiệu xuất hiện cùng lúc, mình sẽ dừng việc implement. Tiếp tục đẩy agent đi trong context đang nhiễu thường chỉ tạo thêm diff để mình dọn.
Một tín hiệu nghe hơi ngớ ngẩn nhưng lại có ích
Mình thấy một tweet khá hài của @changloria0816. Ý tưởng là thêm instruction này vào CLAUDE.md:

Nghe hơi buồn cười, nhưng ý phía sau khá hay. Và thật ra mấy mẹo hơi ngớ ngẩn thường lại là mấy thứ mình nhớ lâu nhất.
Trong vận hành hệ thống, canary là một tín hiệu nhỏ, rẻ và dễ quan sát. Nếu tín hiệu biến mất, mình biết có thứ gì đó đáng kiểm tra.
Với coding agent, canary có thể là một format trả lời, một câu xác nhận ngắn hoặc một rule vô hại nhưng dễ nhận biết. Khi agent đột nhiên không làm nữa, có thể instruction không được load, đã bị context khác lấn át, hoặc mức độ bám instruction đang giảm.
Canary không phải bằng chứng tuyệt đối
Agent quên gọi bạn là Husband chưa chắc context đã hỏng. Một instruction khác có thể xung đột, agent có thể ưu tiên nội dung quan trọng hơn, hoặc chính bạn đã yêu cầu format khác. Hãy dùng nó như tín hiệu để kiểm tra, không phải trigger tự động xoá session ngay lập tức.
Mình cũng không recommend thêm mười câu kỳ lạ vào AGENTS.md chỉ để test agent. Canary mà làm instruction file dài và nhiễu thì nó tự tạo ra vấn đề mình đang muốn phát hiện.
Một tín hiệu nhỏ là đủ.
Mỗi loại thông tin nên có một chỗ ở
Phần khó nhất của quản lý context không phải là nhớ command /compact hay /clear.
Phần khó là biết thông tin nào phải sống lâu và thông tin nào nên biến mất sau task.
Mình thường chia thành năm nhóm:
| Loại thông tin | Nơi nên lưu | Ví dụ |
|---|---|---|
| Rule ổn định của repo | AGENTS.md, CLAUDE.md hoặc project docs | Dùng pnpm, không sửa migration đã deploy |
| Cách hoạt động cần xây | Đặc tả hoặc task | Lời mời hết hạn sau 48 giờ |
| Bằng chứng đang phân tích | Working context của session | File vừa đọc, log test, diff tạm thời |
| Trạng thái để làm tiếp | Handoff hoặc task notes | Đã xong API, còn UI và integration test |
| Bài học dùng lại | Memory hoặc docs | Auth test cần Redis local, pattern pagination của project |
Năm nhóm này liên quan nhau nhưng không thay thế nhau.
Sổ tay project giữ quy tắc bắt buộc
Nếu team luôn phải chạy một command trước khi merge, rule đó không nên chỉ nằm trong memory cá nhân của một agent.
Nó cần ở nơi người khác và agent khác đều đọc được, review được và cập nhật cùng codebase.
Đây là vai trò của AGENTS.md, CLAUDE.md hoặc docs được reference rõ. Chương 03 đã nói kỹ cách viết phần này, nên mình chỉ giữ một nguyên tắc ở đây:
Quy tắc bắt buộc phải có một nguồn chuẩn bền vững.
Spec và task giữ điều mình đang muốn thay đổi
Một quyết định của tính năng không phải quy ước chung của project.
Ví dụ "invitation hết hạn sau 48 giờ" thuộc spec của feature. Nhét nó vào AGENTS.md sẽ khiến mọi task sau này phải mang theo một chi tiết không liên quan.
Task tiếp tục thu nhỏ spec thành kết quả, phạm vi, tiêu chí hoàn thành và cách kiểm tra cho một lát cắt cụ thể.
Context đang dùng là đồ trên bàn
File agent vừa đọc, kết quả test và diff tạm thời giống giấy tờ đang mở trên bàn làm việc.
Chúng hữu ích trong lúc xử lý task. Nhưng không phải thứ gì trên bàn cũng cần được đóng thành tài liệu lâu dài.
Khi session kết thúc, phần lớn working context có thể bỏ.
Bản bàn giao giữ trạng thái chuyển tiếp
Bản bàn giao, hay , trả lời câu hỏi: nếu một agent khác bắt đầu ngay bây giờ, nó cần biết gì để tiếp tục mà không phải tìm hiểu lại từ đầu?
Nó không phải transcript rút gọn. Nó là snapshot có chủ đích của trạng thái hiện tại.
Memory giữ bài học có thể dùng lại
Memory hợp với sở thích, cách làm, quyết định hoặc lỗi có khả năng xuất hiện ở task khác.
Nó không nên là nơi duy nhất giữ rule bắt buộc. Tài liệu hiện tại của Codex cũng khuyên để team guidance bắt buộc trong AGENTS.md hoặc checked-in docs, còn memory là lớp recall hỗ trợ.
Đây là boundary mình thấy dễ nhớ nhất:
Compact hay mở session mới
Không phải lúc nào context dài cũng cần reset.
Nếu agent vẫn bám đúng mục tiêu, quyết định hiện tại còn rõ và mình chỉ cần thêm chỗ để hoàn thành cùng một task, compaction có thể hợp lý. Nó thay phần lịch sử dài bằng một bản tóm tắt ngắn hơn.
Nhưng summary vẫn là summary.
Chi tiết nào được giữ lại phụ thuộc vào tool, instruction mình đưa khi compact và cách model đánh giá mức độ quan trọng. Mục tiêu lớn thường sống sót tốt hơn một edge case nằm giữa vài trăm dòng log.
Mình sẽ mở session mới khi:
- Chuyển sang một task khác không liên quan
- Phần tìm hiểu đã xong và nguồn chuẩn đã được viết thành đặc tả hoặc task
- Session đã đi qua nhiều hướng sai và chứa quá nhiều giả định cũ
- Agent liên tục bỏ qua ranh giới dù mình đã sửa prompt
- Mình không còn tự tin đâu là quyết định mới nhất trong đoạn chat
- Context canary biến mất cùng lúc với các dấu hiệu hiểu sai khác
Mình sẽ giữ session hiện tại hoặc compact khi:
- Vẫn đang xử lý cùng một kết quả
- Các quyết định chính chưa thay đổi
- Agent còn chỉ đúng file, test và giới hạn
- Phần nhiễu chủ yếu là đầu ra công cụ quá dài, không phải nhiều phiên bản yêu cầu
- Mình có thể nói rõ bản tóm tắt cần ưu tiên giữ lại điều gì
Claude Code hiện có /context để xem thứ gì đang chiếm context, /compact để tóm tắt lịch sử và /clear để bắt đầu context sạch trong cùng project. Tên command và hành vi ở tool khác có thể khác, nên đừng biến ba command này thành rule chung cho mọi coding agent.
Quan trọng hơn câu lệnh là ranh giới:
Cùng task, context còn sạch thì tiếp tục. Task mới hoặc context đã mất nguồn chuẩn thì chuyển session.
Bản bàn giao tốt không phải bản chép lại cuộc trò chuyện
Bản bàn giao dài mười trang thường chỉ chuyển nguyên cục rối từ session cũ sang session mới. Agent mới chưa làm gì đã phải đọc hồi ký.
Agent mới không cần biết mọi câu mình và agent cũ đã nói. Nó cần biết quyết định nào đã chốt, trạng thái code hiện tại, cách kiểm tra và bước tiếp theo.
Mình dùng mẫu tối thiểu như sau:
Không phải task nào cũng cần đủ mọi tiêu đề. Nhưng ba thứ không nên thiếu là quyết định đã chốt, kết quả kiểm tra hiện tại và bước tiếp theo.

Ví dụ bản bàn giao từ tính năng lời mời
Tiếp tục ví dụ lời mời vào workspace ở chương 04.
Giả sử task hiện tại là cho phép người nhận chấp nhận lời mời. Session đầu đã tìm hiểu luồng và làm API, nhưng chưa xong phần transaction với thành viên.
Một bản bàn giao hữu ích có thể như vầy:
Session mới không cần đọc lại toàn bộ cuộc tranh luận trước đó về thời hạn 24 hay 48 giờ. Quyết định cuối cùng đã nằm trong bản bàn giao và đặc tả.
Nó cũng không cần đoán bước tiếp theo. Ranh giới đã đủ nhỏ để bắt đầu bằng một lượt tìm hiểu có mục tiêu.
Prompt bắt đầu session tiếp theo
Bản bàn giao chỉ hữu ích khi agent thật sự đọc và đối chiếu nó với nguồn chuẩn.
Mình thường bắt đầu session mới bằng prompt ngắn:
Bước tóm tắt này nghe có vẻ tốn thêm một lượt. Với mình nó rẻ hơn nhiều so với để agent làm dựa trên bản bàn giao đã cũ.
Đừng yêu cầu agent "tiếp tục như cũ" rồi mong nó tự tìm đúng trạng thái session. Hãy đưa cho nó task hoặc bản bàn giao cụ thể và bắt đầu bằng một lượt chỉ đọc.
Cách mình đi qua nhiều session
Nếu một task không thể hoàn thành trong một lượt, mình thường đi theo vòng này:
- Bắt đầu từ sổ tay project và một task có kết quả rõ.
- Cho agent tìm hiểu đúng vùng code liên quan.
- Ghi quyết định quan trọng vào đặc tả hoặc task, không để chúng chỉ nằm trong chat.
- Làm một phần có thể kiểm tra, rồi chạy bước liên quan.
- Nếu phải dừng, viết bản bàn giao từ trạng thái thật của code và test.
- Session mới đọc nguồn chuẩn, kiểm tra lại file rồi mới tiếp tục.
- Khi task xong, chỉ giữ lại memory hoặc tài liệu có khả năng dùng cho task khác.
Từ khi dùng Knowns, mình thường để mục tiêu, tiêu chí hoàn thành và tiến độ trong task; đặc tả hoặc giải thích dài hơn nằm trong doc; còn memory chỉ giữ những cách làm và lỗi đáng dùng lại.
Thay vì chép cả đoạn chat sang session mới, mình có thể trỏ agent tới @task-123 hoặc @doc/feature-invitations. Agent đọc đúng nguồn hiện tại, còn mình đỡ phải nhớ lần trước đã giải thích tới đâu.
Knowns không làm context window lớn hơn.
Nó chỉ giúp những thứ quan trọng có nơi ở bên ngoài context window.
Những thứ mình không đưa vào memory
Memory rất dễ trở thành cái kho "biết đâu sau này cần".
Một thời gian sau, agent phải đọc cả những ghi chú hết hạn, giả định chưa xác nhận và cách chữa tạm đã được xoá khỏi code.
Mấy thứ mình thường không giữ:
- Toàn bộ transcript của session
- Log lỗi đã giải quyết xong
- Tiến độ tạm thời của một task đã hoàn thành
- Giả định chưa được xác nhận
- Quy tắc bắt buộc nhưng không có trong tài liệu repo
- Nội dung có secret, token hoặc thông tin đăng nhập
Nếu một ghi chú chỉ trả lời “hôm qua đang làm tới đâu”, nó là bản bàn giao.
Nếu nó trả lời “project này thường giải quyết loại vấn đề này thế nào”, nó có thể là memory hoặc tài liệu.
Nếu team bắt buộc phải tuân theo nó, đưa nó về nguồn chuẩn được version control.
Kết
Context window lớn tới đâu rồi cũng có lúc chứa quá nhiều thứ cũ.
Mình không cố giữ một session sống mãi nữa. Mình cố giữ nguồn chuẩn rõ, task đủ nhỏ và bản bàn giao đủ gọn để session mới có thể bắt đầu mà không phải nghe kể lại toàn bộ lịch sử.
Project instructions giữ rule ổn định.
Spec và task giữ điều đang cần xây.
Working context phục vụ bước hiện tại.
Handoff giữ trạng thái chuyển giao.
Memory giữ bài học có khả năng dùng lại.
Khi mỗi loại thông tin có đúng nơi ở, reset context không còn đáng sợ. Nó chỉ giống đóng bàn làm việc cuối ngày rồi sáng hôm sau mở lại đúng tài liệu cần thiết.
Và nếu một agent đã có thể nhận việc qua handoff rõ ràng, bước tiếp theo khá tự nhiên là cho nhiều agent làm những phần khác nhau mà không giẫm chân nhau.
Đó sẽ là bài tiếp theo.
See yah.
Tài liệu tham khảo
Powered by giscus · GitHub Discussions