
简介供应设计与优化讲义是一份面向供应链、采购与物流管理从业者及企业中高层管理者的完整培训PPT。内容以物流是第三利润源泉为切入点结合外包物流与供应链从集成型到协作型、智能型的发展趋势梳理采购物流、生产物流、分销及回收物流等核心环节同时覆盖仓储管理系统作业流程、交通运输管理发展方向、SCOR模型等实操工具可帮助读者建立系统化的供应链优化框架。讲义由拥有MIT与中山大学IMBA背景、ITC采购与供应链管理认证的讲师分享兼具行业实践经验与教学视角。文件为1个PPTX演示文稿大小约3.37MB章节结构清晰适合企业内训、课程讲授或个人进阶学习。目前已有99人学习下载适合关注降本增效、物流网络优化与采购战略转型的读者参考。1. 为什么我建议用模型语言讲供应链设计与优化很多供应链讲义的通病是把“设计与优化”拆成两页相互独立的PPT一页放网络图、一页放KPI。听众当时点头回到工位还是不知道一个仓库该不该建、库存水位该定多少。我做了几年网络规划项目后最大的感受是光凭经验拍板的布局和用数学模型算出来的方案相比综合成本往往高出 8% 到 15%更麻烦的是人工方案在需求波动时根本解释不清“为什么这么配置”。所以这份讲义的核心主张是直接反过来讲供应链设计与优化先从可求解的数学模型立住再讨论参数和策略。目标是让听的人回去就能复现而不是只记住结论。它适合网络规划工程师、做决策支持的数据团队以及想从 Excel 跳出来的运营分析师。2. 供应链网络设计模型从成本拆解到 MILP2.1 网络设计要回答的三个问题供应链网络设计不是画一张带箭头的图它必须回答三个具体问题网络设几层是工厂到仓库再到门店还是工厂直发门店设施放在哪些候选地址自建还是租赁每个客户订单由谁履约是按距离就近分配还是按容量均衡分配这三个问题互相耦合单独回答任何一个都会出偏差。常见做法是把网络设计拆成两类模型处理。第一类是覆盖模型目标是在满足服务时效的前提下用最少的设施覆盖全部需求适合“先定数量、再看位置”的布局阶段。第二类是 p-中位模型给定设施数量总运输成本最小适合已经在运营、想调整仓网的场景。讲义里我会先讲 p-中位模型因为它的结果更容易和成本数据对上听众也更有体感。要想在一页 PPT 里把问题讲清楚最好把“成本”拆成两段一段是设施相关的固定成本比如场地租金、设备摊销、基础人力跟吞吐量关系不大另一段是流量相关的变动成本主要是运输和作业费用。网络设计优化的本质就是在这两类成本之间找平衡点。仓库多了运输省了但固定成本涨上去仓库少了固定成本低长途运输和时效风险又上来了。2.2 把问题写成混合整数线性规划用一张符号表讲清楚模型的优势在于把模糊的权衡变成明确的约束。我一般用一个容量受限的设施选址问题作为讲义主案例它属于混合整数线性规划MILP。写模型之前先在讲义里放一张符号表这一步别省略。听众如果看不懂符号后面所有求解结果都等于黑箱。符号含义示例值(D_i)需求点 i 的需求量300 件/周期(F_j)候选设施 j 的固定成本45000 元/周期(C_j)候选设施 j 的容量上限900 件/周期(d_{ij})从 j 到 i 的单位运输成本按距离 ×5 元/件·公里(y_j)决策变量是否启用 j取 0 或 1(x_{ij})决策变量j 分配给 i 的货量连续非负目标函数写为最小化固定成本与运输成本之和决策变量是 (y_j) 和 (x_{ij})。约束就三条每个需求点必须被完全满足每个设施的出货量不能超过自身容量未启用的设施不能出货。第三条约束是靠 (x_{ij} \le C_j y_j) 这类不等式实现的它把整数变量和连续变量捆在一起这正是 MILP 的核心。这里要提醒一句运输成本不要直接写“距离×单价”要把费率单位写清楚。是按件公里、吨公里还是整车按趟单位错了模型结果在方向上有参考价值但在绝对值上完全没法用于预算。讲义里我会单独留一页讲单位换算。2.3 用 Python PuLP 跑通第一个最小案例光有模型公式还不够讲义上必须有一个能当场跑出结果的代码示例。我在课上的做法是先用 5 个需求点、3 个候选仓库的最小案例把完整过程演示一遍。PuLP 是 Python 里最容易上手的 LP/MILP 求解库语法直观开箱即用。import pulp import math # 需求点坐标与需求量 demand { A: (10, 20, 300), B: (30, 40, 250), C: (50, 15, 400), D: (70, 60, 200), E: (90, 35, 350), } # 候选仓库: 坐标, 容量, 固定成本 warehouses { W1: (20, 30, 700, 30000), W2: (60, 30, 900, 45000), W3: (85, 50, 600, 36000), } freight_rate 5 # 元/(件·公里) prob pulp.LpProblem(facility_location, pulp.LpMinimize) # 0/1 变量: 是否启用仓库 open_flag {} for w in warehouses: open_flag[w] pulp.LpVariable(fopen_{w}, catpulp.LpBinary) # 连续变量: 分配量 assign {} for w in warehouses: for d in demand: assign[(w, d)] pulp.LpVariable(fassign_{w}_{d}, lowBound0) # 目标函数: 固定成本 运输成本 prob pulp.lpSum( open_flag[w] * warehouses[w][3] for w in warehouses ) pulp.lpSum( assign[(w, d)] * math.hypot(warehouses[w][0] - demand[d][0], warehouses[w][1] - demand[d][1]) * freight_rate for w in warehouses for d in demand ) # 约束1: 每个需求点被完全满足 for d, (_, _, qty) in demand.items(): prob pulp.lpSum(assign[(w, d)] for w in warehouses) qty # 约束2: 容量上限 未启用仓库不能出货 for w in warehouses: prob pulp.lpSum(assign[(w, d)] for d in demand) warehouses[w][2] * open_flag[w] prob.solve() print(求解状态:, pulp.LpStatus[prob.status]) print(总成本:, round(pulp.value(prob.objective), 2)) for w in warehouses: if pulp.value(open_flag[w]) 0.5: used pulp.value(sum(assign[(w, d)] for d in demand)) print(f启用 {w}, 实际处理量 {used:.0f} 件)代码逻辑不复杂但有三处值得在台上强调。第一open_flag是二进制变量代表仓库开还是不开assign是连续变量表示从哪个仓库向哪个需求点送多少货。两者通过容量约束乘在一起这就是 MILP 和普通线性规划的差别。第二目标函数里把固定成本和运输成本放在同一量纲下比较如果固定成本是年化的运输成本也得折算到同一周期。第三距离用math.hypot算的是欧氏直线距离真实场景应替换为路网距离矩阵否则短途仓和长途仓的相对成本会失真。在这个参数下模型大概率会给出一个包含 W2、W3 的方案因为 W1 虽然固定成本最低但距离需求点群较远运输成本会堆上去。我会现场演示把 W1 的固定成本从 30000 改成 20000再跑一次看模型如何切换方案。这个动作比任何文字解释都更能让听众理解“权衡”的含义。3. 网络定完库存策略里的服务水平参数是下一层优化3.1 为什么网络设计和库存优化要放在同一节课网络设计解决的是“货从哪发”但仓库建好之后每个仓库放多少库存、什么时候补货是另一层优化问题。很多讲义把两者分开讲实际业务里它们互相影响仓库多了每个仓的库存水平可以降低但总库存未必少因为每个仓都要备安全库存。反过来说如果网络优化为了省运输把需求集中到一个大仓这个仓的安全库存会显著上升。我一般把这两部分放在同一节课里的原因是它们共用同一个方法论建模、求参、验证。库存优化的参数更贴近日常听众接受度高网络设计的模型更复杂放在前面打底。这样整份讲义是从“结构”走向“水位”逻辑上顺。3.2 安全库存公式与服务水平 z 值的取舍库存优化里最常用、也最容易讲飘的是安全库存公式。需求与提前期都服从正态分布时安全库存 (SS) 的计算公式是[ SS z \times \sqrt{LT \times \sigma_d^2 d^2 \times \sigma_{LT}^2} ]其中 (LT) 是平均提前期(\sigma_d) 是需求标准差(d) 是平均日需求(\sigma_{LT}) 是提前期标准差。这个公式比只用 (z \times \sigma_d \times \sqrt{LT}) 更完整因为它把提前期本身的波动算进去了。实际供应链里提前期波动对安全库存的影响往往比需求波动更大这一点很多从业超过五年的人都容易忽略。讲义里要放一张服务水平与 z 值的对照表但不能只给数字得说清它们的前提。周期服务水平z 值对应年平均缺货天数(按每日补货周期)90%1.2836.5 天95%1.6518.3 天97.5%1.969.1 天99%2.333.7 天注意这里的服务水平是“周期服务水平”即一个补货周期内不缺货的概率不是“订单满足率”。两者在实际业务里经常被混用。满足率还涉及缺货数量的计算同样的 95% 周期服务水平对应的订单满足率可能只有 92% 到 97%取决于需求分布。如果听众直接拿满足率目标来反查 z 值库存结果会系统性偏低。我会在讲义里建议把服务目标定义成“订单满足率≥98%”而不是“服务水平 98%”。前者的业务含义明确后者的统计口径容易被挑战。3.3 用离散事件模拟验证安全库存参数的合理性公式算完必须验证。最稳妥的验证方法是写一个小型离散事件模拟把需求、提前期、补货策略都放进去看缺货比例是否真的在目标附近。这一步是讲义里最有说服力的演示因为它回答了“z 值设对了没有”这个关键问题。import numpy as np np.random.seed(42) lead_time_mean 7.0 # 平均提前期天 lead_time_std 1.5 # 提前期标准差天 demand_mean 50.0 # 平均日需求件 demand_std 8.0 # 日需求标准差件 reorder_point 430.0 # 再订货点: 提前期需求均值 安全库存 replenish_qty 500.0 # 补货量 sim_days 3650 # 模拟10年 inventory 150.0 stockout_days 0 total_short 0.0 for day in range(sim_days): lt max(0.0, np.random.normal(lead_time_mean, lead_time_std)) daily_demand max(0.0, np.random.normal(demand_mean, demand_std)) inventory - daily_demand if inventory 0: stockout_days 1 total_short -inventory inventory 0.0 # 简化策略: 每天检查再订货点 if inventory reorder_point: # 提前期内需求会继续消耗库存这里用近似方式模拟 inventory replenish_qty - demand_mean * lt print(模拟天数:, sim_days) print(缺货天数占比:, round(stockout_days / sim_days, 4)) print(平均缺货量(件):, round(total_short / max(stockout_days, 1), 2))这段模拟省略了一些细节比如提前期内的滚动消耗但作为讲义演示足够说明方法论。参数里最关键的是reorder_point它由提前期平均需求 (d \times LT) 加上安全库存组成。把reorder_point从 430 改成 410再跑一遍缺货天数占比会明显上升往上加到 460占比下降但库存持有成本增加。听众直观看到“服务水平和库存成本”的交换关系比任何公式都有效。我建议在演示时用同一组随机种子跑两组对比一组按 z1.65 设再订货点一组按 z1.28最后把缺货比例和平均库存量列成对比表。这样既讲了模拟方法又把参数敏感性的概念带了出来。4. 把讲义做成可复现的决策模板数据后处理和演示结构4.1 从固定数据到参数化让听众能自己改讲义最容易翻车的地方是演示案例写死。PPT 里贴了一个固定输入、一个固定输出听众看着觉得有道理回去换个数据就不知道从哪里下手。我在课程里会把所有代码封装成函数输入参数单独放一个单元格方便当场改参数重新求解。常见做法是把案例组织成三块原始数据、模型封装、结果展示。原始数据包括需求点、候选设施、费率这些业务输入模型封装是上文的 PuLP 或模拟代码封装成solve_network(demand, warehouses, freight_rate)这样的函数结果展示则固定输出“启用哪些仓、总成本、各仓处理量”。这样一份讲义实际上就是一个交互式决策模板听众只需要改第一块的数值后面自动重算。PPT 里不要贴大片代码而是放参数表和运行结果截屏。真正可运行的代码放到随课 Jupyter Notebook 里页面上只留关键几行。同时讲义必须在醒目的位置注明参数单位避免重新建模时把吨和件混在一起。4.2 三个最容易翻车的数据后处理错误我见过不少有经验的分析师在建模上没问题反而在数据准备阶段输掉了整个项目。讲义里我会专门安排一页把这三个高频错误列出来并用表格对比正确与错误的做法。坑错误表现正确处理单位/口径不一致需求按件、费率按吨、容量按立方米统一换算到同一单位周期标注每个字段的度量单位需求被均值化抹平年度需求除以 12 当成月需求保留季节性曲线至少区分淡旺季需求求解结果直接当成运营指令模型建议按周分配但采购周期是月检查模型周期与业务执行周期是否一致这一类内容看起来很基础但它决定听众是否信任模型。我会在讲义里强调一个原则任何模型输出在进入决策流程前先跑一遍“极端参数测试”。比如把某需求点需求量翻倍看结果合不合理把某个仓库容量设成极小值看模型是否把它自动关闭。如果这些测试暴露了明显违背常识的结果大概率是数据或约束写错了。4.3 每个章节留一个动手改的参数练习讲义的节奏不要一直由讲师单向输出。我习惯在每章末尾放一个“动手改”任务任务之间互相衔接最终汇成一个完整项目。这种方式比练习题更贴近真实工作因为它要求听众同时理解数据和模型两处都修改才能得到合理结果。章节间的递进可以这样设计网络设计章节任务是把候选仓库固定成本分别调低 20%观察设施组合的变化并说明原因库存章节任务是在同组参数下把服务水平目标从 95% 改成 97.5%重新计算安全库存量化库存成本增量数据准备章节任务则是加入一个季节系数让需求按月度波动再重新跑整个模型。三个任务做完听众基本形成了从数据到模型到决策的完整闭环。同时讲义里要预留“结果记录页”。每一次参数修改后记录四列修改了哪个参数、改前结果、改后结果、业务解释。这四列看起来简单但它能有效防止听众只关注最后一行总成本忽略中间过程。5. 用敏感性分析让优化结论更可执行影子价格和参数边界模型求解出来只会告诉你“最优解是什么”不会告诉你“如果参数错了最优解会怎么变”。可是供应链的数据质量通常是参差的需求预测偏差动辄 20%运输费率也时常调整。所以讲义最后一节我通常不讲新模型而是集中讲敏感性分析这是让优化结论从“理论最优”走向“可执行决策”的关键一步。敏感性分析最直接的做法是固定其他参数把某个关键参数按步长上下扰动重新求解记录总成本和设施组合。比如在设施选址模型里把需求总量分别偏移 ±10%、±20%观察启用仓库的组合是否变化。如果最优方案在一个较宽的参数区间内保持稳定说明方案是稳健的如果参数只要变动 5% 就换仓那这个边界恰恰是决策者最需要知道的风险点。这类分析能直接回答业务方常问的“如果预测不准怎么办”比单纯强调模型精度更有说服力。建模层面还有一个更精细的工具影子价格。PuLP 求解完线性规划后可以读取约束条件的影子价格它反映的是某个约束放松一个单位时总成本可以下降多少。# 工程中检查约束的影子价格判断哪个瓶颈最值得投入 for name, constraint in prob.constraints.items(): if constraint.pi is not None and abs(constraint.pi) 1e-6: print(name, 影子价格:, round(constraint.pi, 4))这段代码的作用是识别瓶颈。比如容量约束的影子价格是负数且绝对值很大说明当前仓库容量不足追加一个单位产能能显著降低成本。在供应链语境下影子价格可以换算成“容量投资的边际价值”帮助判断扩建仓库、增加产线或者更换供应商哪个更划算。讲义里我会放一张汇总表展示三个典型溢价的解读方式。参数扰动灵敏度结果示例业务含义需求总量 10%总成本 4.2%设施组合不变方案稳健不需要调整布局运输费率 -20%一个仓库被关闭成本 -5.1%费率变化会改变仓网结构固定成本 15%两个仓库方案切换到单仓该边界是决策红线判断结论是否可信有一个实用技巧把仿真结果与固定成本对比看仓库组合切换是否合理。比如费率降低导致仓库关闭是合理的但如果模型出现某个仓库只分配了很小一部分产能而另一个仓库接近满载这通常是约束条件设置不平衡的信号值得回到数据检查。我用这个章节收尾是因为离开敏感性分析优化项目交付后几乎必然被业务挑战。而能主动给出边界、给出参数变化影响正是资深工程师与只会跑模型的人的区别。最后建议听众修改完参数后把总成本变化率与参数变化率相除得到一个弹性系数下次评审时直接展示这两个数字说服力比贴模型输出强得多。本文还有配套的精品资源点击获取