ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DeepSeek赋能中小超市SKU级需求预测与智能补货实践

DeepSeek赋能中小超市SKU级需求预测与智能补货实践 简介面向具备数据分析与深度学习基础的中小连锁超市运营管理者这份PDF围绕DeepSeek需求预测模型的完整搭建流程展开针对传统库存方法预测不准、缺乏灵活性、信息传递不及时等痛点提供从模型原理、数据收集与预处理、架构设计与参数选择到训练优化、评估验证的全链路方案。整份资料为1个PDF文件共30页压缩包大小约1.61MB内容排版清晰、目录完整便于按章节查阅。当前已有98人学习/下载。这份资源的价值在于它不仅讲解DeepSeek在零售需求预测中的技术细节还结合库存补货决策、商品陈列优化、促销活动规划等实际场景给出可参考的应用案例同时点明数据质量和预处理的重要性并指出未来可拓展的方向适合用作中小超市管理者与相关从业者的实操指南。1. 零售库存的SKU级预测为什么中小连锁超市默认做不成一家二十家门店的连锁超市SKU动辄四五千个店长每天早上凭经验下补货单。卖得快的断货卖得慢的压在库房里变成损耗和资金占用。ERP里只有POS流水和进销存台账没有预测能力数据分析师也养不起。这就是DeepSeek这类大模型进来之后被快速关注的原因它把「需求预测模型搭建」这件事的门槛降到了prompt工程级别不需要训练自己的神经网络也不需要买昂贵的时序数据库。这篇笔记写给正在犹豫要不要投入的从业者——中小连锁超市怎么低成本把DeepSeek接进补货流程哪些SKU值得跑模型以及真正上线时会在哪里翻车。2. 先定接入路线DeepSeek API调用与本地部署的两套成本账2.1 为什么是DeepSeek而不是直接上时序库传统做法里SKU级需求预测有三个主流方案移动平均和指数平滑这类统计方法、XGBoost这类树模型、LSTM这类深度模型。中小超市在这三条路上都容易卡住。统计方法处理不了促销、节假日和天气这类外部冲击树模型要花几周做特征工程门店一多特征口径就乱深度模型更现实的问题是数据量不够——一个SKU在一个门店一年只有365条日记录其中还夹杂缺货和退货拿来训LSTM基本是玄学。DeepSeek这类大语言模型的优势不在「算得精」而在「理解场景」。它能同时读进去28天的销量序列、本周是否有促销、明天是不是节假日甚至能理解「这个店在写字楼旁边周五下午销量高」这种非结构化信息。对中小连锁超市来说需求预测的核心难点从来不是算法精度而是把环境和事件塞进模型里这恰好是大模型的长板。另外零样本和少样本能力意味着新SKU上架当天就能出预测不用等三个月攒历史数据这直接解决了冷启动问题。2.2 API调用与本地部署数据量、预算与隐私怎么权衡先给结论十到五十家门店、一两千到五千个SKU的规模我一般建议先走DeepSeek API调用不要急着上本地部署。算一笔账就清楚了假设每天对2000个活跃SKU各预测一次未来7天销量每个请求的输入输出加起来大约1500个token一天也就是300万token的量。按目前的API定价这个量级每天的成本相当于一杯咖啡远低于一台GPU服务器的折旧和电费。本地部署DeepSeek要用vLLM这类推理服务拉起来还得有人维护显存、并发和版本更新对小团队来说运维成本比API费用高得多。真正需要本地部署的情况只有三种门店销售数据敏感到不允许出内网、单日预测请求量到千万token级别、或者门店网络环境差到连不稳API。前两种是硬条件第三种其实可以用离线批量预测来绕开。选型时建议先把数据脱敏等级和预算上限写清楚再决定路线不要一开始就追求私有化。2.3 最小可行调用DeepSeek API的Python请求模板无论走官方API还是本地部署的服务请求格式都兼容OpenAI风格。先用一个最小脚本把链路跑通验证响应时间、输出格式和成本再往里面加业务逻辑。import requests import json # 将api_url替换为你当前DeepSeek服务的地址api_key换成实际密钥 API_URL http://你的服务地址/v1/chat/completions API_KEY sk-你的密钥 def ask_deepseek(system_prompt, user_prompt): payload { model: deepseek-chat, temperature: 0.1, # 预测场景要低温度控制在0~0.2之间 messages: [ {role: system, content: system_prompt}, {role: user, content: user_prompt} ], response_format: {type: json_object}, # 强制输出JSON方便后续解析 timeout: 60 } resp requests.post( API_URL, headers{Authorization: fBearer {API_KEY}}, jsonpayload, timeout60 ) resp.raise_for_status() return resp.json()[choices][0][message][content]这段代码有几个参数要解释清楚。temperature设为0.1是因为需求预测要的是稳定输出温度高了同一个SKU同一天预测两次结果差很大店长会直接不信任系统。response_format强制JSON对象输出避免模型给你一段带解释的散文让后处理解析成本大增。timeout设60秒是因为长历史序列在复杂prompt下推理时间会明显变长短了容易误杀正常请求。这里没有做重试和并发控制批量预测之前必须补上后面避坑章节会专门讲。3. 构造训练样本从POS流水到SKU级预测特征3.1 三张表搭建数据基座销售、促销日历与门店信息很多团队一上来就让模型直接读ERP的流水表这是需求预测落地里最容易被忽视的坑。POS流水表里每一行是一笔交易一个SKU一天可能产生几十行需要先聚合更重要的是口径问题——qty字段是实销数量但遇到退货日会有负数遇到缺货日则是0这个0不代表真实需求为零。所以必须先建三张口径干净的表。第一张是日聚合销售表字段包括store_id, sku_id, date, qty, sales_amount按门店加SKU加日期做SUM聚合退货量单独记一列不要在qty里直接抵消。第二张是促销日历表记录每个门店每个SKU的促销开始日、结束日、折扣率、促销类型促销对销量的拉升在结束前一天和结束当天最强这个滞后效应后面特征工程会用到。第三张是门店属性表记录门店类型、商圈类型、营业面积、周边常住人口结构这些字段不会进时间序列但会进prompt作为静态上下文。三张表建好后再做一次数据质量检查把qty为负、日期在未来、SKU不在主数据里的脏行直接剔除这一步能省掉后面大量排错时间。3.2 特征工程代码滚动窗口、滞后特征与外部因子特征工程的目标不是喂给神经网络而是拼出给DeepSeek看的prompt文本。但特征还是得先算出来因为滚动均值、标准差、是否促销这些数值必须落到每一行上。import pandas as pd # 读入三张基础表日期字段先转成datetime类型 sales pd.read_csv(daily_sales.csv, parse_dates[date]) promo pd.read_csv(promo_calendar.csv, parse_dates[sale_start, sale_end]) store pd.read_csv(store_attr.csv) # 按门店SKU日期聚合退货量单独保留 daily ( sales.groupby([store_id, sku_id, date], as_indexFalse) .agg(qty(qty, sum), refund_qty(refund_qty, sum)) ) # 排序后才能正确计算滚动窗口 daily daily.sort_values([store_id, sku_id, date]).reset_index(dropTrue) # 过去7天和28天日均销量shift(1)确保只用历史数据不包含当天 daily[avg_qty_7d] ( daily.groupby([store_id, sku_id])[qty] .transform(lambda x: x.shift(1).rolling(7, min_periods3).mean()) ) daily[avg_qty_28d] ( daily.groupby([store_id, sku_id])[qty] .transform(lambda x: x.shift(1).rolling(28, min_periods7).mean()) ) # 近28天销量标准差用于后续安全库存计算 daily[std_qty_28d] ( daily.groupby([store_id, sku_id])[qty] .transform(lambda x: x.shift(1).rolling(28, min_periods7).std()) ) # 标记当天是否为促销日促销结束前一天的拉升单独给特征 promo[is_promo_day] 1 daily daily.merge( promo[[store_id, sku_id, date, is_promo_day]], on[store_id, sku_id, date], howleft ) # 星期特征周一和周末的销量形态差异很大 daily[weekday] daily[date].dt.weekday daily[is_weekend] daily[weekday].isin([5, 6]).astype(int) # 门店属性合并进来之后作为prompt中的静态上下文 daily daily.merge(store[[store_id, store_type, area_sqm]], onstore_id, howleft)这段代码里最关键的参数是shift(1)和min_periods。shift(1)保证计算7日均值时只用到预测日之前的数据把当天销量放进去就是典型的数据泄漏会让模型看起来在训练集上很准、实盘一塌糊涂。min_periods3和min_periods7解决的是冷启动问题——新SKU上架只有两三天数据时窗口也能算出均值而不是返回NaN。rolling(7)的窗口长度选择要结合超市的进货周期大部分中小超市的生鲜一周进两三次、日杂一周一次7天窗口能覆盖一个完整的进货和销售循环28天窗口则捕捉月度趋势。促销字段只标记了当天是否促销如果你的数据支持建议再加一列promo_remaining_days促销最后一天的抢购效应明显强于促销第一天。3.3 冷启动过滤哪些SKU不值得进模型不是所有SKU都值得跑预测强行跑只会浪费token还打击团队信心。按三个规则过滤月均销量低于一定阈值的长尾SKU直接走自动补货规则上架不足四周的新品不进预测模型季节性过强的品类单独建prompt模板。长尾SKU走简单规则就能管好比如「库存低于安全线就补固定量」不需要大模型介入。上架不足四周的SKU历史数据太短滚动窗口算出来的均值没有统计意义硬要预测还不如用同品类已有SKU的均值做估计。季节性品类更要小心月饼和粽子的销量集中在节前两周平时数据对节日毫无参考价值如果数据里有这类SKU要么单独设计包含去年同期的prompt要么直接交给采购手工下单。这三类SKU在中小超市里通常占60%以上真正进入DeepSeek预测流程的是剩下那部分动销稳定、有历史规律的核心SKU数量一般在几百到两千之间。4. 跑通单SKU需求预测DeepSeek Prompt模板与输出后处理4.1 零样本预测还是微调模型先做对评估再决定很多人听到「搭建模型」第一反应是微调。但在这个场景里我强烈建议先做零样本加少样本预测把评估跑完再决定要不要微调。理由有两个一是需求预测的数据分布每个月都在变促销活动、季节轮换、新品上市都会改变销量规律微调得到的权重更新很快就会过期需要频繁重训二是中小超市根本没有足够的标注数据做微调——你需要的不只是历史销量还要为每个SKU门店组合标注真实的需求值而真实需求恰恰是被缺货和退货污染过的未知数。零样本的做法是把历史销量序列、外部事件、门店属性全部写进prompt让DeepSeek直接输出预测值。少样本则是在prompt里附上一两个同品类SKU的历史对比案例让模型模仿规律。先按这个方法跑一周用后面会讲的MAPE做评估如果精度能到30%以内就说明路线可行微调大概率也没必要。如果评估结果不理想也要先检查数据和prompt不要急着上微调——我见过太多团队把预测不准归咎于模型能力最后发现是数据没做滞后处理。4.2 一个稳定的预测Prompt历史序列、外部事件与输出约束prompt是这套方案的核心设计原则是「把模型当成人店长来交代」。一个人类店长做预测时会看上周卖了多少、去年同期卖了多少、明天有没有促销、是不是周末prompt里就要把这些信息全部显式给到。def build_user_prompt(feature_row, hist_qty_list, future_events): return f请为一家中小连锁超市预测单店单SKU的未来7天销量。 门店信息{feature_row[store_type]}商圈面积{feature_row[area_sqm]}平方米。 商品类型{feature_row[category_name]} 最近28天每日实销销量按日期升序 {hist_qty_list} 未来7天的关键事件 周末情况{future_events[weekend_flags]} 促销安排{future_events[promo_flags]} 节假日{future_events[holiday_flags]} 请只输出JSON对象不要输出任何解释 {{ forecast_7d: [7天每日销量预测取整数], confidence: 高/中/低, reason: 不超过30个字的判断依据 }}这个模板里有几个细节直接决定预测质量。历史序列给28天而不是7天是让模型能看到一个完整的月度波动周期同时28天的token开销可控。future_events必须逐天列出比如[否,否,是,否,否,否,是]这样的布尔序列不要写「下周六促销」这种自然语言模型对日期推算并不擅长你直接告诉它未来的哪一天有事情比让它自己数日历可靠得多。forecast_7d要求输出整数是为了直接对接补货逻辑后面后处理阶段还有一次兜底。reason字段看起来多余实际很有用——它让模型把注意力放在解释销量波动的原因上归因过程本身会提升数值预测的稳定性同时这个文本能被店长看到增加人对系统的信任。4.3 后处理兜底防幻觉、防负数、防整数溢出大模型输出必须先经过一层后处理才能进业务系统这一步不能省。解析JSON只是最基础的一层真正的坑在后面模型可能输出负数、输出超出历史峰值十倍的天文数字、甚至返回一个空数组。import json def postprocess(raw_output, hist_max_qty, sku_id): try: data json.loads(raw_output) forecast data.get(forecast_7d, []) except json.JSONDecodeError: # JSON解析失败时退回用历史均值兜底 raise ValueError(fSKU {sku_id} 返回非法JSON: {raw_output[:200]}) if not isinstance(forecast, list) or len(forecast) ! 7: raise ValueError(fSKU {sku_id} 预测数组长度异常: {len(forecast)}) # 三项规则兜底非负、不超过历史峰值1.5倍、转为int cleaned [] for v in forecast: v 0 if v is None else float(v) v 0 if v 0 else v v min(v, hist_max_qty * 1.5) cleaned.append(int(round(v))) return cleaned三条兜底规则要说一下。负数直接归零销量不可能为负出现负数说明模型把退货逻辑搞混了。设置历史峰值1.5倍的上限是为了挡住幻觉模型在长上下文里有时会突然生成离谱的大数这个截断是最后一道保险。转int是为了和现有补货单的字段类型对齐ERP系统里销量和库存都是整数你传个小数进去采购系统可能直接报错。如果hist_max_qty本身为0历史从未卖过说明这个SKU不该进预测流程应该在前面冷启动过滤时就拦掉。5. 搭建避坑零售需求预测最容易翻车的五个场景5.1 节假日样本太少模型把大促峰值当噪声现象是五一和国庆那几天预测值明显偏低实际销量却是平日的三倍断货断到店长在群里骂人。原因是这些节假日一年只出现一次历史序列里根本没有足够的样本让模型学到峰值规律模型会把峰值当作异常波动处理。解决方法是两手抓一是在prompt里显式声明「该日期为国家法定节假日销量通常为平日2~3倍」把业务知识直接写进去二是如果去年同期的数据存在把去年节假日前后的销量序列也塞进prompt作为参考。注意不要依赖模型自己发现节假日它不会主动去联想「明天是五一所以销量要涨」你需要帮它把因果写明白。5.2 未来数据泄漏把补货单当成实际销量现象是某个月模型在回测里表现特别好MAPE降到10%以内但实盘预测依然不准一查发现特征工程时把「手工补货单数量」当成了一列特征。补货单和真实销量高度相关——店长订了100箱饮料大概率是因为上周卖了90箱——模型学到的是「补货单能预测补货单」而不是「历史销量能预测未来需求」。这在回测里是极大作弊因为补货单本身就是基于当时的需求判断产生的。解决方法只有一个训练和推理特征里只允许使用严格滞后的实销数据补货单、调拨单、报损单一律不进特征标签永远用POS实销。每次新增特征时问一句这个值在预测日当天就能知道吗不能就不准进。5.3 门店之间互相抄作业A店的规律套不到B店现象是同一个SKU在写字楼店和社区店的预测误差方向完全相反——写字楼店工作日卖得多社区店周末卖得多模型取了个中间值两边都不满意。原因是把不同门店的数据混在一起模型学到的是平均规律。解决方法有两种最简单的做法是在prompt里带上store_type字段让模型知道当前是哪个商圈类型更彻底的做法是按门店群分别建模把销售形态相似的3~5家店分到一组每组单独跑预测。我建议直接分群因为中小超市门店数量本来就不多分组后每个群的SKU数量还是够用的而且分群还能顺便解决门店属性差异问题。5.4 API超时与并发限制批量预测的排队策略现象是第一次跑全量2000个SKU的预测脚本跑到第300个就开始报错HTTP 429和超时交替出现脚本中途崩溃前面的结果也丢了。原因是没做并发控制和失败恢复一股脑把所有请求打到了服务端。解决方法是加信号量限制并发数并把每批结果实时落盘失败的任务进入重试队列注意重试要带指数退避。import threading import time from concurrent.futures import ThreadPoolExecutor semaphore threading.Semaphore(8) # 控制最多8个并发请求 def safe_request(sku_id, payload): for attempt in range(3): with semaphore: try: result ask_deepseek(payload[system], payload[user]) return sku_id, result except Exception as e: wait 2 ** attempt # 指数退避1秒、2秒、4秒 time.sleep(wait) return sku_id, None并发数8是保守值具体取决于你的服务端限流策略先从5开始压测逐步加到10观察429出现频率。ThreadPoolExecutor用来并发提交请求但信号量保证真正同时打到服务端的请求永远不超过上限。失败的SKU记到日志里全部跑完后单独补跑不要中断整个流程。5.5 缺货记录把销量算成0模型学成「这个品没人要」现象是某个畅销SKU的预测值越走越低安全库存也越调越低陷入恶性循环。原因是这个SKU经常缺货缺货日的销量是0模型看到的是「经常卖不动」而不是「供不应求」。解决方法是把缺货日单独标记出来建一张缺货登记表记录每天每个SKU是否缺货以及缺货时长。处理时有两种选择训练时把缺货日从序列里剔除只算有货日期的均值或者在序列里保留0值但在prompt里注明「这天缺货实际需求未知」。我倾向第二种因为完全剔除会让序列不连续模型对时间间隔的理解会失真而显式标注能让模型学会区分「卖不出去」和「没货可卖」两种0的含义。6. 从预测到补货单用MAPE滚动验证让店长敢按确认键模型跑通只是第一步真正检验价值的是它能不能变成店长每天按下去的补货单。验证方法不要用整体平均误差要看每个SKU每个门店的分布我习惯用MAPE和偏差率两个指标配合做滚动回测。import numpy as np def mape(y_true, y_pred): y_true np.array(y_true, dtypefloat) y_pred np.array(y_pred, dtypefloat) return np.mean(np.abs((y_true - y_pred) / np.maximum(y_true, 1e-6))) * 100 def bias_rate(y_true, y_pred): # 正值表示系统性高估负值表示系统性低估 return (np.sum(np.array(y_pred) - np.array(y_true)) / np.sum(y_true)) * 100回测时用滚动窗口每周一用过去28天数据预测未来7天然后和真实销量对比连续跑8周观察MAPE和偏差率的稳定性。MAPE在30%以内属于可用水平生鲜类可以放宽到40%。偏差率比MAPE更重要——MAPE只告诉你误差有多大偏差率告诉你补货单是偏多还是偏少如果连续四周都是正偏差说明系统在系统性高估库存会越积越多需要下调安全库存系数。补货建议量公式我固定用建议订货量 未来7天预测销量 - 当前库存 - 在途量 安全库存。安全库存取近28天销量标准差的1.2倍生鲜类降到0.8倍因为生鲜损耗成本高于断货成本。算出来的补货单以「系统建议」的形式出现在店长的PDA上允许修改店长按确认后才真正生成采购订单——这个设计很重要我第一次上线时把系统输出直接接进采购系统当天就被店长投诉「AI乱下单」后来改成建议制店长反而每周采纳率到了七成。做这个项目最深的教训是预测系统的价值不在模型精度在于让有经验的人愿意用把确认键交给店长模型才能从黑匣子变成好用的工具。希望帮到你。本文还有配套的精品资源点击获取
返回列表