APS 与排程

APSer-Aps 的技术选型、系统架构与 AI 能力:思考与实践

APSer-Aps 如何搭建:系统分几层、各层为什么这样分,求解器、后端、前端、数据库和大模型接入各选了什么、付出什么代价,大模型在系统里实际做哪几件事、边界在哪,以及建设中学到的几条经验。

发布于 更新于 青岛艾普仕

先说结论

  • APSer-Aps 的计划由自研排程内核计算,底层约束求解引擎采用开源的 Google OR-Tools CP-SAT;大模型只在外围做预警解读、急单方案解读、问答的意图解析和智能视图选卡,与排程内核之间没有调用关系,模型不可用时排程照常。
  • 排产分两阶段(可按场景启用):构造式派工先很快给出一版满足全部硬约束的可执行计划,求解器再按订单分段优化,结果更好才替换;每一版计划写入之前都要过独立复核,任何一处违反就拒绝写入。
  • 后端用 Python 与 FastAPI,数据层同一套访问代码支持嵌入式数据库和 PostgreSQL,前端用 React 与 TypeScript,大模型调用经过一个统一的网关,换用哪家模型服务改配置即可;每项选择都写明了代价。
  • AI 生成的文字标明来源,说法要能被数字核对,核不过就改用规则生成的说明;行业差异放进数据和求解规则配置,内核代码只有一套。

这篇文章写给正在评估排程系统的工厂信息化负责人,也写给做类似系统的同行:一套排程软件内部怎么分工,出了问题能不能查清楚,具体做了哪些取舍。

APSer-Aps 要解决的是离散制造里常见的排产问题:订单按多层物料清单拆成工单,工单的每道工序都要排到兼容的机台上,同时照顾工装、换型、工作日历、外协周期、良品率和物料齐套;急单插进来时,要能很快拿出几套可比较的方案,由人拍板后再下发。

为什么计划由确定性的约束求解内核计算、大模型只在外围工作,原理见《排程为什么交给确定性求解内核,大模型只在外围工作》。本篇讲具体怎么搭:分几层,选了什么,AI 实际在做什么,以及建设中学到的几条。

APSer-Aps 的系统分几层,为什么这样分?

下表从上到下列出 APSer-Aps 的各层:

层职责为什么这样分
工作台(浏览器)甘特图、订单、评审、物料齐套、预警、问答等页面;计划员在这里看结果、拖改、发起评审计划员在一处完成查看、调整和拍板,不用在多个系统之间来回核对
服务与流程接收请求,把耗时的排产作为后台作业运行并推送进度,组织评审流转,记录每次排产业务流程和计算分开,长时间的求解不卡住页面
写入校验拖改写回、一键排产、急单方案、评审下发等改动计划的操作,写入前按各自的类型经过规则检查;违规的请求被拒绝,系统状态不变;排产和评审下发被拒的原因记入排产记录或评审单人手拖改的计划和程序算出的计划,写入前都要过检查
排程内核(自研)问题建模、约束构造、目标函数、构造式派工、分段求解与占用结转、急单多方案、日历换算、写回前独立复核所有行业共用一个内核,行业差异放在数据和求解规则配置里
约束求解引擎在内核建好的模型上搜索满足约束的排法,给出求解状态和目标下界采用成熟的开源求解器,把精力留给建模和业务约束
数据层主数据、计划、评审单、排产记录的存储同一套数据访问代码支持两种数据库,按部署规模选择
大模型接入(外围)预警解读、急单方案解读、问答的意图解析、智能视图选卡与排程内核之间没有调用关系,模型不可用时排程照常
表格可左右滑动

数据怎么流动

一次完整的排产大致是这样走的:

  1. 主数据进来:通过文件导入读入物料清单、工艺路线、资源、日历、库存等主数据(与 ERP 的直连按项目实施),先经过一轮确定性的数据检查(工时偏差、物料清单缺漏、编码不一致),问题列出来由人处理。
  2. 拆单与齐套:客户订单按物料清单逐层拆成工单,投产量按良品率反推;按优先级和交期给每张工单预分配原料,计划期内配不齐的整棵工单树标为「缺料待排」,不进排程,避免排出等料的计划。
  3. 两阶段排产(可按场景启用):第一阶段由构造式派工很快给出一版满足全部硬约束的可执行计划,先写回,页面就能看;第二阶段在后台用求解器按订单分段优化,只有结果更好才替换第一阶段的计划。两阶段的结果都进排产记录,页面标明采纳的是哪一版。
  4. 独立复核后写回:每一版计划写入之前,按写入类型做一轮独立复核:一键排产核对工序先后与上下层工单依赖,工作台拖改核对机台兼容、机台与工装不重叠,评审下发和急单方案两类都核对;任何一处违反,拒绝写入。
  5. 急单与评审:急单进来时,已经排好的计划作为固定占用,只对急单和尚未锁定的部分重新计算,套用四组不同的目标权重,得到保交期、紧凑产出、最小扰动、少换型四套方案,每套附上代价对比。计划员选定方案后,经评审确认再下发。

技术选型选了什么,为什么,代价是什么?

约束求解引擎:Google OR-Tools CP-SAT

排程内核自研,底层约束求解引擎采用 Google 开源 OR-Tools CP-SAT(Apache 2.0 许可)。

为什么选它:CP-SAT 原生支持区间变量、不重叠约束和可选区间,排程里的「一道工序可以放在几台兼容机台之一」「一台机同一时刻只干一件活」可以直接表达;它会返回明确的求解状态和经过证明的目标下界,便于如实标注每一版计划的成色;Apache 2.0 许可允许商用和闭源分发,也不需要依赖商业求解器。

代价:规模大到一定程度,整本订单放进一个模型,在可接受的时限内往往只能拿到可行解;求解耗时与服务器核数关系很大;多线程结果可能逐次不同。这几点决定了下面的两阶段结构。

排程内核:构造式派工在前,求解器优化在后

选择:内核分两层。第一层是自研的构造式派工,按优先级、交期和上游完工顺序,逐道工序在兼容机台上找最早可用的空隙,不调用求解器;第二层把订单按工单树分成若干段,逐段交给 CP-SAT 求解,段与段之间结转机台和工装占用。两层读同一份求解规则,共用齐套、外协、良品率和日历这几个约束模块,输出的计划都过同一套独立复核。

为什么:我们在同一份订单数据上对比过几条路线。整本订单一个模型,规模大时在时限内停在初始解附近;只用分段求解,在算力较弱的服务器上质量起伏明显。构造式派工几乎不吃算力,在不同机器上结果一致,让计划员很快拿到一版可执行计划;求解器在此基础上继续改进,更好才替换。

代价:构造式派工不证明结果已经做到头;分段求解每段只看到局部,段与段之间的配合不如整体求解,页面会标注「分段内」的求解状态,与整本求解区分开;替换规则本身也要维护(见后文「实践中学到的几条」)。

后端:Python 与 FastAPI

选择:后端用 Python,Web 框架用 FastAPI,接口的数据结构用 pydantic 声明和校验。

为什么:OR-Tools 提供 Python 接口,建模、数据检查和统计用同一种语言完成。我们测过排产的时间分布:绝大部分花在由 C++ 实现的求解器内部,Python 侧的建模、结果提取和数据库读写只占很小一部分,换更快的语言重写内核收益有限。FastAPI 让接口输入输出有明确的结构定义并自动生成接口文档,与 ERP 等外部系统对接时便于核对字段。

代价:构造式派工这类逐道扫描的逻辑是纯 Python 执行的,规模继续增大时,它的耗时需要持续关注。

数据层:同一套访问代码,两种数据库

选择:用 SQLAlchemy 访问数据库,默认使用嵌入式关系数据库,也可以切换到 PostgreSQL。

为什么:中小规模的单机部署,嵌入式数据库不需要单独安装和运维数据库服务;数据量更大或已有数据库运维能力时,换用 PostgreSQL,业务代码不变。

代价:两种数据库行为有细微差别,改动数据访问时两边都要验证。

前端:React 与 TypeScript

选择:前端用 React 和 TypeScript,构建工具 Vite,样式用 Tailwind CSS,基础组件用 Radix UI。

为什么:排程工作台交互密集,甘特图拖改、大表格、评审弹层都需要细粒度的状态管理;TypeScript 的类型检查帮助前后端字段保持一致。

代价:甘特图和大表格要自己控制渲染量,表格采用框内滚动加懒加载,数据看得全,页面也不卡。

大模型接入:一个统一的网关

选择:所有大模型调用都经过一个自研的网关。网关按通用接口接入模型服务。可以配置一串候选模型,前一个不可用或输出不合格时自动尝试下一个;换用哪家模型服务,改配置即可,业务代码不变。

为什么:大模型在这套系统里只做解读和意图识别,模型本身会更新换代,接入方式要能随时替换。网关还承担一道门:要求模型输出结构化的结果,字段齐全、类型正确才采用,否则视为失败。页面自动触发的解读设有时间上限和并发上限,等不到结果就改用规则生成的说明,不让页面因为等模型而卡住。

代价:演示环境的智能解读、问答和驳回意见整理调用云端模型服务,发出的是解读用的汇总数字,以及用户输入的提问、驳回意见原文和相关的设备、订单编号;排产计算本身不调用大模型。系统可以改接本地模型;在交付中,本地大模型可以部署在您的内网服务器上,解读和问答的数据不出厂(见文末)。

AI 在系统里做什么,不做什么?

原则一句话:数字由确定性内核算,大模型负责把数字讲成人话、把问题理解成系统能查的意图,最后由人拍板。下面逐项说明已经上线的部分。

预警解读。 交期风险、产能瓶颈、工装争用、物料缺口等预警由确定性规则扫描得出。大模型读取各类预警的类别、级别、条数和说明,写一段风险总览和一条「最该先做的事」。解读里出现的「多少行、多少单」这类计数,要能在输入的预警计数里找到,找不到就不采用模型的文字,改用规则生成的说明,并把被拒的原文随本次结果一并返回,便于核对。

急单方案解读。 四套方案和每套的代价(总工期、准时率、换型次数、被挤订单、急单完工时刻等)全部由内核算出;系统倾向哪一套,也由确定性规则选定(例如准时率最高,并列时看急单完工和换型)。大模型只把几套方案的差别写成两三句对比,并说明倾向的理由。它写的「最少」「更短」「优于某方案」这类说法,由规则逐条对照方案数字核验,矛盾就整段不用,回到规则生成的说明。

自然语言问答。 计划员可以直接问「哪些订单会延期」「某张订单排在哪台机」「下周产能排得下吗」。大模型的任务是从一组固定的意图里判断这句话问的是哪一类,并提取订单号、客户、设备或车间;答案里的每个数字,都从系统已有的计算结果中取,与页面上看到的同源。模型不可用时,改用关键词规则识别意图,照样能答,只是识别能力弱一些。

智能视图选卡。 计划员用一句话说明想看什么,大模型只从一组固定的页面卡片里挑出几张、排好顺序,卡片里的数据照样来自系统已有的计算结果;模型不可用时,改用关键词挑卡。

驳回意见转成约束再重排。 计划评审被驳回时,驳回意见可以整理成结构化的约束,例如设备停机、班组在岗比例、订单交期、模具分配。草稿由大模型起草,但涉及的设备、订单、模具由代码从系统数据里取,日期按意见原文换算,每条草稿都要对应意见里的原文片段;模型只出草稿,不排程、不决定约束是否成立。约束经驳回人逐条确认后随驳回提交,并记下是人工填写还是模型建议经人确认;系统据此重排并发起新一轮评审。模型不可用时,由人直接选择约束类型。

来源标明。 预警解读和方案解读旁边有标记:由模型生成时显示实际使用的模型名,并注明只作提示、不做决定;改用规则时显示「规则生成」。问答则标明意图由哪个模型解析,或由关键词规则识别。

哪些事大模型不做:

  • 不计算排程,不改写计划。排程内核与模型之间没有调用关系,模型不可用时排产照常。
  • 不决定采纳哪套方案,不下发计划。采纳、是否挪动已承诺的订单、何时下发,由计划员和车间经评审确认,系统建议和最终选择都留记录。
  • 数据检查不用大模型。工时偏差、物料清单缺漏、编码不一致这几项检测都是确定性规则,检出的问题由人确认处理,系统不自动改主数据。

规则核验也有边界:它能核对常见的比较和计数说法,覆盖不了所有自由表述。所以 AI 文字的定位是帮助阅读,决策依据始终是页面上的数字。

实践中学到的几条

生成方案和检查方案分开做。 求解器和构造式派工都在「生成」,写回前的复核单独成一套,只看结果、不管结果怎么来的。两阶段替换时我们还学到一点:比较两版计划之前,先确认第二版是完整的。分段求解中有某一段在时限内没解出来,就会少排一些任务,延期数字反而显得更少。所以替换规则先查求解状态、任务是否一件不少、加班是否超出预算,过了这道门,再比延期和总工期。

AI 生成的文字必须标明来源。 模型调用可能失败,失败时页面改用规则生成的说明。为了让人分清哪句话出自哪里,我们定下两条:页面标记显示的是这一次实际调用的模型,不写死;模型没有参与时明确标「规则生成」,被核验拦下的模型原文随本次结果一并返回。这样计划员和我们自己都能分清哪句话出自哪里。

模型的说法要能被数字核对。 即使要求模型「严格依据数字」写,它仍可能把数字说错。靠提示词约束不够,所以在模型输出之后加了一道确定性的核验,核不过就不用。

可复现要一层层排查。 单线程加固定随机种子是前提条件,但还不够:建模时遍历候选机台这类细节的顺序也要固定下来。急单几套方案并行计算时,时间上限改用求解器自己计量的确定性时间,避免机器忙闲影响停在哪个解上。可复现的前提条件在原理篇里有详细说明。

先在本地用数据副本验证,再上正式环境。 每批改动先在本机完整环境里用真实页面走一遍,测试跑在数据库副本上,不直接读写正在使用的数据;关键时点先做完整备份,恢复流程也演练过。

行业差异放进数据和规则配置,代码只有一套。 注塑、SMT、铸造、电子整机等业态共用同一个内核和同一套界面,差别体现在数据集和求解规则里;每批提交前运行一个检查脚本,防止内核里出现按行业或客户写的分支,早期留下的少量按行业分支已登记,计划清除。每修一个问题,所有业态一起受益。

智能助手与本地大模型怎样配合交付?

与本文相关的还有两项能力,在定制交付中按您工厂的需要启用:

  • 排产、预警、参数三类智能助手:按定时或事件自动工作,例如订单变更后试算并发起变更评审、到货延期时起草催料通知、每月为参数优化报告归纳要点;助手的动作只有计算、起草、发起评审和通知,数字全部来自确定性计算,下发与批准始终由您的人员确认。
  • 内网本地大模型:在您的内网服务器上运行本地大模型,智能解读、问答与助手的文字起草数据不出厂。

以下是我们的看法

以下内容是我们的观点,供您参考。

第一,在排程系统里,大模型最有价值的位置在人和系统之间。只要数字来自内核、文字标明来源、说法能被核对,它就能让计划员更快看懂结果、更方便地提问;这三条缺一条,它的输出就很难被信任。

第二,每一处用到大模型的地方,都应该配一条确定性的退路。模型会超时、会说错、会被替换,退路保证模型出问题时,系统仍给出可用、可查的结果。我们在设计时先想清楚「模型不在时这里显示什么」,再接入模型。

第三,架构上我们区分稳定部分和可替换部分。排程内核、写入前的检查和评审流程是稳定部分,要长期打磨;大模型、数据库、求解时限和线程数是可替换部分,按客户的环境和算力标定。把两者分开,换其中一样不会牵动全局。

第四,可复核最终要落在具体的工程习惯上:独立复核、完整性检查、来源标注、在数据副本上验证,求解统计取自求解器、原样展示。每一条都不复杂,难在每次改动都坚持做。

如果您想用自己的订单、工序和设备数据看一遍这套系统怎么工作,可以在 APSer-Aps 产品页预约演示。