# Món hàng đã bán rồi mà hệ vẫn tưởng còn: tự động hoá cho dân bán online, chỗ khó không nằm ở API
Có một kiểu lỗi mà mình nghĩ ai từng viết tool cho người bán hàng online đều gặp, và nó không giống bất kỳ lỗi nào khác.
Nó không làm hệ sập. Log vẫn xanh. Không có exception nào. Chỉ là sáng hôm sau, người bán nhận hai tin nhắn: một người mua báo "món này tôi chuyển tiền rồi sao vẫn thấy còn hàng", và một người mua khác báo "tôi cũng mua món đó".
Hai người cùng mua một món. Món đó chỉ có một.
Mình không kể chuyện này để doạ nhau về AI. Mình kể vì nó là cửa vào của một thứ rất cụ thể: khi bạn tự động hoá việc bán hàng trên một nền tảng của người khác, dữ liệu bạn đang giữ không phải là sự thật. Nó chỉ là ký ức của bạn về sự thật.
Listing không phải một dòng trong database của bạn
Đây là chỗ mình thấy nhiều người làm tool bán hàng hiểu sai ngay từ đầu, và cái sai đó không bao giờ tự lộ ra trong bản demo.
Trong hệ của bạn, một món hàng là một dòng: mã, tên, giá, số lượng, mô tả. Bạn sửa dòng đó, bạn gọi API, xong. Cảm giác rất giống CRUD.
Nhưng ở phía nền tảng, cái listing đó không phải một dòng. Nó là một thoả thuận đang chạy: có người đang xem, có người đang theo dõi, có lượt xem đã tích, có thứ hạng tìm kiếm đang được tính, có đồng hồ đếm ngược nếu là đấu giá, có chính sách của sàn đang áp lên nó, và có những thay đổi do chính nền tảng hoặc người mua tạo ra mà bạn không hề biết.
Ba hệ quả, và cả ba đều đắt:
Nguồn sự thật không nằm ở bạn. Bạn có thể nghĩ "số lượng còn 5". Nền tảng có thể đang nói "còn 4", vì có một đơn vừa chốt ba phút trước. Nếu hệ của bạn tin vào bộ nhớ của mình thay vì hỏi lại, thì mọi phép tính phía sau đều đúng về mặt số học và sai về mặt thực tế.
Thao tác của bạn là thay đổi trạng thái, không phải ghi file. Sửa giá, đổi số lượng, đổi tiêu đề — đây không phải những thao tác trung tính. Người mua đang nhìn thấy chúng. Đồng hồ đang chạy. Thứ hạng có thể bị tính lại. Và có những thay đổi không hoàn tác được: một món đã bán giá thấp thì đã bán rồi.
Bạn không phải người duy nhất viết vào đó. Người bán tự sửa tay trên app. Người mua tạo đơn. Nền tảng đổi chính sách, ẩn listing, gắn cờ. Bất kỳ kiến trúc nào giả định "chỉ có mình tôi ghi" đều sẽ lệch, và sẽ lệch âm thầm.
Nên câu hỏi đầu tiên khi làm loại tool này không phải "gọi API nào", mà là: làm sao biết trạng thái thật của cái listing này ngay bây giờ. API chỉ là phương tiện trả lời câu đó.
Phản xạ sai: đăng lại thay vì sửa
Khi hệ lệch trạng thái, phản xạ tự nhiên của dev là "chạy lại đi". Xoá rồi tạo mới. Đẩy lại toàn bộ danh sách cho chắc.
Với file thì đúng. Với listing thì đây là kiểu phá hoại lịch sự nhất mà mình biết.
Vì "đăng lại" tạo ra một thực thể mới. Thực thể mới nghĩa là: mất lượt xem đã tích, mất người đang theo dõi, mất lịch sử bán, mất thứ hạng đã xây, và với sàn đấu giá thì mất luôn những lượt đặt giá đang có. Người bán không nhìn thấy gì trong vài ngày, rồi tự nhiên thấy món hàng bán chậm hẳn và không hiểu vì sao.
Nguy hiểm hơn: nếu lần đăng lại đó chạy hai lần, bạn có hai listing cho cùng một món. Hai listing cùng tồn tại thì hệ thống bán hàng của bạn vừa tự tạo ra oversell — chính cái lỗi mình kể ở đầu bài.
Nên nguyên tắc mình cho là bắt buộc: mọi thao tác phải neo vào cái id của chính nền tảng, không phải id trong hệ của mình. Và mỗi cái id đó chỉ được có một thao tác đang bay tại một thời điểm.
# pseudo-code minh hoạ — không phải nguồn triển khai
def cap_nhat(listing):
khoa = khoa_theo(listing.external_id) # không phải id nội bộ
if not khoa.lay_duoc():
return CHO_NGUOI("đang có thao tác khác trên listing này")
hien_tai = doc_tu_nen_tang(listing.external_id) # hỏi lại, đừng tin bộ nhớ
if hien_tai is KHONG_DOC_DUOC: # mạng, hạn mức, listing bị ẩn
return CHUA_BIET(listing.external_id) # KHÔNG retry mù
if hien_tai == listing.mong_muon:
return DA_DUNG # không gọi ghi gì cả
return ghi_delta(hien_tai, listing.mong_muon) # sửa phần lệch, không đẩy cả khốiHai dòng đáng chú ý nhất không phải dòng ghi, mà là hai dòng không ghi: một dòng trả về "đã đúng rồi, thôi", một dòng trả về "chưa biết, đừng làm gì". Hầu hết hệ tự động mà mình thấy đều thiếu cả hai. Chúng chỉ có một đường: cứ ghi.
Và "chưa biết" mới là trạng thái quan trọng nhất. Khi gọi API mà timeout, bạn không biết là nền tảng chưa nhận, hay đã nhận rồi mà trả lời không về. Hai khả năng đó dẫn tới hai hành động trái ngược nhau, và nếu bạn gộp chúng thành "lỗi, thử lại" thì bạn sẽ có lúc sửa hai lần, hoặc tạo hai lần. Với một cái file thì không sao. Với một listing đang có người xem thì có sao.
Cái sổ phải đối chiếu, không phải con bot phải thông minh
Chỗ này mình nghĩ là điểm khác biệt lớn nhất giữa tool bán được và tool demo được.
Tool demo: bạn đưa vào một danh sách món hàng, nó đăng lên, trông rất mượt.
Tool bán được: mỗi ngày nó đọc lại trạng thái thật của từng món, so với ý định, và in ra một tờ giấy ba cột.
| Mình tưởng | Nền tảng đang nói | Chênh |
|---|---|---|
| còn 5, giá 1.200 | còn 3, giá 1.200 | có 2 đơn mới — không phải lỗi của mình |
| đang bán, giá 1.200 | bị ẩn, không rõ lý do | cần người xem, đừng tự bật lại |
| đã sửa tiêu đề | tiêu đề cũ | lần ghi trước chưa ăn — có thể đang bị chặn |
| đang bán, giá 1.200 | không tìm thấy id này | cực kỳ nghiêm trọng: ai đó đã xoá |
Bốn dòng, bốn loại hành động khác nhau. Và điều mình muốn nhấn: cả bốn dòng đều không cần model nào để phát hiện. Chúng là phép so sánh. Cái đắt tiền nằm ở việc có dám đọc lại mỗi ngày hay không, không nằm ở chỗ dùng model gì.
Đến lúc cần model thì nó nên làm đúng một việc hẹp: đọc mô tả lộn xộn của người bán (viết tay, đủ thứ ngôn ngữ, đủ kiểu viết tắt) và rút ra được vài trường có cấu trúc — chất liệu, kích cỡ, tình trạng, phụ kiện. Đó là việc của ngôn ngữ. Việc "cái listing này đang ở trạng thái nào" là việc của một lần đọc API và một phép trừ.
Có một chi tiết vận hành dễ bị bỏ qua: ngân sách gọi API. Sàn nào cũng có hạn mức, và hạn mức đó tính theo cửa sổ thời gian. Nếu mỗi ngày bạn đọc lại toàn bộ 800 món thì bạn vừa đốt hạn mức vừa chậm, và đến lúc cần gọi thật để sửa thì hết quota. Cách mình thấy hợp lý là đọc theo thứ tự nghi ngờ: món có đơn mới, món vừa bị sửa tay, món sắp hết hạn, món có lần ghi trước không xác nhận được. Phần còn lại đọc cuốn chiếu, rải ra. Giống như đi tuần: không cần mở hết mọi cửa mỗi đêm, nhưng phải biết cửa nào đáng mở trước.
Chỗ con người phải giữ, và nó hẹp hơn bạn tưởng
Có một cám dỗ rất lớn khi làm tool này: cho máy tự đổi giá.
Về mặt kỹ thuật thì dễ. Về mặt sống còn thì không, vì giá là thứ không hoàn tác được. Đã bán rẻ là đã bán. Bạn không thể gọi API để lấy lại món hàng đã giao cho người mua.
Nên với mình, ranh giới rất rõ: máy được tự do làm những thứ sửa lại được (tiêu đề, mô tả, ảnh, thứ tự, nhãn phân loại), và phải xin phép ở những thứ không sửa lại được (giá, số lượng đăng bán khi đã có đơn, việc bật lại một listing bị nền tảng ẩn).
Nghe thì như giới hạn năng lực. Thực ra nó là thứ làm khách dám bật tool lên. Người bán hàng không sợ máy viết mô tả dở. Họ sợ máy bán mất món hàng của họ với giá sai. Giữ đúng ranh giới đó thì họ cho bạn quyền chạm vào 800 cái listing. Vượt ranh giới đó một lần thì bạn mất khách, và mất luôn cả lý do họ từng tin bạn.
Đây cũng là lý do mình thích mô hình "máy đề xuất, người bấm" ở giai đoạn đầu — không phải vì nó an toàn về mặt kỹ thuật, mà vì nó tạo ra một dòng dữ liệu cực quý: máy đề xuất gì và người ta có đồng ý không. Tỉ lệ đồng ý cao dần là bằng chứng bạn được phép nới quyền. Không có dòng dữ liệu đó thì việc nới quyền chỉ là cảm tính.
Ra tiền: đừng bán "agent", bán cái sổ
Phần này mới là chỗ mình nghĩ nhiều người làm sai hướng.
Nếu bạn đi bán "AI agent tự động đăng sản phẩm", bạn đang cạnh tranh với hàng chục tool có sẵn, nhiều cái miễn phí, và bạn đang bán đúng cái phần dễ nhất của bài toán — phần gọi API.
Thứ người bán hàng thật sự trả tiền không phải "đăng được". Họ đăng được rồi. Họ trả tiền cho việc không phải tự đi kiểm tra. Cụ thể là ba thứ:
Bán sự đối chiếu, theo tháng. "Mỗi sáng anh có một tờ giấy: món nào lệch, lệch cái gì, món nào cần anh quyết." Đây là nấc "việc đã xong" chứ không phải nấc "bán tool". Và nó thu tiền đều một cách chính đáng, vì nền tảng đổi, người bán đổi, đơn hàng vẫn về — cái sổ luôn có việc để làm.
Bán theo quy mô, không theo ghế. Giá theo số listing đang quản lý, có trần. Người bán 50 món trả ít, người bán 2.000 món trả nhiều hơn nhưng vẫn rẻ hơn một người làm part-time. Đừng bán "tiết kiệm bao nhiêu giờ" — đó là đơn vị của người làm, không phải của người trả tiền. Bán "hôm nay có 7 món lệch, trong đó 2 món đáng lo".
Bán phần khó nhất: bộ luật riêng của từng shop. Mỗi người bán có một kiểu lệch riêng. Người thì luôn quên cập nhật số lượng sau khi bán offline. Người thì có ba listing trùng cho cùng một món vì đăng lại nhiều lần. Người thì bị nền tảng ẩn vì lý do chính sách mà không đọc thông báo. Mấy cái này không có trong tài liệu API nào. Chúng là thứ bạn chỉ có được sau vài tháng ngồi với khách, và đó chính là phần không ai copy được trong một tuần.
Và cũng đừng đo bằng "số listing đã đẩy lên". Đo bằng hai con số khó chịu hơn:
- ▹Số lệch phát hiện được trước khi khách phát hiện. Con số này là giá trị thật của bạn.
- ▹Số lần khách phải sửa tay trên 1.000 lần chạy. Con số này nói lên hệ của bạn còn hở ở đâu.
Nếu con số thứ nhất thấp mà con số thứ hai cũng thấp, rất có thể bạn đang không kiểm tra gì cả — chỉ là chưa ai báo lỗi thôi.
Kết: cái hệ giỏi nhất là cái biết mình không biết
Mình vẫn nghĩ đây là loại bài toán đẹp, vì nó không đòi model khổng lồ, không đòi hạ tầng gì ghê gớm. Nó đòi đúng một thứ: thái độ đúng với trạng thái.
Tin vào bộ nhớ của mình thì hệ sẽ nói dối rất tự tin. Hỏi lại mỗi ngày thì hệ chậm hơn một chút nhưng nói thật. Và trong một cái nghề mà mỗi lần sai là một đơn hàng thật bị huỷ, nói thật quan trọng hơn nhanh.
Nếu anh em đang định dựng tool cho dân bán hàng online, mình xin để lại một câu hỏi tự soi trước khi viết dòng code đầu:
Nếu sáng mai khách mở app ra và sửa tay 20 cái listing, hệ của mình phát hiện chuyện đó lúc nào, và phát hiện bằng cách nào?
Trả lời được thì bạn đang làm một cái sổ. Không trả lời được thì bạn đang làm một cái loa — nó chỉ biết nói, không biết nghe.
Anh em có ai từng làm tool đẩy dữ liệu lên một nền tảng của người khác chưa? Mình rất muốn nghe cái lần đầu tiên anh em phát hiện ra "chạy lại đi" không phải là câu trả lời đúng. Chỗ đó thường là lúc nghề này bắt đầu khó, và cũng là lúc nó bắt đầu đáng tiền.