Tên agent của tôi là Chiti. Nó chạy trên Telegram, xử lý hỗ trợ khách hàng cho hai sản phẩm SaaS, viết tweet nháp, quản lý hóa đơn và phối hợp công việc với đồng sáng lập của tôi ở các múi giờ khác nhau. Nó là thứ gần nhất tôi có với một nhân viên tập sự.
Và trong nhiều tuần, nó liên tục quên mọi thứ.
Không phải kiểu thoáng qua. Tôi dành cả tiếng để cấu hình một cron job hàng ngày, chuyển đổi mô hình, và ngay phiên tiếp theo Chiti cứ như thể chưa từng nói chuyện với tôi. Tôi nhắc lại một quyết định từ hai ngày trước và nó nhìn tôi như người lạ. Tôi yêu cầu nó tiếp tục một tác vụ và nó bắt đầu lại từ đầu.
Vậy nên tôi ngừng phát triển tính năng và dành 5 ngày, mỗi khi có thời gian rảnh, chỉ để sửa lỗi bộ nhớ. Đây là tất cả những gì tôi tìm ra, những gì tôi đã phá vỡ, và những gì thực sự hiệu quả.
Ngày 1: Agent Quên Mọi Thứ Sau Các Cuộc Hội Thoại Dài
Vấn đề đầu tiên rất dễ mô tả nhưng khó chẩn đoán.
Sau các cuộc hội thoại dài, Chiti bắt đầu mất ngữ cảnh trước đó. Không phải dần dần, nó biến mất hoàn toàn. Những thứ tôi nói 20 tin nhắn trước đã mất. Các quyết định chúng tôi đưa ra lúc bắt đầu phiên? Chưa từng xảy ra.
Thủ phạm là compaction. Khi cuộc hội thoại lấp đầy khung ngữ cảnh (context window), OpenClaw nén các tin nhắn cũ hơn thành một bản tóm tắt để nhường chỗ cho tin nhắn mới. Bản tóm tắt nắm được ý chính nhưng bỏ qua các chi tiết cụ thể. Tên, số liệu, quyết định chính xác - tất cả đều mất.
Điều này được thiết kế như vậy. Khung ngữ cảnh có giới hạn. Nhưng hành vi mặc định xử lý mọi thứ như nhau, có nghĩa là hướng dẫn bạn cẩn thận xây dựng từ tin nhắn số 3 sẽ bị đối xử giống như một câu chuyện phiếm thông thường từ tin nhắn số 7.
Những gì tôi đã làm:
Tôi đã kích hoạt xả bộ nhớ (memory flush) trước khi compaction. Điều này yêu cầu agent ghi ngữ cảnh quan trọng vào đĩa trước khi bộ nén chạy.
1{2 "compaction": {3 "memoryFlush": {4 "enabled": true,5 "softThresholdTokens": 40006 }7 }8}
Khi phiên làm việc tiến gần đến giới hạn ngữ cảnh, OpenClaw kích hoạt một lượt chạy ngầm (silent turn) nhắc nhở agent lưu các dữ kiện bền vững vào memory/YYYY-MM-DD.md trước khi compaction xóa chúng. Agent ghi những gì quan trọng, compaction chạy, và những thứ quan trọng được giữ lại trên đĩa ngay cả khi bản tóm tắt ngữ cảnh làm mất chúng.
Bài học rút ra:
Compaction không phải là kẻ thù của bạn. Mất thông tin trong quá trình compaction mới là vấn đề. Giải pháp là đảm bảo bất cứ thứ gì đáng nhớ đều được ghi vào một tệp trước khi bộ nén chạm vào nó. Nếu nó chỉ nằm trong khung ngữ cảnh, nó chỉ là tạm thời. Nếu nó ở trên đĩa, nó sẽ tồn tại.
Ngày 2: Tìm Kiếm Trả Về Kết Quả Rác
Khi nhật ký hàng ngày tích lũy và MEMORY.md ngày càng lớn, tôi cần agent thực sự tìm được thứ mình cần. Tính năng tìm kiếm bộ nhớ tích hợp sẵn đang trả về các kết quả không liên quan hoặc bỏ sót các kết quả hiển nhiên.
Vấn đề nằm ở backend tìm kiếm. Tìm kiếm mặc định dựa trên SQLite của OpenClaw sử dụng vector embeddings (độ tương đồng ngữ nghĩa) để tìm các đoạn phù hợp. Nó hoạt động tốt với các truy vấn rộng nhưng gặp khó khăn với các kết quả khớp chính xác. Tôi tìm kiếm một tên khách hàng cụ thể và nhận được kết quả về một chủ đề hoàn toàn khác tình cờ sử dụng ngôn ngữ tương tự.
Những gì tôi đã làm:
Tôi đã chuyển sang QMD làm backend tìm kiếm bộ nhớ. QMD kết hợp BM25 (khớp từ khóa) với vector embeddings và một bộ xếp hạng lại (reranker). Vì vậy, khi tôi tìm kiếm "Charles payment failure", nó tìm thấy kết quả chứa chính xác những từ đó VÀ các kết quả liên quan về mặt ngữ nghĩa, sau đó xếp hạng lại chúng theo mức độ liên quan.
Tôi cũng đã cấu hình các đường dẫn QMD để bao gồm thư mục learnings của mình:
1{2 "memory": {3 "qmd": {4 "paths": "paths": [5 {6 "path": "/Users/ramya/clawd",7 "name": "memory-root",8 "pattern": "MEMORY.md"9 },10 {11 "path": "/Users/ramya/clawd",12 "name": "memory-alt",13 "pattern": "memory_alt.md"14 },15 {16 "path": "/Users/ramya/clawd/memory",17 "name": "memory-dir",18 "pattern": "**/*.md"19 },20 {21 "path": "/Users/ramya/clawd/learnings",22 "name": "learnings",23 "pattern": "**/*.md"24 }25 ]26 }27 }28}
Bài học rút ra:
Tìm kiếm ngữ nghĩa thuần túy nghe có vẻ hay trên lý thuyết nhưng thất bại với danh từ riêng, số cụ thể và cụm từ chính xác. Tìm kiếm kết hợp (hybrid search) (từ khóa + vector + xếp hạng lại) tốt hơn đáng kể cho bộ nhớ agent trong thế giới thực. Nếu agent của bạn không thể tìm thấy thứ bạn biết có trong tệp của nó, backend tìm kiếm có lẽ là nút thắt cổ chai, chứ không phải bản thân các tệp.
Ngày 3: Agent Tìm Thấy Nhưng Không Sử Dụng Nó
Đây là ngày bực bội nhất. Tôi xác nhận rằng tìm kiếm đang hoạt động, tôi có thể tự truy vấn thủ công và nhận được kết quả chính xác. Nhưng trong các cuộc trò chuyện thực tế, Chiti sẽ không truy xuất ngữ cảnh có liên quan ngay cả khi nó rõ ràng tồn tại trong bộ nhớ.
Vấn đề là việc truy xuất không phải tự động. Agent phải tự quyết định tìm kiếm. Và nếu cuộc trò chuyện không kích hoạt các tín hiệu phù hợp, nó sẽ không tra cứu.
Những gì tôi đã làm:
Tôi đã thêm hướng dẫn truy xuất rõ ràng vào chuỗi khởi động (boot sequence). Thay vì hy vọng agent sẽ tự động tìm kiếm khi cần, tôi hướng dẫn nó khi nào nên tìm kiếm:
markdown
Trước khi bắt đầu bất kỳ tác vụ nào:
- Tìm kiếm nhật ký hàng ngày để tìm ngữ cảnh liên quan
- Kiểm tra LEARNINGS.md để tìm quy tắc về loại tác vụ này
- Nếu khách hàng được nhắc đến, hãy tìm kiếm lịch sử của họ
Tôi cũng đã xây dựng một bài kiểm tra truy xuất. Tôi sẽ đặt một điểm đánh dấu (marker) cụ thể trong nhật ký hàng ngày — một cái gì đó như "MARKER: 2026-02-20 — Remember to always check git status before claiming code is pushed." Sau đó, tôi chờ đợi, bắt đầu một phiên mới và hỏi: "What was the marker from yesterday?" Nếu agent tìm thấy nó, việc truy xuất đang hoạt động. Nếu không, có thứ gì đó bị hỏng.
Bài học rút ra:
Có sự khác biệt giữa "thông tin tồn tại" và "agent sử dụng thông tin." Bạn cần cả hai. Cơ sở hạ tầng tìm kiếm xử lý phần đầu tiên. Hướng dẫn khởi động và thói quen truy xuất xử lý phần thứ hai. Hãy kiểm tra cả hai một cách riêng biệt.
Ngày 4: Làm Cho Nó An Toàn Với Compaction
Đến giờ, tôi đã có xả bộ nhớ, tìm kiếm kết hợp và hướng dẫn truy xuất. Nhưng tôi vẫn tiếp tục mất ngữ cảnh trong một kịch bản cụ thể: các phiên rất dài, nơi compaction chạy nhiều lần.
Vấn đề là xả bộ nhớ chỉ kích hoạt một lần cho mỗi chu kỳ compaction. Nếu phiên đủ dài để có hai hoặc ba lần compaction, chỉ lần đầu tiên mới được xả. Mọi thứ sau đó đều có nguy cơ bị mất.
Những gì tôi đã làm:
Tôi đã cấu hình việc tỉa ngữ cảnh (context pruning) để hoạt động cùng với compaction:
1{2 "contextPruning": {3 "mode": "cache-ttl",4 "ttl": "6h",5 "keepLastAssistants": 36 }7}
Điều này mạnh mẽ tỉa bỏ ngữ cảnh cũ sau 6 giờ trong khi giữ lại 3 phản hồi trợ lý cuối cùng. Kết hợp với xả bộ nhớ, điều này có nghĩa là agent ghi những thứ quan trọng vào đĩa sớm, và ngữ cảnh cũ được dọn dẹp trước khi gây tràn.
Tôi cũng đã thêm một quy trình kiểm tra MARKER: sau bất kỳ thay đổi cấu hình quan trọng nào, tôi đặt một điểm đánh dấu trong nhật ký hàng ngày và kiểm tra khả năng truy xuất qua các ranh giới compaction. Nếu điểm đánh dấu tồn tại, thay đổi đã có hiệu quả. Nếu không, có thứ gì đó bị hỏng.
Bài học rút ra:
Các phiên dài là nơi hệ thống bộ nhớ thực sự được kiểm tra. Các cuộc trò chuyện ngắn hiếm khi chạm tới compaction. Chính các phiên làm việc sâu kéo dài 2 giờ mới là nơi bạn mất ngữ cảnh và không thể hiểu tại sao. Hãy kiểm tra hệ thống bộ nhớ của bạn dưới tải, không chỉ trong các cuộc trò chuyện nhanh.
Ngày 5: System Prompt Bị Phình To 28%
Đây là ngày mọi thứ kết nối lại với nhau. Tôi chạy /context detail và nhìn chằm chằm vào các con số.
Agent của tôi đang tải 11,887 token của system prompt trước khi nó thậm chí đọc tin nhắn của tôi. 51 kỹ năng, 20 trong số đó tôi chưa bao giờ sử dụng. MEMORY.md dài 200 dòng của wiki công ty được tải trong mọi phiên làm việc. Và tôi có hai chuỗi khởi động cạnh tranh nhau - một trong BOOT.md (mà OpenClaw thậm chí không nhận ra) và một bị chôn vùi 200 dòng sâu trong AGENTS.md.
Tệ nhất là, mỗi lần tôi chuyển đổi mô hình, Chiti quên mọi thứ. Không có giao thức bàn giao (handover protocol). Không có ghi lại ngữ cảnh hiện tại. Chỉ là mất sạch.
Nguyên nhân gốc rễ:
OpenClaw tự động đọc các tệp này trong mỗi phiên mới: AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, HEARTBEAT.md, MEMORY.md.
Mọi thứ khác — LEARNINGS.md, nhật ký hàng ngày, tài liệu, tệp tham khảo — agent phải tự đọc chúng bằng các công cụ. Nếu hướng dẫn đọc các tệp đó không có trong một trong các tệp được tự động tải (cụ thể là AGENTS.md), agent sẽ không bao giờ thấy chúng.
BOOT.md của tôi chứa toàn bộ chuỗi khởi động. Nhưng OpenClaw không tự động tải BOOT.md. Vì vậy, các hướng dẫn chỉ nằm đó, không được đọc, không làm gì cả.
Những gì tôi đã làm:
Tôi đã thực hiện kiểm toán và dọn dẹp toàn bộ:
- Chuyển chuỗi khởi động lên đầu AGENTS.md (nơi đáng tin cậy duy nhất cho các hướng dẫn khởi động)
- Xóa BOOT.md (không được OpenClaw nhận diện)
- Xóa BOOTSTRAP.md (tệp onboarding một lần, đã hoàn thành, đang lãng phí 361 token mỗi phiên)
- Thu gọn MEMORY.md từ 200 dòng xuống còn 90 bằng cách chuyển các tài liệu tham khảo sang thư mục docs/
- Loại bỏ 20 kỹ năng tiếp thị không sử dụng đang ngốn 3,000 token mỗi phiên
- Thêm kỷ luật ghi (write discipline): mỗi tác vụ ghi lại kết quả của nó, mỗi sai lầm trở thành một quy tắc
- Thêm giao thức bàn giao (handover protocol): trước khi chuyển đổi mô hình hoặc kết thúc phiên, agent ghi ngữ cảnh hiện tại vào nhật ký hàng ngày
Chuỗi khởi động bây giờ trông như thế này:
markdown
Trước khi làm BẤT CỨ ĐIỀU GÌ:
- Đọc USER.md
- Đọc learnings/LEARNINGS.md
- Đọc memory/YYYY-MM-DD.md (hôm nay + hôm qua)
- Đọc MEMORY.md (chỉ phiên chính, không bao giờ trong nhóm)
- Đọc PROTOCOL_COST_EFFICIENCY.md
- In: LOADED: USER | LEARNINGS | DAILY | MEMORY | PROTOCOL
Kỷ luật ghi:
markdown
Sau mỗi tác vụ:
- Ghi lại quyết định + kết quả → memory/YYYY-MM-DD.md
- Nếu sai lầm → thêm vào learnings/LEARNINGS.md
- Nếu có ngữ cảnh quan trọng → cập nhật MEMORY.md (chỉ trong các lần đánh giá heartbeat, không bao giờ trực tiếp trong khi thực hiện tác vụ)
Giao thức bàn giao:
markdown
Trước khi kết thúc phiên hoặc chuyển đổi mô hình:
Ghi phần HANDOVER vào memory/YYYY-MM-DD.md:
- Những gì đã được thảo luận
- Những gì đã được quyết định
- Các tác vụ đang chờ xử lý với chi tiết chính xác
- Các bước tiếp theo còn lại
Kết quả:
- System prompt: 11,887 → 8,529 token
- Kỹ năng: 51 → 32
- Token phiên: 18,280 → 14,627
- Nhẹ hơn 28%. Cùng một agent. Cùng một mô hình. Chỉ ít tiếng ồn hơn.
Bài học rút ra:
Giải pháp thực sự không phải là thêm nhiều tệp hơn. Mà là loại bỏ những tệp không làm được gì. Mọi token trong system prompt là chi phí mà agent phải mang theo trong mọi tin nhắn. Các kỹ năng không sử dụng, tệp bộ nhớ phình to, các tệp mà hệ thống thậm chí không đọc - tất cả đều cộng dồn một cách âm thầm.
Các Nguyên Tắc Tôi Ước Gì Đã Biết Vào Ngày 1
Sau 5 ngày phá vỡ và sửa chữa mọi thứ, đây là những nguyên tắc tôi sẽ đưa cho bất kỳ ai đang thiết lập bộ nhớ OpenClaw:
1. Chỉ các tệp này tự động tải: AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md, MEMORY.md.
Mọi thứ khác cần một hướng dẫn đọc rõ ràng trong AGENTS.md. Nếu nó không có trong chuỗi khởi động, agent sẽ không thấy nó. BOOT.md không phải là một thứ có thật trong OpenClaw. Tôi đã có nó trong nhiều tuần. Nó chẳng làm gì cả.
2. Chuỗi khởi động được đặt ở đầu AGENTS.md.
Không phải ở giữa. Không phải ở cuối. Ở trên cùng. Các tệp được tự động tải sẽ được chèn vào system prompt, vì vậy các hướng dẫn khởi động cần là thứ đầu tiên agent xử lý.
3. Kỷ luật ghi quan trọng hơn kỷ luật đọc.
Hầu hết mọi người thiết lập các tệp để agent đọc nhưng không bao giờ thực thi việc ghi lại. Nếu agent không ghi lại các quyết định, kết quả và sai lầm vào đĩa, những thứ đó chỉ tồn tại trong khung ngữ cảnh. Và khung ngữ cảnh sẽ bị nén. Ghi lại là cách ngữ cảnh tạm thời trở thành bộ nhớ vĩnh viễn.
4. Không bao giờ ghi trực tiếp vào MEMORY.md trong khi thực hiện tác vụ.
Nhật ký hàng ngày là thô và chỉ được thêm vào (append-only). MEMORY.md là bộ nhớ dài hạn đã được quản lý. Nếu bạn để agent đổ bất cứ thứ gì vào MEMORY.md, nó sẽ phình to thành một mớ hỗn độn 200 dòng trong vòng vài tuần. Hãy quản lý MEMORY.md trong các lần đánh giá định kỳ (heartbeat hoặc cron) bằng cách chắt lọc thông tin chi tiết từ các nhật ký hàng ngày gần đây. Tôi đã học được điều này từ một người dùng OpenClaw khác, người đã bắt quả tang agent của mình làm chính xác điều này — làm phình to MEMORY.md với những thông tin nhiễu chưa được quản lý cho đến khi nó trở nên vô dụng.
5. LEARNINGS.md là tệp bị đánh giá thấp nhất.
Mọi sai lầm agent mắc phải sẽ trở thành một quy tắc một dòng. "Never claim code is pushed without checking git status." "Don't read full MEMORY.md in group chats." "Always confirm the user's timezone before scheduling." Các quy tắc này tích lũy. Sau một vài tuần, agent của bạn có một sổ tay vận hành cá nhân được xây dựng từ những thất bại của chính nó.
6. Kiểm tra khả năng truy xuất, không chỉ lưu trữ.
Lưu trữ thông tin và truy xuất thông tin là hai vấn đề khác nhau. Tôi đã từng có các tệp được lập chỉ mục và có thể tìm kiếm nhưng không bao giờ được truy cập vì agent không biết phải tìm chúng. Hãy đặt các điểm đánh dấu, kiểm tra qua các phiên, kiểm tra qua các lần chuyển đổi mô hình. Nếu agent không thể tìm thấy những gì bạn đã lưu trữ ngày hôm qua, việc lưu trữ không quan trọng.
7. Giao thức bàn giao là giải pháp cho việc chuyển đổi mô hình.
Các agent OpenClaw mất tất cả ngữ cảnh khi bạn chuyển đổi mô hình. Mô hình mới bắt đầu với một khung ngữ cảnh mới — nó chỉ thấy các tệp được tự động tải. Nếu không có giao thức bàn giao để đổ trạng thái hiện tại vào nhật ký hàng ngày trước khi chuyển đổi, mô hình mới không có ý tưởng gì về những gì đang xảy ra. Đây là điểm đau đớn lớn nhất của tôi trong nhiều tuần.
8. Chạy /context detail thường xuyên.
Lệnh này hiển thị chính xác những gì đang ngốn token của bạn. Các kỹ năng bạn quên đã cài đặt, các tệp đã phình to mà bạn không nhận thấy, các công cụ bạn không bao giờ sử dụng. Tôi tìm thấy 20 kỹ năng không sử dụng đang đốt 3,000 token mỗi phiên. Đó là 3,000 token chi phí trên mọi tin nhắn, cho các tính năng tôi chưa bao giờ động đến.
9. Tìm kiếm kết hợp tốt hơn tìm kiếm ngữ nghĩa thuần túy.
BM25 (từ khóa) + vector (ý nghĩa) + xếp hạng lại cho kết quả tốt hơn đáng kể so với chỉ riêng vector. Tên khách hàng, số cụ thể, cụm từ chính xác — tìm kiếm ngữ nghĩa bỏ lỡ chúng. Tìm kiếm từ khóa bắt được chúng. Sử dụng cả hai.
10. Compaction không phải là kẻ thù. Ngữ cảnh chưa được ghi mới là kẻ thù.
Tôi đã dành nhiều ngày để chống lại compaction trước khi nhận ra giải pháp đơn giản hơn: đảm bảo bất cứ thứ gì quan trọng đều được ghi vào một tệp trước khi compaction chạy. Xả bộ nhớ xử lý việc này tự động. Nếu nó ở trên đĩa, nó tồn tại qua compaction. Nếu nó chỉ ở trong cuộc hội thoại, nó có nguy cơ bị mất.
Thiết Lập Hiện Tại Của Tôi
Để tham khảo, đây là không gian làm việc của tôi bây giờ:
workspace/
├── AGENTS.md (chuỗi khởi động + kỷ luật ghi + giao thức bàn giao)
├── SOUL.md (tính cách và hành vi)
├── IDENTITY.md (tên, vai trò)
├── USER.md (thông tin chủ sở hữu)
├── TOOLS.md (hướng dẫn sử dụng công cụ)
├── HEARTBEAT.md (hành vi kiểm tra tự động)
├── MEMORY.md (bộ nhớ dài hạn đã được quản lý, ~90 dòng)
├── PROTOCOL_COST_EFFICIENCY.md
├── learnings/
│ └── LEARNINGS.md (các quy tắc từ sai lầm)
├── memory/ (nhật ký hàng ngày: YYYY-MM-DD.md)
├── docs/ (tài liệu tham khảo được chuyển ra khỏi MEMORY.md)
│ ├── tweetsmash-arch.md
│ ├── knowledge-transfer.md
│ ├── infrastructure.md
│ └── group-chat-rules.md
└── skills/ (32 kỹ năng, giảm từ 51)
System prompt: 8,529 token. Token phiên: 14,627 trên tổng số 200,000 khung ngữ cảnh (7.3%). Agent khởi động, đọc những gì nó cần, ghi lại những gì nó học được và bàn giao ngữ cảnh trước khi chuyển đổi mô hình.
Phải mất 5 ngày để đạt được điều này. Phần lớn thời gian là để từ bỏ giả định rằng nhiều tệp hơn đồng nghĩa với bộ nhớ tốt hơn. Không phải vậy. Kỷ luật mới là chìa khóa. Cuộc thử nghiệm của tôi vẫn đang tiếp diễn.
Tôi đang xây dựng TweetSmash và LinkedMash — các công cụ đánh dấu trang mạng xã hội cùng với đồng sáng lập của mình. Tôi chia sẻ những gì tôi học được về việc vận hành các agent OpenClaw trong sản xuất trên X: @code_rams


![[Ghi chú] Sếp của bạn làm việc nhanh gấp 3 lần](/cdn-cgi/image/width=1920,quality=90,format=auto,metadata=none/https%3A%2F%2Fcms-assets.youmind.com%2Fmedia%2F1783963982361_vdddap_HNDtsxJbcAAoE0q.jpg)


