aps-kernel — Metis 谋序(APS 标准版)
运筹帷幄,谋定后动 —— 同衡·谋序·同枢,智造同频。 One Truth. One Plan. One Rhythm.
可嵌入的确定性排产内核:CP-SAT 精确求解、独立复核器、 工序-资源适配数据模型、设备槽位与班次日历、ε-约束 trade-off、headless CLI。
标准版 vs 专业版:本包只含可嵌入内核(无 UI / 无服务 / 无 LLM)。 甘特图前端、Web 控制台、AI 编排层、多租户 RLS、审批与 IM 通道 属专业版(Docker 镜像 + docker compose)。
🌐 官网:https://aps.zhinengti.online 家族:Nereus 同衡(数字孪生)· Metis 谋序(智能排产)· Hermes 同枢(物流调度)
⭐ 求解能力(横向基准,非自说自话)
在 16 个标准 FJSP 实例(ft/la/abz/orb/swv/ta/yn,来源 job_shop_lib MIT,
含文献公认最优值)上的实测:
| 实例 | 工单×机器 | SPT 基线 | 规则链 | CP-SAT | 文献最优 | vs 最优 |
|---|---|---|---|---|---|---|
| ft06 | 6×6 | 94 | 92 | 55 | 55 | +0.0% OPTIMAL |
| ft10 | 10×10 | 1530 | 1310 | 930 | 930 | +0.0% OPTIMAL |
| ft20 | 20×5 | 1513 | 1565 | 1165 | 1165 | +0.0% OPTIMAL |
| la01-05 | 10×5 | ~1000 | ~940 | 最优 | — | +0.0% OPTIMAL |
| abz5/6 | 10×10 | ~1700 | ~1600 | 1234/943 | 同 | +0.0% OPTIMAL |
| orb01 | 10×10 | 1489 | 1631 | 1082 | 1059 | +2.2% FEASIBLE |
| swv01/02 | 20×10 | ~2100 | ~2100 | 1495/1562 | 1407/1475 | +6% FEASIBLE |
| ta01/02 | 15×15 | ~2100 | ~2040 | 1233/1248 | 1231/1244 | +0.3% FEASIBLE |
| yn1 | 20×20 | 1547 | 1509 | 944 | 884 | +6.8% FEASIBLE |
11/16 达到文献最优,其余为大规模实例(20 秒预算不足,已如实标 gap)。 全部 8/8 独立复核通过。
python benchmarks/run_standard_bench.py --time-limit 30
当前状态
v1.5.1 —— 性能重构(200 工单贪心 16.4s→1.9s)+ aps lotting CLI。451 tests passed
| 模块 | 状态 | 关键能力 |
|---|---|---|
| 数据模型 P0 | ✅ | 工序-资源适配、空适配 ≠ 全设备可用、槽位 |
| 输入校验 P0 | ✅ | 三项 P0 准则 + 5 类检查 |
| 规则引擎 P1 | ✅ | 7 条规则(CR/EDD/SPT/WKWR/ATC/加权优先级/FIFO)+ 8 条链 |
| 日历与齐套 P2 | ✅ | 三日历求交、班次×资源×位置、工单级齐套布尔判定 |
| 换型规则链 P2 | ✅ | frePPLe 语义、无匹配 = 硬约束禁止、参数配置化、非对称 A→B≠B→A、矩阵格式 |
| CP-SAT 求解 P3 | ✅ | 字典序三级目标、容量池用 AddCumulative、冻结窗口 |
| 独立复核器 P4 | ✅ | 10 项真检查(含日历可行、模具互斥、技能资格)、用输入重算不信任求解器 |
| Provenance P4 | ✅ | 快照 hash + 配置/源码/求解器版本 |
| CLI + 基准 P5 | ✅ | solve / benchmark / explain / chains / health / lotting |
| 冲突诊断 | ✅ | aps explain —— 最小冲突集 + 排不下原因 |
| ε-约束 trade-off | ✅ | 钉住交期预算,问 makespan 能压到多少 |
| 数据体检 | ✅ | aps health —— 四张底账逐项核对 + 可执行率估计 |
| 设备负载均衡旋钮 | ✅ | ε-约束第 3 个旋钮:钉住设备负荷不均衡度 |
| 工装模具约束 | ✅ | 跨设备 NoOverlap —— 冲压/注塑的头号约束,「机床等模具」不再是隐患 |
| 并行工序 | ✅ | 同 seq 的工序可同时执行(双人工位装配 / 多工位并行检测) |
| 序列相关换型 | ✅ | 换型真实占用产能(贪心+CP-SAT+复核器三方一致);A→B 与 B→A 可不同 |
| 换型矩阵格式 | ✅ | 直接贴工厂的换型矩阵表(行业通用格式),支持非对称与「禁止该换型」 |
| 拆批合批 | ✅ | 求解前预处理;工时按数量缩放;最小批量约束;合批守交期红线 |
| 人员技能资格 | ✅ | 工序声明技能 → 资源必须持证(1.6.0)。无证资源自动跳过;缺证时警告点名技能而非静默 |
三个设计立场
1. 诚实高于漂亮
OPTIMAL 只在真正证明最优时才标;FEASIBLE 必带真实 gap;
超时回退贪心解时 diagnostics["solver_fallback"] 明确标注来源;
全部未排时标 INFEASIBLE 而非 OPTIMAL(避免"看起来排好了")。
这直接对应论文《Formalize, Don't Optimize》的三个统计口径: 返回结果率 / 验证通过率 / 已返回中通过比例 —— 分母不同,不可混比。
2. 复核器是必需品,不是锦上添花
validator.independent_validate() 用输入数据重算(时长、槽位、日历、
换型、设备资格、技能资格),不信任求解结果自报的值。这不是防御性冗余 ——
开发中它抓到过槽位重叠 48 处而求解器报
OPTIMAL、 makespan = 2.3e18 的垃圾值(UNKNOWN时仍读未赋值变量)。
3. 基准必须公平
所有基线必须在相同约束集下比较。曾实现一个无视日历/工序先后的 SPT 基线, 得出「SPT 比 CP-SAT 还优」的颠倒结论(vsSPT = -203%)。
非法基线比没有基线更糟 —— 它会得出完全相反的结论。
🏗 分层架构:本包的位置
博客园《CP-SAT 排产、排程、排班》:
「APS(长周期规划)+ RTS/RTD(实时派工)双层架构是业界最佳实践」 「前一天做的排程,第二天全乱套」—— 排程 ≠ 派工 是经典误区
┌─────────────────────────────────────────────────┐
│ 上层(aps-platform / 本包之外) │
│ · MRP / 采购 / 库存 │
│ · APS 长周期计划(天/周) │
│ · RTS / RTD 实时派工(分钟级) ← 不在本包 │
│ · MES 执行回写 / 甘特图 UI │
└─────────────────────────────────────────────────┘
↕ ScheduleInput / ScheduleResult
┌─────────────────────────────────────────────────┐
│ aps-kernel(本包)—— 求解内核,不含流程 │
│ ✅ 数据模型 / 输入校验 │
│ ✅ 规则引擎(7 规则 + 8 链) │
│ ✅ CP-SAT 精确求解 + 贪心兜底 │
│ ✅ 冻结窗口(支持增量重排) │
│ ✅ 独立复核器(10 项) │
│ ✅ ε-约束 trade-off / 冲突诊断 / 基准 │
│ ❌ 不做派工、不做 UI、不做持久化、不含 LLM │
└─────────────────────────────────────────────────┘
⚠️ 为什么派工不在本包:派工是高频决策(分钟级刷新), 需要实时状态推送与人工干预;本包是低频决策(计划级), 追求确定性与可审计。把两者混在一个包里会同时失去两者。
⚠️ 本包负责「证明这个计划可执行」,不负责「生成甘特图」:
「排产的难点从来不是生成一个计划,而是证明这个计划在约束下可执行。」 —— 《LLM 不会给你最优排产,求解器会》
版本与兼容性
| 当前 | 1.6.0 —— 功能优先迭代期,API 会随功能演进 |
| 含义 | ⚠️ 1.0.0 的 API 冻结承诺已于 2026-10-17 取消,现按功能优先迭代 |
| 变更记录 | CHANGELOG.md —— 含破坏性变更与迁移动作 |
快速开始
pip install aps-kernel
# 0) ⭐ 上线前先体检(核对工时/BOM/日历/换型矩阵四张底账)
aps health input.json --bom bom.json --inventory stock.json
# 1) 看内置规则链
aps chains
# 2) 求解(贪心,快)
aps solve input.json --chain default
# 3) 求解(CP-SAT,可证 OPTIMAL)
aps solve input.json --solver cpsat --time-limit 30
# 4) 排不下时诊断原因(最小冲突集)
aps explain input.json
# 5) 基准验证(规则链 vs SPT vs CP-SAT)
aps benchmark --sizes 5,8,10 --chains default
aps health的退出码可直接接 CI:0可上线 /1需补数 /2阻断。
from aps_kernel import schedule, solve, CpSatOptions, independent_validate
# 贪心(快,不证明最优)
result = schedule(data, chain="default")
# CP-SAT(可证 OPTIMAL)
result, stats = solve(
data, options=CpSatOptions(time_limit_seconds=30, workers=8),
)
# 独立复核 —— 不信任求解器自报
checks = independent_validate(data, result)
assert all(ok for _, ok, _ in checks)
已知局限(诚实列出)
| 局限 | 说明 |
|---|---|
Job.due_date 只能表达天 |
✅ 已修复(v0.10.0):改为 `date |
| 交期需整日或整时 | 建议传 datetime;传 date 时按当天 00:00 算,不是「当天结束」—— 与部分 APS 的约定不同,转换时请留意 |
| 大规模 gap 仍大 | 20 工单以上、30 秒预算只能到 FEASIBLE。根因已定位: |
| 字典序前两级在「证明贪心已最优」上耗掉 27.5 秒。已加下界剪枝 | |
| (贪心已达理论下界时跳过该级),n=10 改善 3.9% → 7.5%; | |
| n≥15 的 makespan 级本身在 30 秒内证不了最优(gap 60%+), | |
| 这是 CP-SAT 的固有限制(Chalmers 论文:57/100 实例可证最优) | |
| ✅ 已修复(v1.4.0/1.5.0):换型时间真实占用产能(此前只记录不预留,计划现场执行不了);A→B 与 B→A 可不同(换下的模具比装上的更重是物理现实)。仍不支持「A→B→C 链式换型」的组合优化 | |
✅ 已修复(v1.5.0):split_input / merge_compatible_jobs。工时按数量线性缩放(不缩放时拆 4 批 makespan 120→480)。合批守交期红线,默认关闭 |
|
| 换型建模假设「同槽位同组成块」 | CP-SAT 的换型约束是充分非必要的(排除交错排法),非等价改写。换型极贵时该假设成立,但这是真实限制 |
| 模具无寿命/维护周期建模 | 现只有「同一时刻一台机」,没有「这副模还能用几次」 |
| 技能只有资格过滤,无池容量 | 1.6.0 起「无证资源不排工序」,但「几人持证 = 几个并行额度」尚未建模(Resource.skills 是集合,无数量)。多工种共享同一设备的并发上限需专业版 |
| 无持久化状态 | 每次求解无状态,冻结窗口需由调用方传入 |
| 合成 demo 交期偏宽 | demo 默认交期 = horizon+5 天 ≫ makespan → 拖期恒为 0;验证拖期逻辑需改用紧交期 |
| 体检的可执行率是估计值 | 基于静态校验,不检查「现场是否会临时变更」。cp_sat_demo 实测 44%,本估计通常偏乐观 |
安装与依赖
- Python ≥ 3.11
- 运行时依赖:
ortools >= 9.12、PyYAML - 仅发 wheel(
py3-none-any),不发 sdist
License
MIT
Metadata
Release files for aps-kernel 1.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aps_kernel-1.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / aps_kernel-1.6.0-py3-none-any.whl
| Download URL | aps_kernel-1.6.0-py3-none-any.whl |
|---|---|
| Size | 172.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
959216b8d59b675db9a3f908e386a70127ff363e8cba29c0148e82f6f00b12e8
|
|
BLAKE2b-256 checksum How to use checksums |
7f5d9312f98fb7a65c67d58d21803fb3abc0ced8551f64d104096b4ef6a61f33
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|