// BLOG — 2026-10-04

Chạy dài là đơ: con agent không cần thêm ký ức, nó cần một chính sách quên

Có một kiểu hỏng mà mình từng không nhận ra là hỏng.

# Chạy dài là đơ: con agent không cần thêm ký ức, nó cần một chính sách quên

Có một kiểu hỏng mà mình từng không nhận ra là hỏng.

Con máy vẫn chạy. Log vẫn xanh. Nó vẫn trả lời đủ câu, vẫn gọi đủ tool, vẫn ghi "xong" ở cuối. Chỉ có điều... càng về sau càng ngơ.

Đầu phiên thì sắc. Vài chục vòng sau, nó bắt đầu nhắc lại thứ mình đã bỏ. Rồi hỏi lại thứ mình vừa nói. Rồi làm lại một việc đã chốt từ lâu. Không sập, không báo lỗi, chỉ là độ thông minh tụt dần đều như pin điện thoại xài lâu ngày.

Giống hệt một người thức tới ba giờ sáng. Vẫn nói được, vẫn gõ được, nhưng không ai còn dám giao việc.

Mình từng nghĩ đây là bệnh của model. Rồi tuần này mình đọc một bài thực nghiệm đi đúng vào chỗ đó, và mình đổi ý.

Bài đó không so model. Họ giữ nguyên model, chỉ đổi đúng một thứ: luật chơi về chuyện khi nào xé bỏ một phiên làm việc, xé cái gì, và giữ lại cái gì. Kết quả đầu ra khác nhau rõ rệt — đến mức đọc xong mình thấy hơi ngộ: hoá ra cái mình đang tinh chỉnh suốt bao lâu không phải con bot, mà là lịch sử của nó.


Cái bẫy: "nhớ nhiều hơn là tốt hơn"

Phản xạ đầu tiên khi thấy agent chạy dài kém đi là: nó quên -> cho nó nhớ thêm. Bơm memory. Nhồi cả log. Giữ nguyên ngữ cảnh, không xoá gì.

Mình đã tin vậy. Giờ mình nghĩ đó là cái bẫy đắt nhất trong mấy bài gần đây.

Thứ nhất, ngữ cảnh là ngân sách, không phải trí nhớ. Cái cửa sổ đó là tiền. Và không phải trả một lần — model đọc lại toàn bộ cửa sổ ở mỗi vòng. Nên giữ thêm một đoạn cũ là trả tiền cho nó ở mọi vòng tiếp theo, mãi mãi. Càng chạy càng đắt, trong khi giá trị của đoạn cũ đó thì gần như bằng không.

Thứ hai — và cái này mới là cái đau — nội dung cũ không trung tính. Nó là cái ghim.

Khi mình để nguyên trong phiên một quyết định đã bỏ, một giả định đã sai, một đoạn tranh luận đã ngã ngũ, con model không đọc nó như lịch sử. Nó đọc như hiện tại. Rồi nó bám vào. Nó tưởng cái phương án mình loại từ hai mươi vòng trước vẫn đang sống. Nó kéo cái sai đã sửa quay lại. Nó hoang mang giữa hai phiên bản sự thật cùng nằm trong tầm mắt.

Nên cái làm agent đơ dần không phải là quên. Mà là không chịu quên.


Bốn kiểu "chính sách quên"

Mình gom lại thành bốn nhóm — không theo nguyên văn bài kia, mấy nhóm này mình chia lại theo đúng cách mình đang vận hành:

1. Quên theo đếm. Cứ hết N vòng, hoặc chạm trần token, thì cắt. Mở phiên mới.

Dễ làm nhất, rẻ nhất, đoán được nhất. Nhưng nó mù: nó cắt ngang. Đang giữa một mạch quan trọng thì reset, và mình vừa vứt đi đúng phần đang dở. Kiểu như ngắt điện giữa lúc đang render.

2. Quên theo tín hiệu. Reset khi có dấu hiệu "phiên đã bão hoà": agent lặp lại câu đã nói, tỉ lệ trả lời vô ích tăng, kết quả mâu thuẫn với thứ đã chốt trước đó.

Nghe thông minh. Nhưng có một vết nứt: muốn đo chất lượng phiên thì phải chấm phiên — và người chấm dễ nhất lại chính là con model đang đuối. Tự chấm lúc đang mệt thì điểm không đáng tin. Nên mình chỉ tin tín hiệu đến từ bên ngoài model: số lần người phải sửa tay, số lần gọi tool thất bại, số lần vi phạm luật cứng.

3. Quên theo đơn vị việc. Reset khi đổi việc, không reset giữa việc.

Cái này mình học từ ca trực: hết ca thì bàn giao, chứ không ai bàn giao giữa lúc đang mổ. Việc gì cũng có biên rõ — một ticket, một lượt khách, một lần chạy. Biên đó là điểm reset tự nhiên, rẻ, và không phá gì.

4. Quên "ấm". Không xoá trắng. Xoá chữ, nhưng giữ lại một bản bàn giao: cái gì đã xong, đã chốt, còn treo, còn nợ ai cái gì. Phiên mới mở ra từ đúng bản bàn giao đó.

Đây là nhóm mình thấy ăn tiền nhất — và cũng là nhóm bị hiểu sai nhiều nhất.

Điểm chung của nhóm 3 và nhóm 4: chúng tách trạng thái ra khỏi ngữ cảnh. Trạng thái là thứ phải sống qua cơn reset. Ngữ cảnh là thứ tốt nhất nên chết.


Chỗ khó thật sự không phải chọn policy — mà là định nghĩa cái gì phải sống

Mình từng nghĩ bài toán là chọn nhóm nào trong bốn. Sau một thời gian vật lộn, mình nghĩ khó nằm chỗ khác: cái gì phải sống qua lần reset.

Danh sách sống-thật của mình gọn như vậy:

  • ▹Việc đang làm: nó là việc gì, đi tới đâu, bước kế tiếp là gì
  • ▹Những cái đã chốt (không phải "đã bàn")
  • ▹Những cái đã ra ngoài, không hoàn tác được: đã gửi chưa, đã gọi bên kia chưa, đã trả tiền chưa
  • ▹Những cái chưa xác nhận — không phải thất bại, mà là "chưa biết"

Và danh sách cho-chết:

  • ▹Toàn bộ văn bản thô đã đọc, đã trích ra
  • ▹Mọi đoạn "cân nhắc", "có thể", "giả sử" — tranh luận đã ngã ngũ thì không có giá trị lịch sử
  • ▹Mọi phương án đã bị loại

Viết thành bàn giao thì nó trông thế này:

# PSEUDO-CODE minh hoạ — không phải nguồn triển khai
handoff = {
  "việc":           {"id": ..., "làm_tới": ..., "bước_kế": ...},
  "đã_chốt":        [...],   # quyết định, kèm 1 dòng lý do
  "đã_ra_ngoài":    [...],   # hành động không hoàn tác: đã gửi / đã trả
  "chưa_xác_nhận":  [...],   # trạng thái "chưa biết" -> phải đối chiếu lại
  "luật_cứng":      [...]    # không bao giờ nằm trong tay model
}

mở_phiên_mới(từ=handoff)     # ngữ cảnh cũ bị bỏ, chỉ còn đúng bản này

Có một quy tắc mình giữ rất chặt ở đây: bản bàn giao chỉ ghi thứ đã XÁC NHẬN, không ghi thứ đã TIN.

"Con bot tin là đã gửi" và "hệ thống xác nhận là đã gửi" là hai chuyện khác hẳn nhau. Nếu mình đưa niềm tin vào bản bàn giao, thì mình vừa nhân bản lỗi qua mọi phiên — sai một lần là sai mãi, vì phiên sau thừa hưởng cái sai đó như một sự thật đã chốt.

Đây đúng là chỗ mình từng vấp: sửa được cái sai trong một phiên, nhưng để cái "đã xong" sai lọt vào bản bàn giao thì nó sống dai hơn cả con bug gốc.


Nối vào tiền: trí nhớ là hàm chi phí, không phải tính năng

Đây là đoạn mình nghĩ dân bán automation nên dán lên tường.

Một agent chạy liên tục — canh hộp thư, canh hệ thống, trả lời khách — có chi phí bằng token mỗi vòng nhân số vòng. Không reset thì cửa sổ phình dần, tức là chi phí mỗi vòng tăng theo thời gian chạy, trong khi giá trị mỗi vòng gần như phẳng. Nhân lên tới cuối tháng, một phần rất lớn hoá đơn không trả cho việc gì cả — chỉ trả cho con model đang đọc lại lịch sử của chính nó.

Nếu anh em đang bán theo lượt hoặc theo việc, đây là bom hẹn giờ. Ngày ký hợp đồng, giá vốn được tính trên một agent "tỉnh táo". Vài tuần sau agent vẫn chạy y như vậy, nhưng mỗi vòng nặng gấp mấy lần. Biên lợi nhuận co lại âm thầm, mà bảng giá thì không ai đổi.

Và cái hay nhất nằm ở chỗ ngược đời: một chính sách quên tốt cho phép bán đúng việc đó với một cửa sổ nhỏ hơn.

Cửa sổ nhỏ = rẻ hơn mỗi vòng, và quan trọng hơn, model bớt nhiễu vì không còn phải kéo theo đống ghim cũ — nên ít lần khách phải sửa tay hơn. Hai cái đó cộng lại thành đúng hai con số mình vẫn dùng để đo mọi thứ: chi phí cho mỗi việc giao xong, và số lần khách phải sửa tay trên 1.000 lần chạy.

Reset không phải là cắt bớt tính năng. Reset là giảm giá vốn mà tăng chất lượng cùng lúc — thứ hiếm khi có trong nghề này.


Ba câu tự soi trước khi bật agent chạy dài

Không cần framework. Chỉ cần trả lời được ba câu này trước khi để con bot chạy liên tục:

  1. 1.Việc của mình có BIÊN rõ không? Nếu không định nghĩa nổi "một việc" là gì, thì chưa có điểm reset tự nhiên nào cả — và mọi reset sẽ là cắt ngang.
  2. 2.Cái gì phải sống qua reset? Nếu không kể ra được trong năm dòng, mình đang phó mặc phần quan trọng nhất cho may mắn.
  3. 3.Reset có lấy lại được không? Xoá ngữ cảnh mà phiên mới không dựng lại được mạch việc, thì mình vừa thêm một lỗi im lặng nữa — đúng loại lỗi báo thành công mà mình kể mấy bài trước.

Kết

Mình không nghĩ đây là chuyện riêng của mấy ông làm hạ tầng. Ai có một con bot chạy quá vài giờ cũng gặp cảnh này: nó không chết, nó chỉ già đi trong lòng một phiên.

Và cách sửa không phải nuôi nó bằng ký ức. Là cho nó một ca trực, một bản bàn giao, và một chỗ để quên.

Anh em đang chạy agent dài liên tục thì reset kiểu gì — theo đếm, theo tín hiệu, hay theo việc? Mình đang thử trộn nhóm 3 với nhóm 4, và vẫn đang tìm cái ngưỡng "đủ mệt để reset" cho đúng. Ai làm khác mà ăn hơn thì chỉ mình với.