Bộ nhớ của AI agent giữa các phiên: tệp tiến độ, nhật ký quyết định, git và script khởi tạo
AI agent không có bộ nhớ giữa các phiên: mọi thứ không được ghi vào tệp của repository thì phiên mới không biết. Bộ nhớ của AI agent được xây từ các artifact: PROGRESS.md (hiện đang ở đâu), DECISIONS.md (vì sao như vậy và đã loại bỏ những gì), commit git có giải thích ý đồ, và giao thức giao ca trong AGENTS.md yêu cầu đọc chúng khi bắt đầu và cập nhật khi kết thúc; script khởi tạo kiểm tra môi trường và in trạng thái hiện tại.
Vì sao agent không nhớ gì
Mô hình không lưu trạng thái giữa các lần chạy. Mọi thứ agent «biết» về tác vụ của bạn nằm trong cửa sổ ngữ cảnh của phiên hiện tại: các tệp đã đọc, kết quả lệnh, hội thoại với bạn. Phiên đóng lại hoặc ngữ cảnh đầy, phiên mới bắt đầu từ con số không và chỉ thấy những gì đã được ghi trên đĩa.
Một hình dung hữu ích: một kỹ sư tài năng mỗi sáng đến công ty với bộ nhớ đã bị xóa sạch. Anh ta sẽ nhanh chóng hiểu code, nhưng không nhớ hôm qua đã chọn phương án kiến trúc nào, vì sao các phương án khác bị loại, và các test đang ở trạng thái nào. Nếu không có ghi chép, anh ta sẽ mất mười lăm đến hai mươi phút để tìm hiểu lại và rất có thể làm lại đúng cái bạn đã cố ý loại bỏ.
Vì thế, bộ nhớ của AI agent không phải là thuộc tính của mô hình, mà là một phần của harness: một tập tệp và quy tắc do chính bạn thiết kế. Tin tốt là không cần cơ sở dữ liệu vector hay dịch vụ đặc biệt nào. Vài tệp Markdown, git và kỷ luật là đủ.
Vì sao cửa sổ ngữ cảnh lớn không giải quyết được vấn đề
Có vẻ như chỉ cần chờ một mô hình có cửa sổ lớn hơn. Nhưng một tác vụ phức tạp sẽ lấp đầy bất kỳ cửa sổ nào: agent đọc toàn bộ codebase, tích lũy lịch sử quyết định, nhận đầu ra test dài dòng và giữ toàn bộ hội thoại. Nhu cầu lớn lên cùng với cửa sổ. Đây là vấn đề kiến trúc, không phải vấn đề dung lượng.
Còn có một hiệu ứng thứ hai. Gần đến giới hạn cửa sổ, nhiều mô hình bắt đầu vội vàng kết thúc: bỏ qua kiểm tra, chọn giải pháp đơn giản thay vì giải pháp đúng. Anthropic mô tả quan sát này đối với các mô hình của họ, và mức độ biểu hiện khác nhau giữa các mô hình. Một phiên dài sát giới hạn ngữ cảnh không chỉ có nguy cơ mất thông tin mà còn có nguy cơ làm giảm chất lượng công việc.
Nén ngữ cảnh: giữ được gì, mất gì
Nén ngữ cảnh (compaction) là việc rút gọn phần đầu của hội thoại thành một bản tóm tắt ngắn để giải phóng chỗ trong cùng một phiên. Trong Claude Code, việc này do lệnh /compact thực hiện, và cũng tự động xảy ra khi gần đến giới hạn. Ngược lại, lệnh /clear xóa lịch sử và bắt đầu cuộc trò chuyện lại từ đầu.
Vấn đề của nén ngữ cảnh là bản tóm tắt thường giữ lại «cái gì» và làm mất «vì sao». Code đã xong vẫn nằm trong tệp, nhưng lập luận — vì sao chọn phương án B, vì sao không dùng thư viện đó, vì sao cố ý bỏ qua tối ưu hóa — bị nén lại thành vài từ hoặc biến mất. Bước tiếp theo của agent «cải tiến» một quyết định có chủ ý, vì nó không còn thấy lý do.
| Nén ngữ cảnh | Đặt lại (phiên mới) | |
|---|---|---|
| Điều gì xảy ra | Phần đầu hội thoại được thay bằng bản tóm tắt | Phiên đóng lại, phiên mới đọc các tệp trạng thái |
| Cái gì được giữ | Những gì mô hình cho là quan trọng khi nén | Đúng những gì bạn đã ghi vào tệp |
| Vội vàng gần giới hạn | Có thể vẫn còn | Được đặt lại về không |
| Khi nào phù hợp | Tác vụ chắc chắn vừa trong phiên hiện tại | Chân trời tác vụ dài hoặc chưa rõ |
Một quy tắc thực tế, không cần chỉ số phức tạp: khi tác vụ đã chiếm khoảng 60% cửa sổ, hãy ngừng viết code và chuẩn bị bàn giao. Nếu ngữ cảnh mới dùng khoảng 40% và phần việc còn lại đã gần kề, nén ngữ cảnh là đủ.
Bốn artifact tạo nên bộ nhớ của agent
Thay vì trông chờ vào trí nhớ của mô hình, hãy lập một nhật ký hành trình. Nó gồm bốn phần, mỗi phần có vai trò riêng.
- PROGRESS.md — hiện chúng ta đang ở đâu.
- DECISIONS.md — vì sao làm như vậy chứ không phải cách khác.
- Commit git — các điểm kiểm tra trạng thái miễn phí.
- Giao thức giao ca trong AGENTS.md — phải làm gì khi nhận và khi kết thúc ca.
PROGRESS.md: tệp tiến độ
Tệp này trả lời một câu hỏi: dự án đang ở trạng thái nào ngay lúc này. Agent đọc nó đầu tiên khi bắt đầu phiên và cập nhật nó cuối cùng trước khi rời đi. Tệp ngắn, được viết lại chứ không cứ thế nối thêm mãi: lịch sử nằm trong git.
# PROGRESS.md
## Mục tiêu hiện tại
Tìm kiếm trong danh mục sản phẩm (tính năng search-01)
## Trạng thái
- HEAD: 4f2a9c1
- make check: xanh, 142/142 test
- Đã xong: chỉ mục trong PostgreSQL (tsvector), endpoint GET /search
- Đã kiểm chứng: unit test + truy vấn curl thủ công với 3 từ khóa
## Vật cản
- Chưa có dữ liệu hình thái học cho tiếng Kazakh — đang chờ quyết định
## Bước tiếp theo
Thêm phân trang vào GET /search, tiêu chí: test cho trang thứ 2
Hãy chú ý bốn trường đủ để bàn giao công việc: hash commit, tỷ lệ test đạt, vật cản và bước tiếp theo. Nếu một phiên mới không thể tiếp tục công việc một cách rõ ràng từ tệp này, nghĩa là mẫu thiếu trường nào đó.
DECISIONS.md: nhật ký quyết định
Tệp này lưu đúng phần «vì sao» vốn bị mất khi nén ngữ cảnh. Định dạng một mục: quyết định, lý do, những gì đã loại bỏ và vì sao, ràng buộc.
## 2026-03-14 — Cache cài đặt người dùng trong Redis
- Quyết định: Redis, TTL 5 phút, xóa cache chủ động khi ghi.
- Lý do: được đọc ở mọi request, dữ liệu rất nhỏ.
- Đã loại bỏ: materialized view trong PostgreSQL — thay đổi quá thường xuyên,
việc bảo trì không đáng.
- Ràng buộc: không cache cài đặt thanh toán.
Dòng giá trị nhất ở đây là «Đã loại bỏ». Chính nó ngăn phiên sau «tối ưu hóa» quyết định quay trở lại phương án đã được cân nhắc và bác bỏ. Khác với tệp tiến độ, nhật ký quyết định chỉ được bổ sung: các mục cũ không bị xóa mà được đánh dấu là đã bị thay thế bởi mục mới.
Lịch sử git như các điểm kiểm tra
Commit là những ảnh chụp trạng thái có phiên bản, đã được tích hợp sẵn trong quá trình làm việc. Agent có thể đọc git log và git diff để khôi phục những gì đã thay đổi. Để lịch sử hoạt động như bộ nhớ, thông điệp commit phải giải thích ý đồ, chứ không nhắc lại nội dung diff.
# tệ
git commit -m "update search.py"
# tốt
git commit -m "search: chỉ mục tsvector thay cho LIKE
LIKE '%q%' không dùng được chỉ mục, với 200k sản phẩm truy vấn mất 1.8 s.
Phân trang chưa làm, xem PROGRESS.md."
Các commit nhỏ, thường xuyên sau mỗi lần test xanh còn cho một điểm hoàn tác. Nếu phiên đi chệch hướng, quay về trạng thái đã kiểm chứng gần nhất dễ hơn nhiều so với gỡ rối các thay đổi dang dở.
Giao thức giao ca trong AGENTS.md
Các tệp trạng thái vô ích nếu agent không biết về chúng. Vì vậy, trong tệp hướng dẫn đầu vào (AGENTS.md hoặc CLAUDE.md), người ta viết một giao thức ngắn: phải làm gì khi nhận ca và khi kết thúc ca.
## Nhận ca
1. Đọc PROGRESS.md và DECISIONS.md.
2. Tìm tác vụ đang active trong .agent/feature_list.json.
3. Chạy make check — đảm bảo repository nhất quán.
4. Tiếp tục từ «Bước tiếp theo», không mở lại những gì đã quyết định.
## Kết thúc ca
1. Chạy make check, commit trạng thái xanh.
2. Cập nhật PROGRESS.md: HEAD, test, vật cản, bước tiếp theo.
3. Bổ sung quyết định mới vào DECISIONS.md.
4. Không để việc dở dang trong working tree.
Nên giữ giao thức thật ngắn: vài dòng trong tệp đầu vào, không phải một bản dài dòng riêng.
Script khởi tạo: tăng tốc việc bắt đầu phiên
Để agent không phải tự ghép bức tranh, hãy cung cấp một script duy nhất kiểm tra môi trường và in ra trạng thái. Script phải idempotent — chạy bao nhiêu lần cũng được — và kết thúc bằng một thông báo sẵn sàng rõ ràng.
#!/usr/bin/env bash
set -euo pipefail
echo "== 1. Môi trường =="
command -v uv >/dev/null || { echo "FAIL: chưa cài uv"; exit 1; }
uv sync --frozen
echo "== 2. Repository =="
if [ -n "$(git status --porcelain)" ]; then
echo "WARN: working tree chưa sạch"
else
echo "OK: sạch"
fi
echo "HEAD: $(git log -1 --oneline)"
echo "== 3. Kiểm tra =="
make check
echo "== 4. Trạng thái =="
cat PROGRESS.md
echo "Sẵn sàng làm việc"
Khi đó, giao thức nhận ca chỉ cần một dòng: «chạy scripts/init.sh». Trong Claude Code, việc chạy này có thể được tự động hóa bằng hook khi bắt đầu phiên (sự kiện SessionStart), nhưng ngay cả không có hook, agent cũng sẽ chạy script theo chỉ dẫn trong tệp.
Đưa gì vào bộ nhớ của agent, và không đưa gì
Lỗi lớn nhất là biến bộ nhớ thành bãi rác. Mỗi dòng agent đọc khi khởi động đều chiếm chỗ trong ngữ cảnh, và điều thừa làm loãng điều quan trọng.
| Nên đưa vào | Không nên đưa vào |
|---|---|
| Mục tiêu hiện tại và bước tiếp theo | Tóm tắt code mà agent có thể tự đọc |
| Quyết định kèm lý do và phương án bị loại | Toàn bộ nhật ký hội thoại và đầu ra lệnh |
| Hash commit và trạng thái test | Danh sách phụ thuộc — đã có trong manifest của gói |
| Vật cản và câu hỏi còn mở | «Làm xong rất tốt, mọi thứ chạy» mà không ghi cách đã kiểm chứng |
| Ngõ cụt: đã thử gì và vì sao không được | Bí mật, token, mật khẩu |
| Tác vụ kèm tiêu chí nghiệm thu | Ghi chú lỗi thời về các tác vụ đã đóng |
Hãy tách theo thời gian sống. Quy tắc dự án thay đổi hiếm và áp dụng cho mọi tác vụ — chúng thuộc về tệp hướng dẫn đầu vào. Trạng thái thay đổi mỗi phiên — nó thuộc về tệp tiến độ. Nếu trộn lẫn hai loại, tệp đầu vào sẽ nhanh chóng phình ra với những ghi chú lỗi thời.
Phiên đầu tiên: khởi tạo như một giai đoạn riêng
Bộ nhớ giữa các phiên sẽ không giúp được gì nếu phiên đầu tiên đã rối loạn. Một tình huống điển hình: bạn yêu cầu «thêm tìm kiếm» trên repository mới, và sau nửa tiếng mới phát hiện framework test cấu hình sai và định dạng migration không đúng. Tính năng tìm kiếm có đấy, nhưng nền móng đã lệch.
Nguyên nhân là việc triển khai và việc khởi tạo tối ưu hóa những thứ khác nhau: việc đầu tiên là số tính năng hoàn thành trong phiên này, việc thứ hai là tốc độ và độ tin cậy của mọi phiên sau. Agent có xu hướng nghiêng về kết quả nhìn thấy được, tức là code. Vì vậy nên tách khởi tạo thành một phiên riêng với tiêu chí hoàn thành rõ ràng gồm bốn điều kiện.
- Chạy được:
make setupvàmake devhoạt động trên bản clone sạch. - Tự kiểm chứng: có
make testvà ít nhất một test thật sự chạy đạt. - Thấy được tiến độ: tệp trạng thái tồn tại và đọc được.
- Tiếp nhận được công việc: có danh sách tác vụ kèm tiêu chí nghiệm thu.
Nếu bạn thường xuyên bắt đầu dự án mới, hãy tạo một repository mẫu: Makefile, khung test, khung AGENTS.md, thư mục .agent/, scripts/init.sh, linter và CI. Khi đó, khởi tạo chỉ còn là phần đặc thù của dự án cụ thể.
Làm sao biết bộ nhớ đang hoạt động
Chỉ số trung thực nhất là thời gian từ lúc bắt đầu phiên mới đến lần thay đổi code có ý nghĩa đầu tiên. Không có artifact, đó thường là mười lăm đến hai mươi phút tìm hiểu; với bàn giao tốt, chỉ hai đến ba phút. Hãy đo một lần trước và sau, và bạn sẽ thấy kỷ luật này có đáng hay không.
Cách thứ hai là kiểm tra khởi động nguội. Mở một phiên mới, gõ «tiếp tục» và hỏi năm câu: mục tiêu hiện tại là gì, test đang ở trạng thái nào, quyết định nào đã được đưa ra cho chủ đề chính và vì sao, cái gì đang chặn, bước tiếp theo là gì. Nếu agent trả lời đủ năm câu dựa trên tệp, không đoán mò, thì bộ nhớ được thiết kế đúng. Mỗi câu trả lời không chắc chắn là một trường còn thiếu trong mẫu.
Lỗi thường gặp
- Tệp tiến độ chỉ dài thêm. Sau một tháng nó có hàng trăm dòng lịch sử. Hãy viết lại nó theo trạng thái hiện tại; lịch sử thuộc về git.
- Thiếu dòng «đã loại bỏ». Nhật ký quyết định không có phương án bị loại sẽ không ngăn được những tranh luận lặp lại.
- Agent cập nhật trạng thái theo cảm tính. Hãy ghi cách đã kiểm chứng: lệnh và kết quả, chứ không phải «mọi thứ chạy».
- Bàn giao ở sát giới hạn cửa sổ. Gần giới hạn ngữ cảnh, agent đã vội vàng; hãy bắt đầu handoff sớm, khoảng 60%.
- Working tree bẩn khi kết thúc. Thay đổi dở dang không commit làm phiên sau bối rối.
Tóm lại
Bộ nhớ của AI agent giữa các phiên được xây trên tệp chứ không phải trên mô hình: PROGRESS.md giữ trạng thái hiện tại, DECISIONS.md giữ lý do và các phương án bị loại, commit git là điểm kiểm tra kèm giải thích ý đồ, còn giao thức giao ca trong AGENTS.md buộc mọi thứ phải được đọc và cập nhật. Script khởi tạo rút việc bắt đầu xuống còn một lệnh, còn bài kiểm tra khởi động nguội cho biết các ghi chép đã đủ hay chưa. Nhật ký làm việc của agent và hợp đồng khởi tạo được giải thích và thực hành trong khóa học về harness engineering.
Câu hỏi thường gặp
Có thể chỉ cần yêu cầu agent ghi nhớ điều gì đó cho lần sau không?
Agent chỉ nhớ nếu nó ghi vào tệp mà phiên sau sẽ đọc. Trong Claude Code có các tệp bộ nhớ và CLAUDE.md, nhưng với trạng thái của một tác vụ cụ thể, tệp tiến độ rõ ràng trong repository đáng tin hơn.
PROGRESS.md khác gì CHANGELOG?
CHANGELOG mô tả các thay đổi cho người dùng theo phiên bản. PROGRESS.md mô tả trạng thái làm việc hiện tại cho phiên agent tiếp theo, và được viết lại mỗi khi trạng thái thay đổi.
Bộ nhớ của agent lập trình có cần cơ sở dữ liệu vector không?
Khi làm việc trong một repository, thường là không cần: trạng thái tác vụ nằm gọn trong vài tệp ngắn, còn code thì agent đọc trực tiếp. Tìm kiếm vector chỉ có ý nghĩa khi cần tra cứu một khối lượng lớn tài liệu bên ngoài.
Có nên commit các tệp trạng thái vào git không?
Nên, như vậy trạng thái có sẵn cho mọi phiên và mọi thành viên nhóm, còn lịch sử thay đổi của nó được lưu lại. Ngoại lệ là ghi chú cá nhân và mọi thứ có chứa bí mật.
Nếu agent quên cập nhật PROGRESS.md khi kết thúc thì sao?
Hãy biến việc cập nhật thành một phần của tiêu chí hoàn thành trong giao thức kết thúc ca, và kiểm tra nó bằng cơ chế, chẳng hạn một hook hoặc script so sánh HEAD trong tệp với commit hiện tại.
Chủ đề này được giảng chi tiết kèm thực hành trong khóa học “Harness Engineering: инженерия надёжности AI-агентов”.
Đến khóa học