本文记录笔者如何从简单的假设案例开始,通过计算机模拟“人脑”思考模式,逐步构建生产排产调度器,解决生产调度中库存最小化的核心问题。


一、现实中的排产到底有多“麻烦”?

在制造型企业的日常运营中,生产排程(Production Scheduling)几乎是供应链管理中最为关键的环节之一。它不只是“安排生产什么时候开始”,更是对 资源配置时间管理成本控制 和 客户满意度 的多重平衡。在现实中,生产排产至少会遇到以下的难题:

1. 交期压力的“刚性”考验

  • 客户 SLA(Service Level Agreement)往往对交期有严格约定。
  • 延迟交付不仅意味着违约罚金,还可能让客户转向竞争对手。

2. 产能与资源的“多维约束”

  • 产线稼动率:设备效率、巡视/保养窗口、换线切换时间。
  • 人力排班:工时法规、加班成本、技能匹配。
  • 原料库存:原材料到位时间、库存消耗率、JIT(Just-In-Time)风险。

3. 库存成本与资金周转的权衡

  • 持有成本 = 仓储费用 + 资金占用利息 + 保险和损耗。
  • 缺货成本 = 客户赔偿 + 生产线停产损失。
  • 库存周转率 作为 KPI 直接影响企业现金流与利润。

4. 工作日历与非连续时段

  • 标准工时:08:00–18:00,单班制或双班制。
  • 非工作日:周末、国家节假日、计划检修。
  • 排程须嵌入组织日历,才能防止跨期误算。

5. 多订单与多目标的“双刃剑”

  • 同时面对多条产线多工序多产品
  • 目标冲突:最小库存 vs. 最高按时率 vs. 最大产能利用率,涉及多目标优化分层决策

为了解决这个复杂的问题,笔者决定以准时交付为前提,追求最小库存的目标,设计一个排产管理器。在本文中,为了简化问题,本文将暂时忽略一些复杂的情况,比如原材料供应波动、工作日与节假日的变化、多产品多产线的并行等问题。研究将首先以一条产线、一种产品、多个订单、标准工时以及原材料充足为前提进行。随着研究的深入,笔者会在未来的文章中逐步引入更贴近生产实际的条件,进一步充实和优化的模型。


二、从复杂到简化:笔者的“认知建模”思考路径

在以往的学习生涯中,我们知道有许多算法和数学模型可以辅助我们做出科学的决策。但在企业中,那些经验丰富的排产员往往凭借多年直觉与积累,也能完成复杂的生产安排。虽然他们没有使用任何数学模型或算法,但他们的判断往往比系统更贴近现实、更少出错。这种“人脑最优解”是否能被建模并借助计算机复制和放大?这成为了笔者思考的起点。

因此,笔者计划暂时抛开复杂的数学公式,尝试从人类调度员的决策习惯出发,还原他们在资源冲突、交期压缩、订单插队等情境下的应对策略,进而构建出一套更加“人性化”和“实用”的调度模型。

基于这个想法,笔者在项目开始潜在脑海中搭建了一个“思考实验室”,对多种订单组合和极端场景进行想象推演。每一次心智模拟都帮助笔者理清思路,过滤掉不切实际的方案,形成系统化的调度策略。最终交由计算机模拟整个思考逻辑,形成自动化方案。

以下是笔者认知建模的详细过程:

  1. 直觉观察
    • 调度员往往先在白板上迅速手绘甘特图,标出最晚交期节点和各任务所需的工时。
    • 这种“手算”过程中,能快速发现资源冲突和潜在瓶颈。
  2. 策略归纳
    • 从手算中提炼出两大核心逻辑:
      • 后推(Backward):以交期为锚点,从最晚节点往前推算。
      • 前推(Forward):以最早可开工为起点,顺序安排。
  3. 代码演练
    • 将归纳出的主要策略转化为计算机语言
    • 思考几种不同的典型案例用于测试
for each order sorted by due_date desc:
    compute hours_needed
    if backward mode:
        end_time = min(due_date, previous_start)
        start_time = end_time - hours_needed 穿越多个工作日
    else:
        start_time = max(prev_end, earliest_start)
        end_time = start_time + hours_needed 考虑每日班次
  1. 可视化输出
    • 在测试中,为每个案例输出每个订单的生产开始和结束时间以及预计交付时间。
    • 绘制甘特图,直观展示排产结果。
  2. 细节迭代
    • 在主要策略的基础上引入 production_gap 控制订单之间的最小间隔,避免生产时间的重叠。
    • 将“工作日界限”(08:00–18:00)封装成工具函数,实现跨日计算。 

三、案例演绎:四种典型场景剖析与推导流程

认知建模的核心是找到有代表性的案例,辅助策略归纳。在此章节,笔者将介绍自己用到的3个案例,并将每个案例的推导过程具体拆解成多步,配以流程图示意,帮助读者形象理解调度员的决策链条。

📦 Case 1:后推调度——零库存最优解

场景描述

  • 三个订单,交期依次为 4.11、4.21、5.1,原材料供应充足,每件产品生产需要0.5小时,当前日期4.1日。具体订单需求如下:
订单编号需求数量交货日期
11002025-04-11 18:00
2202025-04-21 18:00
31002025-05-01 18:00

这是最理想的情况,通过简单的计算,我们可以发现由于每个订单都可以在交货期间隔内完成,所有订单都可以通过排产实现按时交付且零库存。因此,只需从后向前逐步推算生产计划即可。

推导流程

  1. 定位最晚完工节点:订单3(5.1 18:00)→设为倒推起点。
  2. 分配工时
    • 订单3 需 50h,跨 5 个工作日 → 4.27 08:00 开始。
    • 记录 O3 开始与结束。
  3. 更新倒推边界:下一笔最晚结束点 = O3 开始时间(4.27 08:00)减去 production_gap
  4. 重复分配:依次倒推 O2、O1,保证各自结束 ≤ 倒推边界。
  5. 验证库存时间:生产结束时间即发货,无任何库存产生。

流程图示意

[5.1 18:00] ←—— O3(50h) ——→ [4.27 08:00]
      ↑
      |   production_gap
      ↓
 [倒推边界]
      ↑
 [O2/O1 倒推出发]
OrderQtyDue DateProd Hrs推算开始推算结束Holding
O110004-11 18:005004-07 08:0004-11 18:000 days
O22004-21 18:001004-21 08:0004-21 18:000 days
O310005-01 18:005004-27 08:0005-01 18:000 days

📦 Case 2:前推调度——产能瓶颈下的应急方案

场景描述

  • 三个订单,交期依次为 4.10、4.20、4.30,原材料供应充足,但订单需求量大。每件产品生产需要0.5小时,当前日期4.1日。具体订单需求如下:
订单编号需求数量交货日期
12002025-04-10 18:00
23002025-04-20 18:00
34002025-04-30 18:00

在这种情况下,每个订单的需求量都较大。车间不仅无法在交货间隙完成单个订单的生产,也无法在交货期内完成所有货品的交付。我们的目标不得不由兼顾库存成本改为保证尽早交付,以减少延期交付的损失。因此,最好的方式是从当前时间节节点(4月1日8:00)开始安排生产,然后对延期的情况进行预警。

推导流程

  1. 判断累计可用时长total_available_hours = days * hours_per_day < total_required_hours →切换前推调度模式。
  2. 顺序分配
    • O1 先排:04.01 08:00▶︎04.10 18:00。
    • O2 下一个订单:开始于 O1 结束后 + production_gap (次日 08:00)。
    • O3 类推,完工为 5.15。
  3. 标记延期:O2/O3 完工 > 交期,打⚠️。

流程图示意

04/01 08:00 ──── O1(100h) ──── 04/10 18:00 
      └─+gap→ 04/11 08:00 ──── O2(150h) ──── 04/25 18:00⚠
                  └─+gap→ 04/26 08:00 ──── O3(200h) ──── 05/15 18:00⚠
OrderQtyDue DateStartEndAdjusted DueWarning
O120004-1004-01 08:0004-10 18:0004-10 18:00No
O230004-2004-11 08:0004-25 18:0004-25 18:00Yes
O340004-3004-26 08:0005-15 18:0005-15 18:00Yes

📦 Case 3:局部前移——解决重叠冲突

场景描述

  • 三个订单,交期依次为 4.18、4.20、4.25,原材料供应充足。每件产品生产需要0.5小时,当前日期4.1日。具体订单需求如下:
订单编号需求数量交货日期
11002025-04-18 18:00
2802025-04-20 18:00
31002025-04-25 18:00

这个案例整体工时充足,与case1类似,但各个订单间的时间间隔不足以完成单一订单的生产。例如, O1 与 O2 倒推过程中,如果仅以库存最小化为目标,生产时间区段会发生重叠。因此,综合考虑按时交付,我们不得不局部提前部分订单的生产(哪怕付出一些库存成本)。这是在后推策略基础上的局部调整。

推导流程

  1. 标准后推:先倒推 O3,再倒推 O2 到 [4.20, 4.17]。
  2. 检测冲突:若 O1 倒推结束晚于 O2 推算开始 → 需局部前移。
  3. 局部前移:令 O1 结束点 = min(其交期, O2 开始点 – gap)。
  4. 重新倒推:从新的结束点往前分配 O1 工时,确保无缝衔接。

流程图示意

[倒推O3]→|O3:04-21~04-25|
           ↓(gap)
       [倒推O2]→|O2:04-17~04-20|
           ↓(gap)
【标准O1倒推】|O1:04-09~04-13| ← 冲突!重叠 →【局部前移】|O1:04-12~04-16|
OrderQtyDue DateProd Hrs推算开始推算结束Holding
O110004-18 18:005004-12 08:0004-16 18:002 days
O28004-20 18:004004-17 08:0004-20 18:000 days
O310004-25 18:005004-21 08:0004-25 18:000 days

📦 总结:方法归纳

通过以上三个案例,我们已经找到了生产排产的一般规律:

整体资源充足? ——> 是
  ↳ 后推调度 (Backward)
    ↳ 有局部冲突? ——> 提前局部前移
    ↳ 无冲突 ——> 正常后推
  ↳ 否 ——> 前推调度 (Forward) + 延期预警

五、代码实现:排产计划01(详解与调试指南)

在思路推演和案例验证的基础上,笔者将归纳后的方法落地为一段易用的 Python 代码——“排产计划01”:

5.1 核心模块

class ProductionScheduler:
    def __init__(...):
        # 初始化:起始时间、每日可用工时、产品工时、订单间隔
    def schedule(self, orders):
        # 调度入口:先尝试后推,失败时切换前推
    def _backward_schedule(self, orders):
        # 后推算法:倒序处理、跨日计算、冲突检测
    def _forward_schedule(self, orders):
        # 前推算法:顺序处理、插单预警
    def _calculate_start_time(...):
        # 从结束时间向前循环减小时,跨天处理
    def _calculate_end_time(...):
        # 从开始时间向后累加小时,跨天处理
    def plot_gantt(...):
        # 可视化:甘特图、交付线、数量标注

注意点

  • schedule():务必先将所有 delivery_date 规范到带时分的 datetime,并在切换模式时重置状态。
  • _backward_schedule():倒推时要精准处理 08:00/18:00 边界,并使用 production_gap 调整间隔。
  • _forward_schedule():若完工恰好为 18:00,下一笔应从次日 08:00 开始。
  • _calculate_start_time() 与 _calculate_end_time():跨日累加/扣减工时时,需即时跳转至最近工作时段,避免遗漏工时或卡死循环。
  • plot_gantt():确保条形长度映射为 end - start,并在每条线上添加 adjusted_delivery 的虚线标注。

5.2 当前代码

此处省略…

5.3 输出结果

经过代码调试,最终三个案例的python输出结果完全符合手工推导的预期,如下图所示。这表示我们的简易生产排产器取得了预期的效果。

  • Case1:
  • Case 2:
  • Case 3:

六、未来扩展:智能决策与动态排程

结合现实的复杂情况,在后续的智能排产中,我们可以逐步加入以下的因素,不断优化现有的系统:

模块功能描述挑战
原料可用性 (MRP)对接采购系统、实时判断库存原料提前/延迟到货的动态调整
BOM 多级计划子部件协调、同步排产多级依赖传导与时序约束
多产线 & 机器分配对接多条产线、不同效率、切换成本资源分配优化、机器维护窗口匹配
插单 & 优先级Rush order、插单打断现有计划实时重排与最小化波动
日历 & 停机维护节假日、周末、计划检修复杂日历管理与突发停机处理
需求预测 & 滚动排程利用 ML 预测需求,滚动生成动态排产预测精度与计划稳健性的平衡

思考分享:生产排程不仅是算法问题,更是对调度员经验和直觉的结构化表达。通过认知建模,我们将人脑思考路径映射到程序中,实现“精准生产、精准交付”。从简单到复杂,先理解案例,再编程实现,是每个调度员和工程师共同的最佳实践。


🤩【方案优化】本文对于前述各个案例均假设单个订单要连续生产,但是在很多情况下,当我们有大量订单时,后推迭代的方式可能会带来大量提前排产。当我们的案例更加复杂,例如考虑到原材料供应、BOM结构,安全库等约束条件时,很可能会因为资源不足而引发排产的混乱。因此,我们需要在之前算法的基础上,重新整理和调整逻辑,做出更具扩展性,更接近Just-In-Time(JIT)理念的算法。以下是优化后的算法在下述案例Case 4执行的结果,感兴趣的小伙伴可以通过对比两种算法结果的差异,找到背后逻辑上的变化。当然,也欢迎大家思考找出更优秀的算法策略。

Case 4:密集交付——多批次与插空排产

场景描述

  • 三个订单,交期依次为 4/4、4/7、4/8,需求量均为50,原材料供应充足,订单小,但交期密集。每件产品生产需要0.5小时,当前日期4.1日,每件产品每天的库存成本0.1元。具体订单需求如下:
订单编号需求数量交货日期
1502025-04-04 18:00
2502025-04-07 18:00
3502025-04-08 18:00

排产示意

OrderStartEarliest End处理策略
O104-02 13:0004-04 18:00常规排产
O204-05 13:0004-07 18:00常规排产
O304-01 8:0004-01 13:00分批生产 + 插空排产
O304-02 08:0004-02 13:00分批生产 + 插空排产
O304-05 08:0004-05 13:00分批生产 + 插空排产
O304-08 08:0004-08 18:00分批生产 + 插空排产

这种方式与之前的算法相比,虽然库存成本相同,但可以实现更加灵活的产能调度,在实际生产中更具弹性和实际操作性。

类似文章