Context window là gì
Context window là lượng token tối đa mà model có thể "nhìn thấy" trong một lần gọi — gồm cả prompt bạn gửi vào lẫn phần model sinh ra. Ví dụ một model có cửa sổ 200K token: nếu prompt của bạn chiếm 195K, model chỉ còn 5K để trả lời.
Token không phải là từ. Một quy tắc ước lượng nhanh cho tiếng Anh là ~4 ký tự/token; tiếng Việt có dấu thường "tốn" token hơn. Hãy luôn coi context window như một ngân sách hữu hạn phải chi tiêu khôn ngoan.
Short-term memory sống trong context window
Bộ nhớ ngắn hạn của agent chính là những gì bạn nhồi vào cửa sổ này ở mỗi lượt: system prompt + lịch sử hội thoại + kết quả tool. Khi hội thoại dài ra, phần lịch sử phình lên và bạn sẽ chạm trần.
Hãy nhìn cấu trúc một prompt hội thoại điển hình:
[system] Bạn là trợ lý chăm sóc khách hàng của Shop A...
[user] Đơn VN-8842 bao giờ giao?
[assistant] Đơn của bạn dự kiến giao 12/07.
[user] Đổi sang địa chỉ khác được không?
... (còn 40 lượt nữa) ...
[user] <câu hỏi mới nhất>
Mỗi lượt mới, bạn gửi lại TẤT CẢ. Đây là lý do chi phí và độ trễ tăng dần theo độ dài hội thoại.
Bốn chiến lược quản lý cửa sổ khi hội thoại dài
- Truncation (cắt cụt): chỉ giữ N lượt gần nhất, bỏ phần đầu. Đơn giản, rẻ, nhưng mất ngữ cảnh cũ.
- Summarization (tóm tắt cuộn): khi lịch sử vượt ngưỡng, gọi LLM tóm tắt phần cũ thành một đoạn ngắn, thay thế cho các lượt gốc.
- Sliding window + pinned facts: giữ vài lượt gần nhất + một khối "facts đã ghim" (tên khách, mã đơn) không bao giờ bị cắt.
- Offload ra long-term: đẩy thông tin cũ ra vector store, chỉ nạp lại khi liên quan (đây là cầu nối sang RAG, học ở bài sau).
Các bước triển khai một bộ đệm hội thoại có kiểm soát
- Đặt ngưỡng token tối đa cho phần lịch sử (ví dụ 3000 token).
- Sau mỗi lượt, ước lượng token của toàn bộ lịch sử.
- Nếu vượt ngưỡng: tóm tắt các lượt cũ nhất thành một message
summary. - Luôn giữ nguyên system prompt và các "pinned facts".
- Ghép lại:
[system] + [summary] + [N lượt gần nhất] + [câu mới].
Pseudocode: summarization cuộn
MAX_TOKENS = 3000
def build_prompt(history, pinned_facts, new_msg):
if count_tokens(history) > MAX_TOKENS:
old = history[:-6] # phần cũ
recent = history[-6:] # 6 lượt gần nhất giữ nguyên
summary = llm_summarize(old) # 1 lời gọi LLM để nén
history = [{"role": "system",
"content": "Tóm tắt trước đó: " + summary}] + recent
return [SYSTEM_PROMPT, pinned_facts] + history + [new_msg]
Lưu ý: llm_summarize tốn thêm một lời gọi, nên chỉ chạy khi thật sự vượt ngưỡng, không chạy mỗi lượt.
Checklist quản lý context window
- [ ] Đã biết context window của model đang dùng là bao nhiêu token?
- [ ] Đã đặt ngân sách riêng cho: system / history / tool output / phần chừa cho câu trả lời?
- [ ] Có cơ chế xử lý khi history vượt trần (cắt hay tóm tắt)?
- [ ] Các fact quan trọng (mã đơn, tên) có được ghim để không bị cắt nhầm?
- [ ] Có log lại số token thực tế mỗi request để giám sát chi phí?
Sai lầm thường gặp
- Coi "cửa sổ lớn" là vô hạn. Model 1M token vẫn tốn tiền theo token và vẫn có hiện tượng "lost in the middle" — thông tin ở giữa prompt dài dễ bị bỏ sót.
- Tóm tắt mỗi lượt. Lãng phí lời gọi và làm mất chi tiết dần qua nhiều lần nén liên tiếp.
- Cắt cụt mù quáng. Cắt mất mã đơn hàng ở lượt đầu khiến agent "quên" đúng thứ quan trọng nhất.
- Quên chừa chỗ cho output. Nhồi prompt sát trần khiến model không đủ token để trả lời trọn vẹn.
Tổng kết
Context window là ngân sách token; short-term memory là cách bạn chi tiêu ngân sách đó qua mỗi lượt. Nắm truncation, summarization và pinned facts là bạn đã kiểm soát được 80% bài toán bộ nhớ ngắn hạn.