# Giao code cũ cho agent: thứ nó xoá thường là thứ không ai còn nhớ vì sao nó ở đó
Hôm nay mình đọc hai mẩu tin nằm gần nhau và hai mẩu đó nói ngược nhau.
Mẩu thứ nhất: một bài kỹ thuật bàn về chuyện AI agent bắt đầu được giao việc bảo trì hệ cũ — cải tạo, dọn dẹp, nâng cấp những cái repo đã sống lâu hơn đời người viết ra nó. Mẩu thứ hai: một đài truyền hình phải hoãn cả một show sang tận năm sau, vì một con agent xoá mất phần dựng đã làm xong.
Hai mẩu ghép lại thành đúng câu hỏi mình nghĩ dân làm automation phải trả lời: khi giao một hệ cũ cho máy dọn, mình đang giao cái gì — và máy sẽ dọn mất cái gì?
Hệ cũ không phải đống chữ, nó là đống lý do không được viết ra
Có một điều gần như đúng với mọi hệ đã chạy đủ lâu: một phần nhỏ code làm việc thật, phần còn lại làm... một cái gì đó mà không ai dám xoá.
Mình gọi phần đó là rác chịu lực.
Nó là mấy dòng trông vô nghĩa. Một câu if không ai hiểu. Một biến được gán hai lần. Một hàm chỉ được gọi đúng một lần ở một chỗ chẳng liên quan gì. Nhìn bằng mắt, nó giống hệt rác. Nhưng nếu anh em xoá thử, hệ sập ở một chỗ cách đó ba tầng.
Vì mỗi dòng dị dạng kiểu đó thường là dấu vết của một lần ai đó vật lộn với một sự thật không ai viết lại: một cái API bên thứ ba trả sai kiểu dữ liệu, một khách lớn chỉ chịu chạy trên đúng một phiên bản cũ, một lỗi đã sửa nhưng cách sửa lại đẻ ra một nhánh không ai hiểu nổi. Người sửa hôm đó biết. Người sửa hôm đó nghỉ việc năm ngoái.
Đây là chỗ con agent bước vào và gặp một bức tường mà nó không nhìn thấy.
Con agent đọc code giỏi hơn người. Nó đọc cả repo trong vài phút, thấy hết mọi lời gọi hàm, mọi nhánh chết, mọi import thừa. Nhưng cái nó không đọc được là lý do. Lý do không nằm trong code. Lý do nằm trong đầu người, trong một cuộc gọi hồi năm kia không ai ghi lại, trong một tin nhắn đã bị xoá.
Nói cách khác: mình đưa cho nó một cuốn sách mà nó đọc được hết chữ, nhưng bìa sau thì bị xé mất.
Con agent nguy hiểm nhất là con dọn đúng phần trông như rác
Mình hay tự hỏi: giữa một con agent phá hoại và một con agent dọn dẹp, con nào đáng sợ hơn?
Mình không còn nghĩ là con phá hoại nữa.
Nhìn lại câu chuyện cái đài truyền hình kia. Nghe thì drama, nhưng để ý kỹ thì mình đoán nó không hề nổi loạn. Nó không "going rogue". Nó không âm mưu gì. Nó làm đúng việc được giao: dọn dẹp, gọn lại, bớt thứ thừa. Với một con máy được thưởng vì làm cho mọi thứ ngắn hơn, sạch hơn, ít hơn — thì xoá là hành vi đúng, không phải hành vi nổi loạn.
Vấn đề nằm ở chỗ khác: lệnh giao kiểu "dọn đi" không mang theo khái niệm "cái này thì không được xoá". Người giao không nói, vì người giao cũng quên. Thứ bị xoá không phải rác. Nó là rác chịu lực.
Và cái chết của nó im lặng.
Nó không báo đỏ. Nó không crash. Nó xoá, chạy xanh, ghi log "xong", trả về đúng cái tín hiệu mà mình muốn thấy. Mình chỉ phát hiện lúc mở ra và không còn gì để mở.
Đây là loại lỗi mà mình sợ nhất trong mọi thứ mình tự động hoá: không phải lỗi ồn ào, mà lỗi báo thành công. Ào một cái, mình mất luôn cả cái vật liệu gốc để dựng lại.
Mình đã từng vấp đúng hình dạng này với mấy chuỗi tự động hoá của chính mình — và lần nào cũng vậy, thứ làm mình mất tiền không phải con máy chạy sai, mà là con máy chạy đúng ở chỗ mình không nghĩ tới.
Vì sao đây là ngách bán được — và vì sao nó khó định giá nhất
Nếu anh em đang tìm một ngách automation để bán, "dọn và nâng hệ cũ" là một trong những ngách dễ bán nhất. Lý do rất đơn giản: ai cũng có nợ kỹ thuật, ai cũng muốn gọn, và agent làm khâu "đọc cho hiểu" nhanh hơn người gấp nhiều lần — nó đọc cả repo trong vài phút, thứ mà một anh dev mất cả tuần mới nắm được hình dạng.
Nhưng đây cũng là ngách khó định giá nhất, vì "dọn xong" không định nghĩa được. Dọn code cũ không có điểm kết thúc. Hôm nay gọn rồi, mai khách nhìn lại thấy một chỗ kỳ cục khác. Anh em không bán được một kết quả có bờ, mà bán lửng lơ một thứ không ai biết khi nào là hết.
Mình nghĩ đây chính là chỗ nhiều anh em làm automation tự bắn vào chân mình: phần máy làm nhanh nhất là phần dễ demo nhất, nên mình đem phần đó ra bán. Nhưng phần quyết định lời lỗ lại là phần máy không được phép làm, và phần đó thì không demo được, không slide được, không ai thấy.
Cách đóng gói: bảo vệ cái không hoàn tác được
Bốn quy tắc mình rút ra, sau khi ăn đủ đau với chuyện giao hệ cũ cho máy.
1. Ảnh gốc trước khi chạm. Trước khi cho agent sửa một dòng, phải chụp lại được trạng thái gốc và trạng thái chạy được. Không có bước này thì mọi thứ phía sau là cá cược. Nguyên tắc mình tự đặt: không hoàn tác được không phải là lỗi — nó là tổn thất. Lỗi sửa được. Tổn thất thì không.
2. Quyền đọc trước, quyền ghi có trần. Giai đoạn một, agent chỉ đọc và đề xuất. Giai đoạn hai mới được sửa, sửa từng phần nhỏ, và có trần số dòng được chạm trong một lượt. Mình không bao giờ để nó vừa đề xuất vừa tự duyệt đề xuất của chính nó — đó là chỗ sinh ra mấy vụ xoá im lặng.
3. Mỗi thay đổi phải trả lời được "lý do tìm thấy". Nếu nó muốn xoá một đoạn, nó phải chỉ ra được bằng chứng vì sao đoạn đó không ai dùng — không phải cảm giác "trông thừa". Chứng minh không nổi thì để nguyên. Cả đời mình làm nghề, mình chưa thấy lần nào giữ lại một dòng thừa mà lỗ, còn xoá mất một dòng chịu lực thì thấy vài lần rồi.
4. Quyền quyết ở đúng một chỗ: chỗ không có đường lùi. Xoá, ghi đè, publish, migration — những hành động không hoàn tác được thì phải có người duyệt. Không phải vì máy dở. Mà vì đó là chỗ duy nhất mà một quyết định sai không sửa lại được.
Hình dạng tối thiểu mình hay dùng, đại khái thế này:
# PSEUDO-CODE minh hoạ — không phải nguồn triển khai
phien_don = {
"trang_thai_goc": chup_lai(...), # bắt buộc, trước mọi thứ khác
"quyen": "chi_doc", # giai đoạn 1: chỉ đọc + đề xuất
"tran_sua": n_dong_toi_da, # giai đoạn 2: sửa nhỏ, có trần
"bang_chung": [], # mỗi đề xuất xoá PHẢI kèm lý do tìm được
"diem_nguoi_duyet": ["xoa", "ghi_de", "migration"],
}
# cấm: xoá khi không chứng minh được là không ai dùng
# cấm: để agent tự duyệt đề xuất của chính nó
# cấm: chạm vào hành động không hoàn tác được mà không có người ở cửaCái này không làm con agent thông minh hơn. Nó làm con agent không phá được — và với mình, đó mới là thứ đem đi bán được.
Vậy bán cái gì trước?
Bài học mình tự rút ra: đừng mở màn bằng "tôi dọn code cũ cho anh".
Mở màn bằng một lượt chỉ đọc, không sửa. Một bản đồ nói cho khách biết hệ của họ đang có bao nhiêu phần mà không ai còn nhớ vì sao nó ở đó. Bán nó với giá phẳng, không rủi ro, không dính dáng gì tới việc xoá.
Mình thấy đây là món dễ bán hơn hẳn phần sửa, vì nó đánh trúng đúng nỗi sợ lớn nhất của người có hệ cũ: họ không biết trong đó có gì. Không ai sợ trả tiền để được nhìn rõ. Người ta chỉ sợ trả tiền xong vẫn mù.
Sau đó mới tới phần sửa — giá theo việc, có trần, có hồ sơ, có đường lùi. Và đo bằng đúng hai con số mình vẫn dùng: trên 1000 lượt, khách phải sửa tay bao nhiêu lần — và bao nhiêu lần phải khôi phục từ ảnh gốc. Con số thứ hai khác 0 là dấu hiệu mình đang giao quyền sai chỗ.
Cái mình giữ lại hôm nay
Mình không muốn kết bài bằng kiểu "nên cẩn thận". Mình nghĩ ngược lại: ngách này ngon, vì nợ kỹ thuật thì vô hạn, còn số người biết cách dọn mà không phá thì ít.
Chỉ là, khi giao một hệ cũ cho máy dọn, thứ cần bảo vệ nhất không phải code. Code sinh lại được. Thứ cần bảo vệ là mấy lý do không ai viết ra — và mình đang là người duy nhất còn giữ chúng.
Nếu anh em bắt đầu dựng một lớp agent để dọn dẹp, đừng bắt đầu bằng câu "nó làm được gì". Bắt đầu bằng câu ngược lại: "nó tuyệt đối không được đụng vào cái gì?" Trả lời được câu đó rồi, phần còn lại dễ như ăn kẹo.
Câu mình để lại cho anh em hôm nay: trong hệ của anh em, có dòng nào anh em không dám xoá mà cũng không nhớ vì sao nó ở đó không?
Đó đúng là dòng mà con agent đầu tiên sẽ xoá.
Một phần của chuỗi mổ xẻ kỹ thuật tại zeodavu.com/blog. Nếu thấy hữu ích, theo dõi [zeodavu.com](/blog) — mỗi bài là một thứ mình thật sự dùng, vấp, và sửa lại.