Bạn sẽ lập bảng phân tích 12 tháng từ dữ liệu nội bộ bằng AI mà không cần web. Mình đưa quy trình chuẩn hóa dữ liệu, chỉ số cốt lõi, nguồn thay thế, bộ prompt dùng ngay và ba kịch bản vận hành local, API, Sheet. Ví dụ dùng một sản phẩm giả định để bạn đối chiếu.
Phạm vi, giả định và mục tiêu sử dụng Template
Template này giúp bạn vận hành quy trình phân tích thị trường 12 tháng khi không truy cập web, tận dụng dữ liệu nội bộ và giả định minh bạch. Mình thiết kế để bạn có thể giao được hai đầu ra chính: 1) bảng phân tích 12 tháng có cấu trúc chặt chẽ để dùng ngay trong CSV hoặc Google Sheet, 2) phần tóm tắt gọn cho người ra quyết định, nêu rõ giả định, nguồn và mức tự tin.
Mục tiêu sử dụng
- Chuẩn hóa cách bạn nhập đầu vào cho AI gồm: tên sản phẩm, giá, thành phần, công dụng, nguồn gốc cùng dữ liệu nội bộ như bán hàng, kênh, khu vực, tồn kho, lịch khuyến mãi.
- Hướng AI tính các chỉ số cốt lõi và sinh bảng 12 tháng theo cấu trúc cố định, có cột giả định và nguồn tham chiếu để kiểm toán nội bộ.
- Cho phép chạy trong ba kịch bản môi trường: LLM local offline, LLM qua API nhưng chặn web, và LLM đọc file CSV hoặc Google Sheet nội bộ.
Phạm vi trong bài
- Cung cấp quy trình, bộ prompt, cấu trúc bảng 12 tháng và hướng dẫn chuẩn hóa dữ liệu để thay thế dữ liệu web bằng nguồn nội bộ hợp lệ như POS, CRM, D2C, catalogue nhà phân phối, phiếu nhập xuất, kế hoạch trade marketing.
- Chỉ dẫn cách xử lý thiếu dữ liệu bằng nhãn assumed, phạm vi kịch bản và kiểm tra độ nhất quán, nhằm bạn vẫn lên được kế hoạch thực dụng dù dữ liệu hạn chế.
Giả định nền tảng
- Không dùng tìm kiếm web hay nguồn dữ liệu thị trường bên ngoài tại thời điểm chạy.
- AI làm việc ở chế độ closed world, chỉ dùng dữ liệu bạn cung cấp. Trường nào thiếu sẽ ghi NA hoặc assumed kèm giả định cụ thể.
- Các chỉ số như bao phủ trọng số, vận tốc, thị phần proxy được suy ra từ proxy nội bộ sau khi chuẩn hóa đơn vị và thể tích.
Giới hạn trách nhiệm số liệu
- Kết quả là ước tính và kịch bản dựa trên dữ liệu nội bộ của bạn, có rủi ro sai lệch khi bao phủ kênh thấp hoặc dữ liệu thiếu. Không coi là số liệu thị trường chính thức hay tư vấn tài chính.
- Không khẳng định giá, thị phần, tên đối thủ nếu không có trong dữ liệu bạn nạp. Mọi giá trị phải kèm nguồn nội bộ hoặc gắn nhãn assumed để người ra quyết định đọc hiểu đúng mức độ tin cậy.
Danh sách dữ liệu đầu vào và chuẩn hóa trường
Đầu vào nên được tổ chức thành một bảng phẳng theo tháng hoặc tuần, với khóa định danh rõ. Mục tiêu là tách phần nhận diện sản phẩm khỏi phần giao dịch và điều kiện bán, rồi chuẩn hóa đơn vị để AI tính đúng các chỉ số cốt lõi như ASP theo thể tích, vận tốc bán và bao phủ.
Trường bắt buộc tối thiểu để bảng 12 tháng vận hành được
- period_month
- Định nghĩa: kỳ tháng theo chuẩn ISO yyyy-mm. Ví dụ 2026-01.
- Chuẩn hóa: dùng yyyy-mm, không kèm ngày. Nếu làm theo tuần, thêm cột periodweek ISO yyyy-Www và giữ periodmonth để tổng hợp.
- product_name
- Tên thương mại hiển thị của sản phẩm. Giữ nguyên văn theo nhãn, loại bỏ ký tự thừa.
- Chuẩn hóa: trim khoảng trắng, title case có quy tắc nội bộ. Không ghép kênh hoặc pack vào tên.
- brand, subbrand
- Thương hiệu và nhãn con nếu có.
- Chuẩn hóa: dùng danh mục chuẩn nội bộ, mã hóa bằng brandid, subbrandid.
- sku_id
- Định danh duy nhất cấp SKU trong hệ thống của bạn.
- Chuẩn hóa: khóa duy nhất, không tái sử dụng. Nếu có GTIN/EAN, thêm cột gtin làm đối chiếu.
- packsizevalue, packsizeunit, pack_qty
- Quy cách mỗi đơn vị bán: ví dụ 500 và ml, pack_qty = số đơn vị con trong một pack nếu bán multipack.
- Chuẩn hóa: chuẩn đơn vị về ml hoặc g, packqty ≥ 1. Tạo cột volumeperpackl = (packsizevalue × pack_qty) quy đổi về lít khi là đồ uống hoặc ml tương đương. Với sản phẩm tính theo trọng lượng, chuẩn về kg.
- channel
- Kênh bán hàng: MT, GT, Ecom, D2C, B2B.
- Chuẩn hóa: bộ mã kín channel_code có từ điển. Không dùng mô tả tự do.
- region
- Vùng địa lý: tỉnh thành hoặc vùng bán hàng nội bộ.
- Chuẩn hóa: regioncode theo danh mục chuẩn nội bộ. Nếu đa cấp, thêm provincecode, district_code.
- currencycode, pricenetperunit
- Đơn vị tiền tệ ISO 4217 và giá thuần mỗi đơn vị bán sau chiết khấu, chưa gồm thuế nếu thuế được tách riêng trong doanh thu.
- Chuẩn hóa: một currencycode mặc định cho toàn bảng. Nếu có nhiều tiền tệ, thêm fxratetobase và basecurrency, ngày hiệu lực fxdate từ bảng nội bộ.
- revenuenet, unitssold
- Doanh thu thuần và số đơn vị bán trong kỳ.
- Chuẩn hóa: revenuenet và unitssold là số dương, ăn khớp với pricenetperunit trong sai số làm tròn cho phép. Nếu có refund, ghi nhận âm trong một cột riêng trả hàng và giữ revenuenet đã trừ refund.
- stockopen, stockclose, instockrate
- Tồn đầu kỳ, tồn cuối kỳ và tỷ lệ có hàng trong kỳ theo ngày.
- Chuẩn hóa: instockrate nằm [0,1], nếu không có theo ngày thì ước theo số ngày OOS đã log nội bộ: instockrate = 1 − oosdays/totaldays.
- promoflag, promotype, discount_pct
- Cờ khuyến mãi, loại hình và độ sâu giảm giá trung bình trong kỳ nếu có.
- Chuẩn hóa: promotype có bộ mã kín như pricecut, bundle, display, coupon. discountpct tính trên net hoặc list ghi rõ discountbasis.
Trường tùy chọn nên có để nâng độ tin cậy
- ingredients
- Thành phần chính ở dạng text có cấu trúc nhẹ. Chuẩn hóa: tách list bằng dấu chấm phẩy, chuyển chữ thường có dấu.
- benefits_use
- Công dụng hoặc lợi ích chính. Chuẩn hóa: tối đa 3 gạch đầu dòng tách bạch, mã hóa nhãn claim nếu có chứng nhận.
- origincountry, originprovince
- Nguồn gốc. Chuẩn hóa: dùng ISO 3166 alpha-2 cho quốc gia, mã nội bộ cho tỉnh.
- categorypath, categoryid
- Danh mục chuẩn theo 3 bậc. Chuẩn hóa: Category>L2>L3 và một mã duy nhất category_id để tránh lệch viết hoa thường.
- listpriceperunit, taxrate, pricegrossper_unit
- Giá niêm yết, thuế suất và giá gross nếu cần. Chuẩn hóa: ghi rõ price_basis = net hay gross.
- aspperl, aspperunit
- Chỉ số dẫn xuất: ASP theo lít hoặc theo đơn vị. Chuẩn hóa: aspperl = revenuenet / volumesoldl với volumesoldl = unitssold × volumeperpackl. aspperunit = revenuenet / units_sold.
- accountid, bannerid, store_id
- Định danh khách hàng, chuỗi và cửa hàng nếu dữ liệu POS chi tiết. Chuẩn hóa: mã khóa duy nhất, có từ điển đối chiếu kênh và vùng.
- wdproxy, ndproxy
- Bao phủ trọng số và số trong khung mục tiêu nội bộ. Chuẩn hóa: rõ khung tính và proxy trọng số dùng.
- promocalendarid
- Khóa nối với bảng lịch khuyến mãi chi tiết ngày bắt đầu, ngày kết thúc, loại, mức hỗ trợ.
- oosdays, oosevents
- Số ngày thiếu hàng và số lần thiếu hàng trong kỳ.
- claims_cert
- Chứng nhận hoặc claim như organic, non-GMO. Chuẩn hóa: mã có từ điển.
- shelflifedays
- Hạn dùng. Chuẩn hóa: số ngày, không chuỗi tự do.
- unitofmeasure
- Cho sản phẩm không phải thể tích: kg, piece, pair. Chuẩn hóa: bộ mã kín UoM.
Quy tắc chuẩn hóa đơn vị và phép suy diễn an toàn
- Thời gian
- Chốt một hạt thời gian chính. Nếu làm theo tháng, tất cả chỉ số được quy đổi về mỗi ngày có hàng trước khi cộng dồn tháng để giảm nhiễu số ngày trong tháng và OOS.
- Tiền tệ
- Dùng một basecurrency. Nếu có nhiều currencycode, quy đổi revenuenet, pricenetperunit về base bằng fxratetobase từ bảng nội bộ đã chốt theo tháng. Ghi fxdate để audit.
- Thể tích và trọng lượng
- Với nhóm tính theo thể tích, chuẩn về lít: packsizeunit chuẩn hóa sang ml rồi chia 1000. Với nhóm theo trọng lượng, chuẩn về kg. Với đơn vị đếm, giữ unitofmeasure = piece và aspperl không áp dụng.
- ASP chuẩn
- Mặc định dùng aspperl cho so sánh giá, aspperunit chỉ để vận hành nội bộ theo SKU. Không tính aspperl nếu thiếu packsizevalue hoặc unit sai loại. Để NA và ghi assumption_text nếu ước đoán.
- Giá net
- Ưu tiên pricenetperunit từ giao dịch. Nếu thiếu, nội suy từ revenuenet/unitssold. Nếu cả hai thiếu nhưng có listpriceperunit và discountpct, suy ra pricenetperunit = listpriceperunit × (1 − discountpct). Gắn status = assumed và nêu công thức.
- Bao phủ
- Nếu có wdproxy và ndproxy, ghi rõ scopeframe mô tả khung tính toán. Không dùng giá trị bao phủ nếu scopeframe trống.
Quy tắc mã hóa danh mục và phân cấp nhận diện
- Khóa chính đề xuất cho bảng theo tháng: [periodmonth, skuid, channel, region]. Nếu có độ chi tiết theo banner hoặc account, mở rộng khóa.
- Từ điển chuẩn cho brand, subbrand, category, channel, region cần được đóng băng phiên bản với cột dict_version để truy xuất nguồn. Cấm dùng text tự do không map được.
- Với productname, giữ biến thể text để trình bày, nhưng mọi tính toán chạy trên skuid và category_id để tránh lỗi do chính tả.
Xử lý thiếu dữ liệu và suy diễn có kiểm soát
- Chính sách NA
- Trường nhận diện và khóa không được thiếu. Các chỉ số dẫn xuất như aspperl hoặc wd_proxy có thể NA. Không điền số phỏng đoán nếu không có quy tắc rõ.
- Suy diễn có nhãn
- Khi buộc phải suy diễn, thêm 3 cột: status in [verified, assumed], assumptiontext ngắn gọn, sourceid trỏ đến file nội bộ hoặc lệnh suy diễn. Ví dụ: status = assumed, assumption_text = “Giá net = list × (1 − discount) do thiếu dữ liệu giao dịch”.
- Heuristic an toàn
- packsizevalue có thể trích từ skuname bằng regex nội bộ, nhưng phải ghi status = assumed và kiểm tra biên hợp lý theo category. Không tính aspperl nếu packsize_unit không xác định.
- region có thể suy từ account_id theo bảng mapping. Nếu không tìm được, gán region = Unknown và loại khỏi tổng hợp theo vùng.
Kiểm tra dữ liệu trước khi đưa vào AI
- Kiểu dữ liệu
- Ngày theo yyyy-mm, số thực cho giá trị tiền và ASP, số nguyên cho units_sold, mã chuẩn cho danh mục.
- Ràng buộc
- revenuenet ≈ pricenetperunit × unitssold trong dung sai 1 đến 2 % do làm tròn. aspperl chỉ có giá trị khi unitofmeasure là thể tích và volumeperpackl > 0.
- Phụ thuộc
- promoflag = 1 thì promotype không được trống. instockrate < 1 thì oos_days ≥ 1.
- Phép liên hệ chuẩn
- aspperunit = aspperl × volumeperpack_l. Nếu lệch quá 1 đến 2 %, kiểm tra mix kích cỡ, đơn vị hoặc nhầm gross vs net.
Ví dụ một bản ghi đã điền sẵn cho bảng theo tháng Lưu ý: đây là ví dụ giả định để minh họa cấu trúc và cách chuẩn hóa.
period_month,product_name,brand,subbrand,sku_id,gtin,category_path,category_id,pack_size_value,pack_size_unit,pack_qty,unit_of_measure,volume_per_pack_l,channel,channel_code,region,region_code,currency_code,price_net_per_unit,revenue_net,units_sold,list_price_per_unit,discount_pct,price_basis,stock_open,stock_close,in_stock_rate,promo_flag,promo_type,discount_basis,oos_days,asp_per_unit,asp_per_l,status,assumption_text,source_id,dict_version,scope_frame
2026-01,Nước ép táo 100% FreshJoy,FreshJoy,Classic,FJ-AP-0500,8931234567890,Đồ uống>Juice>Táo,BEV_JC_APP,500,ml,1,volume,0.5,MT,MT,VN-HCM,HCM,VND,15000,150000000,10000,18000,0.167,net,2000,2500,0.92,1,price_cut,net,2,15000,30000,verified,,POS_JAN2026.csv#L238,v1.3,Top10_banners_2026Q1
Template cùng cấu trúc để bạn điền dữ liệu của mình
period_month,product_name,brand,subbrand,sku_id,gtin,category_path,category_id,pack_size_value,pack_size_unit,pack_qty,unit_of_measure,volume_per_pack_l,channel,channel_code,region,region_code,currency_code,price_net_per_unit,revenue_net,units_sold,list_price_per_unit,discount_pct,price_basis,stock_open,stock_close,in_stock_rate,promo_flag,promo_type,discount_basis,oos_days,asp_per_unit,asp_per_l,status,assumption_text,source_id,dict_version,scope_frame
yyyy-mm,<tên sản phẩm>,<thương hiệu>,<nhãn con>,<mã SKU>,<GTIN/EAN>,<Category>L2>L3,<mã danh mục>,<giá trị quy cách>,<đơn vị ml|g|piece>,<số đơn vị/pack>,<volume|weight|piece>,<thể tích lít/pack>,<kênh>,<mã kênh>,<vùng>,<mã vùng>,<ISO4217>,<giá net/đơn vị>,<doanh thu net>,<đơn vị bán>,<giá list/đơn vị>,<tỷ lệ giảm giá>,<net|gross>,<tồn đầu>,<tồn cuối>,<tỷ lệ có hàng>,<0|1>,<loại promo>,<net|list>,<ngày OOS>,<ASP/đơn vị>,<ASP/lít>,<verified|assumed>,<ghi chú giả định>,<id nguồn nội bộ>,<phiên bản danh mục>,<mô tả khung WD/ND>
Gợi ý tổ chức file dữ liệu
- Một file fact theo tháng làm trung tâm như ví dụ. Thêm các bảng từ điển: dimsku, dimcategory, dimchannel, dimregion, dimaccount để map mã về mô tả. Lưu dictversion trong fact để khóa phiên bản danh mục đã dùng.
- Với dữ liệu tuần hoặc theo cửa hàng, giữ hạt mịn ở file chi tiết, rồi tổng hợp lên fact theo tháng bằng quy tắc chuẩn hóa ở trên: chuyển revenue và units về basecurrency, quy đổi ASP theo lít, tính instock_rate từ nhật ký OOS theo ngày, hợp nhất promo theo cửa sổ xảy ra trong tháng.
Sau khi chuẩn hóa như trên, AI có thể tính đúng ASP theo lít, vận tốc bán theo điểm phân phối, và dựng bảng 12 tháng nhất quán mà không cần web. Tất cả suy diễn phải đi kèm status và assumption_text để người ra quyết định đọc đúng mức tin cậy.
Nguồn dữ liệu thay thế web và trích xuất đặc trưng
Bạn có thể dựng một phân tích thị trường hoàn chỉnh chỉ từ dữ liệu nội bộ nếu biết kéo đúng biến đặc trưng. Mình đi theo từng nguồn có sẵn trong hầu hết doanh nghiệp và nêu rõ cách rút ra chỉ số dùng được ngay cho bảng 12 tháng.
POS nội bộ hoặc EDI từ nhà bán lẻ
- Lấy gì: file bán ra theo cửa hàng hoặc theo banner gồm storeid, skuid, ngày, units, revenue_net, tồn đầu-cuối, giá thực trả, cờ đang bán hay OOS.
- Khóa nối: [storeid, skuid, ngày] rồi tổng hợp theo [tháng, kênh, vùng, sku].
- Trích xuất:
- instockrate tháng = số ngày có tồn sẵn bán trong tháng chia cho tổng ngày tháng.
- ND tháng = số cửa hàng có hàng trong tháng chia cho tổng cửa hàng trong khung bạn định nghĩa. Khung phải rõ ràng, ví dụ toàn bộ cửa hàng thuộc 10 banner bạn đang bán.
- SPD tháng theo cửa hàng mỗi tuần = unitssold / activestores / weeksinmonth. Dùng weeksinmonth ≈ số ngày tháng chia 7.
- ASP per unit = revenuenet / unitssold. ASP per L hoặc per kg = revenuenet / volumesoldstandard với volumesoldstandard = unitssold × thể tích hoặc trọng lượng chuẩn mỗi đơn vị.
- Giá net = giá giao dịch bình quân theo ngày hoặc theo lần quét POS. Nếu không có, thay bằng revenuenet/unitssold.
- Promo uplift: tách ngày có promoflag=1. Tính baselineuperinstockday = units ở ngày không promo chia số ngày in-stock và promouperinstockday tương tự. Upliftpct = (promouperinstockday − baselineuperinstockday) chia baselineuperinstockday.
CRM bán hàng B2B và bán sỉ
- Lấy gì: account_id, ngành, quy mô, khu vực, pipeline stage, doanh thu tiềm năng, số lần chạm 90 ngày, lịch sử đơn hàng, giá net theo hợp đồng, tần suất reorder.
- Khóa nối: [account_id, tháng] rồi map sang region, kênh B2B.
- Trích xuất:
- ICP score và tiềm năng B2B: chuẩn hóa doanh thu tiềm năng, quy mô nhân sự, ngành mục tiêu, điểm tương đồng sản phẩm thành thang [0,100]. Bạn có thể đặt ICPpotential = 0.5 × normalizedrevenuepotential + 0.3 × normalizedsize + 0.2 × fittousecase. Ghi rõ công thức ở cột assumptiontext.
- Vận tốc B2B theo tài khoản hoạt động = doanh thu tháng chia số tài khoản có cơ hội ở stage từ Qualification trở lên.
- Win rate, cycle length, ASP net theo hợp đồng để làm chuẩn so sánh theo vùng và kênh.
D2C và Ecommerce analytics nội bộ
- Lấy gì: impressions, product page views, add-to-cart, orders, revenue, search terms nội bộ, vị trí hiển thị trong gian hàng bạn quản trị, ngân sách quảng cáo và lượt hiển thị từ tài khoản ads của bạn.
- Khóa nối: [sku_id, channel=Ecom hoặc D2C, tháng].
- Trích xuất:
- Share of impressions nội bộ: shareimprinternal = impressionsskuchọntậpkeyword chia tổng impressions trong cùng tập keyword hoặc campaign của chính bạn. Nhấn mạnh mẫu số là tổng nội bộ, không phải toàn thị trường.
- Share of shelf nội bộ: số vị trí top trong category page bạn quản trị chia tổng vị trí có thể hiển thị mà bạn kiểm soát.
- CVR, AOV, repeat rate để bổ trợ suy luận nhu cầu và mức giá chấp nhận.
Catalogue nhà phân phối và chính sách giá
- Lấy gì: danh mục SKU họ đang phân phối, list price, bậc chiết khấu, quy cách pack, vùng phục vụ, danh sách banner họ bán vào nếu có thỏa thuận báo cáo.
- Khóa nối: [distributorid, skuid], map về kênh và vùng.
- Trích xuất:
- Giá net dự kiến theo kênh: pricenetexpected = listprice × (1 − discountpct bậc).
- Ràng buộc giá và pack-size để kiểm tra ASP và biên lợi nhuận khi đối chiếu POS.
- Ước lượng thô phạm vi phân phối theo banner nếu có danh mục hợp đồng đã ký.
Phiếu nhập xuất kho từ ERP hoặc WMS
- Lấy gì: GRN nhập, GDN xuất, tồn kho đầu-cuối theo kho, theo ngày, cờ OOS tại kho.
- Khóa nối: [warehouseid, skuid, ngày] và ánh xạ kho sang kênh hoặc vùng giao hàng.
- Trích xuất:
- Sell-in theo tháng làm baseline cung cấp.
- OOS ở kho: nếu tồn tại 0 trong nhiều ngày liên tiếp, ghi oosevents và oosdays để giải thích giảm bán lẻ.
- Kiểm tra cân đối supply-demand: tồn mở + nhập − xuất − tồn đóng gần bằng 0 trong dung sai kiểm kê.
Khảo sát khách hàng nội bộ và CSKH
- Lấy gì: tần suất mua, kênh ưa thích, mức giá sẵn sàng chi trả, NPS, lý do chọn mua, mã cửa hàng hay mã tài khoản nếu thu thập tại điểm bán hoặc sau giao dịch.
- Khóa nối: [surveyid, tháng], nếu có thể map về storeid hoặc account_id.
- Trích xuất:
- Hệ số trọng số nhu cầu theo vùng hoặc kênh để cập nhật w_i tiềm năng cửa hàng.
- Indicator nhạy cảm giá và promo để giải thích biên độ uplift.
Kế hoạch trade marketing
- Lấy gì: lịch sự kiện theo ngày, banner, kênh, mức giảm giá, loại hình trưng bày, ngân sách.
- Khóa nối: [tháng, kênh, banner] và [sku_id] nếu sự kiện theo SKU.
- Trích xuất:
- promodays, promointensity, promocoveragerate theo kênh.
- Ước uplift kỳ vọng theo loại hình dựa trên lịch sử nội bộ cùng kênh. Khi áp dụng, luôn ghi status = assumed nếu bạn mượn hệ số từ SKU khác.
Cách xây đặc trưng phổ biến dùng cho bảng 12 tháng
- SPD tháng:
- Đơn vị: units per store per week.
- Công thức: SPD = unitssoldadj / activestores / weeksinmonth. Với unitssoldadj = unitssold nếu instockrate ≥ 0.85, còn nếu thấp hơn có thể xấp xỉ cầu tiềm năng = unitssold / instock_rate nhưng nên đặt trần x 1.2 để tránh phóng đại.
- instockrate:
- Tính ở hạt ngày rồi tổng hợp theo tháng: số ngày có tồn > 0 chia tổng ngày. Với dữ liệu giờ thì chuyển về ngày bằng quy tắc có hàng nếu có tồn dương ở bất kỳ khung giờ vận hành.
- promo_uplift:
- Upliftpct = (upromoperinstockday − ubaselineperinstockday) chia ubaselineperinstockday. Tách ngày theo promoflag, chỉ tính trên ngày in-stock để tránh nhiễu OOS.
- Giá net và ASP:
- pricenetperunit = revenuenet / units_sold nếu không có trường giá dòng giao dịch.
- aspperl hoặc aspperkg là mặc định để so sánh giá xuyên pack-size.
- ND và WD:
- ND = số điểm có hàng trong tháng chia tổng điểm trong khung mục tiêu nội bộ.
- WD dùng trọng số wi của từng cửa hàng, ví dụ tổng doanh số quầy thu ngân, số hóa đơn, hoặc doanh số danh mục lân cận của bạn. Chuẩn hóa wi về [0,1] bằng min-max theo khung, rồi WD = tổng wi điểm đã phủ chia tổng wi toàn khung.
- w_i tiềm năng cửa hàng:
- Nếu có nhiều tín hiệu, chuẩn hóa từng tín hiệu về [0,1] rồi hợp lại, ví dụ wi = 0.5 × normretailsales + 0.3 × normtxncount + 0.2 × normbanner_tier. Ghi rõ nguồn và trọng số.
- ICP tiềm năng B2B:
- Điểm ICPscore trong [0,100] và một ước lượng doanh thu tiềm năng ICPrevenue_potential. Dùng trường CRM gốc nếu có, nếu không tính bằng hệ số dựa trên quy mô và mức độ khớp use case. Trường hợp ước đoán phải gắn status = assumed.
- Share of impressions online nội bộ:
- shareimprinternal = impressions_sku trên tập keyword hoặc campaign cố định của bạn chia tổng impressions nội bộ cùng tập đó. Rõ ràng phạm vi mẫu số và nguồn đo là tài khoản của bạn.
Lưu ý vận hành để kết quả sát thực tế
- Đặt trước scope_frame cho ND và WD, nếu không thì mọi tỷ lệ bao phủ vô nghĩa.
- Ưu tiên ASP theo đơn vị chuẩn thay vì theo đơn vị gốc để tránh ảo giá do mix kích cỡ.
- Promouplift chỉ tin khi giá net ổn giữa nhóm promo và non-promo hoặc bạn đã thêm discountpct vào mô hình điều chỉnh.
- Với kênh đang mở rộng, theo dõi hội tụ của SPD và ASP theo decile w_i để biết ngưỡng bao phủ trước khi ngoại suy.
Ví dụ điền sẵn các đặc trưng tháng 2026-01 cho một SKU giả định ở kênh MT Lưu ý: đây là ví dụ minh họa cấu trúc và cách tính, số liệu do mình đặt để khớp công thức nội bộ.
period_month,channel,region,sku_id,active_stores,total_stores_in_scope,ND_pct,WD_pct,units_sold,revenue_net,pack_size_ml,volume_sold_l,in_stock_days,promo_days,baseline_u_per_instock_day,promo_u_per_instock_day,SPD_units_per_store_per_week,price_net_per_unit,asp_per_l,share_impr_internal,status,assumption_text,source_id,scope_frame
2026-01,MT,VN-HCM,FJ-AP-0500,110,200,0.55,0.57,10000,150000000,500,5000,29,6,320,440,20.5,15000,30000,0.20,verified,Promo uplift tính trên ngày in-stock; WD dựa w_i từ doanh số quầy thu ngân,POS_JAN2026.csv#HCM;TRADE_CAL_JAN2026.xlsx#MT,Top10_banners_2026Q1
Mẫu biến thể để bạn thay số của mình
period_month,channel,region,sku_id,active_stores,total_stores_in_scope,ND_pct,WD_pct,units_sold,revenue_net,pack_size_ml,volume_sold_l,in_stock_days,promo_days,baseline_u_per_instock_day,promo_u_per_instock_day,SPD_units_per_store_per_week,price_net_per_unit,asp_per_l,share_impr_internal,status,assumption_text,source_id,scope_frame
yyyy-mm,<kênh>,<vùng>,<sku>,<cửa hàng hoạt động>,<tổng cửa hàng trong khung>,<ND>,<WD>,<đơn vị bán>,<doanh thu net>,<ml/đơn vị>,<lít bán ra>,<ngày in-stock>,<ngày promo>,<units/ngày không promo>,<units/ngày promo>,<SPD>,<giá net/đơn vị>,<ASP/L>,<share impressions nội bộ>,<verified|assumed>,<ghi chú>,<id nguồn>,<mô tả khung>
Khi đã bóc được các đặc trưng này từ POS, CRM, D2C, catalogue, phiếu nhập xuất và kế hoạch trade marketing, bạn có đủ vật liệu để AI chạy phân tích 12 tháng mà không cần đụng web: tốc độ bán, mức sẵn có hàng, tác động khuyến mãi, mặt bằng giá, tiềm năng điểm bán và tài khoản, cùng mức hiện diện nội bộ trên kênh online. Chỉ cần giữ kỷ luật định nghĩa khung và gắn nguồn cho mọi phép ước đoán, bạn sẽ kiểm soát được độ sát thực tế.
Chỉ số và phép biến đổi cốt lõi để suy luận thị trường
Bộ chỉ số dưới đây là xương sống để bạn cho AI lập bảng phân tích 12 tháng mà không dùng web. Mình định nghĩa ngắn gọn, kèm công thức tính và điểm kiểm cần chạy để tránh sai lệch khi bao phủ thấp.
Chuẩn hóa thể tích và ASP để tránh ảo giác do pack-size
- Chuẩn thể tích: quy về đơn vị chuẩn như lít hoặc kg. volumesoldstandard = unitssold × packsize_l.
- ASP per L: aspperl = revenuenet / volumesoldstandard. So sánh giá nên dùng aspper_l để loại ảnh hưởng mix kích cỡ.
- ASP per unit: aspperunit = revenuenet / unitssold. Chỉ dùng cho theo dõi nội bộ SKU cố định kích cỡ. Nhớ rằng aspperunit = aspperl × avgvolumeperunit, vì vậy aspper_unit sẽ nhảy theo mix pack.
- Cảnh báo: mọi tăng giảm giá, thị phần, uplift phải tính sau khi đã chuẩn hóa thể tích. Trường hợp danh mục có nhiều quy cách 250 ml, 500 ml, 1 L, sai lệch có thể rất lớn nếu dùng đơn vị gốc.
Bao phủ số và bao phủ trọng số để đo hiện diện
- Scope frame bắt buộc: xác định vũ trụ tính toán, ví dụ toàn bộ cửa hàng thuộc 10 banner đang chào hoặc toàn bộ huyện quận có đội bán. Không có khung thì ND và WD vô nghĩa.
- ND số: ND = activestores / totalstoresinscope. Tính theo tháng và theo kênh, vùng.
- WD trọng số: WD = sum(wi của điểm đã phủ) / sum(wi toàn khung). w_i là tiềm năng điểm bán, chuẩn hóa về [0,1] từ proxy nội bộ như:
- Doanh số quầy thu ngân trong CRM bán buôn hoặc POS nếu có EDI.
- Doanh số các SKU lân cận của bạn tại chính cửa hàng đó.
- Số hóa đơn, số giao dịch, phân hạng banner hoặc cỡ cửa hàng.
- Kiểm: tính chênh lệch b = mean(wi của điểm đã phủ) trừ mean(wi toàn khung. b dương lớn nghĩa mẫu thiên về cửa hàng ngon, ngoại suy dễ phóng đại.
Vận tốc bán chuẩn và điều chỉnh OOS
- SPD units per store per week: SPD = unitssoldadj / activestores / weeksinmonth. weeksin_month ≈ số ngày bán chia 7.
- Điều chỉnh OOS: instockrate = instockdays / totaldays. Nếu instockrate < 0.85, xấp xỉ cầu tiềm năng unitssoldadj = min(unitssold / instockrate, unitssold × 1.2) để tránh nổ số. Nếu có dữ liệu theo ngày, tính uperinstockday trước rồi nhân số ngày in-stock chuẩn.
- Vận tốc B2B theo tài khoản: velocityb2b = revenuemonth / số tài khoản ở stage từ Qualification trở lên. Trọng số tiềm năng là doanh thu dự kiến trong CRM.
Seasonality nội bộ và tách hiệu ứng giá khuyến mãi
- Xây seasonalindex theo tháng từ chuỗi đã điều chỉnh OOS và tách khuyến mãi. Với đủ ≥ 12 tháng, seasonalindexm = ym / trend_m, bình quân 12 tháng bằng 1.
- Nếu chuỗi ngắn, dùng lịch nội bộ làm neo như kỳ lương, dịp cao điểm công ty đã biết. Shrink biên độ nhỏ để tránh overfit và luôn gắn status = assumed.
- Tách khuyến mãi: tính baselineuperinstockday trên ngày không promo và promouperinstockday trên ngày promo. promoupliftpct = (promo − baseline) / baseline. Khi mô tả seasonality, loại bỏ ngày promo để không nhầm uplift thành mùa.
Ước lượng tăng trưởng nội bộ theo cấu phần
- Phân rã tăng trưởng MoM hoặc YoY thành 3 phần: bao phủ, vận tốc, giá mix chuẩn thể tích.
- Coverage effect ≈ WDt / WD{t-1} hoặc NDt / ND{t-1}.
- Velocity effect ≈ SPDadjt / SPDadj{t-1} trên cùng cohort cửa hàng.
- Price-mix effect ≈ aspperlt / aspperl{t-1}.
- Kiểm: tăng trưởng quan sát ≈ coverage × velocity × price_mix. Lệch lớn thường do OOS chưa điều chỉnh hoặc cohort khác nhau.
Market share proxy không dùng web theo 3 cấp độ tin cậy
- Cấp 1 trực tiếp trong phạm vi có POS danh mục: shareproxyscope = yourvolume / categoryvolume trong cùng tập cửa hàng và tháng. Đây là proxy tốt nhất vì mẫu số có thật từ POS nội bộ của nhà bán lẻ.
- Cấp 2 ngoại suy từ tập con có danh mục:
- Bước 1: tính sharesub = yourvolumeS / categoryvolume_S trên tập S có dữ liệu danh mục.
- Bước 2: hiệu chỉnh thiên lệch bao phủ bằng B = SPDS / SPDstable. SPDstable là vận tốc ở vùng đã hội tụ theo phương pháp điểm gãy bên dưới, đo trên cohort ổn định. Nếu B > 1, mẫu S là cửa hàng ngon, giảm sharesub tương ứng.
- Bước 3: shareproxyscope ≈ share_sub / B. Gắn status = assumed và ghi rõ cách hiệu chỉnh.
- Cấp 3 định hướng khi không có mẫu số danh mục: dùng share of impressions nội bộ trên gian hàng Ecommerce D2C làm chỉ báo thứ hạng, không diễn giải thành phần trăm thị trường. Ghi chú rõ phạm vi và đơn vị đo. Dùng để theo dõi xu hướng, không để tính quy mô.
- Cảnh báo: cấm ngoại suy share ra ngoài scope_frame. Share không ổn định khi WD thấp. Luôn kèm khoảng tin cậy định tính dựa trên độ phủ và thiên lệch b.
Decile WD và điểm gãy hội tụ vận tốc
- Mục tiêu: tìm ngưỡng WD mà SPD trở nên ổn định, từ đó mới dám nhân rộng hoặc suy quy mô.
- Cách làm:
- Tính wi cho từng điểm bán, chuẩn hóa về [0,1]. Sắp xếp cửa hàng theo wi giảm dần, chia thành 10 decile.
- Với mỗi k từ 1 đến 10, tính WDk là tổng trọng số đến decile k chia tổng trọng số toàn khung. Tính SPDk là doanh số cộng dồn đến decile k chia số tuần và chia WD_k × tổng trọng số để nhận vận tốc đã chuẩn hóa theo WD.
- Điểm gãy là WDk tại đó biến thiên tương đối |SPDk − SPD{k−1}| / SPD{k−1} rơi xuống ngưỡng thấp trong 2 đến 3 bước liên tiếp. Kèm kiểm chéo hội tụ của ASP, promo rate, instockrate giữa k và k−1 đều lệch nhỏ.
- Sau điểm gãy, dùng SPDstable để nội suy trong phạm vi scopeframe. Trước điểm gãy, mọi phép nhân lên toàn khung đều có nguy cơ lệch hệ thống.
- Kiểm thêm: tính CV vận tốc per điểm bán theo vùng. Khi WD tăng và CV giảm bền xuống ngưỡng thấp ổn định trong vài kỳ, đó là tín hiệu đã qua ngưỡng.
Capture-recapture để ước tổng điểm trong khung khi thiếu mẫu số
- Tình huống: bạn không biết totalstoresin_scope nhưng có nhiều danh sách từ CRM như A cửa hàng đã viếng, B cửa hàng đã có đơn thử, C cửa hàng có đơn lặp.
- Ước lượng 2 danh sách: N_hat ≈ |A| × |B| / |A ∩ B|. Dùng cho từng cặp độc lập tương đối.
- Thực thi an toàn: tính NhatAB, NhatAC, NhatBC rồi lấy trung vị để giảm ảnh hưởng vi phạm độc lập. Ghi rõ giả định độc lập tương đối giữa các danh sách. Dùng Nhat làm mẫu số cho ND và nền tảng để tính WD sau khi có wi.
- Kiểm: nếu tỉ lệ chồng lắp quá thấp khiến N_hat vọt cao bất thường, điều tra quy tắc ghi nhận dữ liệu hoặc tách theo vùng để tăng mức độc lập.
Cảnh báo sai lệch khi bao phủ thấp và cách lượng hóa nhanh
- Lệch chọn kênh: thường vào cửa hàng ngon trước. Bài thuốc: đo b = mean(wi phủ) − mean(wi toàn khung. Nếu b dương lớn, giảm kỳ vọng SPD khi ngoại suy.
- Ngoại ứng phân phối và nhận biết: dưới ngưỡng hiện diện, SPD per store bị nén vì thiếu sẵn có và nhận biết. Quan sát tăng SPD bình quân khi mở rộng ở nhóm thử là dấu hiệu chưa qua ngưỡng.
- Khác biệt mix kênh: kênh đang phủ có promo, giá, quầy kệ khác biệt. Bài thuốc: so SPD và ASP giữa nhóm phủ sớm và phủ muộn theo w_i tương đương.
- Thiên lệch địa lý và mùa vụ: vùng phủ có cấu trúc cầu khác vùng chưa phủ. Bài thuốc: phân tích theo tỉnh quận, theo dõi CV. Không ghép vùng dị biệt vào một mẫu.
- Phi tuyến theo độ sâu phân phối: SPD mỗi cửa hàng chỉ ổn định sau khi vượt một ngưỡng phủ. Bài thuốc: dùng đường cong SPDk theo WDk để tìm điểm gãy, cấm nhân run-rate trước ngưỡng.
- Quy tắc vận hành: khi WD nội bộ còn thấp, chỉ xuất share và quy mô theo phạm vi đã phủ hoặc theo tập cửa hàng có danh mục. Nếu buộc ngoại suy, gắn cờ assumed, hiệu chỉnh bằng b, B và báo độ bất định định tính.
Ví dụ tính nhanh và kiểm lệch
- Giả định tháng 1: 120 cửa hàng đang bán trên 300 cửa hàng trong khung, ND = 120/300 = 0.40. Tổng wi toàn khung là 220, tổng wi đã phủ là 88 nên WD = 88/220 = 0.40.
- Unitssold = 9.600, instockdays trung vị 24 ngày trên 30 ngày, instockrate ≈ 0.80. Điều chỉnh cầu tiềm năng: unitssold_adj = min(9.600/0.80, 9.600 × 1.2) = min(12.000, 11.520) = 11.520. SPD ≈ 11.520 / 120 / (30/7) ≈ 22.4 units per store per week.
- aspperunit = 15.000, packsize = 500 ml, aspper_l = 30.000.
- Nếu có POS danh mục trên 40 cửa hàng đầu bảng, categoryvolumeS = 60.000 units, yourvolumeS = 8.000 units, sharesub = 13.3%. Đường cong SPD theo decile cho thấy SPDstable ≈ 20, còn SPDS ≈ 24 ở nhóm phủ đầu. B = 24/20 = 1.2, shareproxyscope ≈ 13.3% / 1.2 ≈ 11.1% trong phạm vi scopeframe. Gắn status = assumed, note nguồn S và cách hiệu chỉnh.
Khi bạn tính và kiểm những chỉ số trên theo đúng phạm vi, chuẩn hóa thể tích, điều chỉnh OOS và định vị ngưỡng hội tụ, AI có thể suy luận thị trường nội bộ một cách có kỷ luật. Trường hợp dữ liệu thiếu, luôn chọn proxy ở cấp tin cậy thấp hơn và đánh dấu assumed kèm lý do thay vì lấp số.
Quy trình tổng quan để AI phân tích thị trường không dùng web
Đây là lộ trình vận hành để bạn cho AI tạo phân tích thị trường 12 tháng chỉ từ dữ liệu nội bộ. Quy trình ưu tiên kỷ luật dữ liệu và minh bạch giả định để tránh lệch khi bao phủ thấp, đồng thời cho ra bảng 12 tháng có thể xuất CSV hoặc Sheet ngay.
- Bước 1. Gom gói đầu vào và thiết lập phạm vi
- Tạo gói Input Bundle gồm: metadata sản phẩm bắt buộc tên sản phẩm và giá hiện hành, tùy chọn thành phần, công dụng, nguồn gốc; dữ liệu nội bộ cần thiết sales theo SKU cửa hàng theo tuần hoặc tháng, tồn kho và instockdays, lịch promo, bảng giá net sau chiết khấu, CRM danh sách điểm bán đã chào và đã mở, POS danh mục nếu có, proxy tiềm năng điểm bán w_i, dữ liệu Ecommerce nội bộ share of impressions nếu có.
- Khai báo scope_frame rõ ràng theo kênh và vùng. Đặt đơn vị chuẩn thể tích hoặc khối lượng, tiền tệ, múi giờ, lịch tháng.
- Cấu hình AI ở chế độ closed-world, bắt buộc status và source_id cho mọi số, sampling an toàn temperature 0 đến 0.2.
- Bước 2. Chuẩn hóa và làm sạch
- Quy đổi thể tích về đơn vị chuẩn và tính aspperl. Chuẩn hóa ngày về tháng và số tuần tương đương.
- Điều chỉnh OOS: tính instockrate theo tháng, chuyển về unitsperinstockday rồi suy ra unitssold_adj theo ngày in-stock chuẩn.
- Đồng bộ mã kênh, vùng, pack-size, SKU. Bỏ bản ghi lỗi đơn vị hoặc thiếu khóa ghép.
- Bước 3. Tính chỉ số cốt lõi
- ND số điểm bán có hàng chia cho tổng điểm trong scope. WD trọng số theo wi. Tính b thiên lệch chọn kênh bằng chênh lệch mean wi.
- SPD vận tốc chuẩn theo tuần trên cửa hàng đã mở và đã điều chỉnh OOS.
- Giá và mix: aspperl, aspperunit chỉ để tham khảo khi pack cố định.
- Promo_uplift theo ngày có promo so với baseline.
- Market share proxy theo phạm vi có POS danh mục. Nếu chỉ có tập con, hiệu chỉnh bằng hệ số B dựa trên SPD ổn định. Nếu không có mẫu số danh mục, chỉ xuất chỉ báo định hướng, gắn assumed.
- Decile WD và SPD_k để tìm điểm gãy hội tụ. Tính CV vận tốc theo vùng để kiểm sự hội tụ.
- Bước 4. Chẩn đoán lệch và khóa ngoại suy
- Đánh giá đã qua điểm gãy chưa. Nếu WD thấp hoặc B lệch, giới hạn mọi ngoại suy trong scope_frame và gắn assumed cùng lý do. Không nhân run-rate ra ngoài phạm vi nếu chưa hội tụ.
- Bước 5. Chọn phương pháp dự báo 12 tháng
- Nội suy đơn giản khi biến động thấp và không có neo mùa vụ đáng tin.
- Seasonal index tối giản khi có template nội bộ hoặc lịch sự kiện nội bộ đáng tin và có neo kiểm định. Shrink biên độ nếu neo ít.
- Kịch bản phạm vi khi bất định cao, đang ramp hoặc sắp có thay đổi cấu trúc. Tạo biên dưới cơ sở biên trên theo driver nội bộ độ phủ, promo, giá, OOS.
- Ghi rõ assumptions, tham số và nguồn neo dùng.
- Bước 6. Sinh bảng phân tích 12 tháng
- Tạo bảng theo tháng cho từng kênh và vùng trong scope, gồm các trường cốt lõi như Month, Channel, Region, ND, WD, SPDadj, Unitsactual, UnitspotentialOOSadj, Revenuenet, ASPperL, Mixpack, Seasonalindex, Forecast, OOSrate, Promoplan, Shareproxyscope, Confidence, Status, Sourceid, Assumptionnote.
- Điền số lịch sử ở các tháng đã có dữ liệu và tạo 12 tháng dự báo theo phương pháp đã chọn. Mọi trường không có dữ liệu phải ghi NA và status assumed kèm giả định ngắn.
- Bước 7. Sinh nhận định quản trị kèm giả định
- Tổng hợp 6 đến 8 ý chính cho người ra quyết định: trạng thái hội tụ, driver tăng trưởng bao phủ vận tốc giá, rủi ro và độ bất định, điểm gãy, kế hoạch kênh. Mỗi ý phải trỏ source_id hoặc nêu assumption rõ.
- Bước 8. Kiểm tra chất lượng đầu ra
- Kiểm tính nhất quán đơn vị và cộng dồn theo tháng và vùng. Kiểm phương trình tăng trưởng decomposition coverage × velocity × price-mix xấp xỉ tăng trưởng quan sát.
- Kiểm OOS_rate nằm trong 0 đến 1 và điều chỉnh OOS không làm nổ số.
- Kiểm SPDk hội tụ theo WDk ổn định trong 2 đến 3 decile liên tiếp. Kiểm share chỉ xuất trong scope có mẫu số.
- Nếu lỗi, quay lại bước 2 hoặc 3, điều chỉnh và chạy lại. Kiểm tra diễn ra nội bộ và không in kèm vào báo cáo.
- Bước 9. Xuất bản CSV hoặc Sheet và lưu vết
- Xuất file CSV chuẩn hóa cột và tạo Google Sheet nếu cần cho chia sẻ. Kèm Data Dictionary sheet mô tả từng trường và đơn vị. Lưu thêm Assumption Register gồm assumption_id, mô tả, phạm vi ảnh hưởng, hướng nhạy cảm. Ghi version, timestamp, tham số dự báo và phạm vi dữ liệu.
Ví dụ nhanh minh họa quy trình cho một sản phẩm giả định
- Sản phẩm giả định: Nước thảo mộc 500 ml, giá net 15.000, công dụng giải khát, nguồn gốc Việt Nam. Dữ liệu nội bộ cho thấy WD hiện tại 0.42, SPD đã điều chỉnh OOS ổn định sau decile 6, promouplift 18%, aspper_l 30.000.
- Chọn phương pháp: seasonal index tối giản dựa trên lịch lương và hai dịp nội bộ, shrink biên độ 0.4. Gắn assumptions về biên độ mùa và kế hoạch promo đã chốt 2 quý đầu.
- Xuất một dòng minh họa tháng 01 cho kênh MT Hà Nội như sau.
Month,Channel,Region,ND,WD,SPD_adj,Units_actual,Units_potential_OOS_adj,Revenue_net,ASP_per_L,Mix_pack,Seasonal_index,Forecast,OOS_rate,Promo_plan,Share_proxy_scope,Confidence,Status,Source_id,Assumption_note
2026-01,Modern Trade,Ha Noi,0.38,0.42,21.7,9200,10850,276000000,30000,"500ml:100%",0.95,10200,0.12,"Tết -10% price lift",NA,Medium,assumed,"sales_2025Q4.csv:L220;promo_cal_2026.xlsx:C12","Biên độ mùa shrink 0.4; kế hoạch promo 1 đợt"
Kịch bản vận hành A LLM local offline
Giả định trong kịch bản này: máy của bạn hoàn toàn không có internet khi chạy mô hình. Mục tiêu là nạp dữ liệu nội bộ bằng copy paste hoặc chèn nội dung file local vào prompt, khóa chế độ closed world và sampling an toàn để tránh bịa, rồi xuất bảng và sổ nguồn có thể lưu ra file trên máy.
Quy trình thao tác tối thiểu, chạy được ngay
- Chọn công cụ local và kiểm tra model có sẵn
- Tùy hệ điều hành, bạn có thể dùng một trong các công cụ phổ biến sau, đều chạy offline sau khi model đã nằm trên máy:
- Ollama: chạy model local, có REST API tại localhost:11434, đặt được temperature và top_p. Dùng lệnh ollama list để kiểm tra model đã có sẵn.
- LM Studio: giao diện desktop, đặt được System prompt, temperature, top_p, copy paste dữ liệu vào cửa sổ chat. Hoạt động offline sau khi đã tải model.
- llama.cpp: chạy qua CLI với file .gguf, đặt được –temp, –top-p, đọc prompt từ file hoặc tham số -p.
- Kiểm tra nhanh trên máy không mạng:
- Ollama: ollama list để xem danh sách model. Chỉ tiếp tục nếu model bạn cần đã hiện ra.
- llama.cpp: đảm bảo có file model.gguf trên đĩa, ví dụ ./models/llama3.gguf.
- Nạp dữ liệu vào context khi không có mạng
- Cách A – copy paste trực tiếp: mở file CSV nội bộ, copy nguyên phần cần dùng rồi dán vào vùng CONTEXT trong prompt. Mẹo giảm lỗi:
- Gắn nhãn nguồn cho mỗi khối dán: ví dụ [sourceid: sales2025Q4.csv:L200-260] ở ngay trên block dữ liệu.
- Chuẩn hóa định dạng về CSV, UTF-8, phẩy làm dấu tách, dấu chấm làm thập phân. Ghi đơn vị ở header khi cần.
- Cách B – chèn nội dung file vào prompt qua shell, không cần mở file:
- Mac hoặc Linux, với llama.cpp hay Ollama API, bạn có thể nội suy nội dung file vào biến shell:
- Ví dụ đặt VARSALES="$(cat ./data/sales2025Q4.csv)" rồi nhúng $VAR_SALES vào trường context của prompt JSON.
- Cách C – chia nhỏ khi file dài: cắt file thành các phần dưới 3.000 token mỗi phần, gắn sourceid khác nhau, dán tuần tự. Ở cuối, yêu cầu model chỉ dùng trường có sourceid hợp lệ.
- Khóa closed world và sampling an toàn
- Nguyên tắc: để giảm bịa, bạn cần vừa hạ nhiệt độ vừa đặt ràng buộc closed world và bắt buộc nguồn theo trường. Giới hạn mặc định an toàn:
- temperature 0.0 đến 0.2
- top_p 0.8 đến 0.9
- System prompt khuyến nghị bằng tiếng Anh, đã khóa closed world và schema. Bạn có thể dùng nguyên văn sau. Tóm ý: chỉ dùng dữ liệu trong CONTEXT, số nào cũng phải có source_id, thiếu thì NA, xuất đúng schema.
You are a market analyst working in closed-world mode.
Rules:
- Use ONLY the data provided in CONTEXT. Do not use outside knowledge.
- Never guess numbers or competitor names. If a field is missing, return "NA".
- Every numeric value must include source_id that maps to the pasted CONTEXT block.
- If a number is derived, set status="assumed" and add a short assumption.
- Output two blocks only:
1) BEGIN:CSV ... END:CSV with a 12-month market analysis table in CSV. Columns:
Month,Channel,Region,ND,WD,SPD_adj,Units_actual,Units_potential_OOS_adj,Revenue_net,ASP_per_L,Mix_pack,Seasonal_index,Forecast,OOS_rate,Promo_plan,Share_proxy_scope,Confidence,Status,Source_id,Assumption_note
2) BEGIN:SOURCES ... END:SOURCES listing the source register as machine-readable lines that start with a hyphen, fields separated by a vertical bar. Columns: id|file|range|note
- Do not add narrative or explanations outside these two blocks.
Before answering, self-check that each numeric value has either a source_id or status="assumed". If not, replace with NA.
- Gọi model và lưu file kết quả hoàn toàn offline
- Với Ollama qua REST API local. Ví dụ dưới đây chèn dữ liệu bằng biến shell, khóa nhiệt độ và top_p, rồi trích xuất phần text từ JSON streaming để lưu.
# 1) Chuẩn bị context nội bộ
VAR_META="PRODUCT_NAME: Nuoc thao moc 500 ml
PRICE_NET_VND: 15000
UNIT_STD: L
SCOPE: MT|Ha Noi
[source_id: sales_2025Q4.csv:L220-228]
Month,Store,Units,In_stock_days,Revenue_net
2025-10,Supreme Mart 01,310,29,4650000
2025-11,Supreme Mart 01,340,30,5100000
2025-12,Supreme Mart 01,270,24,4050000
[source_id: price_list_2025.csv:L12-18]
SKU,Pack_ml,ASP_per_L
Herbal Drink 500,500,30000
"
# 2) Gọi Ollama offline tại localhost
curl -s http://localhost:11434/api/generate \
-H "Content-Type: application/json" \
-d "{
\"model\": \"llama3\",
\"prompt\": \"SYSTEM:\\n$(printf '%s' "$(<./system_closed_world.txt)")\\n\\nCONTEXT:\\n$(printf '%s' \"$VAR_META\")\\n\\nTASK: Build the 12-month table and the source register as instructed in SYSTEM.\",
\"options\": {\"temperature\": 0.1, \"top_p\": 0.9}
}" | jq -r '.response' | tee ./out_offline.txt
# 3) Tách CSV và sổ nguồn từ file kết quả
awk '/^BEGIN:CSV/{flag=1;next}/^END:CSV/{flag=0}flag' ./out_offline.txt > ./market_12m.csv
awk '/^BEGIN:SOURCES/{flag=1;next}/^END:SOURCES/{flag=0}flag' ./out_offline.txt > ./sources_register.txt
- Với llama.cpp qua CLI. Ví dụ dưới đọc prompt từ file, xuất ra .txt rồi tách tương tự.
# Tạo file prompt_in.txt gồm SYSTEM, CONTEXT và TASK y như phần Ollama
./llama-cli -m ./models/llama3.gguf \
--temp 0.1 --top-p 0.9 \
-p "$(cat ./prompt_in.txt)" \
> ./out_offline.txt
awk '/^BEGIN:CSV/{f=1;next}/^END:CSV/{f=0}f' ./out_offline.txt > ./market_12m.csv
awk '/^BEGIN:SOURCES/{f=1;next}/^END:SOURCES/{f=0}f' ./out_offline.txt > ./sources_register.txt
Ví dụ output mẫu – điền sẵn 1 tháng để bạn đối chiếu định dạng
- Đây là ví dụ giả định. Mục đích là bạn kiểm nhanh schema, status, source_id và sổ nguồn. Khi chạy thật, model sẽ sinh đủ 12 tháng.
BEGIN:CSV
Month,Channel,Region,ND,WD,SPD_adj,Units_actual,Units_potential_OOS_adj,Revenue_net,ASP_per_L,Mix_pack,Seasonal_index,Forecast,OOS_rate,Promo_plan,Share_proxy_scope,Confidence,Status,Source_id,Assumption_note
2026-01,Modern Trade,Ha Noi,0.38,0.42,21.7,9200,10850,276000000,30000,"500ml:100%",0.95,10200,0.12,"Tet -10% price lift",NA,Medium,assumed,"sales_2025Q4.csv:L220-228;price_list_2025.csv:L12-18","Seasonality inferred from internal calendar, shrink=0.4"
END:CSV
BEGIN:SOURCES
- sales_2025Q4.csv|./data/sales_2025Q4.csv|L220-228|Sell-out by month, in_stock_days included
- price_list_2025.csv|./data/price_list_2025.csv|L12-18|Net ASP per L for 500 ml pack
END:SOURCES
Mẫu prompt thay biến để tái sử dụng nhanh
- Dùng khi bạn muốn chạy lại với file khác. Thay phần in hoa bằng giá trị của bạn.
SYSTEM:
[Paste the closed-world rules block here exactly as above]
CONTEXT:
PRODUCT_NAME: <TEN_SAN_PHAM>
PRICE_NET_<DON_VI_TIEN>: <GIA_NET>
UNIT_STD: <DON_VI_CHUAN_VD_L_HOAC_KG>
SCOPE: <KENH>|<VUNG>
[source_id: <TEN_FILE_1>:<PHAM_VI_DONG>]
<NOI_DUNG_FILE_1_DA_COPY>
[source_id: <TEN_FILE_2>:<PHAM_VI_DONG>]
<NOI_DUNG_FILE_2_DA_COPY>
TASK:
Build the 12-month table and the source register as instructed in SYSTEM.
Lưu ý vận hành quan trọng khi hoàn toàn offline
- Giới hạn bộ nhớ context: nếu công cụ báo đầy context, cắt nhỏ file và dán theo đợt, giữ kỷ luật source_id cho từng đợt.
- Không bật bất kỳ tính năng web search hay plugin RAG bên ngoài nếu công cụ của bạn có hỗ trợ. Mục tiêu là closed world từ chính CONTEXT bạn dán vào.
- Chỉ xuất hai khối BEGIN và END như yêu cầu. Mọi văn bản rơi ngoài hai khối sẽ làm sai bước tách file tự động.
- Nếu bạn dùng LM Studio, hãy đặt System prompt ở panel bên phải, hạ Temperature và tăng Top P ở phần Sampling theo mức mình đã gợi ý, rồi dán CONTEXT và TASK vào ô chat. Sau khi model trả về, copy khối CSV và sổ nguồn ra file đúng tên để lưu cùng dự án.
Kịch bản vận hành B LLM qua API nhưng không dùng web
Mình giả định bạn gọi LLM qua API trong môi trường server nội bộ hoặc VPC, có thể upload file làm ngữ cảnh dài hoặc cung cấp công cụ đọc CSV nội bộ, nhưng bị chặn hoàn toàn outbound web. Mục tiêu là cho model phân tích dựa trên dữ liệu bạn cấp, theo chế độ closed world, sinh ra bảng 12 tháng và sổ nguồn có thể audit.
Cách tổ chức kiến trúc tối thiểu
- Chặn web ở tầng hạ tầng: Security Group hoặc egress firewall chặn HTTP ra ngoài, chỉ mở outbound tới endpoint API LLM bạn dùng. Không đăng ký bất kỳ tool HTTP nào cho model.
- Hai cách nạp context dài an toàn:
- Upload file vào kho của nhà cung cấp hỗ trợ retrieval nội bộ, không gọi web bên ngoài. Ví dụ Assistants API có retrieval dựa trên file đã upload. Chỉ bật retrieval, tắt mọi plugin tìm kiếm.
- Dùng function calling để model gọi hàm read_csv của chính backend bạn. Hàm này đọc file từ storage nội bộ, lọc cột cần thiết, cắt phạm vi dòng theo yêu cầu để tiết kiệm token, rồi trả kết quả về tool message.
Sampling an toàn cho bài toán bảng số liệu
- temperature 0.0 đến 0.2
- top_p 0.8 đến 0.9
- frequencypenalty = 0, presencepenalty = 0
- max_tokens giới hạn theo dung lượng bạn cho phép ở mỗi lượt để kiểm soát chi phí và tránh output lạc đề dài.
Quản trị token, chi phí, log và audit
- Gắn runid và traceid cho mỗi yêu cầu. Lưu toàn bộ system prompt, tham số decode, danh sách source_id và sổ nguồn model trả ra.
- Ghi usage do API trả về: prompt tokens, completion tokens, total. Tính chi phí dựa trên bảng giá nội bộ của bạn. Đặt quota theo user hoặc theo dự án.
- Ẩn hoặc băm PII trong input trước khi log. Lưu sổ nguồn riêng để cấp cho người quyết định đọc cùng bảng 12 tháng.
- Kiểm soát kích cỡ context: chunk file theo chủ đề, chỉ đính kèm phần liên quan. Nếu dùng function calling, bắt buộc model nêu rõ file_id và range trước khi đọc để bạn có thể cắt token.
Ví dụ Python với function calling đọc CSV nội bộ và khóa closed world
- Ý chính: model chỉ được xem dữ liệu bạn trả qua tool read_csv. Không có tool HTTP. Bạn log usage và chi phí mỗi lần chạy.
import os, json, time, uuid, csv
from openai import OpenAI
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
SYSTEM = """You are a market analyst in closed-world mode.
Rules:
- Use ONLY data returned via tools. Do not invent numbers or names.
- If a field is missing, return "NA".
- Every numeric value must include source_id that matches one of the provided files.
- If a number is derived, set status="assumed" and add a short assumption.
Output two blocks only:
1) BEGIN:CSV ... END:CSV with 12-month market analysis table in CSV. Columns:
Month,Channel,Region,ND,WD,SPD_adj,Units_actual,Units_potential_OOS_adj,Revenue_net,ASP_per_L,Mix_pack,Seasonal_index,Forecast,OOS_rate,Promo_plan,Share_proxy_scope,Confidence,Status,Source_id,Assumption_note
2) BEGIN:SOURCES ... END:SOURCES listing lines that start with a hyphen, fields separated by a vertical bar:
id|file|range|note
Do not add any other text.
"""
# File registry của bạn: map id -> path thật trên storage nội bộ
FILE_REG = {
"sales_2025Q4": "./data/sales_2025Q4.csv",
"price_list_2025": "./data/price_list_2025.csv"
}
def handle_tool_call(tool_call):
fn = tool_call.function
if fn.name == "read_csv":
args = json.loads(fn.arguments or "{}")
file_id = args.get("file_id"); cols = args.get("columns") or []
start = int(args.get("start_row", 1)); end = int(args.get("end_row", start + 200))
path = FILE_REG.get(file_id)
if not path:
return {"error": f"unknown file_id {file_id}"}
rows_out = []
with open(path, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
all_cols = reader.fieldnames or []
use_cols = cols if cols else all_cols
for i, row in enumerate(reader, start=2): # header on row 1
if i < start or i > end:
continue
rows_out.append({c: row.get(c, "") for c in use_cols})
if len(rows_out) >= 500:
break
return {
"file_id": file_id,
"columns": use_cols,
"range": f"L{start}-L{min(end, start-1+len(rows_out))}",
"rows": rows_out
}
return {"error": "unsupported function"}
tools = [{
"type": "function",
"function": {
"name": "read_csv",
"description": "Read a CSV slice from an internal file by id to minimize tokens.",
"parameters": {
"type": "object",
"properties": {
"file_id": {"type": "string", "enum": list(FILE_REG.keys())},
"columns": {"type": "array", "items": {"type": "string"}},
"start_row": {"type": "integer", "minimum": 2},
"end_row": {"type": "integer", "minimum": 2}
},
"required": ["file_id"]
}
}
}]
run_id = str(uuid.uuid4())
messages = [
{"role": "system", "content": SYSTEM},
{"role": "user", "content": (
"TASK: Build the 12-month table and sources from our internal files.\n"
"CONTEXT_META:\n"
"PRODUCT_NAME: Nuoc thao moc 500 ml\n"
"PRICE_NET_VND: 15000\n"
"UNIT_STD: L\n"
"SCOPE: MT|Ha Noi\n"
"Available files and ids: sales_2025Q4 -> sales_2025Q4.csv, price_list_2025 -> price_list_2025.csv\n"
"First, call read_csv to load needed slices.")},
]
resp = client.chat.completions.create(
model="gpt-4o-mini", # chọn model bạn có quyền dùng
messages=messages,
tools=tools,
temperature=0.1,
top_p=0.9,
max_tokens=1200
)
tool_calls = resp.choices[0].message.tool_calls or []
tool_messages = []
for tc in tool_calls:
result = handle_tool_call(tc)
tool_messages.append({
"role": "tool",
"tool_call_id": tc.id,
"name": tc.function.name,
"content": json.dumps(result, ensure_ascii=False)
})
# Tiếp tục vòng thứ hai, đưa kết quả tool cho model
messages2 = messages + [resp.choices[0].message] + tool_messages
resp2 = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages2,
temperature=0.1,
top_p=0.9,
max_tokens=1800
)
text = resp2.choices[0].message.content or ""
usage1 = resp.usage.model_dump() if hasattr(resp, "usage") else {}
usage2 = resp2.usage.model_dump() if hasattr(resp2, "usage") else {}
# Log máy đọc cho audit
log_line = "|".join([
time.strftime("%Y-%m-%dT%H:%M:%S"),
run_id,
"gpt-4o-mini",
str(usage1.get("prompt_tokens", 0) + usage2.get("prompt_tokens", 0)),
str(usage1.get("completion_tokens", 0) + usage2.get("completion_tokens", 0)),
"OK"
])
with open("./logs/llm_runs.log", "a", encoding="utf-8") as lf:
lf.write(log_line + "\n")
# Lưu output để tách CSV và SOURCES như pipeline phần A
with open("./out_api.txt", "w", encoding="utf-8") as f:
f.write(text)
Gợi ý khi dùng upload file context dài của nhà cung cấp
- Nếu bạn dùng Assistants với retrieval file, chỉ upload file nội bộ, không bật bất kỳ tool web nào. Luôn yêu cầu model xuất sổ nguồn với id file và range. Với file lớn, phân tách theo chủ đề và upload nhiều file nhỏ để nhắm đúng truy vấn, giảm token.
Kịch bản vận hành C LLM với dữ liệu nội bộ CSV Google Sheet
Mình coi LLM là analyst chạy ở chế độ closed world, chỉ đọc dữ liệu bạn cấp qua CSV hoặc Google Sheet đã được làm sạch. Đầu ra là bảng 12 tháng và sổ nguồn có thể audit. Mấu chốt là chuẩn hóa schema, gắn source_id tới từng ô, khóa phạm vi đồng bộ 12 tháng và loại PII trước khi cấp quyền cho LLM.
Giả định truy cập an toàn
- CSV nội bộ: file nằm trong storage nội bộ hoặc Drive của công ty, thư mục chỉ chia sẻ cho nhóm phân tích dưới quyền xem. LLM chỉ thấy các file CSV đã duyệt.
- Google Sheet: dùng service account hoặc tài khoản kỹ thuật tổ chức. Chia sẻ sheet ở quyền Viewer cho đúng email service account. Tắt link sharing. Bật Domain restriction nếu có.
- Không cấp quyền edit cho LLM. Mọi tính toán nằm ở sheet phụ, LLM chỉ đọc sheet đã khử PII.
Chuẩn schema cột và source_id per cell
- Tổ chức workbook theo 3 lớp:
- raw_*: dữ liệu gốc như sales, inventory, promo, price, CRM.
- calc*: chỉ số tính ra như ND, WD, SPDadj, ASPperL, seasonalindex, shareproxy_scope.
- outmarket12m: bảng 12 tháng LLM sẽ đọc.
- Đề xuất cột trong outmarket12m: Month, Channel, Region, ND, WD, SPDadj, Unitsactual, UnitspotentialOOSadj, Revenuenet, ASPperL, ASPperunit, Mixpack, Seasonalindex, Forecast, OOSrate, Promoplan, Shareproxyscope, Confidence, Status, Sourceid, Assumptionnote.
- Đặt source_id theo ô gốc, dùng chuẩn A1 hoặc file row-col:
- Với Google Sheet: sourceid = <sheet>!<A1range>, ví dụ rawsales!E125. Trường hợp tổng hợp, cho phép dải như rawsales!E2:E125.
- Với CSV: sourceid = <file>#R<row>C<col>, ví dụ sales2025Q1.csv#R125C5.
- Tạo tự động sourceid trong calc* để không phải nhập tay:
- Tại mỗi ô calc tham chiếu đúng một ô raw, thêm một cột phụ _src với công thức:
=CONCAT("rawsales!", ADDRESS(ROW(rawsales!E2), COLUMN(rawsales!E2), 4)) và thay tham chiếu E2 bằng địa chỉ tham chiếu thực tế của bạn. Với tổng hợp, ghép range: =CONCAT("rawsales!", ADDRESS(ROW(E2), COLUMN(E2), 4), ":", ADDRESS(ROW(E125), COLUMN(E125), 4))
- Trong outmarket12m, cột Sourceid trỏ tới các src tương ứng hoặc là danh sách source_id phân cách dấu phẩy nếu chỉ số tổng hợp từ nhiều phạm vi.
- Chuẩn hóa đơn vị ở calc* trước khi đổ ra outmarket_12m:
- Thể tích về L, giá về đơn vị chuẩn theo L, pack size chuẩn hóa mã. ASPperunit và ASPperL rõ ràng để tránh ảo giác mix pack.
Đồng bộ phạm vi dữ liệu 12 tháng
- Chốt phạm vi bằng Named range window12m gồm 12 tháng gần nhất đã khóa sổ. Mọi QUERY hoặc FILTER trong calc* tham chiếu window_12m để đảm bảo nhất quán.
- Snapshot định kỳ:
- Google Apps Script time-driven trigger xuất outmarket12m thành CSV tên outmarket12m_YYYYMMDD.csv vào thư mục đã chỉ định. Dùng snapshot đó cho LLM để tái lập phân tích sau này.
- Với CSV thủ công, quy ước thư mục yyyymm và chỉ tải phiên bản mới nhất theo ngày build.
- Phiên bản hóa: thêm cột Buildid và Buildtime trong outmarket12m. LLM đọc và ghi lại vào sổ nguồn.
Bảo mật PII và quyền chia sẻ
- Phân loại cột PII ở raw* như tên khách, số điện thoại, địa chỉ email. Không đưa PII sang calc* và outmarket12m. Nếu cần liên kết thực thể, băm định danh bằng SHA-256 có muối trong Apps Script, giữ salt trong kho bí mật, không lưu trong sheet.
- Dùng Protected ranges cho cột raw* nhạy cảm. Lưu ý: Ẩn cột không phải biện pháp bảo mật. Chỉ chia sẻ outmarket_12m hoặc bản CSV snapshot đã khử PII cho service account LLM.
- Nhật ký truy cập: bật Version history của Sheet, lưu log export CSV kèm Build_id. Không ghi PII vào log.
Cách LLM đọc Google Sheet hoặc CSV một cách tối thiểu
- Cách 1 đọc Google Sheet bằng service account với Python và gspread. Chỉ đọc sheet outmarket12m_sanitized.
- Cách 2 dùng Apps Script Web App nội bộ để trả về JSON một range có whitelisting. Chỉ triển khai nếu hạ tầng cho phép, bắt buộc xác thực domain.
Ví dụ Python đọc Google Sheet đã khử PII và kết hợp với LLM Giải thích: đoạn này đọc một range an toàn, ánh xạ thành bảng và chuyển cho LLM ở chế độ closed world.
import json, os
import gspread
from google.oauth2.service_account import Credentials
from openai import OpenAI
# 1) Kết nối Google Sheet bằng service account
SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"]
creds = Credentials.from_service_account_file("svc_account.json", scopes=SCOPES)
gc = gspread.authorize(creds)
SHEET_ID = os.environ["SHEET_ID_OUT_12M"] # chỉ sheet đã khử PII
WS_NAME = "out_market_12m" # tab chỉ-đọc
sh = gc.open_by_key(SHEET_ID)
ws = sh.worksheet(WS_NAME)
# Đọc tiêu đề và 12 tháng gần nhất theo Build_id hiện hành
headers = ws.row_values(1)
rows = ws.get("A2:U1000") # cắt phạm vi đủ dùng để tiết kiệm token
table = [dict(zip(headers, r + [""]*(len(headers)-len(r)))) for r in rows if any(r)]
# 2) Gọi LLM ở chế độ closed world với dữ liệu table
SYSTEM = """You are a market analyst in closed-world mode.
Rules:
- Use ONLY the rows provided in TABLE below.
- Do not invent numbers or names. If a cell is empty, return NA.
- Every numeric value in your output must carry a source_id copied from the TABLE's Source_id field.
Output the 12-month table unchanged except fill computed fields if they are empty, and produce a SOURCE ledger.
Format:
BEGIN:CSV
<CSV with the same columns as input, 12 rows minimum>
END:CSV
BEGIN:SOURCES
- id|sheet|range|note
END:SOURCES
"""
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
user = "TABLE:\n" + json.dumps(table, ensure_ascii=False)
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": SYSTEM},
{"role": "user", "content": user}],
temperature=0.1, top_p=0.9, max_tokens=1500
)
print(resp.choices[0].message.content)
Ví dụ định dạng máy đọc cho sổ nguồn
- id|sheet|range|note
- 2025Q1SPD|rawsales|E2:E125|SPD derived from daily units-in-stock adjusted
- 2025Q1PRICE|rawprice|D2:D50|Net price after discounts
- 2025_SCOPE|meta|B2|Scope MT Ha Noi
Mẫu mini cho outmarket12m với source_id điền sẵn
- Month: 2025-01
- Channel: MT
- Region: Ha Noi
- ND: 0.45
- WD: 0.31
- SPD_adj: 12.4
- Units_actual: 18240
- UnitspotentialOOS_adj: 19600
- Revenue_net: 273600000
- ASPperL: 30000
- ASPperunit: 15000
- Mix_pack: 500ml:100%
- Seasonal_index: 0.95
- Forecast: 18500
- OOS_rate: 0.07
- Promo_plan: none
- Shareproxyscope: 0.12
- Confidence: medium
- Status: verified
- Sourceid: rawsales!E2:E125,raw_price!D2:D50
- Assumptionnote: OOS adjusted by instock_rate 0.93
Gợi ý triển khai nhanh với CSV
- Chuẩn bị outmarket12mYYYYMMDD.csv chứa đúng các cột ở trên và cột Sourceid đã ghép từ calc_*.
- Cấp cho LLM chỉ file CSV snapshot mới nhất. Lưu kèm file sources_YYYYMMDD.txt ở định dạng máy đọc để người quyết định đối chiếu khi duyệt báo cáo.
Bộ prompt chuẩn dùng ngay phiên bản chung và biến thể theo kịch bản
Mục tiêu của bộ prompt này là để bạn chạy AI ở chế độ closed world, không dùng web, lấy dữ liệu từ nội bộ và xuất đúng hai khối: bảng 12 tháng và sổ nguồn có thể audit. Các biến thể bên dưới bao phủ 3 kịch bản vận hành. Mình đưa kèm hướng dẫn chèn dữ liệu đầu vào và tham số decode an toàn để giảm bịa.
System prompt chuẩn closed world Giải thích ngắn: dán nguyên khối này vào vai trò system khi gọi model.
You are a Market Analysis Assistant operating in strict closed-world mode.
Objective:
- Produce a 12-month market analysis table from INTERNAL data only.
- Do not use any external knowledge or web search.
Rules:
1) Use ONLY the data present in the user's CONTEXT blocks: META, INPUTS, TABLES, ALLOWED_SOURCES. If a required value is missing, return NA.
2) No guessing. If you derive or impute a value from internal transformations, mark status=assumed and write a short assumption.
3) Every numeric value and every named entity in the CSV must carry a source_id from ALLOWED_SOURCES. If no valid source_id applies, return NA.
4) Verbatim extraction for named entities: output company, brand, SKU names exactly as they appear in TABLES. Do not synthesize new names.
5) Normalize units consistently: volumes in liters, prices as net price per liter and per unit. If units are inconsistent in input, write NA and note the issue in Assumption.
6) Do NOT change the column schema. Do NOT add prose outside the required blocks.
Output format:
- Exactly two blocks in this order.
BEGIN:CSV
<CSV with columns>
Month,Product,Channel,Region,ND,WD,SPD_adj,Units_actual,Units_potential_OOS_adj,Revenue_net,ASP_per_L,ASP_per_unit,Mix_pack,Seasonal_index,Forecast_units,Share_proxy_scope,OOS_rate,Promo_plan,Confidence,Status,Source_id,Assumption
<12 rows minimum, one per month>
END:CSV
BEGIN:SOURCES
- id|sheet|range|note
<each line is a source descriptor used in Source_id>
END:SOURCES
Validation before answering:
- Ensure every numeric cell in CSV has a non-empty Source_id taken from ALLOWED_SOURCES or is NA. If a row mixes multiple sources, join source_id tokens by comma.
- If deriving metrics like ND, WD, SPD_adj, or Seasonal_index, set Status=assumed for those cells and write a concise Assumption.
- Output only the two blocks. No extra commentary.
User prompt khung chuẩn – dùng ngay Giải thích: đây là prompt người dùng để đưa meta sản phẩm và dữ liệu nội bộ. Có một bản điền sẵn hoàn chỉnh bên dưới, rồi đến bản khuôn sườn thay biến.
Ví dụ hoàn chỉnh đã điền sẵn Ghi chú: ví dụ này minh họa cách chèn dữ liệu. Tên sản phẩm và số liệu là giả định phục vụ hướng dẫn.
META:
- scope_months: 2025-01 to 2025-12
- channels: MT
- regions: Ha Noi
- currency: VND
- volume_unit: L
- objective: Build a 12-month market analysis table without web search. If data is missing, return NA and mark assumed.
INPUTS:
- product_name: CoolHerb 500ml Herbal Drink
- base_packsize_ml: 500
- ingredients: herbal extract, sugar, water
- uses: refreshment
- origin: Vietnam
- price_policy_note: target ASP_per_L 32000 VND if not contradicted by internal data
TABLE:raw_sales.csv
Month,SKU,Channel,Region,Units,Revenue_net
2025-01,CoolHerb 500ml,MT,Ha Noi,18240,273600000
2025-02,CoolHerb 500ml,MT,Ha Noi,17680,265200000
2025-03,CoolHerb 500ml,MT,Ha Noi,18800,282000000
TABLE:raw_inventory.csv
Month,SKU,in_stock_rate
2025-01,CoolHerb 500ml,0.93
2025-02,CoolHerb 500ml,0.96
2025-03,CoolHerb 500ml,0.92
TABLE:raw_price.csv
Month,SKU,ASP_per_unit
2025-01,CoolHerb 500ml,15000
2025-02,CoolHerb 500ml,15000
2025-03,CoolHerb 500ml,15000
TABLE:raw_promo.csv
Month,SKU,Promo_flag
2025-01,CoolHerb 500ml,0
2025-02,CoolHerb 500ml,1
2025-03,CoolHerb 500ml,0
TABLE:raw_coverage.csv
Month,Channel,Region,ND_proxy,WD_proxy
2025-01,MT,Ha Noi,0.28,0.22
2025-02,MT,Ha Noi,0.30,0.24
2025-03,MT,Ha Noi,0.31,0.25
ALLOWED_SOURCES:
- 2025Q1_SALES|raw_sales.csv|R2C1:R4C6|Monthly sell-out by SKU
- 2025Q1_INV|raw_inventory.csv|R2C1:R4C3|Monthly in-stock rate
- 2025Q1_PRICE|raw_price.csv|R2C1:R4C3|Net price per unit
- 2025Q1_PROMO|raw_promo.csv|R2C1:R4C3|Promo flags
- 2025Q1_COV|raw_coverage.csv|R2C1:R4C5|ND and WD proxies
- 2025_SCOPE|meta|R1C1:R1C4|Scope definition
TASK:
- Normalize ASP_per_L from ASP_per_unit and packsize.
- Adjust Units for OOS: Units_potential_OOS_adj = Units / in_stock_rate with reasonable cap if needed.
- Estimate ND, WD for missing months by interpolation if and only if within the same scope; mark assumed.
- Compute SPD_adj = Units_potential_OOS_adj / active_points if active_points derivable; else return NA and explain in Assumption.
- Produce the 12-month table for 2025-01 to 2025-12. For months without data, project cautiously using internal signals only and mark assumed with a short note.
Khuôn sườn thay biến
META:
- scope_months: {{YYYY-MM to YYYY-MM}}
- channels: {{list of channels}}
- regions: {{list of regions}}
- currency: {{ISO or local}}
- volume_unit: L
- objective: Build a 12-month market analysis table without web search. If data is missing, return NA and mark assumed.
INPUTS:
- product_name: {{Product name}}
- base_packsize_ml: {{integer ml}}
- ingredients: {{optional string or NA}}
- uses: {{optional string or NA}}
- origin: {{optional string or NA}}
- price_policy_note: {{optional guardrail on ASP_per_L or NA}}
TABLE:{{file_or_block_name_1.csv}}
{{header}}
{{rows}}
TABLE:{{file_or_block_name_2.csv}}
{{header}}
{{rows}}
... add as many TABLE blocks as needed ...
ALLOWED_SOURCES:
- {{id_1}}|{{sheet_or_file}}|{{A1_or_RxCy_range}}|{{note}}
- {{id_2}}|{{sheet_or_file}}|{{A1_or_RxCy_range}}|{{note}}
TASK:
- {{bullet instructions specific to your scope, e.g., normalization, OOS adjustment, ND WD estimation, seasonality handling within internal data only}}
Biến thể theo kịch bản A – LLM local offline
- Cách dùng: bạn copy toàn bộ System prompt chuẩn vào phần system của UI local, rồi dán User prompt khung chuẩn lên, kèm các TABLE ở dạng CSV như ví dụ.
- Gợi ý decode an toàn khi chạy local bằng thư viện transformers:
- do_sample: true
- temperature: 0.1
- top_p: 0.9
- repetition_penalty: 1.1
- maxnewtokens: 2000
- Lưu ý: nếu model local hay lạc chủ đề, hạ temperature về 0.0 đến 0.2 và giữ nguyên schema CSV + SOURCES để ép tuân thủ. Không bật sampling beam search cho tác vụ này vì dễ sinh văn xuôi dư thừa.
Biến thể theo kịch bản B – LLM qua API nhưng không dùng web
- Cách dùng: truyền System prompt chuẩn ở role system, truyền User prompt khung chuẩn ở role user. Không nạp bất kỳ tool web-search nào. Nếu SDK có tool gọi file cục bộ, chỉ whitelisting các file snapshot CSV bạn cấp.
- Tham số decode an toàn tham khảo khi gọi OpenAI compatible API:
- temperature: 0.1
- top_p: 0.9
- frequency_penalty: 0.0
- presence_penalty: 0.0
- max_tokens: 2000
- Quản trị chi phí: cắt TABLE về đúng cột cần thiết, ghép ALLOWED_SOURCES ngắn gọn. Nếu cần nhiều lần chạy, cache kết quả SOURCES để đối chiếu.
Biến thể theo kịch bản C – LLM với dữ liệu nội bộ trên CSV hoặc Google Sheet
- Cách dùng: nếu bạn đã chuẩn hóa một sheet outmarket12m, hãy đưa chính sheet đó vào một TABLE duy nhất và yêu cầu LLM chỉ điền các cột còn trống, giữ nguyên phần đã có. Nếu bạn mới chỉ có các sheet raw_*, dán lần lượt từng TABLE như ở ví dụ.
- Gợi ý decode: giống kịch bản B. Với sheet, bổ sung danh sách ALLOWED_SOURCES dùng định dạng máy đọc theo A1, ví dụ:
- 2025Q1SALES|rawsales!A2:F1000|Sell-out monthly
- 2025Q1INV|rawinventory!A2:C1000|In-stock rate
- 2025_SCOPE|meta!A1:D1|Scope
Hướng dẫn chèn dữ liệu đầu vào cho đúng
- Mỗi TABLE chỉ một nguồn, định dạng CSV có header. Tránh trộn đơn vị. Ví dụ:
- rawsales.csv tối thiểu có Month, SKU, Channel, Region, Units, Revenuenet.
- rawinventory.csv có Month, SKU, instock_rate trong [0,1].
- rawprice.csv có Month, SKU, ASPperunit hoặc ASPperL. Nếu chỉ có ASPperunit, kèm basepacksizeml trong INPUTS để suy ra ASPper_L.
- rawcoverage.csv có Month, Channel, Region, NDproxy, WD_proxy nếu bạn đã tính từ CRM.
- ALLOWED_SOURCES phải liệt kê hết các nguồn bạn cho phép tham chiếu, đúng định dạng máy đọc:
- id|sheet|range|note
- Source_id trong kết quả CSV sẽ sử dụng các id này, nên đặt id ngắn gọn, duy nhất, có nghĩa.
- Nếu thiếu bảng nào, để trống TABLE đó và để NA trong dữ liệu. Model sẽ đánh dấu Status=assumed cho các trường phải suy luận từ nguồn còn lại.
Bộ tham số decode an toàn – tóm tắt nhanh
- Độ chính xác số liệu và bảng:
- temperature 0.0 đến 0.2
- top_p 0.7 đến 0.9
- repetition_penalty 1.1 đến 1.2 với model local
- maxnewtokens đủ để in 12 hàng CSV và SOURCES
- Diễn giải ngắn gọn trong Assumption vẫn chính xác:
- temperature 0.2 đến 0.3
- top_p 0.85 đến 0.9
- Không bật creativity bổ sung như nucleus quá cao hoặc temperature ≥ 0.7 trong tác vụ này.
Mẹo kiểm soát bịa trong thực tế
- Giữ cặp Status và Source_id là bắt buộc trong schema, buộc model tự soát trước khi in số.
- Ràng buộc tên đối thủ, tên SKU theo verbatim từ TABLES. Nếu không có, phải trả NA.
- Ép closed world rõ ràng: không được dùng kiến thức nền. Nếu phát hiện bất kỳ giá hoặc thị phần không có nguồn, model phải để NA và ghi giả định.
Cấu trúc suy luận khi thiếu dữ liệu giả định minh bạch phạm vi và sensitivity
Khi thiếu dữ liệu thị trường bên ngoài, bạn vẫn có thể ra quyết định nếu xây được cấu trúc suy luận chặt chẽ: tách rõ phần nào là nội suy từ dữ liệu nội bộ, phần nào là giả định, đặt phạm vi dải kết quả thay vì một con số duy nhất, và kiểm tra độ nhạy theo những biến chính như độ phủ kênh, giá, khuyến mãi và OOS. Mình hướng dẫn bộ quy tắc ghi nhãn assumed, cách tạo dải ba kịch bản, dùng heuristic ngưỡng WD và các kiểm định hội tụ theo thời gian, cộng thiết kế thí nghiệm nhỏ nhóm thử nhóm đối chứng. Cuối cùng là danh sách tình huống không nên ngoại suy.
Cách ghi giả định gắn nhãn assumed để truy vết
- Quy tắc sử dụng Status và Assumption
- Status=verified khi số được trích trực tiếp từ dữ liệu nội bộ hoặc phép tính cơ học từ các số đã verified và đơn vị chuẩn hóa rõ ràng.
- Status=assumed khi số là nội suy, ước lượng, mượn từ analog nội bộ, hoặc phụ thuộc vào phạm vi kịch bản.
- Assumption mô tả gọn cơ sở giả định, biến dùng để tính, cửa sổ thời gian và rủi ro lệch nếu có.
- Sourceid phải trỏ đến id trong ALLOWEDSOURCES. Nếu số là assumed từ phép biến đổi nội bộ, gắn đủ các id nguồn mà biến đầu vào đến từ, ngăn cách bằng dấu phẩy.
- Nhật ký giả định dạng máy đọc để audit
- Dùng ledger đơn giản, mỗi dòng là một giả định có thể map về ô trong bảng 12 tháng. Giữ đúng định dạng: dòng bắt đầu bằng dấu gạch ngắn, các trường ngăn bằng dấu gạch đứng.
- Trường khuyến nghị: id|scope|field|period|value|status|assumption|source_id.
Ví dụ ledger điền sẵn
- A01|MT Ha Noi|WD|2025-04|0.28|assumed|Nội suy tuyến tính WD từ 2025-01..03 trong cùng scope, chưa qua ngưỡng ổn định|2025Q1_COV
- A02|MT Ha Noi|SPD_adj|2025-04|NA|assumed|Không có active_points để chia SPD, treo NA và thay bằng Units_potential_OOS_adj trong suy luận|2025Q1_SALES,2025Q1_INV
- A03|MT Ha Noi|Promo_uplift|Scope 2025|1.10|assumed|Ước hệ số uplift từ so sánh nội bộ tháng có cờ promo vs không promo 2025-01..03 sau OOS-adjust|2025Q1_PROMO,2025Q1_SALES,2025Q1_INV
- A04|MT Ha Noi|OOS_rate|Scope 2025|0.07|assumed|Dùng median in_stock_rate 0.93 của 2025-01..03 để gán OOS_rate 7% cho Base case|2025Q1_INV
- A05|MT Ha Noi|Seasonal_index|2025-09|1.05|assumed|Mượn template nội bộ cùng danh mục, shrink λ=0.3 vì thiếu neo|2025_SCOPE
- Mẹo để trình bày với lãnh đạo
- Gom giả định theo nhóm driver: phủ kênh, giá, promo, OOS, mùa vụ, cung ứng.
- Mỗi giả định gắn mức Confidence High, Medium, Low dựa trên chất lượng nguồn và kiểm định ổn định nội bộ. Thể hiện một cột Confidence ngay trong bảng 12 tháng để người ra quyết định đọc nhanh.
Tạo khoảng tin cậy và ba kịch bản sensitivity
- Mục tiêu: thay vì một con số, xuất dải Low, Base, High cho từng tháng trong 12 tháng, phản ánh bất định theo các driver nội bộ.
- Chuẩn bị dữ liệu nền
- Làm sạch và chuẩn hóa:
- Quy đổi doanh số về Units mỗi ngày-in-stock và ASPperL để tránh nhiễu do OOS và pack size.
- Tính UnitspotentialOOSadj = Unitsactual / instockrate, ghi Status=assumed và nêu cách đặt ngưỡng nếu bạn giới hạn mức bù OOS.
- Tạo run-rate cơ sở L0:
- L0 là trung bình có trọng số theo số ngày in-stock của 2 đến 3 tháng gần nhất, chỉ tính các ngày không có siêu ngoại lệ nội bộ đã biết. Nếu có ramp sau launch, dùng xu hướng theo tuần đã fit cho tập cửa hàng cốt lõi để ước L0 ở thời điểm đầu kỳ dự báo.
- Xác định driver và phạm vi từng driver
- WD, ND: dùng proxy WD nội bộ. Với tháng tương lai, đặt dải WD theo kế hoạch bán hàng và khả năng mở điểm bán. Nếu chưa chốt kế hoạch, nội suy WD trong cùng scope, nhưng ghi rõ Status=assumed.
- Giá và promo: tạo chỉ số ASPperLindex so với hiện tại. Ước uplift promo bằng tỷ lệ UnitspotentialOOSadj ở tháng có cờ promo so với tháng không promo trong cùng scope và mức WD tương đương. Nếu không đủ điểm, để NA và ghi assumed kịch bản promo theo lịch nội bộ đã duyệt.
- OOS: đặt dải instockrate theo phân vị lịch sử của chính bạn. Ví dụ Base dùng median, Low dùng phân vị xấu hơn, High dùng phân vị tốt hơn. Gắn rõ các phân vị bạn chọn trong Assumption.
- Cấu thành ba kịch bản
- Low: WD ở biên dưới, ASPperL_index bất lợi, promo tối thiểu hoặc hiệu quả thấp, OOS cao hơn bình thường.
- Base: WD theo kế hoạch trung bình trong khung, ASPperL_index theo chính sách hiện có, promo theo lịch đã duyệt ở mức uplift quan sát được, OOS ở median.
- High: WD chạm mục tiêu khung và đã qua ngưỡng ổn định, ASPperL_index không giảm, promo đạt uplift quan sát tốt, OOS thấp.
- Công thức kết hợp
- Với từng tháng m:
- Demandbasem = L0 × Seasonalindexm nếu có template nội bộ. Nếu không có, để Seasonalindexm = 1 và ghi assumed.
- Apply coverage: nếu có SPD ổn định theo điểm, Demandcovm = SPDstable × Activepointsm. Nếu không có Activepoints, dùng Demandbasem × fcovm, trong đó fcovm là hệ số từ WD theo đường cong SPDvsWD của bạn. Nếu chưa ước được đường cong, không nhân fcovm và ghi Assumption rằng bạn đang giả sử vận tốc không phụ thuộc WD.
- Apply price and promo: Demandpricepromom = Demandcovm × gpricem × gpromom, trong đó gpricem và gpromo_m là hệ số nội bộ bạn ước từ dữ liệu có cờ. Nếu không có, để 1 và Status=assumed.
- Apply OOS về Unitsactual dự kiến: Unitsforecastm = Demandpricepromom × instockrate_m.
- Mỗi hệ số đều phải ghi rõ nguồn và Status, hoặc NA nếu bạn chưa có cơ sở nội bộ.
Sử dụng heuristic ngưỡng WD và hiệu chỉnh thiên lệch khi bao phủ thấp
- Định nghĩa và đo WD nội bộ
- WD là bao phủ trọng số dựa trên proxy tiềm năng điểm bán trong khung bạn tự định nghĩa. Proxy có thể là doanh số tổng quầy, doanh số SKU lân cận của bạn, số giao dịch, phân hạng banner, hoặc doanh thu tiềm năng từ CRM.
- Sắp xếp điểm bán theo trọng số wi, chia decile, tính WDk và SPDk là vận tốc cộng dồn đến decile k chia cho WDk.
- Tìm ngưỡng ổn định
- Theo dõi |SPDk − SPD{k−1}|/SPD_{k−1} và coi là ổn định khi rơi dưới 5 đến 10 phần trăm liên tiếp 2 đến 3 bậc. Cross check thêm ASP, tỷ lệ đơn có promo, OOS giữa k và k−1.
- Nếu chưa đủ điểm để chia decile, chuyển sang kiểm định hội tụ theo thời gian trên tập cửa hàng cốt lõi xuất hiện xuyên suốt.
- Hiệu chỉnh nhanh khi WD còn thấp
- Tính b là chênh lệch trung bình w_i giữa điểm đã phủ và toàn khung. b dương lớn báo hiệu thiên về cửa hàng mạnh, cảnh báo nguy cơ phóng đại khi nội suy. b âm lớn báo hiệu ngược lại.
- Nếu đã có SPD trong vùng gần ổn định, tính hệ số B = SPDtạimứcphủhiệntại chia cho SPDvùngổnđịnh để biết mức lệch vận tốc. Khi buộc phải ngoại suy quy mô tiềm năng, nhân ngược với B để giảm lệch và gắn Status=assumed.
Kiểm định hội tụ theo thời gian để thay thế khi thiếu WD đáng tin
- Chia dữ liệu thành 3 đến 4 giai đoạn rollout, cố định tập cửa hàng cốt lõi.
- Tính SPD, ASP, tỷ lệ promo, OOS theo từng giai đoạn trên cùng tập cốt lõi.
- Khi các chỉ số hội tụ và biến thiên rơi dưới 5 đến 10 phần trăm trong 2 đến 3 kỳ liên tiếp, bạn có thể coi vận tốc nền đã ổn định tạm thời và dùng làm neo cho kịch bản Base. Ghi rõ phạm vi tập cốt lõi và kỳ dùng làm neo trong Assumption.
Thí nghiệm nhỏ nhóm thử nhóm đối chứng để phát hiện điểm gãy
- Thiết kế
- Chọn một quận hoặc cụm cửa hàng đủ đồng nhất làm bệ thử.
- Ngẫu nhiên mở thêm 10 đến 15 cửa hàng hạng trung đến thấp trong nhóm thử, giữ nguyên mọi điều kiện khác.
- Duy trì nhóm đối chứng là khu vực tương tự nhưng không mở thêm.
- Đo lường và dừng
- So sánh thay đổi SPD bình quân per cửa hàng giữa nhóm thử và đối chứng theo tuần. Dùng kiểm định chênh lệch trung bình hoặc bootstrap đơn giản để xem hiệu ứng khác 0 một cách đáng kể.
- Lặp lại mở thêm theo lớp đến khi hiệu ứng biên tiến gần 0. Ghi nhận WD tại đó như mức bao phủ cần để vận tốc ổn định. Dùng kết quả này để chỉnh f_cov trong kịch bản High và Base.
Khi nào không nên ngoại suy
- Không có khung mục tiêu nội bộ nhất quán, không thể tính ND, WD trong một vũ trụ cố định.
- WD proxy dưới mức bạn quan sát SPD chưa ổn định theo decile và các chỉ số mix chưa hội tụ theo thời gian trên tập cốt lõi.
- Thiên lệch chọn kênh mạnh: b lớn và dương, hoặc chênh lệch địa lý rõ, hệ số biến thiên vận tốc giữa tỉnh quận cao và không giảm theo thời gian.
- OOS hoặc promo chiếm tỷ trọng ngày quá lớn trong chuỗi quan sát khiến run-rate cơ sở không đại diện.
- Pack size mix thay đổi mạnh giữa các kỳ, ASPperunit biến động do mix chứ không do giá, nhưng bạn chưa chuẩn hóa về ASPperL.
- Không có Active_points hoặc proxy để tính SPD, dẫn đến phép nhân kênh dựa trên giả định phẳng về vận tốc.
- Kế hoạch giá, promo, phân phối cho 1 đến 2 quý tới chưa chốt, rủi ro cung ứng lớn. Khi đó chỉ sử dụng dải kịch bản rộng, không đưa ra điểm ước lượng đơn.
Ví dụ minh họa ngắn về dải kịch bản cho một tháng
- Bối cảnh giả định: MT Hà Nội, L0 sau OOS adjust là 18.500 units, Seasonalindextháng 9 assumed 1.05, WD hiện tại 0.25, kế hoạch WD tăng dần về 0.35 vào tháng 9.
- Hệ số driver nội bộ ước được:
- fcovtháng 9 assumed 1.10 vì WD tăng nhưng chưa qua ngưỡng ổn định, dựa trên đường cong SPDvsWD nội bộ quý 1.
- gpricetháng 9 = 1.00 vì chính sách giá giữ nguyên, ASPperL_index = 1.00.
- gpromotháng 9 Base = 1.00 do không có promo đã duyệt, High = 1.08 nếu thêm 1 đợt mini promo nội bộ, Low = 1.00.
- instockrate Base = 0.93, High = 0.96, Low = 0.90 theo phân vị nội bộ quý 1.
- Tính nhanh
- Demandbase9 = 18.500 × 1.05 = 19.425 units.
- Demandcov9 = 19.425 × 1.10 = 21.368 units.
- Low: Units_9 = 21.368 × 1.00 × 0.90 ≈ 19.231. Status=assumed.
- Base: Units_9 = 21.368 × 1.00 × 0.93 ≈ 19.872. Status=assumed.
- High: Units_9 = 21.368 × 1.08 × 0.96 ≈ 22.140. Status=assumed.
- Ghi ledger
- S01|MT Ha Noi|Units_forecast|2025-09|19231|assumed|Low: WD 0.33, f_cov 1.10, no promo, in_stock_rate 0.90|2025Q1_SALES,2025Q1_INV,2025Q1_COV
- S02|MT Ha Noi|Units_forecast|2025-09|19872|assumed|Base: WD 0.35, f_cov 1.10, no promo, in_stock_rate 0.93|2025Q1_SALES,2025Q1_INV,2025Q1_COV
- S03|MT Ha Noi|Units_forecast|2025-09|22140|assumed|High: WD 0.35, f_cov 1.10, mini promo g_promo 1.08, in_stock_rate 0.96|2025Q1_SALES,2025Q1_INV,2025Q1_COV,2025Q1_PROMO
Cách đưa sensitivity vào bảng 12 tháng
- Thêm các cột phụ hoặc một bảng kèm theo thể hiện Low, Base, High cho các trường Forecastunits, Revenuenet_forecast nếu cần trình bày cho lãnh đạo. Nếu chỉ có một cột chính, chọn Base làm cột hiển thị và đưa Low, High vào Confidence và Assumption để người đọc biết biên độ.
Tóm lại, khi thiếu dữ liệu, chìa khóa không phải là cố tìm một đáp án duy nhất, mà là khóa chặt mọi phép suy luận vào phạm vi nội bộ có thể kiểm tra, đánh dấu assumed đúng chỗ, và cho thấy dải kết quả cùng cơ chế nhạy cảm theo WD, giá, promo và OOS. Đi kèm là các kiểm định hội tụ theo thời gian và thí nghiệm nhỏ để biến phần assumed ngày càng nhỏ theo thời gian. Khi các điều kiện không đạt, thẳng thắn dừng ngoại suy và để NA kèm kế hoạch thu thập bổ sung.
Mẫu bảng phân tích thị trường 12 tháng cột định nghĩa và kiểu dữ liệu
Bảng này là data dictionary kèm ví dụ để bạn dựng một bảng 12 tháng cho từng sản phẩm theo kênh và khu vực, hoạt động hoàn toàn bằng dữ liệu nội bộ. Mỗi dòng thường tương ứng với một tháng cho 1 sản phẩm x 1 kênh x 1 khu vực. Quy ước chuẩn hóa giúp bạn tránh lệch do pack size, OOS và bao phủ thấp.
Quy ước chung cho toàn bảng
- Phạm vi thời gian: theo tháng dương lịch, định dạng YYYY-MM.
- Đơn vị phần trăm: dùng tỷ lệ 0 đến 1 cho mọi chỉ số dạng tỷ lệ phần trăm. Nếu bạn muốn hiển thị %, nhân 100 khi trình bày.
- Tiền tệ: ghi rõ currency_code, ví dụ VND. Các cột giá trị tiền ở dạng net price sau chiết khấu, chưa bao gồm VAT nếu quy trình nội bộ đang hạch toán như vậy.
- Chuẩn hóa thể tích: các chỉ số giá nên có phiên bản trên 1 L để loại bỏ nhiễu mix pack.
- NA và assumed: khi thiếu dữ liệu, để NA, kèm cột Status và Assumption mô tả cách nội suy hay lý do thiếu.
Nhóm khóa định danh và phạm vi
- period
- Ý nghĩa: tháng của dòng dữ liệu.
- Đơn vị: YYYY-MM.
- Kiểu: string cố định 7 ký tự.
- Ví dụ: 2025-01.
- product_name
- Ý nghĩa: tên sản phẩm hoặc nhãn SKU cấp báo cáo.
- Đơn vị: text.
- Kiểu: string.
- Ví dụ: Nước giải khát A 500 ml.
- sku_code
- Ý nghĩa: mã SKU nội bộ duy nhất.
- Đơn vị: text.
- Kiểu: string.
- Ví dụ: SKU_A500.
- packsizeL
- Ý nghĩa: thể tích mỗi đơn vị, để chuẩn hóa.
- Đơn vị: lít.
- Kiểu: float.
- Ví dụ: 0.5.
- channel
- Ý nghĩa: kênh bán hàng.
- Đơn vị: enum.
- Kiểu: string trong danh sách cho phép.
- Ví dụ: MT. Hợp lệ: MT, GT, Pharmacy, D2C, Marketplace, B2B.
- region
- Ý nghĩa: khu vực hoặc tỉnh thành theo chuẩn nội bộ.
- Đơn vị: text.
- Kiểu: string.
- Ví dụ: Ha Noi.
- scope_id
- Ý nghĩa: mã khung mục tiêu định nghĩa bao phủ cho dòng này.
- Đơn vị: text.
- Kiểu: string.
- Ví dụ: MTHNSCOPE_2025.
Nhóm bao phủ và điểm bán
- ND
- Ý nghĩa: bao phủ số điểm bán đạt hàng chia cho tổng điểm bán mục tiêu trong scope.
- Đơn vị: tỷ lệ 0 đến 1.
- Kiểu: float.
- Ví dụ: 0.32.
- WD
- Ý nghĩa: bao phủ trọng số theo tiềm năng điểm bán trong scope.
- Đơn vị: tỷ lệ 0 đến 1.
- Kiểu: float.
- Ví dụ: 0.28.
- active_points
- Ý nghĩa: số điểm bán có hàng và phát sinh bán trong tháng.
- Đơn vị: điểm bán.
- Kiểu: integer.
- Ví dụ: 185.
- totalpointsin_scope
- Ý nghĩa: tổng điểm bán mục tiêu trong scope kỳ này.
- Đơn vị: điểm bán.
- Kiểu: integer.
- Ví dụ: 580.
Nhóm vận tốc và cầu
- SPDunitsperactivepointperweek
- Ý nghĩa: vận tốc bán theo đơn vị trên mỗi điểm bán hoạt động mỗi tuần.
- Đơn vị: units per point per week.
- Kiểu: float.
- Ví dụ: 14.2.
- weeksinperiod
- Ý nghĩa: số tuần quy đổi trong tháng để nhân SPD về tháng.
- Đơn vị: tuần.
- Kiểu: float.
- Ví dụ: 4.3.
- demandpotentialOOS_adj
- Ý nghĩa: cầu tiềm năng đã điều chỉnh thiếu hàng trên tập điểm hiện có.
- Đơn vị: units.
- Kiểu: float.
- Ví dụ: 21500.0.
- units_actual
- Ý nghĩa: sản lượng thực bán ra trong tháng.
- Đơn vị: units.
- Kiểu: integer.
- Ví dụ: 19870.
- volume_L
- Ý nghĩa: thể tích bán ra đã quy về lít.
- Đơn vị: lít.
- Kiểu: float.
- Ví dụ: 9935.0.
Nhóm tồn kho và thiếu hàng
- instockrate
- Ý nghĩa: tỷ lệ ngày có hàng trong tháng ở các điểm hoạt động.
- Đơn vị: tỷ lệ 0 đến 1.
- Kiểu: float.
- Ví dụ: 0.93.
- OOS_rate
- Ý nghĩa: tỷ lệ thiếu hàng 1 trừ instockrate.
- Đơn vị: tỷ lệ 0 đến 1.
- Kiểu: float.
- Ví dụ: 0.07.
Nhóm giá và doanh thu
- currency_code
- Ý nghĩa: mã tiền tệ chuẩn cho các cột giá trị tiền.
- Đơn vị: ISO 4217.
- Kiểu: string.
- Ví dụ: VND.
- revenue_net
- Ý nghĩa: doanh thu thuần sau chiết khấu trong kỳ.
- Đơn vị: VND.
- Kiểu: number.
- Ví dụ: 298050000.
- ASPperunit
- Ý nghĩa: giá bán bình quân trên một đơn vị.
- Đơn vị: VND per unit.
- Kiểu: number.
- Ví dụ: 15000.
- ASPperL
- Ý nghĩa: giá bán bình quân trên 1 lít đã chuẩn hóa thể tích.
- Đơn vị: VND per L.
- Kiểu: number.
- Ví dụ: 30000.
- priceindexvs_base
- Ý nghĩa: chỉ số giá so với kỳ gốc nội bộ bằng 1 ở gốc.
- Đơn vị: index.
- Kiểu: float.
- Ví dụ: 1.02.
Nhóm khuyến mãi
- promo_flag
- Ý nghĩa: có hoạt động khuyến mãi trong tháng không.
- Đơn vị: boolean.
- Kiểu: true hoặc false.
- Ví dụ: true.
- promo_uplift
- Ý nghĩa: hệ số nâng sản lượng do khuyến mãi so với không khuyến mãi, 1 là không đổi.
- Đơn vị: hệ số.
- Kiểu: float.
- Ví dụ: 1.08.
- promodepthpct
- Ý nghĩa: mức giảm giá trung bình quy đổi, nếu theo dõi nội bộ.
- Đơn vị: tỷ lệ 0 đến 1.
- Kiểu: float.
- Ví dụ: 0.12.
Nhóm mix pack và tiêu chuẩn hóa
- avgunitvolume_L
- Ý nghĩa: thể tích trung bình mỗi đơn vị bán trong tháng.
- Đơn vị: lít.
- Kiểu: float.
- Ví dụ: 0.50.
- mixpacksmall_pct
- Ý nghĩa: tỷ trọng units pack nhỏ trong tháng theo định nghĩa nội bộ.
- Đơn vị: tỷ lệ 0 đến 1.
- Kiểu: float.
- Ví dụ: 0.35.
- mixpackmedium_pct
- Ý nghĩa: tỷ trọng units pack trung bình.
- Đơn vị: tỷ lệ 0 đến 1.
- Kiểu: float.
- Ví dụ: 0.45.
- mixpacklarge_pct
- Ý nghĩa: tỷ trọng units pack lớn.
- Đơn vị: tỷ lệ 0 đến 1.
- Kiểu: float.
- Ví dụ: 0.20.
Nhóm mùa vụ và kịch bản
- seasonal_index
- Ý nghĩa: chỉ số mùa vụ đã chuẩn hóa trung bình năm bằng 1.
- Đơn vị: index.
- Kiểu: float.
- Ví dụ: 1.05.
- scenario
- Ý nghĩa: nhãn kịch bản nếu bạn chạy sensitivity theo Low, Base, High.
- Đơn vị: enum.
- Kiểu: string.
- Ví dụ: Base.
Nhóm meta dữ liệu nguồn và giả định
- Status
- Ý nghĩa: trạng thái nguồn gốc số liệu ở cấp dòng hoặc cho trường chính của dòng.
- Đơn vị: enum.
- Kiểu: string với giá trị verified hoặc assumed.
- Ví dụ: assumed.
- Assumption
- Ý nghĩa: mô tả ngắn gọn giả định chính áp cho dòng.
- Đơn vị: text.
- Kiểu: string.
- Ví dụ: OOS adjust theo instockrate median Q1 và seasonal_index mượn template nội bộ.
- source_id
- Ý nghĩa: mã nguồn nội bộ hoặc sheet cell id dùng để truy vết.
- Đơn vị: text.
- Kiểu: string, cho phép nhiều id phân tách dấu phẩy.
- Ví dụ: 2025Q1SALES,2025Q1INV.
- confidence
- Ý nghĩa: mức tin cậy vận hành cho dòng dữ liệu.
- Đơn vị: enum.
- Kiểu: string với giá trị High, Medium, Low.
- Ví dụ: Medium.
- notes
- Ý nghĩa: ghi chú bối cảnh, sự kiện nội bộ trong tháng.
- Đơn vị: text.
- Kiểu: string.
- Ví dụ: Thiếu hàng 3 ngày tuần 2, không chạy trưng bày.
- action
- Ý nghĩa: hành động khuyến nghị gắn với dòng này để đưa vào kế hoạch.
- Đơn vị: text ngắn.
- Kiểu: string.
- Ví dụ: Ưu tiên mở thêm 40 điểm hạng B, kiểm soát OOS < 5%.
Mối liên hệ và quy tắc tính cơ bản trong bảng
- revenuenet = ASPperunit × unitsactual nếu ASPperunit đã tính trên cùng phạm vi và đơn vị chuẩn hóa đúng.
- ASPperL = revenuenet ÷ volumeL. Kiểm tra chéo để phát hiện mix pack gây ảo giác giá.
- demandpotentialOOSadj xấp xỉ = unitsactual ÷ instockrate, có thể giới hạn trần để tránh nổ số khi instockrate thấp.
- unitsactual có thể được ước từ SPDunitsperactivepointperweek × activepoints × weeksinperiod nếu thiếu dữ liệu sell-out chi tiết, nhưng phải gắn Status là assumed.
CSV mẫu 1 dòng điền sẵn để bạn kiểm đối chiếu cấu trúc Lưu ý đây là ví dụ minh họa, không phải số liệu thị trường thực tế.
period,product_name,sku_code,pack_size_L,channel,region,scope_id,ND,WD,active_points,total_points_in_scope,SPD_units_per_active_point_per_week,weeks_in_period,demand_potential_OOS_adj,units_actual,volume_L,in_stock_rate,OOS_rate,currency_code,revenue_net,ASP_per_unit,ASP_per_L,price_index_vs_base,promo_flag,promo_uplift,promo_depth_pct,avg_unit_volume_L,mix_pack_small_pct,mix_pack_medium_pct,mix_pack_large_pct,seasonal_index,scenario,Status,Assumption,source_id,confidence,notes,action
2025-01,Nước giải khát A 500 ml,SKU_A500,0.5,MT,Ha Noi,MT_HN_SCOPE_2025,0.32,0.28,185,580,14.2,4.3,21500,19870,9935,0.93,0.07,VND,298050000,15000,30000,1.02,true,1.08,0.12,0.50,0.35,0.45,0.20,1.05,Base,assumed,"OOS adjust theo in_stock_rate median Q1, seasonal_index mượn template nội bộ",2025Q1_SALES,Medium,"Thiếu hàng 3 ngày tuần 2","Ưu tiên mở thêm 40 điểm hạng B, kiểm soát OOS < 5%"
Gợi ý tối thiểu các cột bắt buộc nếu bạn muốn phiên bản gọn hơn
- period, productname, skucode, channel, region
- ND, WD, active_points
- unitsactual, revenuenet, ASPperL, ASPperunit
- instockrate, demandpotentialOOS_adj
- seasonal_index, scenario
- Status, Assumption, source_id, confidence, notes, action
Với bộ cột trên và quy ước đơn vị nhất quán, bạn có thể tạo bảng 12 tháng cho mọi sản phẩm mà không cần dữ liệu web, đồng thời giữ được khả năng truy vết giả định và nguồn nội bộ.
Hướng dẫn điền bảng bằng dữ liệu nội bộ thủ công và bằng AI
Bạn có đủ cấu trúc cột rồi, việc tiếp theo là đổ dữ liệu vào từng cột theo một quy trình kỷ luật. Mình đưa hai lối đi song song: làm thủ công bằng CRM, POS, tồn kho và lịch sử khuyến mãi; và tự động bằng LLM theo chế độ closed world để điền thiếu bằng NA thay vì đoán.
Quy trình thủ công từng bước
- Chuẩn bị 5 nguồn lõi và khóa nối
- Master sản phẩm: skucode, productname, packsizeL, kênh, vùng.
- Bán ra POS hoặc sell-out D2C: storeid, skucode, date, units, revenue_net.
- Lịch sử tồn kho hoặc in-stock theo ngày: storeid, skucode, date, instockflag.
- CRM bán hàng hoặc danh sách điểm bán: storeid, channel, region, scopeid, weightproxy wi, totalpointsin_scope.
- Lịch khuyến mãi nội bộ: date range, channel, region, skucode, promodepth.
Khóa nối tối thiểu: storeid, skucode, date; hoặc sku_code, channel, region, period với dữ liệu đã tổng hợp theo tháng.
- Tổng hợp theo tháng và phạm vi
- Chuẩn hóa period về dạng YYYY-MM.
- Tạo skeleton 12 tháng cho từng cặp product x channel x region x scope_id đã hoạt động trong năm gốc của bạn để tránh bỏ sót tháng không bán.
- Điền nhóm đơn vị bán và doanh thu
- units_actual: tổng units theo tháng trên đúng phạm vi channel x region x product.
- revenue_net: tổng doanh thu thuần tương ứng.
- volume_L:
- Nếu dòng báo cáo là 1 pack size: volumeL = unitsactual * packsizeL.
- Nếu dòng báo cáo gộp nhiều pack: volumeL = tổng(unitsi * packsizeL_i) sau khi group by.
- avgunitvolumeL: volumeL / units_actual.
- ASPperunit = IFERROR(revenuenet / unitsactual, NA).
- ASPperL = IFERROR(revenuenet / volumeL, NA).
- priceindexvsbase: ASPperL của kỳ này chia cho ASPper_L của kỳ gốc nội bộ bằng 1.
- Điền nhóm tồn kho và OOS
- instockrate: trung bình theo điểm bán của tỷ lệ ngày có hàng trong tháng.
- Cách tính thực dụng khi có daily flag: instockrate = tổng ngày có hàng trên tất cả điểm bán đang hoạt động trong tháng chia cho tổng ngày có thể bán của các điểm đó.
- OOSrate = 1 − instock_rate.
- demandpotentialOOS_adj:
- Nếu instockrate đủ tin cậy, có thể xấp xỉ unitsactual / instock_rate.
- Khi instockrate thấp, để NA và ghi rõ Assumption. Tránh nội suy quá tay khi dữ liệu thiếu hàng nặng.
- Điền bao phủ và điểm bán
- active_points: số điểm phát sinh bán hoặc có hàng trong tháng.
- totalpointsinscope: lấy từ CRM cho scopeid tương ứng của tháng đó. Nếu không đổi theo tháng, tham chiếu bản mới nhất.
- ND = activepoints / totalpointsinscope.
- WD: dùng wi từ CRM hoặc proxy nội bộ, tính WD = tổng wi của điểm bán có hàng trong tháng chia cho tổng wi của toàn bộ điểm trong scope. Lưu ý chỉ tính trong cùng scopeid.
- Điền vận tốc và tuần quy đổi
- weeksinperiod: số ngày trong tháng chia 7, làm tròn 1 chữ số.
- SPDunitsperactivepointperweek = IFERROR(unitsactual / activepoints / weeksinperiod, NA).
- Điền khuyến mãi
- promo_flag: true nếu có hoạt động khuyến mãi nội bộ theo lịch hoặc tag giao dịch trong tháng.
- promodepthpct: trung bình có trọng số theo doanh số hoặc theo ngày nếu quản lý ở cấp tuần.
- promo_uplift: nếu có tuần có và không có khuyến mãi trong tháng, dùng tỷ lệ sản lượng trung bình tuần có promo so với không promo. Nếu không có điều kiện so sánh, để NA.
- Điền mix pack và mùa vụ
- mixpacksmall_pct, medium, large: tính trên units theo định nghĩa nội bộ, đảm bảo tổng bằng 1. Với dòng 1 pack size, điền small 0, medium 1 hoặc large 1 theo mapping nội bộ, hai cột còn lại 0.
- seasonal_index: nếu có template nội bộ hợp lệ, điền chỉ số của tháng. Nếu chưa có, để NA.
- Điền meta dữ liệu nguồn và giả định
- Status: verified nếu tính trực tiếp từ nguồn nội bộ kèm source_id; assumed khi dùng nội suy hay ước lượng.
- Assumption: mô tả ngắn ngọn, ví dụ OOS adjust theo instockrate, promo_uplift lấy từ so sánh tuần.
- source_id: mã file hoặc sheet range, cho phép nhiều id phân tách dấu phẩy.
- confidence: High khi đủ nguồn và kiểm tra chéo hợp lý, Medium khi có phần assumed, Low khi nhiều NA.
Công thức Excel hoặc Google Sheets nhanh
- weeksinperiod nếu period ở ô A2 dạng text 2025-01:
=ROUND(DAY(EOMONTH(DATEVALUE(A2&"-01"),0))/7,1)
- ND:
=IFERROR(activepoints/totalpointsinscope, NA())
- SPD:
=IFERROR(unitsactual/activepoints/weeksinperiod, NA())
- ASPperunit, ASPperL:
=IFERROR(revenuenet/unitsactual, NA()), =IFERROR(revenuenet/volumeL, NA())
- demandpotentialOOS_adj an toàn:
=IF(instockrate>=0.85, unitsactual/instock_rate, NA())
Ví dụ điền sẵn 1 dòng có số để đối chiếu công thức Lưu ý đây là ví dụ minh họa độc lập.
- period: 2025-01
- product_name: Nước giải khát A 500 ml
- skucode: SKUA500
- packsizeL: 0.5
- channel: MT
- region: Ha Noi
- scopeid: MTHNSCOPE2025
- active_points: 185
- totalpointsin_scope: 580
- units_actual: 11290
- revenue_net: 169350000
- instockrate: 0.93
- weeksinperiod: 4.3
- Tính ra:
- ND = 185/580 = 0.32
- volume_L = 11290*0.5 = 5645.0
- ASPperunit = 169350000/11290 = 15000
- ASPperL = 169350000/5645 = 30000
- SPD = 11290/(185*4.3) = 14.2
- demandpotentialOOS_adj = 11290/0.93 = 12140.86
Điền tự động bằng LLM theo chế độ closed world
- Khi dùng LLM, mục tiêu là đọc CSV bạn dán vào, tính đúng các cột suy dẫn theo công thức cố định, và điền thiếu bằng NA nếu đầu vào không đủ. Không cho phép suy đoán đối thủ, giá thị trường hay bù thông tin ngoài context.
Prompt system mẫu Tiếng Việt tóm ý: khóa chế độ closed world, nếu thiếu thì điền NA, đánh dấu Status và Assumption theo quy tắc.
You are a data analyst working in closed-world mode. Only use fields present in the CSV I provide. Do not infer from outside knowledge. For any field that cannot be computed exactly from the available columns or rules, output NA. For any derived field marked NA because inputs are missing, set Status=assumed and add a short Assumption. Keep numeric precision reasonable. Return CSV with the same header order as input if I send a header, or with the full schema I provide.
Prompt user mẫu cho CSV đã có một số cột đầu vào Tiếng Việt tóm ý: cung cấp schema, dán CSV, yêu cầu điền và giữ NA khi thiếu.
Task: Fill the 12-month market analysis table from internal data only. Do not invent values.
Schema columns to output in this order:
period,product_name,sku_code,pack_size_L,channel,region,scope_id,ND,WD,active_points,total_points_in_scope,SPD_units_per_active_point_per_week,weeks_in_period,demand_potential_OOS_adj,units_actual,volume_L,in_stock_rate,OOS_rate,currency_code,revenue_net,ASP_per_unit,ASP_per_L,price_index_vs_base,promo_flag,promo_uplift,promo_depth_pct,avg_unit_volume_L,mix_pack_small_pct,mix_pack_medium_pct,mix_pack_large_pct,seasonal_index,scenario,Status,Assumption,source_id,confidence,notes,action
Rules to compute:
- ND = active_points/total_points_in_scope if both exist, else NA.
- volume_L = units_actual*pack_size_L if single pack per row, else NA.
- weeks_in_period = days_in_month/7 rounded to 1 decimal for the given period.
- SPD = units_actual/active_points/weeks_in_period if inputs exist, else NA.
- OOS_rate = 1 - in_stock_rate if in_stock_rate exists.
- ASP_per_unit = revenue_net/units_actual if both exist.
- ASP_per_L = revenue_net/volume_L if both exist.
- demand_potential_OOS_adj = units_actual/in_stock_rate if in_stock_rate>=0.85, else NA.
- If any input for a formula is missing, leave the derived field as NA.
- promo_* and seasonal_index: if no promo calendar fields provided, set NA and Status=assumed.
- WD: if weight data is not present in the input, set NA.
Set:
- Status=verified only if the field is directly present in the input or exactly computed from present inputs, otherwise assumed.
- Assumption: short Vietnamese note for any assumed field or NA reason.
- Keep source_id unchanged from input if present, otherwise leave empty.
Input CSV:
period,product_name,sku_code,pack_size_L,channel,region,scope_id,active_points,total_points_in_scope,units_actual,in_stock_rate,currency_code,revenue_net,price_index_vs_base,source_id
2025-01,Nước giải khát A 500 ml,SKU_A500,0.5,MT,Ha Noi,MT_HN_SCOPE_2025,185,580,11290,0.93,VND,169350000,1.00,2025Q1_SALES,2025Q1_INV
Kết quả mong đợi LLM trả về
- LLM sẽ tính ND, SPD, volume_L, ASP và để NA cho WD, promo nếu bạn chưa cấp dữ liệu đó. Ví dụ:
period,product_name,sku_code,pack_size_L,channel,region,scope_id,ND,WD,active_points,total_points_in_scope,SPD_units_per_active_point_per_week,weeks_in_period,demand_potential_OOS_adj,units_actual,volume_L,in_stock_rate,OOS_rate,currency_code,revenue_net,ASP_per_unit,ASP_per_L,price_index_vs_base,promo_flag,promo_uplift,promo_depth_pct,avg_unit_volume_L,mix_pack_small_pct,mix_pack_medium_pct,mix_pack_large_pct,seasonal_index,scenario,Status,Assumption,source_id,confidence,notes,action
2025-01,Nước giải khát A 500 ml,SKU_A500,0.5,MT,Ha Noi,MT_HN_SCOPE_2025,0.32,NA,185,580,14.2,4.3,12140.86,11290,5645.0,0.93,0.07,VND,169350000,15000,30000,1.00,NA,NA,NA,0.50,0,1,0,NA,Base,assumed,"WD không có trọng số; promo không có lịch; demand_potential tính khi in_stock_rate đủ cao",2025Q1_SALES,2025Q1_INV,Medium,,
Gợi ý vận hành an toàn khi dùng LLM
- Dán CSV hoặc trích xuất vùng Sheet ra CSV rồi dán. Không yêu cầu LLM truy cập web hay gọi API khác.
- Đặt nhiệt độ thấp 0.0 đến 0.2 và yêu cầu closed world. Bất kỳ trường nào không thể suy ra trực tiếp từ CSV phải là NA.
- Giữ lại log input và output CSV theo period để audit nội bộ. Kiểm tra chéo 3 công thức cốt lõi trước khi chấp nhận: ASPperL, SPD và ND.
- Ưu tiên để LLM điền các cột meta và văn bản ngắn như Assumption, notes, action dựa trên nguồn nội bộ đi kèm. Tính toán số học có thể để Sheets hoặc Python thực hiện rồi cho LLM kiểm định hình thức và trạng thái Status.
Với hai lối đi trên, bạn có thể dựng bảng 12 tháng đúng cấu trúc, lấp được dữ liệu từ CRM, POS, tồn kho và lịch sử nội bộ, đồng thời dùng AI để tăng tốc mà không đánh đổi tính kỷ luật nguồn hay chấp nhận suy đoán.
Tiêu chí chọn phương pháp dự báo 12 tháng và áp dụng
Quyết định đúng giữa nội suy đơn giản, seasonal index tối giản và kịch bản phạm vi là cách nhanh nhất để giữ dự báo thực tế khi dữ liệu ít. Mình dùng một khung chẩn đoán theo số đo định lượng, có bước xử lý ramp sau launch và quy tắc co biên độ mùa khi thiếu neo. Bạn có thể thực hiện ngay trên số tuần và tháng đã chuẩn hóa theo instockrate và quy đổi về mỗi tuần.
Khung chọn phương pháp theo chỉ số định lượng
- Bước 1 – làm sạch nền tảng
- Điều chỉnh OOS: tính cầu tiềm năng tháng bằng unitsactual/instockrate nếu instock_rate ≥ 0.85. Tháng nào thấp hơn, đánh dấu không tin cậy và loại khỏi ước lượng nền.
- Loại hoặc gắn cờ promo: nếu tháng có promo sâu, giữ lại nhưng đánh dấu để kiểm tra độ nhạy riêng.
- Chuẩn hóa về tuần: dùng SPDadj = demandpotentialOOSadj / activepoints / weeksin_period.
- Bước 2 – tính 4 chỉ số ra quyết định
- CV giữa-tháng của demandpotentialOOS_adj trên 2-3 tháng quan sát.
- CV giữa-tuần trung vị trong từng tháng quan sát.
- |slope per month|/mean của chuỗi tuần đã OOS-adjust trong 6-10 tuần gần nhất.
- Tỷ lệ ngày ngoại lệ trong tháng quan sát gồm promo và OOS nặng.
- Bước 3 – kiểm neo mùa và ràng buộc vận hành
- Có template chỉ số mùa nội bộ hợp lệ cho cùng kênh và phân khúc hay không.
- Có bao nhiêu tháng neo rõ ràng khớp template theo pha cao hoặc thấp.
- Có ramp phân phối rõ ràng sắp tới hay đang diễn ra.
Quy tắc chọn phương pháp
- Chọn nội suy đơn giản khi hội đủ
- CV giữa-tháng ≤ 0.15.
- CV giữa-tuần trung vị ≤ 0.20.
- |slope per month|/mean ≤ 0.08 sau khi đã OOS-adjust.
- Tỷ lệ ngày ngoại lệ trong các tháng quan sát ≤ 10%.
- Ramp phân phối nhẹ hoặc chậm hơn 5% theo active_points mỗi tháng.
- Cách áp dụng: lấy SPDadj trung bình làm run-rate, nhân với activepoints và weeksinperiod dự kiến để ra cầu tiềm năng, rồi nhân ngược với instockrate mục tiêu để ra bán quan sát.
- Chọn seasonal index tối giản khi hội đủ
- Có template chỉ số mùa nội bộ đã kiểm chứng ở cùng kênh – phân khúc, amplitude dự kiến ≥ 0.2.
- Có ≥ 1 tháng neo khớp template theo pha cao hoặc thấp, và CV giữa-tuần của tháng neo ≤ 0.25.
- Không có thay đổi cấu trúc lớn trong 1 quý tới.
- Cách áp dụng: ước L từ neo bằng L = yiadj/si* với yiadj là cầu tiềm năng tháng i đã OOS-adjust, si là chỉ số mùa template tháng i. Dự báo F_m_potential = L × [(1 − λ) + λ × s_m], chọn λ theo quy tắc shrink ở phần dưới. Bán quan sát = Fmpotential × instockrate mục tiêu.
- Chọn kịch bản phạm vi khi rơi vào ít nhất một tình huống
- CV giữa-tháng > 0.35 hoặc tỷ lệ ngày ngoại lệ > 20% trong các tháng quan sát.
- Đang ramp mạnh hoặc có thay đổi cấu trúc chắc chắn trong ≤ 1 quý như mở kênh lớn, đổi giá sâu, đổi mix pack.
- Không có template mùa hợp lệ hoặc tháng neo không đáng tin.
- Cách áp dụng: dựng 3 dải theo driver nội bộ đã chốt hoặc ràng buộc cứng – phủ kênh ND hoặc activepoints, instockrate mục tiêu, lịch promo – rồi nhân lên từ run-rate SPDadj trung bình.
Xử lý ramp sau launch theo driver phân phối
- Phát hiện ramp: slope tuần dương rõ và ND hoặc active_points tăng theo thời gian. Kiểm tra cầu tiềm năng theo tuần trên cùng một tập điểm bán cốt lõi để tách hiệu ứng mở rộng kênh ra khỏi hiệu ứng vận tốc.
- Ước ramp tối giản:
- Phương án thực dụng khi dữ liệu tuần ngắn: ràng buộc tăng trưởng cầu tiềm năng tháng gm không vượt tổng tăng trưởng kênh quan sát được theo trọng số, ví dụ gm ≤ growthactivepointsm + growthWD_m.
- Nếu bạn có đủ tuần, fit đường cong tăng trưởng mượt dạng log hoặc Gompertz trên SPD_adj theo tuần, giữ nguyên trần theo khả năng phân phối hiện tại. Khi đã fit được ramp, dùng phần dư ổn định còn lại làm nền để dự báo.
- Áp dụng vào dự báo:
- Nội suy: unitspotentialm = SPDadjbase × activepointsplanm × weeksm, với SPDadjbase lấy từ tập cốt lõi đã loại ramp. Sau đó nhân instockrateplanm.
- Seasonal index: Fmpotential = L × [(1 − λ) + λ × sm*] × Rm, trong đó Rm là hệ số ramp do kế hoạch phân phối tạo ra, xấp xỉ bằng activepointsplanm/activepointsanchor hoặc WDplanm/WD_anchor.
Shrink biên độ mùa khi thiếu neo
- Công thức: Fmpotential = L × [(1 − λ) + λ × sm*], với mean(sm*) = 1.
- Chọn λ theo bằng chứng
- Không có neo, chỉ có lịch sự kiện nội bộ tổng quát như payday hay lễ: λ = 0.2.
- 1 tháng neo tin cậy: λ = 0.3.
- 2 neo ở hai pha đối lập theo template: λ = 0.5.
- Có analog nội bộ 12 tháng cùng kênh và 2 neo tại SKU này: λ = 0.6 đến 0.8, chọn thấp nếu promo hoặc OOS trong tháng neo vượt 20% ngày.
- Nếu số ngày ngoại lệ của tháng neo > 20% hoặc CV giữa-tuần của tháng neo > 0.25, giảm λ xuống một bậc.
- Kiểm an toàn: khi thay đổi λ trong khoảng ±0.1 mà MAPE trên holdout tháng gần nhất không cải thiện đáng kể, giữ λ thấp hơn để tránh overfit.
Ví dụ áp dụng đầy đủ – giả định để minh họa
- Dữ liệu đã có
- Sản phẩm: Nước giải khát A 500 ml, kênh MT, region Ha Noi, scope 580 điểm.
- 2025-01: activepoints 185, weeks 4.3, unitsactual 11290, instockrate 0.93, ND 0.32.
- 2025-02: activepoints 195, weeks 4.0, unitsactual 11800, instockrate 0.95, ND 0.34.
- Làm sạch và chỉ số
- Cầu tiềm năng tháng: Jan 12140.86, Feb 12421.05.
- CV giữa-tháng ≈ 0.016 – đạt. Giữa-tuần ổn định – đạt. |slope|/mean nhỏ hơn 0.08 – đạt. Ngưỡng ngoại lệ < 10% – đạt.
- SPDadj: Jan 12140.86/(185×4.3) = 15.27; Feb 12421.05/(195×4.0) = 15.92. Run-rate SPDadj_base = 15.6.
- Quyết định phương pháp: nội suy đơn giản là phù hợp nhất. Ramp nhẹ theo active_points, dưới 5% mỗi tháng – chấp nhận giữ run-rate, không cần mô hình ramp riêng.
- Dự báo tháng 2025-03 theo 3 kịch bản phạm vi nhỏ để trình lãnh đạo
- weeks 4.4.
- Low: activepoints 185, instockrate 0.90. unitsforecast = 15.6×185×4.4×0.90 = 11430.
- Base: activepoints 195, instockrate 0.95. unitsforecast = 15.6×195×4.4×0.95 = 12716.
- High: activepoints 205, instockrate 0.98. unitsforecast = 15.6×205×4.4×0.98 = 13789.
- Nếu buộc phải có hình dạng mùa tối giản cho kế hoạch truyền thông
- Template nội bộ giả định mean 1: Jan 0.92, Feb 0.95, Mar 1.00, Apr 1.05, May 1.10, Jun 1.12, Jul 1.08, Aug 1.00, Sep 0.95, Oct 0.90, Nov 0.95, Dec 1.03.
- Neo dùng Feb: L = yFebadj/s_Feb = 12421.05/0.95 = 13075.84.
- Chọn λ = 0.3 vì chỉ có 1 neo.
- Mar potential = 13075.84 × [(1 − 0.3) + 0.3×1.00] = 13075.84. Quan sát với instockrate 0.95: 12422. Jun potential với sJun = 1.12: 13075.84×[(0.7 + 0.336)] = 13548.03, quan sát với instock_rate 0.95: 12870.
Template công thức điền nhanh theo tham số
- Nội suy đơn giản
- SPDadjbase = mean(demandpotentialOOSadjt/(activepointst×weeks_t)) trên tập tháng đạt điều kiện ổn định.
- unitsforecastm = SPDadjbase × activepointsplanm × weeksm × instockrateplanm.
- Seasonal index tối giản
- L = yiadj/s_i* với tháng i là neo tin cậy.
- unitsforecastm = L × [(1 − λ) + λ × sm*] × instockrateplanm × Rm, với Rm = 1 nếu bỏ qua ramp hoặc Rm = activepointsplanm/activepoints_anchor.
- Kịch bản phạm vi
- L0 = SPDadjbase × activepointsbase × weeks_m.
- Low/Base/High = L0 × instockratelow/base/high × driverlow/base/high khác như promo_uplift nếu đã được chốt nội bộ.
Với khung trên, bạn ra quyết định có kiểm chứng: khi dữ liệu sạch, ổn định và không có neo mùa, nội suy đơn giản là tối ưu. Khi có template mùa nội bộ và neo đủ tin cậy, seasonal index tối giản tận dụng được cấu trúc lặp lại nhưng phải co biên độ bằng λ. Khi bất định cao hoặc đang ramp, gắn mọi thứ vào phạm vi bằng driver nội bộ và cập nhật dần khi có neo mới.
Kiểm tra chất lượng output và câu hỏi kiểm chứng nội bộ
Đầu ra chỉ đáng dùng khi vượt qua một lớp kiểm toán số và một lớp suy xét nghiệp vụ. Mình gom thành bộ kiểm tra nhất quán có thể chạy ngay trên bảng 12 tháng, kèm ví dụ điền sẵn để bạn đối chiếu nhanh, và một bộ câu hỏi kiểm chứng nội bộ trước khi trình lãnh đạo.
Bộ consistency checks cần chạy
- Toán học cơ bản và đơn vị
- Doanh thu tháng = Units × ASP_unit. Sai số làm tròn cho phép ≤ 0.5%.
- Thể tích tháng = Units × AvgVolperunit. ASPperL = Doanh thu/Thể tích. ASPunit phải bằng ASPperL × AvgVolper_unit trong cùng tháng.
- Sum theo tuần hoặc ngày phải khớp tổng tháng. Nếu lệch > 1% phải có cờ missing hoặc loại trừ có chủ đích.
- OOS và cầu tiềm năng
- instockrate trong [0,1]. Gắn cờ xem xét khi < 0.85.
- Cầu tiềm năng tháng ≈ Unitsactual/instockrate. SPDadj = demandpotential/(activepoints × weeks). Khi WD ổn định, SPD_adj không nên dao động quá ±10% nếu không có promo lớn.
- Đà tăng demandpotential không vượt đà tăng WD hoặc activepoints cùng kỳ một khoảng phi lý. Gắn cờ khi growthpotential > growthWD + 10 điểm phần trăm.
- Bao phủ ND và WD
- ND, WD nằm trong [0,1]. WD thường ≥ ND nếu trọng số phản ánh tiềm năng bán cao. Nếu WD < ND, kiểm lại cách gán trọng số.
- Tăng mạnh ND hoặc WD phải đi kèm chuyển dịch SPD hoặc ASP theo hướng hợp lý. Ví dụ WD tăng mà SPD giảm sâu cần kiểm xem mở điểm bán yếu.
- Giá và mix pack size
- ASPunit thay đổi phải phân rã được thành giá theo lít và mix kích cỡ. Nếu ASPperL phẳng nhưng ASPunit biến động mạnh, giải thích do mix pack.
- Tổng ASPperL toàn danh mục phải là trung bình có trọng số doanh thu của ASPperL theo pack. Chênh > 1% gắn cờ trọng số sai.
- Thị phần theo đơn vị vs theo thể tích
- Nếu có ước tính share, tính lại SUA/SVA = AvgVoltotal/AvgVolA. Khi AvgVolA nhỏ hơn trung bình ngành, SUA sẽ cao hơn SVA theo hệ số này. Gắn cờ nếu SU tăng nhưng SV đi ngang và AvgVolA giảm.
- Chéo kênh, vùng và thời gian
- Tổng vùng = quốc gia, tổng kênh = all-channels trong cùng tháng. Lệch > 1% gắn cờ trùng lặp hoặc thiếu mã.
- Tổng tháng = tổng quý nếu lịch chuẩn hóa tuần giống nhau. Lệch do số tuần khác phải được chú thích rõ.
- Khi không có sự kiện, tăng trưởng theo tuần trong tháng không nên đảo pha đột ngột giữa các vùng tương đồng trừ khi có khác biệt promo hoặc tồn kho.
- Seasonality và template
- Seasonal_index 12 tháng có mean bằng 1 sau khi shrink. Nếu mean khác 1, chuẩn hóa lại.
- Tháng dùng làm neo mùa không được có tỷ lệ ngày ngoại lệ quá cao. Gắn cờ nếu > 20% ngày promo hoặc OOS trong tháng neo.
- Promo và uplift
- Promo_uplift không âm trừ khi giá theo lít tăng trong thời gian promo hoặc bị pha bởi OOS. Nếu âm, cần có giải thích.
- Tỷ lệ đơn có promo tăng nên đi kèm ASPperL giảm hoặc Units tăng. Nếu cả ba không tương thích, kiểm lại gắn cờ promo.
- Kiểm soát nguồn và giả định
- Mọi số phải có source_id hợp lệ hoặc status=assumed kèm assumption. Thiếu cả hai là lỗi dừng.
- Mọi trường có đơn vị đo phải điền unit. Không có unit coi như lỗi định dạng.
Ví dụ kiểm tra điền sẵn cho một tháng
- Ngữ cảnh minh họa: Tháng 2025-02, kênh MT, region HN, pack 0.5 L. activepoints=195, weeks=4.0, unitsactual=11,800, instockrate=0.95, ASPperL dự kiến 24,000 VND, revenue báo cáo 141,600,000 VND.
- Kiểm 1 – Doanh thu: revenue = 11,800 × ASPunit. Với ASPperL=24,000 và pack 0.5 L, ASPunit = 12,000 VND. 11,800 × 12,000 = 141,600,000 VND. Pass.
- Kiểm 2 – Thể tích và ASPperL: Volume = 11,800 × 0.5 = 5,900 L. ASPperL = 141,600,000/5,900 = 24,000 VND. Pass.
- Kiểm 3 – OOS adjust: demandpotential = 11,800/0.95 = 12,421.05. SPDadj = 12,421.05/(195 × 4.0) = 15.92. Nếu SPDadjbase kỳ vọng ~15.6 từ tháng cận kề, chênh +2.1% nằm trong dải 10%. Pass.
- Kiểm 4 – Tính hợp lý tăng trưởng: nếu WD, ND không đổi hoặc tăng nhẹ, việc SPD_adj chỉ nhích 2% là hợp lý. Pass.
Bộ câu hỏi kiểm chứng nội bộ
- Dữ liệu và đơn vị
- Bảng đã quy đổi về đơn vị chuẩn theo thể tích chưa. Mọi ASP đã có cả per unit và per L chưa. Pack size đã được chuẩn hóa theo L hoặc ml nhất quán chưa.
- Bao phủ và thiên lệch
- ND, WD được tính trên khung mục tiêu nhất quán chưa. Có thiên lệch kênh hay địa lý trong mẫu quan sát không. SPD có hội tụ khi WD không đổi trong 2 đến 3 tháng không.
- OOS và tồn kho
- Tháng nào có instockrate thấp dưới 0.85 và đã loại khỏi ước lượng nền chưa. Có tháng nào Units vượt khả năng cung ứng logic không, ví dụ sell-out vượt sell-in điều chỉnh tồn kho.
- Giá và khuyến mãi
- Tháng promo có ASPperL giảm và Units tăng tương ứng không. Có tháng nào uplift âm mà không có nguyên nhân hợp lệ không.
- Mix pack và thị phần
- Sự thay đổi thị phần theo đơn vị có khớp với thay đổi AvgVolperunit không. Kết luận thị phần trình lãnh đạo dựa trên thể tích hay đơn vị.
- Chéo vùng, kênh và tổng hợp
- Tổng theo vùng, kênh khớp tổng toàn bộ chưa. Có double count khi một điểm bán được gắn nhầm 2 kênh không.
- Thời gian và mùa vụ
- Seasonalindex mean bằng 1 chưa. Tháng neo có nhiều ngoại lệ không. Nếu có ramp phân phối, dự báo đã ràng theo WD hoặc activepoints chưa.
- Nguồn và giả định
- Trường nào status=assumed ảnh hưởng mạnh đến quyết định. Assumption có thể chuyển thành kế hoạch thu thập dữ liệu trong tháng tới không. Source_id có truy vết đến file và dòng cụ thể chưa.
Nếu toàn bộ kiểm trên pass hoặc có chú thích hợp lệ tại những điểm gắn cờ, bạn có thể tin cậy bảng 12 tháng để đưa vào kế hoạch và trình lãnh đạo mà không lo ảo giác do đơn vị đo, mix kích cỡ hay lệch bao phủ.
Ví dụ minh họa với sản phẩm giả định và một hàng tháng 1
Dưới đây là một CSV mẫu có đủ cấu trúc cột để dùng cho bảng phân tích thị trường 12 tháng. Mình chèn 1 hàng minh họa cho tháng 1 với một sản phẩm giả định, tất cả số liệu đều là ví dụ phục vụ cấu trúc, gắn status=assumed và source_id nội bộ để bạn thấy cách điền đúng quy tắc truy vết. Hàng này dùng các công thức chuẩn để bạn kiểm nhanh tính nhất quán:
- ASPperunitvnd = ASPperLvnd × packsizeL
- revenuevnd = unitsactual × ASPperunit_vnd
- demandpotentialunits = unitsactual / instock_rate
- spdactual = unitsactual / (activepoints × weeksin_month)
- spdadjusted = demandpotentialunits / (activepoints × weeksinmonth)
Bản điền sẵn dưới đây có thể copy ra file .csv để chạy kiểm tra tự động hoặc nhập thẳng vào Sheet.
month,product_name,sku,channel,region,pack_size_L,avg_vol_per_unit_L,units_actual,revenue_vnd,asp_per_unit_vnd,asp_per_L_vnd,nd,wd,active_points,weeks_in_month,in_stock_rate,demand_potential_units,spd_actual,spd_adjusted,seasonal_index,promo_flag,promo_uplift_pct,oos_days,status,source_id,assumption,confidence,notes
2025-01,"Nước giải khát Demo","DEMO-500","MT","HN",0.5,0.5,12000,144000000,12000,24000,0.28,0.35,180,4.3,0.93,12903,15.50,16.67,0.98,1,0.12,2,"assumed","INT-EX-001","Ví dụ giả định phục vụ cấu trúc. Không phải số liệu thật.",0.50,"ASP_unit = ASP_per_L × pack_size_L. Revenue = Units × ASP_unit. SPD dựa trên active_points và weeks."
Ngay bên dưới là phiên bản template cùng cấu trúc với placeholder để bạn nhân bản cho 12 tháng và nhiều SKU. Giữ nguyên header, thay placeholder bằng dữ liệu của bạn. Nếu chưa có dữ liệu, điền NA và giữ status=assumed kèm mô tả ngắn trong assumption. source_id nên trỏ tới file hoặc sheet nội bộ cụ thể để tiện audit.
month,product_name,sku,channel,region,pack_size_L,avg_vol_per_unit_L,units_actual,revenue_vnd,asp_per_unit_vnd,asp_per_L_vnd,nd,wd,active_points,weeks_in_month,in_stock_rate,demand_potential_units,spd_actual,spd_adjusted,seasonal_index,promo_flag,promo_uplift_pct,oos_days,status,source_id,assumption,confidence,notes
{{YYYY-MM}},"{{PRODUCT_NAME}}","{{SKU}}","{{CHANNEL}}","{{REGION}}",{{PACK_SIZE_L}},{{AVG_VOL_PER_UNIT_L}},{{UNITS_ACTUAL}},{{REVENUE_VND}},{{ASP_PER_UNIT_VND}},{{ASP_PER_L_VND}},{{ND}},{{WD}},{{ACTIVE_POINTS}},{{WEEKS_IN_MONTH}},{{IN_STOCK_RATE}},{{DEMAND_POTENTIAL_UNITS}},{{SPD_ACTUAL}},{{SPD_ADJUSTED}},{{SEASONAL_INDEX}},{{PROMO_FLAG}},{{PROMO_UPLIFT_PCT}},{{OOS_DAYS}},"{{STATUS}}","{{SOURCE_ID}}","{{ASSUMPTION}}",{{CONFIDENCE}},"{{NOTES}}"
Gợi ý điền nhanh để bảo toàn tính nhất quán và đủ thông tin cho người ra quyết định:
- Điền packsizeL và avgvolperunitL bằng lít để ASP theo lít tính ra đúng và không bị ảo do mix kích cỡ.
- Nếu bật promoflag=1, đảm bảo có promouplift_pct hợp lý và giải thích ngắn trong notes.
- Khi instockrate < 1, luôn tính demandpotentialunits và spd_adjusted để tách hiệu ứng thiếu hàng khỏi nhu cầu.
- ND và WD nằm trong [0,1]. WD thường lớn hơn hoặc bằng ND nếu bạn dùng trọng số theo tiềm năng.
- Với mọi hàng không có nguồn nội bộ, để status=assumed, viết rõ assumption đủ ngắn gọn nhưng kiểm toán được. Khi đối chiếu báo cáo cho lãnh đạo, ghi chú này giúp phân biệt số đã xác minh và số giả định.
Kế hoạch thu thập dữ liệu nội bộ tối thiểu và roadmap lấp lỗ trống
Mục tiêu là dựng trong 4 tuần một bộ dữ liệu tối thiểu có thể dùng ngay để AI phân tích thị trường 12 tháng không cần web, gồm POS, CRM, survey cửa hàng, chỉ số w_i, nhật ký OOS theo ngày, log khuyến mãi theo SKU và cấu hình tracking share of impressions online trong phạm vi kênh sở hữu. Kế hoạch dưới đây tập trung vào thiết kế biểu mẫu mỏng, dễ vận hành, chuẩn hóa đơn vị và gắn ID nguồn để audit.
Các biểu mẫu tối thiểu cần có
- POS sell-out cơ bản theo ngày hoặc tuần
- Trường bắt buộc: date, storeid, banner, region, sku, packsizeL, unitssold, revenuevnd, onhandendunits, receiptsunits, returnsunits, scannedpricevnd.
- Quy tắc: packsizeL tính bằng lít. revenuevnd phải xấp xỉ unitssold × scannedpricevnd. Nếu lệch > 5% cần ghi chú giảm giá tại quầy.
- Dùng để: tính ASPperunit, ASPperL, SPD, instockrate sơ bộ nếu có onhandend_units và receipts.
- CRM hồ sơ điểm bán và tiềm năng
- Trường: accountid, storeid, bannerclass, storesizem2 hoặc hạng, channel, region, statusactive, potentialrevenueband, visits90d, ordersotherskus90d, paymenttermscode.
- Dùng để: tính ND, WD, proxy tiềm năng và trọng số w_i.
- Survey audit tại cửa hàng mỗi lần viếng thăm
- Trường: date, storeid, sku, shelffacingscount, shelflengthcm, priceonshelfvnd, secondarydisplayflag, competitorpresencetext, photolinkinternal.
- Dùng để: đối chiếu giá, promo thực thi, ước share of shelf nội bộ tại điểm bán.
- OOS theo ngày per store per SKU
- Trường: date, storeid, sku, openingstockunits, deliveriesunits, salesunits, closingstockunits, oosflag, oosstarttime, oosendtime, checks_count.
- Quy tắc: oosflag = 1 nếu closingstockunits = 0 hoặc có khoảng thời gian hết kệ. instockrate theo ngày = 1 − oosminutes/1440, theo tháng = trung bình ngày.
- Promo log theo SKU
- Trường: promoid, sku, scopelevel (storeid hoặc banner), mechanictype, discountdepthpct, startdate, enddate, featuretype, fundingsource, estupliftpct, executed_flag.
- Dùng để: dán cờ promo theo ngày vào POS, tách uplift khỏi nền.
- Share of impressions online nội bộ
- Phạm vi: website D2C của bạn, app, gian hàng marketplace của bạn, media bạn mua cho chính SKU của bạn. Không cần crawl bên ngoài.
- Trường: date, channel, scopeid, keywordsetid hoặc pageid, sku, impressions, clicks, totalimpressionsinscope, shareimpr = impressions/totalimpressionsin_scope.
- Quy tắc: scope_id là tập so sánh nội bộ cố định theo tuần, ví dụ Category A trong gian hàng của bạn hoặc tập keyword thương hiệu.
Ví dụ điền sẵn và template cho 3 biểu mẫu then chốt
- OOS theo ngày
date,store_id,sku,opening_stock_units,deliveries_units,sales_units,closing_stock_units,oos_flag,oos_start_time,oos_end_time,checks_count,source_id,notes
2025-01-12,ST-001,DEMO-500,36,0,36,0,1,15:20,23:59,3,"VISIT-APP-012","Hết kệ từ 15:20, không có giao bổ sung."
date,store_id,sku,opening_stock_units,deliveries_units,sales_units,closing_stock_units,oos_flag,oos_start_time,oos_end_time,checks_count,source_id,notes
{{YYYY-MM-DD}},{{STORE_ID}},{{SKU}},{{OPENING_STOCK}},{{DELIVERIES}},{{SALES}},{{CLOSING_STOCK}},{{OOS_FLAG}},{{OOS_START}},{{OOS_END}},{{CHECKS_COUNT}},"{{SOURCE_ID}}","{{NOTES}}"
- Promo log theo SKU
promo_id,sku,scope_level,scope_value,mechanic_type,discount_depth_pct,start_date,end_date,feature_type,funding_source,est_uplift_pct,executed_flag,source_id,notes
PR-2025-01A,DEMO-500,banner,MT-Top,price_cut,12,2025-01-10,2025-01-16,endcap,trade,15,1,"TMKT-PLAN-2025Q1","Giảm giá kèm endcap tại chuỗi MT-Top."
promo_id,sku,scope_level,scope_value,mechanic_type,discount_depth_pct,start_date,end_date,feature_type,funding_source,est_uplift_pct,executed_flag,source_id,notes
{{PROMO_ID}},{{SKU}},{{SCOPE_LEVEL}},{{SCOPE_VALUE}},{{MECHANIC}},{{DEPTH_PCT}},{{START_DATE}},{{END_DATE}},{{FEATURE_TYPE}},{{FUNDING}},{{EST_UPLIFT_PCT}},{{EXECUTED_FLAG}},"{{SOURCE_ID}}","{{NOTES}}"
- Share of impressions online nội bộ
date,channel,scope_id,keyword_set_id,sku,impressions,clicks,total_impressions_in_scope,share_impr,source_id,notes
2025-01-15,Website,D2C-Cat-A,KW-BrandA,DEMO-500,8200,640,41000,0.2,"GA4-EXP-001","Cat A trên website, tập keyword BrandA."
date,channel,scope_id,keyword_set_id,sku,impressions,clicks,total_impressions_in_scope,share_impr,source_id,notes
{{YYYY-MM-DD}},{{CHANNEL}},{{SCOPE_ID}},{{KEYWORD_SET_ID}},{{SKU}},{{IMPRESSIONS}},{{CLICKS}},{{TOTAL_IMPRESSIONS}},{{SHARE_IMPR}},"{{SOURCE_ID}}","{{NOTES}}"
Thiết lập chỉ số w_i tiềm năng điểm bán
- Chọn 3 đến 5 proxy có trong CRM hoặc POS của bạn, ví dụ:
- ordersotherskus_90d: số đơn lặp SKU khác của bạn trong 90 ngày.
- potentialrevenueband: bậc doanh thu tiềm năng nhập CRM, map sang số.
- bannerclass hoặc storesize_m2: phân hạng hoặc diện tích.
- visits_90d: mức độ tiếp cận nội bộ, phản ánh khả năng phục vụ.
- Chuẩn hóa từng proxy về [0,1] bằng min-max trong khung mục tiêu nhất quán. Nếu phân phối lệch mạnh, dùng winsor trước khi min-max.
- Tính w_i = trung bình cộng của các proxy đã chuẩn hóa hoặc trọng số bạn định nghĩa dựa trên khả năng dự báo nội bộ. Ghi rõ công thức trong data dictionary.
Ví dụ tính w_i cho một điểm bán
- Proxy thô: ordersotherskus90d = 12, potentialrevenueband = 3 trên thang 1 đến 5, storesize_m2 = 180.
- Sau chuẩn hóa trên khung: ordersnorm = 0.60, revenuenorm = 0.50, size_norm = 0.55.
- w_i = (0.60 + 0.50 + 0.55) / 3 = 0.55. Lưu cả ba thành phần để sau này hiệu chỉnh trọng số nếu cần.
Cấu hình đo instockrate và SPD
- instockrate tháng = 1 − tổng phút OOS trong tháng chia cho tổng phút hoạt động. Nếu không có phút, thay bằng 1 − oosdays/daysopen.
- SPDactual = unitssold / (activepoints × weeksinmonth). activepoints là số điểm bán có bán SKU trong tháng. SPDadjusted = demandpotentialunits / (activepoints × weeksinmonth), với demandpotentialunits = unitssold / instock_rate.
Nguyên tắc ID và kiểm soát chất lượng
- ID duy nhất: sku, storeid, accountid, banner, region, source_id. Không đổi giữa các sheet.
- Đơn vị: chuẩn hóa packsizeL, giá theo VND, thời gian theo ISO 8601, múi giờ cố định.
- Ràng buộc nhập liệu: danh sách chọn cho banner, region, mechanictype. Công thức kiểm tra revenuevnd ≈ unitssold × scannedpricevnd. Tự động gắn promoflag theo ngày từ Promo log.
- Ghi nguồn: mỗi dòng có source_id trỏ tới file, form hoặc module nội bộ sinh ra dòng đó. Với dữ liệu giả định, ghi rõ assumption trong notes.
Roadmap 4 tuần để có bộ dữ liệu tối thiểu
Tuần 1 – Chuẩn hóa schema và khởi động
- Việc cần làm:
- Chốt schema 6 biểu mẫu ở trên trong một workbook chuẩn, tạo data dictionary.
- Sinh ID từ điển cho sku, store_id, banner, region. Map CRM hiện hữu sang từ điển.
- Tạo form nhập nhanh cho OOS và Audit trên mobile, ràng buộc dữ liệu tối thiểu.
- Cấu hình sheet tính tự động ASPperL, SPD, instockrate, promo_flag theo ngày.
- Sản phẩm bàn giao: bộ template đã khóa header, từ điển ID, hướng dẫn điền 1 trang, checklist QC.
Tuần 2 – Triển khai tại hiện trường và nối POS
- Việc cần làm:
- Rollout form OOS và Audit cho 10 đến 20 điểm bán pilot, hướng dẫn ảnh chụp kệ.
- Thiết lập lịch xuất POS từ hệ thống nội bộ hoặc nhà phân phối, tối thiểu theo tuần.
- Đào tạo đội trade marketing ghi Promo log ngay khi campaign được chốt và khi kết thúc.
- Thu thập CRM các trường proxy cho wi, điền thiếu tối thiểu potentialrevenueband và visits90d.
- Sản phẩm bàn giao: dữ liệu tuần 2 điền đủ form, POS tuần đầu, promo log đang chạy.
Tuần 3 – Tính w_i, phân tầng và bật tracking online
- Việc cần làm:
- Chuẩn hóa proxy, tính wi, phân decile theo wi, kiểm tra phân phối và các giá trị ngoại lệ.
- Cấu hình theo dõi share of impressions trong kênh sở hữu: xác định scopeid và keywordset_id cố định, bật export hàng ngày từ analytics nội bộ.
- Kịch bản kiểm lỗi: đối chiếu revenuevnd và scannedprice, đối chiếu promo_flag với uplift sơ bộ, soát OOS trống.
- Sản phẩm bàn giao: bảng w_i, báo cáo decile WD sơ bộ, feed impressions nội bộ bắt đầu cập nhật.
Tuần 4 – Lấp lỗ trống và khóa phiên bản 0
- Việc cần làm:
- Backfill tối thiểu 4 đến 8 tuần gần nhất cho POS và OOS, đồng bộ CRM trường còn thiếu.
- Chạy QC: ND, WD trong [0,1], ASPperunit = ASPperL × packsizeL, SPD hợp lý, instockrate trên 0.85 ở điểm bán không có OOS ghi nhận.
- Đóng băng snapshot dữ liệu tối thiểu, xuất CSV theo schema phân tích 12 tháng, lưu kèm data dictionary và changelog.
- Sản phẩm bàn giao: bộ dữ liệu tối thiểu v0, sẵn sàng nạp vào AI, kèm danh sách ô trống còn NA và giả định.
Gợi ý vận hành thực dụng
- Ưu tiên độ phủ chiều dọc thay vì nhiều trường màu mè. Nếu không có phút OOS, dùng oosflag theo ngày và oosdays, sau này nâng cấp.
- Nếu thiếu proxy w_i, bắt đầu với 2 proxy dễ có nhất trong CRM của bạn và để trọng số bằng nhau. Ghi rõ công thức để lần sau cập nhật.
- Nếu POS về chậm, dùng tuần làm kỳ báo cáo đầu, công thức vẫn giữ như trên với weeksinmonth = 1 cho mỗi tuần.
- Với share of impressions, giữ scopeid cố định 4 tuần đầu để so sánh được. Không đổi keywordset giữa chừng.
Khi hoàn tất 4 tuần, bạn sẽ có một pipeline tối thiểu nhưng đủ chuẩn: POS và OOS theo ngày để điều chỉnh cầu, CRM đủ trường để tính w_i và WD, Promo log để tách uplift, và share of impressions nội bộ để đo bao phủ điểm chạm online. Từ đây có thể chạy phân tích 12 tháng dựa trên dữ liệu nội bộ và giả định minh bạch.
Lỗi thường gặp và cách tránh khi phân tích không dùng web
Khi phân tích dựa trên dữ liệu nội bộ, vài sai lệch tưởng nhỏ có thể kéo lệch cả bảng 12 tháng. Dưới đây là các lỗi mình thấy lặp lại nhiều nhất cùng cách chặn từ gốc bằng quy tắc, prompt, kiểm định và cơ chế xuất NA bắt buộc.
- Bao phủ thấp rồi nội suy quy mô
- Dấu hiệu: ND hoặc WD thấp, mẫu quan sát tập trung vào cửa hàng hạng cao, SPD tăng giảm mạnh khi mở thêm điểm. Chênh lệch trung bình w_i giữa điểm đã phủ và khung mục tiêu lớn.
- Cách tránh:
- Luôn tính ND và WD trên một khung mục tiêu nội bộ nhất quán. Tạo wi từ proxy CRM và POS, phân decile theo wi để kiểm đường cong ổn định SPD theo WD trước khi scale.
- Nếu WD dưới ngưỡng vận hành bạn đặt, hoặc SPD chưa ổn định theo decile, không nội suy quy mô thị trường. Gắn status=assumed hoặc để NA cho các trường quy mô.
- ASP tính theo đơn vị thay vì thể tích chuẩn
- Dấu hiệu: ASPperunit biến động cùng lúc mix pack_size đổi, dù giá theo lít không đổi.
- Cách tránh:
- Chuẩn hóa packsizeL. Tính ASPperL = revenuevnd / volumeL thay vì ASPperunit. Kiểm QC: ASPperunit phải xấp xỉ ASPperL × packsizeL cho từng SKU.
- Mùa vụ giả do khuyến mãi hoặc OOS
- Dấu hiệu: đỉnh rơi đúng tuần promo, đáy rơi đúng tuần OOS, phần dư tương quan mạnh với cờ promo hoặc instockrate.
- Cách tránh:
- Gắn cờ promo theo ngày và tính instockrate. Điều chỉnh cầu về mỗi ngày in stock trước khi ước lượng mùa. Nếu instockrate tháng quá thấp hoặc promo phủ dày, đóng băng mùa, chỉ xuất baseline hoặc NA cho seasonal_index.
- Sai khác mix kênh
- Dấu hiệu: ASP, promo_rate, facings khác xa giữa MT, GT, D2C nhưng bạn lại gộp để ngoại suy.
- Cách tránh:
- Phân tích theo kênh tách biệt. Khi cần tổng hợp, dùng WD theo kênh làm trọng số. Nếu thiếu WD của kênh chưa vào, không nội suy, để NA và ghi giả định.
- Thiên lệch địa lý
- Dấu hiệu: chỉ phủ vài tỉnh trọng điểm, CV vận tốc giữa tỉnh cao, nhưng bạn lại suy ra toàn quốc.
- Cách tránh:
- Báo cáo theo vùng trước, chỉ hợp nhất khi độ biến thiên vùng giảm bền vững. Nếu vùng chưa đủ đại diện, giữ NA cho ước lượng toàn quốc và nêu rõ hạn chế.
- OOS không được xử lý như kiểm duyệt
- Dấu hiệu: tháng bán thấp bất thường đi kèm tồn kho cạn, nhưng vẫn tính như cầu giảm.
- Cách tránh:
- Tính demandadjusted = unitssold / instockrate, đặt trần hợp lý để tránh phóng đại. Coi các tháng instockrate thấp là thiếu tin cậy khi ước lượng đường mùa hoặc SPD nền.
- Hallucination của LLM
- Dấu hiệu: model tự điền tên đối thủ, thị phần, giá mà không có trong CONTEXT.
- Cách tránh:
- Dùng closed-world, bắt buộc xuất NA khi thiếu dữ liệu, ép source_id theo từng trường, giảm temperature. Với thực thể nhạy như tên đối thủ, chỉ cho phép verbatim từ CONTEXT.
System prompt khuyến nghị để chặn bịa, ép NA và gắn nguồn
- Tóm tắt: đặt chế độ closed-world, ép schema có status và source_id, giảm nhiệt độ khi sinh số liệu.
You are an analyst. Closed-world mode. Use only data in CONTEXT.
Rules:
- Do not guess. If a field is missing, output "NA" and set status="assumed" with a short assumption.
- Every number and competitor name must include a valid source_id from CONTEXT.
- Competitor names must be verbatim matches from CONTEXT.
Output JSON only with schema:
[{field, value, unit, period, scope, source_id, status in ["verified","assumed"], assumption}]
Temperature <= 0.2, top_p 0.8.
Validate internally that all numbers have source_id or status="assumed". If not, replace with NA.
Ví dụ output một trường có NA được kiểm soát
{
"field": "market_size_volume",
"value": "NA",
"unit": "L",
"period": "2025-01 to 2025-12",
"scope": "National",
"source_id": "NA",
"status": "assumed",
"assumption": "WD < 30% và SPD chưa ổn định theo decile; không nội suy quy mô toàn thị trường."
}
Mẫu thay thế với biến số
{
"field": "{{FIELD_NAME}}",
"value": "{{VALUE_OR_NA}}",
"unit": "{{UNIT}}",
"period": "{{PERIOD}}",
"scope": "{{SCOPE}}",
"source_id": "{{SOURCE_ID_OR_NA}}",
"status": "{{verified_or_assumed}}",
"assumption": "{{REASON_IF_ASSUMED}}"
}
Checklist QC ngắn để tự động gắn cờ
- Nếu WD < ngưỡng nội bộ và SPD theo decile chưa ổn định trong 2 đến 3 bậc liên tiếp, không scale, xuất NA cho market_size và share.
- Nếu bất kỳ trường giá chỉ có ASPperunit mà thiếu packsizeL hoặc ASPperL, gắn cờ và không tính so sánh giá, xuất NA.
- Nếu tháng có promoflag hoặc instock_rate thấp, không học mùa, chỉ xuất baseline và đánh dấu assumed.
- Nếu kết quả hợp nhất kênh làm ASP chênh quá lớn so với từng kênh, dừng hợp nhất, giữ báo cáo theo kênh.
- Nếu vùng phủ dưới số vùng tối thiểu bạn quy định hoặc CV vận tốc vùng cao, chặn ngoại suy toàn quốc, xuất NA.
Kết luận
Sau khi áp dụng, bạn có thể tự dựng bảng phân tích 12 tháng từ dữ liệu nội bộ, chuẩn hóa chỉ số cốt lõi và sinh dự báo có nhãn giả định, đồng thời kiểm soát bias cùng chất lượng. Mình đã cung cấp kịch bản vận hành và bộ prompt để bạn chạy local, qua API hoặc trên Sheet mà không cần web.
Lưu ý quan trọng: nếu độ phủ kênh thấp hoặc OOS cao, hãy gắn nhãn assumed và xuất NA thay vì ngoại suy mạnh.