Web Storefront
Chọn vị trí hiển thị, trang và số sản phẩm cần lấy. Trang chi tiết gửi thêm productId làm sản phẩm mốc.
Trước khi sản phẩm được gợi ý
Không chỉ hỏi “sản phẩm nào bán chạy?” — hệ thống còn kết nối người mua quan tâm gì, đang xem gì và sản phẩm nào liên quan. Từ đó, danh sách được xếp theo từng ngữ cảnh; mỗi tương tác lại góp dữ liệu cho lần gợi ý tiếp theo.
Chưa có lịch sử? Hệ thống vẫn thử nguồn candidate dự phòng và xếp hạng bằng Standard.
Sở thích, phiên truy cập và sản phẩm đang xem
Tìm từ hồ sơ, xu hướng, nội dung tương đồng và hành vi.
Standard chấm theo trọng số; AI-Enhanced kết hợp dự đoán ML.
Sản phẩm phù hợp, thứ hạng và lý do gợi ý
Kết quả mở đầu cho lần gợi ý tiếp theo. Impression và click đi qua Kafka để cập nhật hồ sơ, không chặn request hiện tại.
Đọc tiếp: mở Kiến trúc hệ thống bên dưới để xem service nào đứng sau từng bước.
Chọn vị trí hiển thị, trang và số sản phẩm cần lấy. Trang chi tiết gửi thêm productId làm sản phẩm mốc.
Chuyển tiếp GET /api/v1/recommendation/recommendations cùng user đã xác thực hoặc session khách; Web không tự truy vấn catalog hay xếp hạng sản phẩm.
Kiểm tra surface, định dạng ID và phân trang. Mỗi trang tối đa 24 sản phẩm; khách chỉ xem trang đầu, trang chi tiết tối đa 6.
Mục đích
Nếu kết quả còn dùng được, service bỏ qua việc đọc hồ sơ/phiên, gom sản phẩm tiềm năng và chạy xếp hạng/ML. Nhờ đó giảm thời gian chờ và tải lặp lên các nguồn dữ liệu, nhất là ở trang có nhiều request cùng ngữ cảnh.
Dữ liệu được lưu
Redis lưu response của đúng trang: sản phẩm, thứ hạng, điểm, nguồn/lý do và metadata. Khi cache miss, kết quả được dựng từ hồ sơ/catalog trong PostgreSQL, hành vi gần đây trong session và candidate từ xu hướng, quan hệ hoặc Qdrant khi có dữ liệu phù hợp. Redis chỉ giữ bản kết quả tạm, không thay dữ liệu gốc.
Điều kiện cache hit
Key phải khớp người dùng/phiên khách, vị trí, sản phẩm mốc, trang, phiên bản luật xếp hạng/thử nghiệm và version cache; kết quả cũng phải còn hạn. TTL mặc định 5 phút, cấu hình từ 30 giây đến 1 giờ. Mỗi lượt hit vẫn có requestId và item token mới.
Đánh đổi & kiểm soát
Hành vi mới có thể cần chờ Kafka cập nhật hồ sơ. Khi cập nhật xong, phiên bản cache của người đó tăng để request kế tiếp bỏ qua snapshot cũ; catalog đổi cũng tăng phiên bản cache chung. Nếu Redis lỗi, hệ thống chạy lại pipeline từ PostgreSQL nhưng thiếu ngữ cảnh phiên, nên phản hồi có thể chậm và kém cá nhân hóa hơn. TTL giới hạn thời gian lưu snapshot.
HIT · response đã xếp hạng + requestId/token mới
MISS · dựng ngữ cảnh → tìm ứng viên → xếp hạng → lưu cache
03 chặng ·09 nguồn
Kết hợp sở thích đã lưu với hành vi mới để chọn hướng tìm.
Hồ sơ dài hạn
PostgreSQL · tối đa 30 sản phẩm, 12 danh mục và 12 thương hiệu.
Phiên hiện tại
Redis · các mặt hàng và nhóm hàng vừa được tương tác.
Chiến lược tìm
Có sở thích → cá nhân hóa; thiếu dữ liệu → theo phiên hoặc cold-start.
Các nguồn chạy độc lập; nguồn thiếu dữ liệu được bỏ qua, không chặn nguồn khác.
01 · PRODUCT_AFFINITY · HỒ SƠ
Đưa lại mặt hàng từng tạo tín hiệu sở thích tích cực.
02 · CATEGORY_AFFINITY · HỒ SƠ + PHIÊN
Mở rộng sang nhóm hàng người mua đang quan tâm.
03 · BRAND_AFFINITY · HỒ SƠ + PHIÊN
Giữ lại thương hiệu người mua thường chọn.
04 · TRENDING · NGUỒN NỀN
Bổ sung sản phẩm có xu hướng tăng.
05 · BEST_SELLING · COLD-START
Tạo điểm bắt đầu khi chưa rõ sở thích.
06 · NEWEST · COLD-START
Dành chỗ cho sản phẩm mới chưa có lịch sử.
07 · EXPLORE · COLD-START
Thêm lựa chọn mà không ngẫu nhiên mỗi request.
Loại trùng và giới hạn tập đầu vào trước khi xếp hạng.
Thu nguồn
Một nguồn lỗi không dừng phần còn lại.
Loại món vừa xem
Bỏ sản phẩm mốc và tối đa 3 món mới tương tác.
Gộp sản phẩm trùng
Giữ một productId cùng nguồn và lý do tìm thấy.
Giới hạn pool
Tối đa 300 món, chia lượt giữa các nguồn nếu cần.
Pool ≤300 · ứng viên chuyển sang Standard hoặc AI-Enhanced Ranking; chưa phải thứ tự hiển thị.
Chi tiết hợp nhấtHai phương pháp dùng chung quy trình tìm sản phẩm, chỉ khác cách chấm điểm. Trong thử nghiệm, mỗi tài khoản hoặc phiên khách luôn ở cùng một nhánh; lượt hiển thị, nhấp và đơn hoàn tất được gắn về đúng gợi ý để so sánh. AI không mặc định được xem là tốt hơn.
Công thức điểm
clamp(Σ(weight × feature) − negativePenalty, 0, 1)8 feature được chuẩn hóa; trọng số policy có tổng 100%, penalty từ sở thích âm được trừ riêng.
hybridWeights trong policy; HYBRID là baseline để đối chiếu ranking mode.Đánh đổi · Dễ kiểm soát, không cần gọi model; nhưng phụ thuộc trọng số con người đặt và khó nắm hết tương tác phức tạp giữa tín hiệu.
Công thức điểm
clamp(Standard × (1 − mlBlend) + ML × mlBlend, 0, 1)Model dự đoán điểm cho từng ứng viên từ cùng feature vector; không tạo thêm nguồn sản phẩm.
mlBlend mặc định 0,3, giới hạn tối đa 0,5. Analytics nhóm theo ranking mode thực tế để đo hiệu quả có attribution.Đánh đổi · Có thể khai thác quan hệ giữa nhiều tín hiệu, nhưng cần model ổn định, thêm độ trễ inference và attribution đủ tin cậy để chứng minh hiệu quả.
Quyết định bằng outcome, không chỉ bằng score
So impression → click → đơn hoàn tất có attribution; dùng kết quả để tinh chỉnh trọng số Standard hoặc tỷ lệ blend.
Sau xếp hạng, cả hai nhánh cùng qua bước cân bằng độ đa dạng; danh sách chuẩn tối đa 180 sản phẩm.
Trên từng sản phẩm
source cho biết nguồn ứng viên được ưu tiên; reasons là câu viết sẵn ánh xạ từ nguồn đó (ví dụ PRODUCT_AFFINITY → “Dựa trên sản phẩm bạn từng quan tâm”). Nếu nhiều nguồn cùng tìm thấy sản phẩm, API chọn nguồn đứng trước theo thứ tự ưu tiên — đây không phải lời giải thích do AI tạo.Trên toàn bộ response
Dấu vết xếp hạng
null.null.Giới hạn danh sách
Tối đa 24 sản phẩm mỗi trang · trang chi tiết tối đa 6 · khách chỉ xem trang đầu.
Ghi nhận đúng lượt tương tác
recommendationItemId được ký theo người dùng/phiên, request, sản phẩm, thứ hạng và policy để xác thực impression/click đúng lượt gợi ý. Ngay cả khi Redis trả danh sách đã cache, mỗi response vẫn có requestId và token mới, tránh gộp nhầm nhiều lần hiển thị.
Nguồn 01 · tín hiệu quan tâm
Ghi lại điều người mua quan tâm trước khi phát sinh giao dịch.
Bước 01
Web Storefront
Ghi impression, view, click, tìm kiếm và thêm giỏ.
Bước 02
API Gateway
Nhận event đơn/lô và identity user/guest.
POST /api/v1/recommendation/events · /events/batchBước 03
InteractionIngestionService
Kiểm tra event, attribution; gắn eventId và giờ server trước khi gửi Kafka.
Nguồn 02 · giao dịch đã xác nhận
Chỉ ghi nhận giao dịch do Order Service xác nhận, không suy đoán từ click.
Bước 01
Order Service
Phát event khi đơn hoàn tất hoặc hàng hoàn được xác nhận.
Bước 02
PostgreSQL Outbox
Ghi event cùng transaction cập nhật đơn hoặc hoàn hàng.
Bước 03
Outbox dispatcher
Gửi event lên Kafka; retry nếu broker chưa xác nhận.
Event bus · buffer và phân phối
Web chỉ trả HTTP 202 sau khi broker nhận event, không chờ consumer xử lý xong. Với đơn hàng, Order Service ghi event vào PostgreSQL Outbox trước khi dispatcher gửi lên Kafka.
Luồng event (Kafka topic)
recommendation.interactions.v1order.purchase.completedorder.purchase.returnedKafka giải quyết gì?
Kafka đệm event rồi phân phối cùng luồng cho hai consumer group: một cập nhật hồ sơ, một dựng quan hệ sản phẩm. Hai nhánh scale và retry độc lập; key user/session giữ thứ tự tương đối của tương tác cùng một người.
Đánh đổi & xử lý lỗi
HTTP 202 chỉ xác nhận broker đã nhận, không có nghĩa dữ liệu đã cập nhật. Consumer chỉ đánh dấu offset sau xử lý; ledger chống ghi trùng nếu event được gửi lại. Lỗi được retry giới hạn rồi chuyển vào dead-letter queue (DLQ) để xử lý riêng. Nếu publish Web lỗi, API trả 503; event đơn hàng còn trong outbox để dispatcher gửi lại.
Hai loại dữ liệu · hai điểm sử dụng
Consumer 01 lưu người mua quan tâm gì; Consumer 02 tìm các sản phẩm thường xuất hiện cùng nhau. Luồng đọc lấy hai loại dữ liệu này khi Redis cache miss; cache hit trả kết quả đã lưu.
Consumer group 01 · hồ sơ người mua
Consumer group 02 · quan hệ sản phẩm
Nhận event không đồng nghĩa hồ sơ đã cập nhật.
HTTP 202 xác nhận event Web đã vào hàng đợi; Order Service dùng outbox để không mất event khi cập nhật đơn. Hai consumer xử lý nền, nên hồ sơ và quan hệ chỉ ảnh hưởng request gợi ý sau khi projection hoàn tất.
Gọi API gợi ý, hiển thị kết quả và gửi impression/click gắn với đúng request.
Chuyển tiếp request/event cùng identity user hoặc session; không tự tạo hay xếp hạng gợi ý.
Đọc cache/ngữ cảnh, gom ứng viên, xếp hạng và trả sản phẩm kèm nguồn, lý do, attribution.
Dự đoán điểm cho AI-Enhanced; nếu prediction không dùng được, Recommendation quay về Standard.
Gửi lượt xem, click, tìm kiếm và thêm giỏ vào luồng ghi nhận hành vi.
Phát thay đổi sản phẩm; Recommendation đồng bộ vào catalog read model riêng.
Phát đơn hoàn tất/hoàn trả qua outbox để tín hiệu mua dựa trên giao dịch đã xác nhận.
Consumer trong Recommendation cập nhật catalog, profile/session và quan hệ sản phẩm cho request sau.
Ranh giới service: Catalog read model và Kafka consumer là module/worker bên trong Recommendation Service, không phải microservice độc lập. Request gợi ý đọc dữ liệu đã đồng bộ, không truy cập trực tiếp database của Product hoặc Order.
Mỗi lần trang yêu cầu gợi ý, hệ thống xử lý để trả danh sách ngay. Lượt xem, nhấp và đơn hàng được xử lý nền qua Kafka; dữ liệu mới chỉ tác động đến những request tiếp theo.
Đọc sở thích đã tích lũy, hoạt động gần đây, màn hình và sản phẩm đang xem để chọn gợi ý cá nhân hóa, theo phiên hoặc dành cho khách mới.
Giải quyết: không dùng chung một danh sách cho mọi người.
Catalog tìm theo sản phẩm, danh mục, thương hiệu và xu hướng; hệ thống còn có thể tìm mặt hàng gần nội dung hoặc thường được xem/mua cùng nhau khi đủ dữ liệu.
Giải quyết: mở rộng lựa chọn mà không để một nguồn quyết định tất cả.
Standard chấm 8 tiêu chí trên cùng thang điểm. AI-Enhanced dự đoán lại điểm trên chính danh sách đó; bước cân bằng sau cùng tránh để một nhóm chiếm quá nhiều vị trí.
Giải quyết: vừa có baseline giải thích được, vừa có đường thử ML an toàn.
Web nhận danh sách kèm thứ hạng, nguồn, lý do và mã truy vết đã ký để nối lượt thấy/nhấp với đúng sản phẩm. Consumer cập nhật dữ liệu nền cho request sau.
Giải quyết: giữ request nhanh và biết được item nào đã được hiển thị.
Các phần dưới giải thích dữ liệu đến từ đâu, từng điểm số ảnh hưởng thế nào và hệ thống cân bằng độ mới, đa dạng với tốc độ ra sao.
Dữ liệu bền vững · PostgreSQL
Ý định ngắn hạn · Redis
Chọn cách tìm ứng viên
Hồ sơ là sở thích đã tích lũy; phiên là sản phẩm hoặc danh mục người mua đang xem lúc này.
PERSONALIZED
Ưu tiên sở thích đã tích lũy; hoạt động trong phiên và nguồn catalog vẫn có thể bổ sung sản phẩm.
SESSION_BASED
Chưa có sở thích ghi nhận nhưng đang xem sản phẩm hoặc danh mục? Dùng hoạt động trong phiên làm tín hiệu, kể cả với khách chưa đăng nhập.
COLD_START
Tạo danh sách mở đầu từ hàng bán chạy, hàng mới và khám phá; xu hướng vẫn được bổ sung riêng.
Một lần mở trang sản phẩm được tính +1. Các hành vi khác quy đổi theo mốc này để dễ so sánh và điều chỉnh.
+1=một lượt xem sản phẩm
Impression được tính rất nhẹ; click và thêm giỏ thể hiện quan tâm rõ hơn. Đơn hoàn tất là tín hiệu mạnh nhất.
0,05→2→4→8
Hiển thị → click → giỏ → mua
Bỏ giỏ chỉ trừ một phần điểm; trả hàng đảo điểm mua theo đúng số lượng được trả.
Bỏ giỏ −2·Trả hàng −8 / sản phẩm
Mặc định trong RecommendationRuleService; có thể ghi đè bằng RECOMMENDATION_WEIGHT_*.
Impression
+0,05 · 1/20 lượt xem
Tìm kiếm
+1,5 · giữa +1 / +2
Click
+2 · 2 lượt xem
Thêm giỏ
+4 · 2 click
Mua hàng
+8 · mỗi SP
Điểm âm: bỏ giỏ −2 giảm một nửa điểm thêm giỏ; trả hàng −8 đảo điểm mua theo số lượng được trả.
Impression
0,05Chỉ xác nhận sản phẩm đã xuất hiện. 20 impression cùng một sản phẩm cộng bằng +1 trước suy giảm thời gian, tránh exposure lấn át ý định thật.
Xem sản phẩm
1Một lần mở trang sản phẩm cộng một đơn vị. Chọn mốc 1 để các hành vi khác có thể đọc thành bội số dễ so sánh.
Tìm kiếm
1,5Tìm kiếm chủ động hơn lướt xem nhưng chưa gắn chắc với một sản phẩm. Hiện điểm được lưu ở QUERY, request chưa dùng chiều này để gợi ý.
Click
2Mở sản phẩm được tính gấp đôi lượt xem vì có hành động chủ động; vẫn thấp hơn giỏ hàng vì chưa thể hiện ý định mua.
Thêm vào giỏ
4Tín hiệu mua mạnh hơn mở trang nhưng chưa phải giao dịch đã xác nhận, nên giữ dưới mức +8 của đơn hoàn tất.
Xóa khỏi giỏ
−2Nếu thêm giỏ +4 rồi xóa −2, hồ sơ còn +2: giảm ý định mua nhưng không xóa lịch sử xem. Đây là điều chỉnh nhẹ hơn một lần trả hàng.
Đơn hoàn tất
+8Đơn đã xác nhận là tín hiệu mạnh nhất. Điểm nhân với số lượng: mua 2 sản phẩm cùng mã cộng +16 vào preference sản phẩm và danh mục nếu có mã.
Đơn trả hàng
−8Cùng độ lớn ngược dấu với mua hàng: trả 1 sản phẩm trừ −8, trả một phần chỉ hiệu chỉnh đúng số lượng đã trả.
Ngữ cảnh đầu vào
Hồ sơ
Tối đa 30 sản phẩm, 12 danh mục và 12 thương hiệu có preference dương.
Phiên
Bổ sung danh mục và thương hiệu vừa xem để phản ánh ý định mới.
Loại trừ
Sản phẩm đang mở và tối đa 3 sản phẩm tương tác gần nhất.
Chuẩn hóa trước khi truy vấn
Ba nhánh truy vấn chạy song song
Mỗi nhánh tìm candidate theo một loại tín hiệu; các giới hạn dưới đây được áp dụng riêng cho từng nhánh.
PRODUCT_AFFINITY
Tối đa 30Tra product ID có preference dương, giữ thứ tự sở thích; chỉ trả món đang hoạt động và còn hàng.
Đổi lại: sát sở thích đã biết, nhưng không tự tìm món mới nếu profile thiếu ID phù hợp.
CATEGORY_AFFINITY
Tối đa 100Ghép danh mục hồ sơ với danh mục vừa xem; ưu tiên món còn hàng có tổng đã bán cao.
Đổi lại: tăng độ phủ, nhưng cùng danh mục chưa chắc cùng ý định cụ thể.
BRAND_AFFINITY
Tối đa 80Ghép thương hiệu hồ sơ với thương hiệu vừa xem; ưu tiên món còn hàng có tổng đã bán cao.
Đổi lại: hợp với người trung thành thương hiệu, nhưng có thể làm lựa chọn kém đa dạng.
Hợp nhất kết quả
Ba danh sách candidate có thể trùng nhau. Hợp nhất khử trùng theo productId, đồng thời giữ lại nguồn đã tìm thấy từng món.
Ranking quyết định thứ tự
Feature hồ sơ được tính từ preference đã suy giảm theo thời gian và chuẩn hóa về 0–1:
profileAffinity = clamp(P + 0,6C + 0,4B)
P/C/B lần lượt là điểm sản phẩm/danh mục/thương hiệu. Trọng số Standard mặc định là 25%, có thể thay theo policy.
Chọn theo dữ liệu thực sự có
Không có điểm đủ lớn thì hệ thống không tự bịa ra sở thích.
PERSONALIZED
Có preference dương trong hồ sơ
Dùng affinity cá nhân và các nguồn mở rộng; trending vẫn bổ sung góc nhìn thị trường.
SESSION_BASED
Chưa có hồ sơ dương, nhưng có context phiên
Dựa vào danh mục/thương hiệu vừa xem; không thêm cả bộ best-selling, newest và explore.
COLD_START
Chưa có hồ sơ hay context phiên
Bổ sung ba nguồn catalog ổn định để request đầu tiên vẫn có lựa chọn.
Truy vấn catalog song song
Tất cả chỉ lấy sản phẩm đang hoạt động, còn hàng và không nằm trong danh sách loại trừ.
TRENDING
mọi strategyTối đa 80 món, xếp theo tổng hợp hành vi: 0,1×view hôm nay + 0,5×click hôm nay + 2×add-to-cart 7 ngày + 3×purchase 30 ngày.
Nếu thiếu aggregate gần đây, code dùng legacy popularity; hòa điểm thì ưu tiên total_sold rồi productId. Vẫn là xu hướng chung, không phải sở thích riêng.
BEST_SELLING · COLD_START
Tối đa 80 món, sắp theo total_sold giảm dần; tạo mốc khởi đầu đáng tin khi chưa có hành vi cá nhân.
Có thể nghiêng về món lâu năm, chưa chắc đang tăng nhu cầu.
NEWEST · COLD_START
Tối đa 80 món, sắp theo created_at mới nhất; không đợi sản phẩm tích lũy view hay đơn bán.
Đổi lại, hàng mới chưa có đủ dữ liệu để xác nhận chất lượng.
EXPLORE · COLD_START
Tối đa 60 món theo productId tăng dần; cùng request sẽ không đổi ngẫu nhiên vì thứ tự nguồn.
Ổn định và đa dạng, nhưng thứ tự này không biểu thị độ phù hợp.
Hợp nhất và bàn giao
Đầu ra & xử lý lỗi
Mỗi nguồn trả về một list riêng, không trả vị trí cuối. Nguồn chạy song song; nếu một truy vấn lỗi, nguồn khác vẫn được giữ. Candidate Union gộp trùng và giới hạn toàn pool ở 300 trước ranking.
Đánh đổi & cách cải thiện
Nguồn thị trường giúp tránh danh sách rỗng nhưng có thể quá đại trà; bestseller nhìn về tổng bán, newest ưu tiên độ mới, explore ưu tiên tính ổn định. Các mức 80/80/60/80 là giới hạn hiện tại, cần đánh giá coverage, latency và hiệu quả ranking trên toàn bộ traffic trước khi tinh chỉnh.
Chuẩn bị trước · bất đồng bộ
Recommendation request không gọi model để tạo embedding mới.
01 · NỘI DUNG
Catalog snapshot
Tên, thương hiệu, đường dẫn danh mục, mô tả và thuộc tính.
02 · CHUẨN HÓA
Tạo nội dung chuẩn + hash
Loại HTML, chuẩn Unicode/khoảng trắng, giới hạn độ dài; hash chỉ đổi khi nội dung ngữ nghĩa đổi.
03 · EMBEDDING JOB
Tạo vector ngoài request
Job phát yêu cầu; worker embedding xử lý theo model/số chiều cấu hình rồi cập nhật Qdrant. Giá, tồn kho không buộc tạo lại vector.
04 · LƯU VECTOR
Qdrant · trạng thái READY
Lưu vector cùng productId, contentHash và modelVersion để request tra đúng phiên bản.
Khi có request · retrieval online
Mỗi bước chỉ đọc hoặc biến đổi dữ liệu đã có.
Món đang xem có trọng số 1; lấy tối đa 5 món gần đây theo event weight dương (thiếu thì dùng 1, bằng 0/âm thì bỏ); lấy tối đa 5 món sở thích hồ sơ, mỗi món × 0,5.
Khử trùng anchor và cộng trọng số nếu trùng ID. Đọc vector theo productId + contentHash; chỉ nhận vector READY, đúng model, đúng số chiều và toàn giá trị hữu hạn.
Tính trung bình có trọng số của vector các anchor. Món đang xem hoặc event mạnh tác động nhiều hơn; hồ sơ dài hạn vẫn bổ sung ngữ cảnh.
Qdrant tìm gần nhất theo metric cấu hình (Cosine mặc định), tối đa 60. Chỉ xét hàng ACTIVE, còn tồn, embedding READY, đúng model và không thuộc danh sách loại trừ.
Lấy thông tin sản phẩm từ Catalog. Chỉ nhận kết quả nếu contentHash trong Qdrant vẫn bằng snapshot hiện tại; raw similarity được giữ làm bằng chứng cho ranking.
Đầu ra · chuẩn hóa
Công thức · gộp nhiều ý định thành một query
q = Σ(wᵢ × vᵢ) / Σwᵢ
vᵢ là vector nội dung của sản phẩm anchor; wᵢ là mức ưu tiên từ ngữ cảnh. Ví dụ: món đang xem = 1, món vừa thêm giỏ = event weight, món hồ sơ = 0,5. Nếu cùng một ID xuất hiện ở nhiều nhóm, trọng số được cộng trước khi tính.
Đây là weighted mean của vector đã có, không phải cộng điểm sản phẩm và không phải AI sinh danh sách bằng prompt.
Đầu ra, cách dùng và giới hạn
CANDIDATE_PIPELINE_V3_ENABLED/SEMANTIC_CANDIDATES_ENABLED, thiếu vector tương thích, Qdrant lỗi hoặc nội dung đã đổi thì source trả rỗng; các nguồn khác vẫn chạy.Giai đoạn A · chiếu dữ liệu bất đồng bộ
Mỗi quan hệ được lưu hai chiều: A → B và B → A.
CO_VIEWcùng session · 30 phútXem, click hoặc impression gần nhau
Ghép tối đa 20 tín hiệu PRODUCT_VIEWED, PRODUCT_CLICKED, PRODUCT_IMPRESSED trong cùng session. Trọng số mặc định lần lượt là 1, 2 và 0,05.
CO_CARTcùng user/session · 7 ngàyCùng được thêm vào giỏ
Ghép tối đa 50 event PRODUCT_ADDED_TO_CART trong cửa sổ thời gian; trọng số mặc định là 3. Có thể nối qua user hoặc session nếu định danh tương ứng tồn tại.
CO_PURCHASEcùng một đơn hàngCác món xuất hiện trong cùng đơn
Tạo cặp từ các productId khác nhau trong đơn (tối đa 50 mã). Đơn hoàn tất mặc định +6; đơn trả hàng tạo hiệu chỉnh −6 để giảm quan hệ đã ghi.
Các trọng số là default có thể cấu hình. Event ledger và pair ledger giúp retry không cộng cùng một cặp hai lần; quan hệ được giới hạn top 100 đích cho mỗi anchor/loại.
Event → pair → relation scoreGiai đoạn B · request recommendation
Không quét lại toàn bộ lịch sử event trong mỗi request.
Gộp món đang xem, tối đa 30 product preference dương và product trong session; khử trùng rồi giữ 10 ID đầu theo thứ tự: món đang xem → hồ sơ → session.
Tra quan hệ đi ra từ từng anchor theo CO_VIEW/CART/PURCHASE. Điểm giảm theo tuổi quan hệ; chỉ lấy effective score > 0, top 100 mỗi cặp anchor/loại rồi giới hạn toàn truy vấn ở 100.
Bỏ món trong danh sách exclude của request. Nếu một target nối từ nhiều anchor/loại quan hệ, gom thành một sản phẩm và giữ từng contribution; điểm mạnh nhất được xếp trước.
Lấy (hydrate) dữ liệu Catalog cho tối đa 100 target; gắn source, anchor, relationType, rawScore và vị trí nguồn để bước ranking sử dụng.
Chuẩn hóa và bàn giao
Công thức · giảm ảnh hưởng của quan hệ cũ
effective = relationScore × 0,5(age / halfLife)
Mặc định halfLife = 30 ngày: quan hệ 30 ngày tuổi còn một nửa điểm; 60 ngày còn khoảng một phần tư. Giá trị được cấu hình bằng RELATION_SCORE_HALF_LIFE_DAYS.
Ví dụ: relationScore 8, tuổi 30 ngày → effective score 4. Đây là ví dụ tính decay, không phải điểm cố định cho mọi cặp.
Ý nghĩa đầu ra và trade-off
CO_BEHAVIOR_CANDIDATES_ENABLED, không có anchor/quan hệ hoặc query lỗi thì nguồn trả rỗng; candidate từ nguồn khác vẫn được dùng.n = score / (score + scale[loại]); coBehavior = max(n) qua các anchor/quan hệ của món đó. Scale mặc định: CO_VIEW 1, CO_CART 3, CO_PURCHASE 6 — không cộng mọi đường nối thành điểm phình lớn.Bàn giao sang ranking: mỗi quan hệ được chuẩn hóa thành feature theo loại (CO_VIEW/CART/PURCHASE); Standard Hybrid mặc định dành trọng số 0,10 cho coBehavior (policy có thể thay đổi).
Candidate ≠ thứ hạngThu thập và chuẩn hóa pool
Các nguồn được thu độc lập; pool sau cùng chỉ giữ một entry cho mỗi productId và tối đa 300 sản phẩm.
01 · THU KẾT QUẢ
Các nguồn chạy song song bằng Promise.allSettled: nguồn lỗi hoặc không có kết quả được bỏ qua, kết quả từ nguồn khác vẫn được giữ.
Đánh đổi: nguồn lỗi làm pool ít lựa chọn hơn, nhưng không làm hỏng cả request.
02 · LỌC ID
Tạo danh sách loại trừ gồm sản phẩm đang mở và tối đa 3 sản phẩm tương tác gần nhất. Các nguồn lọc danh sách này; union kiểm tra lại trước khi nhận món.
Đánh đổi: giảm gợi ý lặp, nhưng món đang mở sẽ không được đề xuất lại trong request đó.
03 · GỘP TRÙNG
Dùng productId làm khóa Map. Nếu nhiều nguồn cùng trả một món, chỉ giữ một sản phẩm; nguồn, lý do, rawScore và món làm mốc vẫn được lưu riêng.
Ý nghĩa: không cộng điểm nguồn thành điểm cuối; ranking nhận đủ dấu vết để tự chấm và giải thích.
04 · GIỚI HẠN POOL
Nếu vượt 300, mỗi vòng lấy một món từ từng nguồn. Trong nguồn đó, ưu tiên rawScore cao; món đã được chọn ở nguồn khác thì bỏ qua.
Đánh đổi: request nhẹ và có giới hạn, nhưng món ít ưu tiên có thể bị cắt. 300 là guardrail hiện tại, chưa phải ngưỡng tối ưu đã được kiểm chứng.
Ví dụ minh họa
Hợp nhất theo productId; thông tin từng nguồn vẫn được giữ để ranking sử dụng.
Ví dụ · đầu vào từ ba nguồn
PRODUCT_AFFINITY→SP-01, SP-02
SEMANTIC_SIMILARITY→SP-01, SP-03
CO_BEHAVIOR→SP-01, SP-04
Sau khi hợp nhất
SP-01 chỉ còn một entry; ba nguồn và lý do xuất hiện vẫn được lưu riêng.
Đầu ra · ranking
Ứng viên chưa phải thứ hạng hiển thị; bước ranking tiếp theo mới quyết định thứ tự.
Pool đầu vào
Tối đa 300 productId duy nhất
Sản phẩm đang xem và tối đa 3 sản phẩm tương tác gần nhất đã bị loại khỏi pool.
Dấu vết nguồn
Giữ thông tin đóng góp của nguồn
Candidate lưu nguồn tìm thấy; reasonCode và rawScore được giữ theo đóng góp, anchor được lưu khi nguồn cung cấp.
Bước kế tiếp
Standard hoặc AI Ranking
Ranking dùng pool candidate để tính điểm và quyết định thứ tự hiển thị; Candidate Union không cộng điểm nguồn thành điểm cuối.
Luồng xếp hạng candidate
Hệ thống tính điểm theo chế độ Standard hoặc AI-Enhanced, sắp candidate theo điểm rồi áp dụng trộn nguồn cold-start (nếu có) và diversity trước khi trả danh sách.
01 · ĐẦU VÀO
Mỗi sản phẩm đi kèm dữ liệu sản phẩm, ngữ cảnh hồ sơ/phiên và thông tin nguồn đã tìm thấy.
02 · TẠO FEATURE
Feature đo mức phù hợp trong khoảng 0–1; tín hiệu không có dữ liệu hỗ trợ được tính bằng 0.
03 · TÍNH ĐIỂM
Standard cộng feature theo trọng số rồi trừ penalty (tối đa 0,15). AI-Enhanced pha điểm Standard với dự đoán AI; thiếu điểm AI hợp lệ thì giữ Standard.
04 · SẮP XẾP
Sắp điểm giảm dần; nếu là COLD_START thì trộn theo quota nguồn, sau đó diversity giới hạn lặp danh mục, thương hiệu và shop. Các bước này có thể đổi thứ tự trả về.
Cách đọc công thức
Mỗi tín hiệu của sản phẩm được chuẩn hóa về khoảng 0–1.
Mặc định tổng trọng số là 100%; policy có thể đổi tỷ lệ và hệ thống chuẩn hóa lại.
Preference âm ở sản phẩm, danh mục hoặc thương hiệu giảm theo thời gian (mặc định còn nửa sau 7 ngày); penalty tối đa 0,15.
Clamp về 0–1 rồi sắp điểm giảm dần; hòa điểm xét số đóng góp rồi productId. Cold-start và diversity có thể đổi thứ tự trả về.
Bước 1 · Tính điểm Standard
S_standard = clamp(Σ(featureᵢ × weightᵢ) − negativePenalty, 0, 1)
Σ weightᵢ = 1 · 0 ≤ negativePenalty ≤ 0,15Feature: độ phù hợp theo một tín hiệu; mỗi tín hiệu nằm trong khoảng 0–1.
Weight: mức ảnh hưởng của tín hiệu. Tám trọng số được chuẩn hóa để tổng bằng 100%.
Điểm phạt: trừ phần sở thích tiêu cực đã ghi nhận; giới hạn tối đa 0,15.
Clamp: chặn điểm cuối trong khoảng 0–1, không âm hoặc vượt trần.
Bước 2 · Nhân từng tín hiệu với trọng số
Bảng này giải thích đúng vai trò của Standard: mỗi tín hiệu có ý nghĩa và nguồn điểm riêng, sau đó mới nhân với weight để tạo phần đóng góp. Đây là phép tính xác định, không phải prediction từ model AI.
| Tín hiệu | Ý nghĩa / nguồn điểm | Điểm · weight | Đóng góp |
|---|---|---|---|
| Sở thích hồ sơ | Mức hợp với sở thích dài hạn theo sản phẩm, danh mục và thương hiệu. | 0,80·25% | 0,80 × 25% = 0,200 |
| Phiên hiện tại | Mức khớp với danh mục, thương hiệu và sản phẩm người dùng vừa xem. | 0,60·18% | 0,60 × 18% = 0,108 |
| Tương tự nội dung | Độ gần nội dung hoặc embedding giữa candidate và ngữ cảnh hiện tại. | 0,90·15% | 0,90 × 15% = 0,135 |
| Hành vi đi cùng | Mức candidate thường được xem, thêm giỏ hoặc mua cùng sản phẩm khác. | 0,50·10% | 0,50 × 10% = 0,050 |
| Phổ biến | Tín hiệu nhu cầu chung từ tổng đã bán và thứ hạng trending/best-selling. | 0,70·12% | 0,70 × 12% = 0,084 |
| Độ mới | Mức ưu tiên dành cho sản phẩm mới dựa trên tuổi trong catalog. | 0,55·8% | 0,55 × 8% = 0,044 |
| Chất lượng | Kết hợp rating, số review và khả năng còn hàng để phục vụ. | 0,90·8% | 0,90 × 8% = 0,072 |
| Khám phá | Cơ hội thử sản phẩm mới từ EXPLORE/NEWEST khi sở thích chưa rõ. | 0,00·4% | 0,00 × 4% = 0,000 |
Cách đọc: ví dụ “Sở thích hồ sơ” có điểm 0,80 và trọng số 25%, nên đóng góp 0,80 × 0,25 = 0,200. Cộng tám đóng góp được 0,693 trước khi trừ penalty.
Bước 3 · Cộng đóng góp
Tổng có trọng số 0,693
Bước 4 · Trừ phạt, rồi giới hạn
0,693 − 0,040 phạt giả định = 0,653 Standard
Cách đọc kết quả: 0,653 là điểm dùng để so thứ tự các ứng viên trong lần gợi ý này, không phải xác suất mua 65,3%. Ví dụ là số giả định để minh họa.
Hướng dẫn
Mỗi tiêu chí tạo một phần đóng góp vào điểm Standard; điểm feature và trọng số là hai giá trị khác nhau.
1. Điểm feature · 0–1
Đo mức phù hợp của sản phẩm theo riêng tiêu chí này: 0 là không có tín hiệu phù hợp, 1 là mức tối đa của công thức.
2. Trọng số · %
Cho biết tiêu chí ảnh hưởng nhiều hay ít đến tổng điểm. Đây là cấu hình của policy, không phải mức phù hợp của sản phẩm.
3. Phần đóng góp
Ví dụ: 0,8 × 25% = 0,20 điểm. Hệ thống cộng đóng góp của tám tiêu chí rồi trừ penalty riêng.
Các trọng số hiển thị bên dưới là mặc định trong code, chưa phải cấu hình tối ưu theo dữ liệu thực tế. Mỗi tiêu chí được tách thành một hàng để dễ xem công thức, ví dụ và đánh đổi.
Tỷ trọng 25% là mức quan trọng bạn dành cho tiêu chí này, không phải điểm sản phẩm đạt được. Điểm riêng của tiêu chí nằm trong khoảng 0–1: 0 là không có dấu hiệu phù hợp, 1 là mức tối đa công thức cho phép. Ví dụ 0.8 tương đương 80/100 điểm riêng; nó không có nghĩa người dùng có 80% khả năng mua.
Khi chấm điểm, hệ thống cộng tất cả tỷ trọng rồi chia tỷ trọng của tiêu chí này cho tổng đó. Ví dụ 25% trên tổng 100% trở thành 0.25; điểm riêng 0.8 × 0.25 = 0.20, tức đóng góp 20/100 điểm tổng. Nếu tổng các ô là 80%, một ô 20% được quy đổi thành 20 ÷ 80 = 25% trước khi tính. Nếu tất cả tỷ trọng đều bằng 0, hệ thống quay về bộ mặc định thay vì chia cho 0.
Lưu ý về các con số: tỷ trọng trong các ô là thứ bạn đang chỉnh. Còn các số nằm bên trong công thức như 0.6, 7 ngày hay 12 là quy tắc mặc định do dự án đặt để bắt đầu — không phải kết quả hệ thống đã học từ khách hàng thật. Một số có thể đổi trong cấu hình dịch vụ; những số khác hiện cố định trong code. Đây là Standard Ranking, không phải mô hình AI-Enhanced Ranking.
Điểm từng sở thích = giới hạn 0–1 [max(0, điểm tích lũy × 0.5^(số ngày ÷ số ngày giảm một nửa)) ÷ 8]
Độ phù hợp hồ sơ = giới hạn 0–1 [điểm sản phẩm + 0.6 × điểm danh mục + 0.4 × điểm thương hiệu]
Mỗi hành động sẽ cộng hoặc trừ điểm vào lịch sử sở thích của người dùng. Mặc định các điểm là:
Ví dụ mua 2 sản phẩm sẽ cộng 16 điểm cho sản phẩm đó. Điểm tìm kiếm chỉ cộng vào sản phẩm, danh mục hoặc thương hiệu nếu hành động tìm kiếm có thông tin tương ứng; riêng nội dung từ khóa được lưu nhưng không được dùng trong phép tính này. Các điểm mặc định có thể thay đổi bằng cấu hình. Danh mục và thương hiệu lấy từ thông tin sản phẩm trong hệ thống.
điểm_lưuTổng điểm đã tích lũy cho một sản phẩm, một danh mục hoặc một thương hiệu. Ví dụ hai lần xem và một lần bấm có điểm mặc định là 1 + 1 + 2 = 4.số_ngàySố ngày từ lần tương tác gần nhất với đúng mục đó đến hiện tại. Mục mới tương tác thì số này gần 0.halfLifeDaysSố ngày để điểm sở thích giảm còn một nửa. Mặc định là 7 ngày; có thể đổi bằng cấu hình.0.5^(số_ngày / halfLifeDays)Hệ số làm điểm cũ yếu dần. Ví dụ một sở thích có 8 điểm: ngay sau tương tác vẫn là 8; sau 7 ngày còn 8 × 0.5 = 4; sau 14 ngày còn 8 × 0.25 = 2. Như vậy hệ thống ưu tiên điều người dùng quan tâm gần đây hơn.chia cho 8Đổi điểm hành vi sang thang 0–1. Điểm 8 trở lên được xem là mức tối đa 1; 4 điểm thành 0.5; 0 điểm thành 0.max(0, điểm đã giảm)Chỉ lấy sở thích dương cho phần phù hợp. Nếu điểm đang âm, phần phù hợp này nhận 0. Nói cách khác, không thích không thể biến thành “thích”; nó chỉ làm giảm tổng điểm ở khoản trừ riêng.0.6 × điểm danh mục; 0.4 × điểm thương hiệuĐiểm khớp danh mục được nhân 0.6; điểm khớp thương hiệu được nhân 0.4. Ví dụ danh mục đạt 0.5 thì đóng góp 0.5 × 0.6 = 0.3; thương hiệu đạt 0.5 thì đóng góp 0.5 × 0.4 = 0.2. Khớp đúng sản phẩm không bị nhân giảm.giới hạn trong 0–1Tổng cao hơn 1 vẫn chỉ nhận 1, để một tiêu chí không vượt thang điểm chung.Nói gọn: điểm sở thích sau khi giảm theo thời gian → đổi về 0–1 → cộng điểm sản phẩm, danh mục và thương hiệu.
Giả sử sau khi tính độ cũ/mới, hồ sơ đang có: sản phẩm này 4 điểm, danh mục 4 điểm và thương hiệu 2 điểm.
Cộng lại: 0.5 + 0.3 + 0.1 = 0.9. Nghĩa là sản phẩm khớp khá mạnh với hồ sơ ở tiêu chí này; không có nghĩa người dùng có 90% khả năng mua.
điểm âmĐiểm âm trong hồ sơ của đúng sản phẩm, danh mục hoặc thương hiệu đang được chấm, thường đến từ hành động như bỏ giỏ hoặc hoàn trả.chia độ lớn điểm âm cho 8Đổi mức không thích sang thang chung. Ví dụ −4 điểm thành 4 ÷ 8 = 0.5; dấu trừ chỉ dùng để nhận ra đây là sở thích âm.cộng các điểm âm rồi nhân 0.15Nhiều dấu hiệu không thích có thể cộng lại. Kết quả bị giới hạn tối đa 0.15, tức tối đa 15 điểm trên thang 100.Ví dụ một sở thích âm −4 điểm, chưa tính giảm theo thời gian, tạo khoản trừ (4 ÷ 8) × 0.15 = 0.075, tương đương 7.5 điểm trên thang 100. Nếu tổng khoản trừ lớn hơn 0.15 thì chỉ trừ 0.15.
Tỷ trọng 18% là mức quan trọng bạn dành cho tiêu chí này, không phải điểm sản phẩm đạt được. Điểm riêng của tiêu chí nằm trong khoảng 0–1: 0 là không có dấu hiệu phù hợp, 1 là mức tối đa công thức cho phép. Ví dụ 0.8 tương đương 80/100 điểm riêng; nó không có nghĩa người dùng có 80% khả năng mua.
Khi chấm điểm, hệ thống cộng tất cả tỷ trọng rồi chia tỷ trọng của tiêu chí này cho tổng đó. Ví dụ 25% trên tổng 100% trở thành 0.25; điểm riêng 0.8 × 0.25 = 0.20, tức đóng góp 20/100 điểm tổng. Nếu tổng các ô là 80%, một ô 20% được quy đổi thành 20 ÷ 80 = 25% trước khi tính. Nếu tất cả tỷ trọng đều bằng 0, hệ thống quay về bộ mặc định thay vì chia cho 0.
Lưu ý về các con số: tỷ trọng trong các ô là thứ bạn đang chỉnh. Còn các số nằm bên trong công thức như 0.6, 7 ngày hay 12 là quy tắc mặc định do dự án đặt để bắt đầu — không phải kết quả hệ thống đã học từ khách hàng thật. Một số có thể đổi trong cấu hình dịch vụ; những số khác hiện cố định trong code. Đây là Standard Ranking, không phải mô hình AI-Enhanced Ranking.
Điểm ngữ cảnh = giới hạn 0–1 [(khớp danh mục ? 0.60 : 0) + (khớp thương hiệu ? 0.25 : 0) + (được gợi ý từ sản phẩm hiện tại ? 0.15 : 0)]
Mỗi điều kiện trong ngoặc nhận 1 nếu đúng, 0 nếu sai.
0.60 điểmCộng khi sản phẩm đang chấm thuộc danh mục người dùng vừa xem/tương tác. Nếu không trùng, phần này cộng 0.0.25 điểmCộng khi thương hiệu của sản phẩm nằm trong các thương hiệu vừa tương tác; không trùng thì cộng 0.0.15 điểmCộng khi sản phẩm đang chấm được tìm thấy nhờ sản phẩm người dùng đang xem/bấm. Nếu không có mốc này thì cộng 0.tổng điểmCộng các phần khớp lại. Ba phần cộng tối đa 0.60 + 0.25 + 0.15 = 1.00. Các số này là điểm của tiêu chí, không phải xác suất mua.Tỷ trọng 15% là mức quan trọng bạn dành cho tiêu chí này, không phải điểm sản phẩm đạt được. Điểm riêng của tiêu chí nằm trong khoảng 0–1: 0 là không có dấu hiệu phù hợp, 1 là mức tối đa công thức cho phép. Ví dụ 0.8 tương đương 80/100 điểm riêng; nó không có nghĩa người dùng có 80% khả năng mua.
Khi chấm điểm, hệ thống cộng tất cả tỷ trọng rồi chia tỷ trọng của tiêu chí này cho tổng đó. Ví dụ 25% trên tổng 100% trở thành 0.25; điểm riêng 0.8 × 0.25 = 0.20, tức đóng góp 20/100 điểm tổng. Nếu tổng các ô là 80%, một ô 20% được quy đổi thành 20 ÷ 80 = 25% trước khi tính. Nếu tất cả tỷ trọng đều bằng 0, hệ thống quay về bộ mặc định thay vì chia cho 0.
Lưu ý về các con số: tỷ trọng trong các ô là thứ bạn đang chỉnh. Còn các số nằm bên trong công thức như 0.6, 7 ngày hay 12 là quy tắc mặc định do dự án đặt để bắt đầu — không phải kết quả hệ thống đã học từ khách hàng thật. Một số có thể đổi trong cấu hình dịch vụ; những số khác hiện cố định trong code. Đây là Standard Ranking, không phải mô hình AI-Enhanced Ranking.
Dãy số nội dung chung = tổng(dãy số của từng mốc × trọng số mốc) ÷ tổng trọng số mốc
Điểm tương đồng = giới hạn 0–1 (điểm bộ tìm kiếm trả về khi so sản phẩm với dãy số chung)
Sản phẩm hiện tại — trọng số 1Sản phẩm người dùng đang xem hoặc sản phẩm được truyền vào làm điểm bắt đầu.Tối đa 5 sản phẩm vừa tương tácMỗi sản phẩm được đặt trọng số theo hành động gần nhất: mặc định xem = 1, bấm = 2, thêm giỏ = 4. Nếu không có trọng số thì dùng 1. Hành động có điểm 0 hoặc âm, như bỏ giỏ, không được dùng làm mốc nội dung.Tối đa 5 sản phẩm hồ sơ — trọng số 0.5Chỉ lấy sản phẩm người dùng đã thể hiện sở thích dương; mỗi sản phẩm này có ảnh hưởng bằng một nửa mốc trọng số 1.dấu vân tay × trọng sốLấy dãy số của từng sản phẩm mốc nhân với trọng số tương ứng. Mốc có trọng số lớn sẽ ảnh hưởng nhiều hơn đến “dấu vân tay chung” mà hệ thống dùng để tìm sản phẩm.chia cho tổng trọng sốCộng trọng số của các mốc rồi chia để lấy mức trung bình có cân nhắc độ quan trọng. Nhờ vậy, thêm nhiều sản phẩm mốc không tự làm điểm cao hơn.điểm giống nhau từ 0 đến 1Bộ tìm kiếm so sánh dấu vân tay chung với từng sản phẩm. 0 nghĩa là rất ít giống; 1 là mức giống cao nhất. Ví dụ 0.82 nghĩa là bộ tìm kiếm cho điểm tương đồng 0.82 trên thang 0–1. Đây không phải phép đếm 82% từ ngữ trùng nhau hay xác suất mua 82%.Dãy số được tạo trước bằng mô hình mã hóa nội dung — mô hình biến tên, thương hiệu, danh mục, mô tả và thuộc tính sản phẩm thành số — rồi lưu lại. Khi có yêu cầu, hệ thống dùng các số này để tìm sản phẩm gần giống; đây không phải AI-Enhanced Ranking và cũng không phải AI trò chuyện viết câu trả lời mới cho từng lượt.
Tỷ trọng 10% là mức quan trọng bạn dành cho tiêu chí này, không phải điểm sản phẩm đạt được. Điểm riêng của tiêu chí nằm trong khoảng 0–1: 0 là không có dấu hiệu phù hợp, 1 là mức tối đa công thức cho phép. Ví dụ 0.8 tương đương 80/100 điểm riêng; nó không có nghĩa người dùng có 80% khả năng mua.
Khi chấm điểm, hệ thống cộng tất cả tỷ trọng rồi chia tỷ trọng của tiêu chí này cho tổng đó. Ví dụ 25% trên tổng 100% trở thành 0.25; điểm riêng 0.8 × 0.25 = 0.20, tức đóng góp 20/100 điểm tổng. Nếu tổng các ô là 80%, một ô 20% được quy đổi thành 20 ÷ 80 = 25% trước khi tính. Nếu tất cả tỷ trọng đều bằng 0, hệ thống quay về bộ mặc định thay vì chia cho 0.
Lưu ý về các con số: tỷ trọng trong các ô là thứ bạn đang chỉnh. Còn các số nằm bên trong công thức như 0.6, 7 ngày hay 12 là quy tắc mặc định do dự án đặt để bắt đầu — không phải kết quả hệ thống đã học từ khách hàng thật. Một số có thể đổi trong cấu hình dịch vụ; những số khác hiện cố định trong code. Đây là Standard Ranking, không phải mô hình AI-Enhanced Ranking.
Điểm quan hệ sau giảm = điểm quan hệ ban đầu × 0.5^(số ngày ÷ số ngày giảm một nửa)
Điểm một mối liên hệ = max(0, điểm sau giảm) ÷ [max(0, điểm sau giảm) + mốc so sánh]
Điểm Hành vi liên quan = điểm cao nhất trong các mối liên hệ tìm được
Cùng được xemTrong cùng phiên ghé website, nếu hai sản phẩm được xem, bấm hoặc hiển thị trong khoảng 30 phút thì ghi nhận một mối liên hệ.Cùng được thêm giỏNếu cùng người dùng hoặc cùng phiên thêm hai sản phẩm vào giỏ trong vòng 7 ngày, hệ thống ghi nhận chúng liên quan.Cùng đơn hàngCác sản phẩm trong một đơn mua hoàn tất được nối với nhau. Nếu đơn hàng bị hoàn trả, điểm của mối liên hệ mua sẽ bị trừ.Mỗi hành động đóng góp một số điểm mặc định: xem = 1, bấm = 2, chỉ được hiển thị = 0.05, thêm vào giỏ = 3, mua chung = 6 và hoàn trả = −6. Đây là điểm quy ước để so sánh, không phải số người. Nhiều lần liên quan sẽ cộng dồn; điểm cũ giảm còn một nửa sau mỗi 30 ngày. Các mức này có thể được đổi bằng cấu hình.
điểm quan hệĐiểm tích lũy giữa hai sản phẩm sau khi đã tính các lần cùng xem/thêm giỏ/mua và làm giảm ảnh hưởng của điểm cũ. Điểm càng cao nghĩa là mối liên hệ càng mạnh.0 nếu điểm quan hệ âmMột lần hoàn trả có thể kéo điểm quan hệ mua xuống. Điểm âm không tạo gợi ý liên quan dương.mốc so sánh (scale)Đây là số dùng để đổi điểm quan hệ sang thang 0–1: mặc định 1 cho cùng xem, 3 cho cùng thêm giỏ và 6 cho cùng mua. Chọn mốc lớn hơn khiến cùng một điểm tích lũy được đổi thành điểm thấp hơn. Có thể thay các mốc này bằng cấu hình.điểm quan hệ ÷ (điểm quan hệ + mốc so sánh)Đổi điểm tích lũy sang thang 0–1. Khi điểm quan hệ bằng mốc so sánh thì kết quả là 0.5. Điểm càng tăng thì kết quả tiến gần 1, nhưng không vượt 1.lấy điểm mạnh nhấtNếu một sản phẩm liên quan qua nhiều sản phẩm mốc hoặc nhiều loại hành vi, hệ thống dùng mối liên hệ có điểm cao nhất, không cộng tất cả lại.3 ÷ (3 + 3) = 0.5. 0.5 ở đây là điểm liên quan đã quy đổi, không có nghĩa 50% người dùng chắc chắn mua sản phẩm.Tỷ trọng 12% là mức quan trọng bạn dành cho tiêu chí này, không phải điểm sản phẩm đạt được. Điểm riêng của tiêu chí nằm trong khoảng 0–1: 0 là không có dấu hiệu phù hợp, 1 là mức tối đa công thức cho phép. Ví dụ 0.8 tương đương 80/100 điểm riêng; nó không có nghĩa người dùng có 80% khả năng mua.
Khi chấm điểm, hệ thống cộng tất cả tỷ trọng rồi chia tỷ trọng của tiêu chí này cho tổng đó. Ví dụ 25% trên tổng 100% trở thành 0.25; điểm riêng 0.8 × 0.25 = 0.20, tức đóng góp 20/100 điểm tổng. Nếu tổng các ô là 80%, một ô 20% được quy đổi thành 20 ÷ 80 = 25% trước khi tính. Nếu tất cả tỷ trọng đều bằng 0, hệ thống quay về bộ mặc định thay vì chia cho 0.
Lưu ý về các con số: tỷ trọng trong các ô là thứ bạn đang chỉnh. Còn các số nằm bên trong công thức như 0.6, 7 ngày hay 12 là quy tắc mặc định do dự án đặt để bắt đầu — không phải kết quả hệ thống đã học từ khách hàng thật. Một số có thể đổi trong cấu hình dịch vụ; những số khác hiện cố định trong code. Đây là Standard Ranking, không phải mô hình AI-Enhanced Ranking.
Điểm thứ hạng = giới hạn 0–1 [1 − (hạng − 1) ÷ max(số sản phẩm trong danh sách − 1, 1)]
Điểm phổ biến = giới hạn 0–1 [max(ln(1 + max(số đã bán, 0)) ÷ 12, điểm thứ hạng cao nhất từ danh sách thịnh hành/bán chạy)]
Số lượng đã bánTổng số lượng đã bán được đồng bộ trong thông tin sản phẩm. Bán nhiều giúp tăng điểm, nhưng mức tăng chậm dần để một sản phẩm bán cực nhiều không lấn át tất cả sản phẩm khác.Thứ hạng trong danh sáchVị trí sản phẩm trong danh sách thịnh hành hoặc bán chạy: hạng 1 là đầu danh sách. Danh sách bán chạy được dùng khi hệ thống đang gợi ý cho người chưa có hồ sơ sở thích.lấy điểm cao hơnSo sánh điểm từ số bán với điểm từ thứ hạng rồi chọn điểm lớn hơn. Cuối cùng giới hạn kết quả tối đa là 1.rankVị trí của sản phẩm trong một danh sách: hạng 1 là đầu danh sách, hạng 10 là vị trí thứ 10.sizeTổng số sản phẩm trong chính danh sách đó. Nếu danh sách có 10 sản phẩm thìsize = 10.1 − (rank − 1) ÷ (size − 1)Công thức đổi vị trí thành điểm. Ví dụ danh sách có 10 sản phẩm: hạng 1 được 1; hạng 4 được 1 − (4−1) ÷ (10−1) = 0.67; hạng 10 được 0. Danh sách chỉ có một sản phẩm thì sản phẩm đó được 1.ln(1 + totalSold) ÷ 12totalSold là tổng số lượng đã bán; ln là phép đổi khiến số bán tăng điểm chậm dần; số 1 giúp trường hợp chưa bán món nào cho kết quả 0. Số 12 là mức điều chỉnh độ lớn, không đảm bảo riêng phép tính này luôn nằm dưới 1: nếu vượt 1, bước cuối sẽ chặn điểm ở 1. Ví dụ bán 100 món: ln(101) ÷ 12 ≈ 0.38.1 − (4 − 1) ÷ (10 − 1) = 0.67. Hệ thống chọn điểm cao hơn, nên Độ phổ biến của sản phẩm là khoảng 0.67.Tỷ trọng 8% là mức quan trọng bạn dành cho tiêu chí này, không phải điểm sản phẩm đạt được. Điểm riêng của tiêu chí nằm trong khoảng 0–1: 0 là không có dấu hiệu phù hợp, 1 là mức tối đa công thức cho phép. Ví dụ 0.8 tương đương 80/100 điểm riêng; nó không có nghĩa người dùng có 80% khả năng mua.
Khi chấm điểm, hệ thống cộng tất cả tỷ trọng rồi chia tỷ trọng của tiêu chí này cho tổng đó. Ví dụ 25% trên tổng 100% trở thành 0.25; điểm riêng 0.8 × 0.25 = 0.20, tức đóng góp 20/100 điểm tổng. Nếu tổng các ô là 80%, một ô 20% được quy đổi thành 20 ÷ 80 = 25% trước khi tính. Nếu tất cả tỷ trọng đều bằng 0, hệ thống quay về bộ mặc định thay vì chia cho 0.
Lưu ý về các con số: tỷ trọng trong các ô là thứ bạn đang chỉnh. Còn các số nằm bên trong công thức như 0.6, 7 ngày hay 12 là quy tắc mặc định do dự án đặt để bắt đầu — không phải kết quả hệ thống đã học từ khách hàng thật. Một số có thể đổi trong cấu hình dịch vụ; những số khác hiện cố định trong code. Đây là Standard Ranking, không phải mô hình AI-Enhanced Ranking.
Điểm độ mới theo số ngày từ lúc tạo sản phẩm:
1.00 nếu không quá 1 ngày
0.80 nếu trên 1 ngày và không quá 7 ngày
0.55 nếu trên 7 ngày và không quá 30 ngày
0.30 nếu trên 30 ngày và không quá 90 ngày
0.10 nếu trên 90 ngày
ngày tuổi sản phẩmSố ngày từ ngày sản phẩm được tạo đến lúc chấm điểm. Nếu ngày tạo bị ghi trong tương lai do lệch đồng hồ, hệ thống tính tuổi là 0 ngày.1.00Sản phẩm được tạo trong vòng 1 ngày; đây là điểm mới cao nhất.0.80Sản phẩm đã hơn 1 ngày nhưng chưa quá 7 ngày.0.55Sản phẩm đã hơn 7 ngày nhưng chưa quá 30 ngày.0.30Sản phẩm đã hơn 30 ngày nhưng chưa quá 90 ngày.0.10Sản phẩm đã hơn 90 ngày.Tỷ trọng 8% là mức quan trọng bạn dành cho tiêu chí này, không phải điểm sản phẩm đạt được. Điểm riêng của tiêu chí nằm trong khoảng 0–1: 0 là không có dấu hiệu phù hợp, 1 là mức tối đa công thức cho phép. Ví dụ 0.8 tương đương 80/100 điểm riêng; nó không có nghĩa người dùng có 80% khả năng mua.
Khi chấm điểm, hệ thống cộng tất cả tỷ trọng rồi chia tỷ trọng của tiêu chí này cho tổng đó. Ví dụ 25% trên tổng 100% trở thành 0.25; điểm riêng 0.8 × 0.25 = 0.20, tức đóng góp 20/100 điểm tổng. Nếu tổng các ô là 80%, một ô 20% được quy đổi thành 20 ÷ 80 = 25% trước khi tính. Nếu tất cả tỷ trọng đều bằng 0, hệ thống quay về bộ mặc định thay vì chia cho 0.
Lưu ý về các con số: tỷ trọng trong các ô là thứ bạn đang chỉnh. Còn các số nằm bên trong công thức như 0.6, 7 ngày hay 12 là quy tắc mặc định do dự án đặt để bắt đầu — không phải kết quả hệ thống đã học từ khách hàng thật. Một số có thể đổi trong cấu hình dịch vụ; những số khác hiện cố định trong code. Đây là Standard Ranking, không phải mô hình AI-Enhanced Ranking.
Điểm Chất lượng = giới hạn 0–1 [(giới hạn ratingAvg ÷ 5 trong 0–1 × 0.55) + (giới hạn ln(1 + max(reviewCount, 0)) ÷ ln(101) trong 0–1 × 0.25) + (còn hàng ? 0.20 : 0)]
ratingAvg ÷ 5 × 0.55ratingAvg là điểm sao trung bình, từ 0 đến 5. Chia 5 để đổi thành thang 0–1; nhân 0.55 nghĩa là số sao có thể đóng góp tối đa 55% điểm Chất lượng. Ví dụ 4.5 sao: 4.5 ÷ 5 × 0.55 = 0.495.ln(1 + reviewCount) ÷ ln(101) × 0.25reviewCount là số lượt đánh giá. Phép ln làm số lượt tăng điểm chậm dần. Số 101 là 100 lượt đánh giá cộng 1; vì vậy chia cho ln(101)để 100 lượt tương ứng mức 1. Nhân 0.25 nên phần đánh giá đóng góp tối đa 25%. Không có lượt đánh giá thì phần này bằng 0; trên 100 lượt cũng không vượt mức 25%.còn hàng × 0.20Trạng thái còn hàng chỉ có hai trường hợp: còn hàng thì cộng 0.20, hết hàng thì cộng 0. Phần này đóng góp tối đa 20% điểm Chất lượng.0.55 + 0.25 + 0.20Ba phần trên chia toàn bộ điểm Chất lượng: sao chiếm 55%, số lượt đánh giá 25%, tình trạng còn hàng 20%. Tổng cuối được giới hạn trong khoảng 0–1.Tỷ trọng 4% là mức quan trọng bạn dành cho tiêu chí này, không phải điểm sản phẩm đạt được. Điểm riêng của tiêu chí nằm trong khoảng 0–1: 0 là không có dấu hiệu phù hợp, 1 là mức tối đa công thức cho phép. Ví dụ 0.8 tương đương 80/100 điểm riêng; nó không có nghĩa người dùng có 80% khả năng mua.
Khi chấm điểm, hệ thống cộng tất cả tỷ trọng rồi chia tỷ trọng của tiêu chí này cho tổng đó. Ví dụ 25% trên tổng 100% trở thành 0.25; điểm riêng 0.8 × 0.25 = 0.20, tức đóng góp 20/100 điểm tổng. Nếu tổng các ô là 80%, một ô 20% được quy đổi thành 20 ÷ 80 = 25% trước khi tính. Nếu tất cả tỷ trọng đều bằng 0, hệ thống quay về bộ mặc định thay vì chia cho 0.
Lưu ý về các con số: tỷ trọng trong các ô là thứ bạn đang chỉnh. Còn các số nằm bên trong công thức như 0.6, 7 ngày hay 12 là quy tắc mặc định do dự án đặt để bắt đầu — không phải kết quả hệ thống đã học từ khách hàng thật. Một số có thể đổi trong cấu hình dịch vụ; những số khác hiện cố định trong code. Đây là Standard Ranking, không phải mô hình AI-Enhanced Ranking.
Điểm khám phá = 1 nếu độ phù hợp hồ sơ ≤ 0.4 VÀ nguồn sản phẩm là NEWEST hoặc EXPLORE
Trong mọi trường hợp khác, điểm khám phá = 0.
Độ phù hợp hồ sơ ≤ 0.4Dùng kết quả của tiêu chí Độ phù hợp hồ sơ đã giải thích ở trên. 0.4 tương đương 40/100; nghĩa là hệ thống chưa có bằng chứng sở thích mạnh. Mốc này là điều kiện bật khám phá, không phải tỷ trọng.NEWESTSản phẩm được lấy từ danh sách sản phẩm mới trong dữ liệu sản phẩm.EXPLORESản phẩm được lấy từ danh sách sản phẩm dành cho khám phá.điểm 1 hoặc 0Nếu đồng thời hồ sơ không quá 0.4 và sản phẩm đến từ NEWEST hoặc EXPLORE, tiêu chí này cho 1 điểm. Thiếu một trong hai điều kiện thì cho 0 điểm.01 · ĐỌC TRƯỚC FLOW TỔNG QUAN
AI không tự tạo danh sách sản phẩm. Hệ thống chọn ra các sản phẩm phù hợp trước, chấm điểm theo cách thông thường, rồi chỉ nhờ AI sắp xếp lại khi đủ điều kiện. Nếu AI gặp lỗi, hệ thống vẫn trả kết quả bằng cách chấm điểm ban đầu.
Đầu vào · candidate pool
Gộp candidate từ catalog, profile/session và các nguồn liên quan.
Baseline · Standard Ranking
Tính từ 8 feature, weight và negative penalty.
Điều kiện · runtime policy
Kiểm tra policy, khả năng gọi model và trạng thái model.
Inference · LightGBM
Gửi 9 feature theo batch đến AI Service.
Blend · hybrid score
λ quyết định mức ảnh hưởng AI.
Đầu ra · final ranking
Sort, diversity/quota và trả metadata.
Cách đọc flow: Nếu một bước AI thất bại, flow không dừng. Nó quay về Standard ở đúng boundary phù hợp và vẫn trả được recommendation.
02 · CÔNG THỨC CỐT LÕI
Mục tiêu của công thức là xếp sản phẩm phù hợp lên trước nhưng vẫn giữ kết quả ổn định, giải thích được và có thể quay về Standard bất cứ lúc nào.
Standard score
S_standard = clamp(Σ(featureᵢ × weightᵢ) − negativePenalty, 0, 1)Đây là điểm nền do code tính trực tiếp từ 8 tín hiệu nghiệp vụ. Mỗi tín hiệu nằm trong khoảng 0–1, được nhân với trọng số, cộng lại rồi trừ riêng tín hiệu không phù hợp.
Mục tiêu: luôn có một thứ tự sản phẩm an toàn để phục vụ người dùng và làm mốc so sánh khi thử AI.
AI-Enhanced final score
S_final = clamp((1 − λ) × S_standard + λ × S_AI, 0, 1)AI không thay thế điểm nền. Model chỉ dự đoán thêm S_AI, sau đó hệ thống pha hai điểm bằng λ = mlBlend.
Mục tiêu: tận dụng quan hệ phức tạp mà model học được nhưng giới hạn rủi ro; λ chỉ từ 0 đến 0,5 nên Standard luôn giữ ít nhất 50% ảnh hưởng.
Feature: tín hiệu đã đưa về 0–1.
Weight: mức ảnh hưởng của feature trong Standard.
λ: mức ảnh hưởng của AI ở điểm cuối.
Clamp: giữ score cuối trong khoảng 0–1.
Đọc các ký hiệu trong công thức
featureᵢ: một tín hiệu của candidate, ví dụ sản phẩm có hợp sở thích hay đang được xem cùng sản phẩm hiện tại không. Tất cả đều được chuẩn hóa về 0–1.
weightᵢ: mức ưu tiên của tín hiệu trong Standard. Weight không phải điểm của sản phẩm; nó là “quyền biểu quyết” của từng feature.
negativePenalty: mức trừ cho preference âm như sản phẩm, category hoặc brand người dùng từng trả lại hay thể hiện không phù hợp. Penalty bị giới hạn tối đa 0,15.
S_AI: điểm LightGBM dự đoán từ đúng 9 giá trị đầu vào. Đây là ranking score 0–1, không phải xác suất mua hàng.
λ = mlBlend: tỷ lệ ảnh hưởng của AI. λ = 0 nghĩa là chỉ Standard; λ = 0,3 nghĩa là 70% Standard và 30% AI.
clamp(x, 0, 1): nếu x nhỏ hơn 0 thì đưa về 0, lớn hơn 1 thì đưa về 1. Việc này giữ mọi score cùng một thang đo.
Công thức tạo ra từng feature
Đây là lớp chuẩn hóa trước khi cộng weight. Mục đích là đưa các nguồn dữ liệu khác nhau — preference, phiên truy cập, Qdrant, quan hệ hành vi và catalog — về cùng thang 0–1 để so sánh công bằng.
profileAffinity = clamp(P + 0,6C + 0,4B)
P/C/B lần lượt là preference của product/category/brand. Mỗi preference được decay theo score × 0,5^(tuổi / halfLife), chia 8 rồi clamp. Mặc định half-life là 7 ngày.
sessionContext = clamp(0,6C + 0,25B + 0,15A)
C = trùng category gần đây, B = trùng brand gần đây, A = candidate có cùng sản phẩm neo hiện tại. Mỗi điều kiện là 0 hoặc 1; trọng số giúp nhu cầu trong phiên phản ứng nhanh.
semanticSimilarity = clamp(rawSimilarity)
Lấy similarity từ embedding/Qdrant. Source chỉ đóng góp khi vector còn khớp snapshot catalog; clamp bảo vệ ranker nếu provider trả giá trị ngoài 0–1.
coBehavior = max(raw / (raw + scale))
Chuẩn hóa từng quan hệ rồi lấy giá trị lớn nhất của candidate. Scale mặc định: CO_VIEW = 1, CO_CART = 3, CO_PURCHASE = 6; hành vi mua vì thế có ngưỡng mạnh hơn xem.
popularity = clamp(max(log1p(totalSold) / 12, sourceRankScore))
Kết hợp tổng đã bán với vị trí trong TRENDING/BEST_SELLING. Dùng log1p để vài sản phẩm bán quá nhiều không lấn át toàn bộ danh sách.
freshness = bucket theo tuổi sản phẩm
≤ 1 ngày: 1, ≤ 7 ngày: 0,8, ≤ 30 ngày: 0,55, ≤ 90 ngày: 0,3, cũ hơn: 0,1. Bucket ổn định hơn một hàm liên tục và vẫn tạo cơ hội cho item mới.
quality = clamp(0,55R + 0,25V + 0,2I)
R = rating/5, V = log1p(reviewCount) / log1p(100), I = 1 nếu còn tồn kho. Rating là tín hiệu chính, review tạo độ tin cậy, stock ngăn đẩy item không thể phục vụ.
exploration = profileAffinity > 0,4 ? 0 : sourceMatch
Nếu đã có affinity mạnh thì không cộng thêm exploration. Nếu chưa, candidate từ EXPLORE/NEWEST nhận 1 để khám phá có kiểm soát thay vì ngẫu nhiên.
Penalty riêng: các preference âm được decay giống preference dương, cộng theo product/category/brand, chuẩn hóa theo 8 rồi giới hạn negativePenalty ≤ 0,15. Tách penalty khỏi feature dương giúp “không phù hợp” luôn làm giảm điểm và không bị triệt tiêu bởi một tín hiệu tích cực khác.
| Tín hiệu | Weight mặc định | Nguồn dữ liệu | Mục tiêu |
|---|---|---|---|
| profileAffinity | 0,25 · 25% | Preference dài hạn theo sản phẩm, category, brand | Cá nhân hóa theo sở thích đã tích lũy |
| sessionContext | 0,18 · 18% | Category, brand và sản phẩm gần đây trong phiên | Bắt kịp nhu cầu hiện tại nhanh hơn profile dài hạn |
| semanticSimilarity | 0,15 · 15% | Similarity từ embedding/Qdrant | Tìm sản phẩm gần nhau về nội dung |
| coBehavior | 0,10 · 10% | Quan hệ xem, thêm giỏ và mua cùng nhau | Khai thác hành vi “người xem món này cũng xem món kia” |
| popularity | 0,12 · 12% | Total sold và thứ hạng trending/best-selling | Giữ sản phẩm có nhu cầu chung không bị bỏ quên |
| freshness | 0,08 · 8% | Tuổi sản phẩm trong catalog | Tạo cơ hội cho sản phẩm mới |
| quality | 0,08 · 8% | Rating, số review và tình trạng tồn kho | Ưu tiên item có chất lượng và còn khả năng phục vụ |
| exploration | 0,04 · 4% | Nguồn EXPLORE/NEWEST khi affinity chưa cao | Mở rộng khám phá nhưng không lấn át cá nhân hóa |
| Tổng | 1,00 · 100% | Backend tự normalize tổng weight về 1. Admin có thể thay đổi tỷ lệ, nhưng không được gửi key lạ hoặc tổng bằng 0. | |
Các con số này lấy từ đâu?
Weight mặc định là policy khởi đầu được khai báo trong RecommendationRuleService. Chúng là quyết định sản phẩm có thể điều chỉnh qua Admin, không phải con số tự sinh bởi LightGBM.
AI học từ đâu?
LightGBM được train offline từ dataset gồm 9 feature và label 0–1. Runtime chỉ load artifact đã train; model không tự thay đổi trọng số trong lúc người dùng gửi request.
Vì sao không để AI quyết định hết?
Standard dễ audit và luôn có sẵn. Giới hạn mlBlend ≤ 0,5, kiểm tra prediction và fallback giúp rollout AI có kiểm soát.
03 · ĐI CHI TIẾT THEO FLOW
Đọc lần lượt từ Bước 01 đến Bước 06. Phần này giải thích tại sao bước đó tồn tại, nó dùng thành phần nào và đánh đổi là gì.
Điều kiện · runtime policy
Khi policy bật, mọi request đều được thử bằng AI; model lỗi sẽ fallback Standard.
Tại sao cần: Cần biết AI đang được bật hay tắt trước khi chọn mode phục vụ request.
Dùng để làm gì: Đọc mlEnabled. Khi bật, AI áp dụng cho 100% request đủ điều kiện; không hash actor/session để chia nhóm.
Đánh đổi: AI có thể tốn thêm độ trễ; vì vậy model lỗi hoặc không hợp lệ vẫn phải fallback về Standard để không làm hỏng response.
Baseline · Standard Ranking
Baseline phải sẵn sàng ngay cả khi AI chưa tồn tại hoặc không phản hồi.
Tại sao cần: Người dùng luôn cần kết quả; Standard cũng là mốc để so sánh AI.
Dùng để làm gì: Tính 8 feature theo hybrid weights, trừ negativePenalty và clamp thành S_standard.
Đánh đổi: Dễ giải thích và ổn định, nhưng không học được tương tác phức tạp giữa nhiều tín hiệu.
Đầu vào · model contract
Một candidate được biến thành 9 cột số mà artifact đã được train để hiểu.
Tại sao cần: JSON đúng format chưa đủ; sai thứ tự cột sẽ khiến model hiểu sai ý nghĩa dữ liệu.
Dùng để làm gì: Gửi profileAffinity, sessionContext, semanticSimilarity, coBehavior, popularity, freshness, quality, exploration, negativePenalty.
Đánh đổi: Kết quả nhất quán và dễ validate, nhưng đổi feature bắt buộc kiểm tra hoặc train lại artifact.
Inference · AI Service
Recommendation Service gọi batch prediction; browser không được gọi trực tiếp AI Service.
Tại sao cần: Tách model thành AI Service giúp thay model, scale inference và theo dõi readiness độc lập.
Dùng để làm gì: Gửi tối đa 300 item bằng internal token; AI Service validate payload và trả S_AI trong 0–1.
Đánh đổi: Có network hop và timeout. Batch hiệu quả hơn nhưng lỗi có thể khiến cả batch fallback.
Safety check · validation
Response nội bộ vẫn được xem là untrusted input cho đến khi đủ điều kiện.
Tại sao cần: Prediction sai có thể làm sai thứ hạng và cả số liệu phân tích hiệu quả.
Dùng để làm gì: Kiểm tra item ID, duplicate, số lượng, 9 feature, số hữu hạn, score 0–1 và model version. ranking-fallback-v1 không được tính là ML.
Đánh đổi: Validation chặt làm fallback nhiều hơn, nhưng bảo vệ chất lượng và độ tin cậy của metrics.
Đầu ra · final ranking
AI điều chỉnh score; nó không được bypass diversity, quota hoặc fallback của hệ thống.
Tại sao cần: Điểm AI chỉ là tín hiệu bổ sung, không phải quyết định kinh doanh cuối cùng.
Dùng để làm gì: Tính S_final, sort giảm dần, áp cold-start mix/diversity và trả rankingModevà model version.
Đánh đổi: Diversity có thể đẩy item điểm cao xuống để tránh lặp shop/category, nhưng danh sách cân bằng và hữu ích hơn.
04 · MODEL ĐƯỢC TRAIN NHƯ THẾ NÀO?
Training là quy trình offline. Request online chỉ load artifact đã train và gọi prediction; không train lại, không gọi provider AI để tạo dữ liệu trong lúc người dùng chờ.
LightGBM là thuật toán gì?
LightGBM là thuật toán học có giám sát thuộc nhóm Gradient Boosting Decision Tree. Model tạo ra nhiều cây quyết định nhỏ. Cây sau quan sát lỗi của các cây trước rồi học thêm phần còn thiếu; tổng của các cây tạo thành dự đoán cuối.
Mỗi nhánh cây có thể học một điều kiện như “sessionContext cao nhưng quality thấp” hoặc “semanticSimilarity cao và candidate đến từ nhóm liên quan”. Vì vậy model nhìn được mối quan hệ kết hợp giữa nhiều feature mà phép cộng tuyến tính của Standard không biểu diễn được.
Trong hệ thống này: LightGBM chỉ re-rank tối đa 300 candidate đã được Recommendation Service chọn. Nó không tìm sản phẩm, không đọc trực tiếp catalog và không thay thế bước filter, quota hay diversity.
Model cải thiện điểm nào?
Model chỉ tốt khi nào?
Vì sao chọn LightGBM thay vì các hướng khác?
LightGBM không được chọn vì nó luôn tốt hơn mọi thuật toán. Nó được chọn vì khớp với các ràng buộc đang có: mỗi candidate chỉ có 9 feature dạng số, label được chuẩn hóa về 0–1, request cần inference nhanh, model phải dễ kiểm tra và có thể fallback về Standard bất cứ lúc nào.
Cách ra quyết định: So sánh mức phù hợp với input hiện tại, chi phí inference, độ phức tạp vận hành và khả năng rollback. XGBoost là đối thủ gần nhất và vẫn cần benchmark thực tế nếu dữ liệu hoặc tải thay đổi; các lựa chọn còn lại chỉ nên thay thế khi contract dữ liệu và mục tiêu sản phẩm thay đổi.
| Thuật toán | Phù hợp ở đâu? | Hạn chế với hệ thống hiện tại | Quyết định |
|---|---|---|---|
| LightGBM | Dữ liệu bảng, feature số, quan hệ phi tuyến và inference theo batch. | Chất lượng phụ thuộc label, dữ liệu lịch sử và việc giữ đúng thứ tự 9 feature. | Chọn làm model hiện tại vì cân bằng tốt giữa chất lượng, tốc độ và khả năng rollback. |
| Logistic Regression | Nhanh, dễ giải thích, phù hợp làm baseline. | Chủ yếu học quan hệ tuyến tính; khó biểu diễn tương tác phức tạp giữa 9 feature. | Giữ làm mốc so sánh, không chọn làm AI re-ranker. |
| Random Forest | Ổn định, ít nhạy với scale và dễ triển khai. | Các cây độc lập có thể nặng hơn cho batch inference; không tận dụng boosting để sửa lỗi tuần tự. | Chưa ưu tiên vì cần footprint lớn hơn cho cùng pipeline. |
| XGBoost | Rất mạnh trên dữ liệu bảng và là đối thủ gần nhất. | Thêm một lựa chọn runtime cần benchmark, đóng gói và vận hành song song; chưa có bằng chứng đủ để đổi model hiện tại. | Ứng viên benchmark khi tải, dữ liệu hoặc metric thay đổi. |
| CatBoost | Xử lý categorical feature tốt, giảm công sức encode. | Input hiện tại đã là 9 số đã chuẩn hóa; chưa cần lợi thế categorical trực tiếp. | Chưa dùng để tránh thêm độ phức tạp không cần thiết. |
| Neural Network | Học pattern rất phức tạp khi dữ liệu lớn và feature phong phú. | Cần nhiều dữ liệu, tuning và giám sát hơn; khó audit và thường tăng chi phí/độ trễ với tabular nhỏ. | Chỉ cân nhắc khi dữ liệu đủ lớn và có nhu cầu biểu diễn sâu hơn. |
| LambdaMART / LTR | Tối ưu trực tiếp thứ tự trong từng query/session group. | Dataset hiện tại mới là từng dòng feature + label, chưa có group/query label contract. | Có thể chuyển sang khi log đủ session và mục tiêu ranking rõ hơn. |
Kết luận: LightGBM là quyết định phù hợp với giai đoạn hiện tại, không phải cam kết vĩnh viễn. Khi có dataset lớn hơn, label theo session rõ hơn hoặc metric thực tế cho thấy model khác tốt hơn, hệ thống có thể benchmark model mới rồi thay artifact theo version; contract 9 feature, validation và fallback vẫn là các điều kiện bắt buộc.
TRAINING INPUT
LIGHTGBM CONFIGURATION
Từ dữ liệu đến model artifact
| Tham số | Giá trị hiện tại | Tác dụng |
|---|---|---|
| objective | binary | Học điểm dự đoán cho label nhị phân/0–1 theo contract hiện tại. |
| metric | binary_logloss | Đo mức lệch giữa dự đoán và label trên validation; thấp hơn là tốt hơn. |
| learning_rate | 0,05 | Mỗi cây sửa một phần nhỏ, học chậm hơn nhưng giảm nguy cơ nhảy quá mạnh. |
| num_leaves | 31 | Giới hạn độ phức tạp mỗi cây; cao hơn học được pattern sâu hơn nhưng dễ overfit. |
| feature/bagging_fraction | 0,9 / 0,9 | Mỗi vòng chỉ dùng khoảng 90% feature/data để giảm phụ thuộc vào một mẫu duy nhất. |
| rounds / early stopping | 200 / 20 | Tối đa 200 vòng; dừng nếu 20 vòng liên tiếp không cải thiện validation. |
| seed | 42 | Giúp lần train lặp lại được trong cùng dữ liệu và cấu hình. |
Train xong: lưu LightGBM artifact và metadata như model version, feature count, train rows, validation rows, best iteration.
Khi boot: AI Service chỉ load artifact nếu model có đúng 9 feature; thiếu file hoặc sai count thì dùng fallback.
Đánh đổi: LightGBM nhanh và nhẹ khi inference, nhưng chất lượng phụ thuộc label, dữ liệu lịch sử và việc train lại khi hành vi thay đổi.
05 · MODEL NHẬN 9 GIÁ TRỊ
| Feature | Đang đo gì? | Lấy từ đâu / cách tính | Mục tiêu và đánh đổi |
|---|---|---|---|
| profileAffinity | Mức hợp với sở thích dài hạn. | Preference theo product/category/brand, có decay theo thời gian. | Cá nhân hóa tốt; có thể lặp sở thích cũ. |
| sessionContext | Ý định trong phiên hiện tại. | Match category, brand và sản phẩm neo gần đây. | Bắt kịp nhu cầu nhanh; có thể nhiễu nếu phiên ngắn. |
| semanticSimilarity | Độ gần về nội dung. | Raw similarity từ embedding/Qdrant, clamp về 0–1. | Tìm item tương tự; phụ thuộc catalog và vector mới. |
| coBehavior | Mức thường đi cùng item khác. | Quan hệ xem/giỏ/mua, chuẩn hóa bằng raw/(raw + scale). | Tận dụng hành vi cộng đồng; yếu ở cold-start. |
| popularity | Nhu cầu chung của sản phẩm. | Max giữa log1p(totalSold)/12 và rank trending/best-selling. | Có điểm tựa khi thiếu profile; tránh để item hot lấn át cá nhân hóa. |
| freshness | Sản phẩm mới đến mức nào. | Bucket theo tuổi: 1, 7, 30 và 90 ngày. | Tạo cơ hội cho item mới; item mới chưa chắc phù hợp. |
| quality | Chất lượng và khả năng phục vụ. | Rating 55%, review 25%, còn hàng 20%. | Ưu tiên item đáng tin; shop mới ít review có thể bất lợi. |
| exploration | Cơ hội khám phá sản phẩm mới. | Chỉ bật khi affinity ≤ 0,4 và source là EXPLORE/NEWEST. | Tăng discovery; có thể giảm precision tức thời. |
| negativePenalty | Mức không phù hợp cần trừ. | Preference âm đã decay, cộng theo product/category/brand, tối đa 0,15. | Giảm lặp item không thích; cần decay để không phạt nhầm tín hiệu cũ. |
Giả sử S_standard = 0,653 và S_AI = 0,800:
S_final = (1 − 0,3) × 0,653 + 0,3 × 0,800
= 0,4571 + 0,2400 = 0,6971Standard đóng góp 70%, AI đóng góp 30%. 0,6971 là ranking score, không phải xác suất mua 69,71%.
0,653: điểm Standard đã tính từ 8 feature và penalty.
0,800: điểm model dự đoán từ 9 feature của cùng candidate.
0,6971: điểm cuối dùng để sort trước diversity/quota.
Ảnh hưởng lên thứ tự: nếu AI đánh giá candidate cao hơn Standard, điểm cuối có thể tăng; nếu AI thấp hơn, điểm có thể giảm. Mức thay đổi bị giới hạn bởi λ, nên AI không thể tự thay thế hoàn toàn baseline.
Fallback không phải là xóa kết quả. Hệ thống bỏ phần điểm AI không đáng tin, giữ điểm Standard đã tính và tiếp tục trả danh sách cho người dùng.
| Điều kiện | Điểm được dùng | Metadata response |
|---|---|---|
| Policy AI tắt | 100% Standard | HYBRID · modelVersion=null · rankingMode=HYBRID |
| Model chưa sẵn sàng hoặc không có artifact thật | 100% Standard | HYBRID · ghi nhận Standard/Fallback |
| Timeout, lỗi HTTP hoặc response sai schema | 100% Standard | HYBRID · modelVersion=null · rankingMode=HYBRID |
| Artifact thật trả prediction hợp lệ | Blend theo λ | ML_HYBRID · modelVersion · rankingMode=ML_HYBRID |
01 · TÌM SẢN PHẨM
02 · CHẤM ĐIỂM
03 · TRẢ KẾT QUẢ
01 · GHI NHẬN
Impression chỉ ghi khi ít nhất 50% thẻ sản phẩm hiện trong màn hình. Click mang token đã ký để xác định đúng món, thứ hạng, nguồn và ranking mode.
02 · XÁC THỰC
Token giúp đối chiếu item và attribution. Thiếu attribution hợp lệ thì event có thể còn là hành vi chung, nhưng không được tính vào phép đo recommendation.
03 · CẬP NHẬT
Client gom tối đa 20 event mỗi lần gửi; Kafka consumer cập nhật hồ sơ sau đó. Vì xử lý bất đồng bộ, event mới không làm đổi ngay danh sách đang xem.
Đánh đổi: ngưỡng 50% tránh tính thẻ chỉ vừa ló vào màn hình là đã được thấy, nhưng có thể bỏ sót lượt nhìn rất nhanh. Gửi theo lô và xử lý nền giảm request/chờ đợi, đổi lại feedback cập nhật trễ.