为什么生鲜补库存不能直接套通用公式?聊聊补货系统的设计逻辑

1 评论 327 浏览 0 收藏 19 分钟

生鲜配送的补货难题,靠经验还是算法?本文拆解了一套基于MRP改造的补货模型,从预测、损耗率到安全库存,每个参数都藏着生鲜品类的特殊取舍。算法不是万能,但加上人工审核和可解释性,才能真正落地。

做生鲜配送这行久了,你会发现一个挺反直觉的事:最难的不是怎么把菜送到门店,而是每天到底该采多少菜。

采少了,门店断货,客户骂街;采多了,卖不掉,叶菜放一晚上就蔫,第二天只能折价甚至报损。我见过不少配送商,补货全靠老采购的经验和手感——干了十几年的老师傅确实准,可一旦他请假、离职,或者品类扩张超出他的经验范围,整个链条就开始乱。

所以我们花了挺长时间,把补货这件事从”拍脑袋”往”算法化”推。过程里踩了不少坑,也推翻过几版方案。这篇文章就把我们最后落地的设计逻辑讲清楚,重点不是说我们多牛,而是生鲜这个品类逼着你做哪些不一样的取舍。

先说结论:MRP那一套,生鲜用不了

如果你做过制造业或者看过ERP,对MRP(物料需求计划)不会陌生。它的逻辑很干净:订单量 × BOM用量 = 物料需求,再减去库存,就是采购量。精确、可追溯,上下游能对上账。

我们最早也想过直接搬这套。搬完发现不对劲。

问题出在生鲜的三个特性上:

  1. 需求是波动的。同一颗大白菜,工作日和周末能差出30%,碰上下雨天、节假日、促销,波动更夸张。制造业订单是确定的,生鲜订单是概率性的。
  2. 有损耗。白菜从采购到门店,清洗去根、运输磕碰、水分蒸发,到手可能只剩八成。MRP算的是净需求,不处理这种“路上就少了”的情况。
  3. 保质期短。不能像工业品那样囤安全库存兜底,囤多了过期,囤少了断货,安全库存本身就是个矛盾体。

所以最后我们的补货模型,本质上是对MRP做了一层”概率化改造”:用预测代替订单,用损耗率反向还原,用低水位安全库存做缓冲。下面拆开讲。

算法本身没那么玄,关键是每个参数怎么定

先上总公式,看着唬人,其实一句话能说清:

建议采购量 = (预测需求量 + 安全库存补差 − 当前可用库存) ÷ (1 − 损耗率)

翻译成人话就是:你明天大概要卖多少,加上你想留的底仓,减去现在手上还能用的,就是净需求;然后因为路上会损耗一部分,要往上除一下把损耗补回来。算出来要是小于等于0,就不采——说明库存够用。

预测需求量:别用简单平均

最直觉的做法是拿过去几天的销量平均一下当明天的预测。我们试过,不准。

原因很简单:最近的销量比早期的更能代表当下的趋势。一个月前卖得好不代表明天还卖得好,但昨天的销量大概率跟明天有关。所以最后用了加权移动平均,越近的权重越高。我们默认取最近7天,最近3天权重给到3,4到7天给2,再往前的给1。

基础销量算出来还不是最终的预测。还得乘一个波动系数,把”明天跟平时不一样”的因素叠上去。我们拆了四个因子相乘:季节、节假日、天气、促销。

这里有个设计选择值得说说:为什么是相乘不是相加?

相加是各自独立叠加,相乘是会放大的。国庆撞上促销,两个因子都往上拉,相乘能反映出”1+1>2″的叠加效应;相加的话就只是简单累加,会把这种共振给抹平。生鲜大促踩节点的场景不少,我们觉得相乘更贴近真实。

举个真实的例子。大白菜,最近7天日均走200kg,明天周末节假日系数1.3,手上有张50kg的预售单,那么:

基础销量 = 200kg(加权后)

波动系数 = 1.0 × 1.3 × 1.0 × 1.0 = 1.3

预测需求量 = 200 × 1.3 + 50 = 310kg

这310kg就是”明天大概率要准备的量”。

损耗率:用除法,不是加法

这是我自己踩过的一个坑,值得单独拎出来讲。

最初版本我们是把损耗加进去的:建议采购量 = 净需求 × (1 + 损耗率)。看着也对——损耗5%,那就多采5%嘛。

后来对账发现一直少采。想了一下才反应过来:加法是按”净需求”的比例补,但损耗是发生在采进来的总量上的。你采100kg、损耗5%,到手是95kg,不是105kg。要拿到手的量正好满足需求,得反向除回去:净需求 ÷ (1 − 损耗率)。

所以是除法。别小看这个区别,损耗率一高(叶菜能到8%-10%),加法和除法算出来的采购量能差出一截,天天少采,天天断货。

损耗率我们在商品档案里预设好了,按品类给经验值:叶菜5%-10%,根茎3%-5%,冻品1%-2%。不是拍脑袋,是跑了三个月历史加工数据回算的均值。

安全库存:低到反直觉

制造业的安全库存动辄按周算,生鲜不行。白菜你囤三天试试?

我们最后定的是1.5天。说实话这个数定下来的时候我也犹豫——这么低,万一预测偏差大不就断货了?

后来想通了:生鲜的安全库存不是用来”扛住一切波动”的,那不现实。它的作用是兜住日常的小幅偏差和供应链到货的时差。真正的大波动(节假日、促销)靠波动系数在预测端就处理掉了,不该全压在安全库存上。安全库存兜底兜的是”算法没料到的小意外”,不是”已知的大事件”。

这个区分挺重要。很多人做补货会把所有不确定性都塞进安全库存,结果安全库存越调越高,损耗跟着起飞。把已知波动交给预测系数、把未知小波动交给安全库存,各司其职,整个模型反而更稳。

可用库存:别把临期的算进去

可用库存这个数看着简单——仓库里有多少就是多少嘛。其实不是。

仓库里的货不是都能拿来配的。临期的要锁掉(配给门店也是坑客户),已经报损的要剔除,已经分配给别的订单但还没出库的得扣掉,可用库存 = 在仓可用 − 已分配未出库

少算一个”已分配未出库”,就会出现一货两配,A门店的货被算给了B门店,到时候谁都拿不到。 这种低级错误早期我们犯过,被运营追着骂。后来把可用库存的口径锁死,才消停。

把这四个数凑齐,公式就能跑起来了。

还拿那颗大白菜:预测需求量 = 310kg

安全库存 = 200 × 1.5 = 300kg

当前可用库存 = 80kg

安全库存补差 = max(300 − 80, 0) = 220kg

建议采购量 = (310 + 220 − 80) ÷ (1 − 0.05) = 450 ÷ 0.95 ≈ 473kg

第二天凌晨采销上班,系统已经把473kg这个数摆在那了,他过一眼、调一调、点确认,采购单就下去了。

流程上:算完不等于买,必须留人工这道关

算法算得再漂亮,我们也没敢做成全自动下单。每天凌晨跑完建议量,按供应商自动拆好单,生成采购建议单,然后采销人工审核,确认后才转成正式采购单。

有人会觉得这不就退化成半自动了嘛,算法白做了。我不这么看。算法有算法的盲区。突发的大客户订单、供应商临时通知涨价或缺货、某个门店被罚停配送——这些信息算法看不到,但采销知道。留这道口子,是为了让”算法的稳定基线”和”人的现场判断”能接上。

我们也试过提高自动化程度,结果就是偶尔翻车——某次系统按历史规律建议大批量采购某单品,结果当天那个门店因为食安问题被停业整顿,采销没拦住就采进来了,全砸手里。从那以后人工审核就成铁律了。

不过人工审核有个前提:算法得把”为什么建议这个数”讲清楚,不然采销审不动,最后还是凭感觉改。我们在建议单上会标出来这个数是怎么算的——预测多少、库存多少、损耗多少,让采销能快速判断哪个数不对、该调哪里。算法要可信,得先可解释。

真正绕不开的:生鲜加工BOM

前面讲的补货,默认门店要的是”原料”——大白菜就是大白菜。但实际业务里,很多门店要的是净菜成品:净白菜段、净土豆丝、蔬菜拼盘。这时候补货量和采购量就不是一回事了。

1kg大白菜洗完切完,到手大概0.85kg净白菜段。门店要85kg净白菜段,你采购的不能是85kg大白菜,得是100kg。

这个”原料→成品”的转换关系,我们借了制造业BOM的思路来做,但做了适配。

出成率是整个BOM的命门

BOM里最关键的参数是出成率:1kg原料能出多少kg净菜。它直接决定采购量和成本。

出成率这东西,难点不在”给个值”,而在”它不是个固定值”。同一颗白菜,产地不同、季节不同、加工的人手熟不熟,出成率都能上下浮动。你要是写死一个85%,实际加工出来只有78%,要么原料不够得临时补采,要么采多了浪费。

我们的处理是双轨:

  • 标准出成率:商品档案里的预设值,按品类经验给(叶菜80%-85%,根茎85%-92%,瓜果90%-95%这些),作为采购反算的基准。
  • 实际出成率:每次加工都记录“实际领了多少料、实际出了多少成品”,算出真实的出成率。 两个值对比,偏差超过5%就预警。这个预警不是为了罚谁,是用来发现问题的——持续偏低可能是原料品质在下滑,或者加工岗位需要培训;偶尔偏高可能是称重有问题。出成率波动控制在5%以内,对补货大局基本没影响,因为安全库存有缓冲兜着。

多层BOM:净菜还能再拼成拼盘

单层BOM是”1个原料→1个净菜”,比如白菜→净白菜段。但还有种业务:把好几个净菜拼成一个蔬菜拼盘卖给门店。这时候净菜成品本身又变成了下一层BOM的原料。”净白菜段”既是白菜加工的成品,又是蔬菜拼盘的子件。系统靠成品编码串起来,层层往上展开算原料需求。

拼盘500g = 净白菜段0.3kg + 净土豆丝0.2kg

净白菜段0.3kg ← 需要大白菜 0.3 ÷ 0.85 ≈ 0.35kg

净土豆丝0.2kg ← 需要土豆 0.2 ÷ 0.88 ≈ 0.23kg

这种多层结构的好处是,门店不管要净菜还是要拼盘,系统都能一路反推到最底层的原料采购量,采销看到的永远是”今天该买多少斤白菜、多少斤土豆”,不用人工换算。

成本怎么算回来:BOM不只是算采购量,还要算成本。毕竟你得知道这盘净菜到底花了多少钱。

成品单位成本 = (原料用量 ÷ 出成率 × 原料采购价 + 加工费) ÷ 成品量

还是白菜那个例子:大白菜采购价2块/kg,出成率85%,每kg成品加工费3毛。

净白菜段成本 = (1 ÷ 0.85 × 2.0 + 0.3) = 2.35 + 0.3 = ¥2.65/kg

卖3.5/kg,毛利大概24%。这个数采销才敢定价。

这里有个细节我们一开始没做好:成本要用实际出成率回写,不能用标准值。早期我们图省事用标准出成率算成本,结果库存账面价值和实际总有出入,月底盘点对不上。后来改成每次加工完按实际出成率重算成本、更新库存账面价值,账才平了。生鲜这块,账实相符是硬指标。

补货和BOM是怎么接上的

最后把两块拼起来,说说它们怎么衔接,因为这是新人最容易绕晕的地方。逻辑其实一句话:门店要的是成品(净菜/拼盘),系统通过BOM反算成原料需求,再把原料需求喂给补货公式算采购量

举个串联的例子。门店明天要85kg净白菜段:

  1. BOM反算:85 ÷ 0.85 = 100kg大白菜(这是原料需求)
  2. 补货公式:100kg作为“预测需求量”的一部分,减去可用库存、加安全库存补差、除以损耗率,得到建议采购量
  3. 采销审核确认,下单给供应商
  4. 到货后进材料库,加工时领料出库,按工序加工,成品入库到成品
  5. 配送时从成品库出给门店BOM负责“成品↔原料”的转换,补货公式负责“该买多少”。

两者各管一段,接口就是那个反算出来的原料需求量。这样设计的好处是解耦——改BOM不用动补货算法,调补货参数也不影响BOM结构。

几个值得反思的点

做完这套之后回头看,有几个判断我觉得是对的,也有几个当初可以做得更好。

  • 对的地方,是没盲目追求全自动。生鲜这个品类变量太多,全自动下单的翻车成本太高,留人工审核反而是更务实的选择。算法的价值不在于“替代人”,在于“把人从算数的苦力活里解放出来,让他专注做判断”。
  • 对的地方,是出成率用双轨、损耗用除法这两个细节。看着小,实际天天在影响准确率,是模型能不能站住脚的关键。

可以更好的地方,是预测模型还比较粗。我们用的是加权移动平均+四个手工系数,系数靠经验调。品类一多(光蔬菜就好几百个SKU),调系数就成了体力活,而且人调出来的系数带主观偏差。下一步想做的是把波动系数从”人工配置”往”数据驱动”推——至少季节和天气这两个因子,用历史数据回归出来比拍脑袋准。不过这是后话,现阶段手工系数配合采销审核,够用。

还有一点想聊的:生鲜补货的尽头不是算法多精巧,而是数据多干净。我们模型升级了好几版,每次准确率提升最大的,往往不是算法变复杂了,而是上游数据质量改善了——销量录入及时了、库存盘点准了、损耗登记不漏了。算法决定下限,数据决定上限;算法是放大器,喂进去的数据有多干净,放大出来的结果就有多可信。

写在最后

补货这件事,制造业有现成的MRP可以抄,但是生鲜业务抄不动。需求波动、损耗、短保质期,这三个特性逼着你把”确定性”的MRP改造成”概率性”的补货模型。

我们这套不算多先进,但好在贴着业务跑,踩过的坑都填了,能稳定地每天凌晨把建议单摆到采销面前。至于它算不算”智能”,我倒不太在意——能帮采销少加点班、少断几次货、少报几次损,就值了。如果你也在做生鲜或者类似的短保品类配送,欢迎聊聊。

本文由 @Totoro畅 原创发布于人人都是产品经理,未经许可,禁止转载

题图来自 Unsplash,基于 CC0 协议

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
评论
评论请登录
  1. 人工审核留一道口的做法很靠谱,算法负责算数,人负责判断异常,两者互补才能落地。生鲜配送就是需要这种半自动的节奏。

    来自广东 回复