简介:面向生产制造场景的DEEPSEEK智能排产APS落地方案PPT,系统讲解如何用数据算法替代人工经验排产,适合计划排产工程师、生产运营管理者以及推进工厂智能化转型的团队参考。方案覆盖智能排产核心价值、核心算法架构、行业应用挑战、传统调度算法局限、实施框架与案例验证等模块,并给出需求预测准确率85%、交付周期缩短15%、库存周转提升20%等量化效果,同时针对流程制造和离散制造的不同工艺特点提出差异化配置思路,帮助应对频繁换线、设备故障、物料短缺等突发扰动。资源为1个PPT文件,压缩包约16.33MB,内容以图文结构呈现,包含关键指标对比、资源优化路径和NP-hard调度问题解法说明,便于直接用于内部汇报或项目规划参考。目前已有119人学习,适合正在评估APS选型或希望快速建立智能排产整体认知的读者使用。
1. 为什么排产排不动:APS 求解瓶颈与 DeepSeek 的切入点
车间调度员每天早上的第一件事,就是在表格里把昨天的返工、设备故障和新插单重新摆一遍。APS(高级计划排程)工具不是没用,而是边界条件一变,排产引擎的重算时间动辄几十分钟,遇到多品种、小批量的订单,甚至不如老师傅手排来得快。DeepSeek 在这类场景里不是“聊天机器人”,而是把排产约束翻译成结构化规则、再把规则喂给优化求解器的调度层。这套落地方案,适合工艺工程师、MES 实施顾问、做产线数字化的团队——让 DeepSeek 负责排产规则的生成与解释,让传统求解器负责暴力搜索,两边配合,把智能排产从“拍脑袋”变成“可解释、可回退、可复盘”的结果。
2. 排产问题建模:把车间约束翻译成 DeepSeek 能读懂的 JSON
先立住一个原则:不要让 DeepSeek 直接输出甘特图。大模型看得到文字,但看不到车间里正在转的机床。把它当作“翻译器”和“规则解释器”,输入必须是结构化数据,输出也必须是结构化数据。常见做法是先建一个最小数据集,把排产涉及的全部要素归一化成 JSON,再决定哪些交给 DeepSeek 分析,哪些直接交给求解器。
2.1 从 MES/ERP 取哪些数据:排产所需的最小数据集
APS 落地失败的头号原因,不是算法不行,是数据根本喂不饱。排产至少需要四类数据。工单数据:工单号、产品编码、数量、交期、优先级。工艺路线:每个工单经过哪些工序、标准工时、可用的设备组。设备状态:当前是否开机、是否有维护计划、上一道任务何时结束。物料齐套:可用库存、在途数量、采购到货时间。这四样缺一样,排产结果就是一张漂亮的废纸。
我一般会先写一个取数脚本,从 MES 库里把最近一个月的在制工单和未来两周的计划工单拉出来,转成统一结构。下面这段代码是取数加归一化的核心逻辑:
import pandas as pd from datetime import datetime def load_aps_input(db_conn, horizon_days=14): # 1. 取工单主数据 orders = pd.read_sql(""" SELECT work_order_id, item_code, qty, due_date, priority FROM mes_work_order WHERE due_date BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL %s DAY) """, db_conn, params=[horizon_days]) # 2. 取工艺路线(按工单展开到工序级) routes = pd.read_sql(""" SELECT work_order_id, seq_no, op_code, std_time_min, allowed_machine_group FROM mes_op_routing WHERE work_order_id IN (SELECT work_order_id FROM mes_work_order) """, db_conn) # 3. 取设备在未来窗口的占用与维护计划 machines = pd.read_sql(""" SELECT machine_id, machine_group, status, plan_maintenance_start, plan_maintenance_end FROM mes_machine """, db_conn) # 合并成按工单-工序展开的宽表 df = routes.merge(orders, on="work_order_id", how="left") df = df.merge(machines, left_on="allowed_machine_group", right_on="machine_group", how="left") return df[["work_order_id", "item_code", "qty", "due_date", "priority", "seq_no", "op_code", "std_time_min", "machine_id", "status"]]这段代码把排产输入拆成三个查询:工单主表、工艺路线表、设备表,然后按 allowed_machine_group 关联。参数里 horizon_days 控制排产窗口,一般取 7 到 14 天。窗口小了,插单和后工序被截断;窗口大了,远期数据不准确,反而干扰排产。priority 字段在下一步做规则权重时会直接用,注意在 MES 里必须有人维护,不然默认值清一色的 0,规则就失效了。
取数这块有个容易翻车的细节:工单可能多版本。MES 里经常存在同一个工单被改过工艺路线的情况,如果直接 join 会按版本拆成多行,导致数量被重复计算。处理办法是只取 max(revision_no) 的那版,或者在查询里加上 is_current = 1 的过滤条件。
2.2 约束归一化:用 JSON 描述工序、设备、物料与交期
取数之后,下一步是把宽表转成适合 DeepSeek 阅读的 JSON。为什么要转而不是直接把 SQL 结果贴给大模型?因为表的字段名是给系统看的,大模型需要的是命题式描述:谁、在什么设备上、先做什么、后做什么、不能和什么冲突。字段名叫 allowed_machine_group,模型不一定会理解它代表“这台设备不能干这道工序”。
我常用的归一化结构是这样:
{ "horizon": {"start": "2025-07-01 08:00", "end": "2025-07-15 20:00"}, "orders": [ { "id": "WO-24071", "item": "A-1042", "qty": 120, "due": "2025-07-10 18:00", "priority": 1, "ops": [ {"seq": 10, "op": "CNC_TURN", "std_min": 45, "group": "G1"}, {"seq": 20, "op": "QC_INSP", "std_min": 15, "group": "G3"} ] } ], "machines": [ {"id": "MC-01", "group": "G1", "unavailable": [{"start": "2025-07-08 08:00", "end": "2025-07-08 12:00"}], "start_free_at": "2025-07-01 08:00"} ], "materials": { "A-1042": {"stock": 86, "incoming": [{"qty": 60, "eta": "2025-07-04 10:00"}]} } }这个 JSON 只保留了排产真正需要的字段。orders 数组里每一条的 ops 是按工艺顺序排好的,求解器可以直接按 seq 遍历。machines.unavailable 数组用来表达设备日历:换模、保养、点检都放进这里,比单独建一个日历表更容易让 DeepSeek 理解“为什么这台设备有空档却排不进去”。materials 里放的是齐套约束,缺料的工单要么推迟开工,要么标记为不可排。
在把这段 JSON 交给 DeepSeek 之前,我会做一次校验:每个工单的工序必须连续、工时必须大于 0、设备组必须存在。这个校验脚本不复杂,按字段遍历一遍即可,但它能避免大模型拿到脏数据后产生幻觉式排产。
2.3 一个最小排产提示词模板与其输出格式约定
有了归一化 JSON,下一步是设计提示词。常见错误是把整段 JSON 塞进去然后问“请给出最优排程”,DeepSeek 会给出一大段 Markdown 表格,看起来像模像样,但落到系统里完全无法解析。问题不是模型,是没约定输出格式。
我会在提示词里明确两件事:第一,你的角色是排产规则分析师,不是调度员;第二,输出必须是合法 JSON,不允许 Markdown 代码块包裹。模板大致如下:
PROMPT_TEMPLATE = """你是离散车间的排产规则分析师。 下面是一份未来 {days} 天的工单、设备、物料数据(JSON)。 你的任务: 1. 找出硬冲突:交期 < 累计工时、关键设备超载、缺料无法开工。 2. 为每个工单给出 priority 的调整建议(0-9,9 最紧急)。 3. 给出三条排产规则建议,每条规则说明影响哪些工单。 输出格式(严格 JSON,不要用 markdown 代码块): {{"conflicts": [{{"order_id": "...", "type": "...", "desc": "..."}}], "priority_suggestions": [{{"order_id": "...", "priority": 7}}], "rules": [{{"rule": "重排时不打断已开工工序", "affected_orders": ["..."]}}]}} 数据如下: {input_json} """这段模板的精髓是“让模型做分析,不做决策”。输出限定三个字段:conflicts、priority_suggestions、rules。求解器拿这些当约束和权重的输入,比直接拿甘特图要稳定得多。上面的 days、input_json 是运行时填进去的参数;days 和套壳的排产窗口保持一致,input_json 就是 2.2 节里归一化后的数据。
参数上有个建议:temperature 设到 0.2 以下,这步要的是稳定分析,不是创意。max_tokens 给 2048 就够,conflicts 和 rules 不会太长。如果返回 JSON 里出现多余字段,解析时用白名单过滤,别让它污染下游。
还有一个小坑:模型返回的 priority_suggestions 不能直接覆盖系统里的 priority,只能作为建议。正确的做法是把建议存到一张待确认表,计划员批量确认后再参与重排。否则模型一分析,全厂优先级变了,计划员第二天上班会想打人。
3. 两阶段排产编排:DeepSeek 生成规则、求解器填槽位
建模完成以后,进入执行层。这套方案的核心是把排产拆成两个阶段:DeepSeek 在前端做规则生成和冲突预判,优化求解器在后端做槽位分配。两个阶段通过 JSON 传递中间结果,互不掺和。这样设计是为了让每一层的输出都可检查、可回退——DeepSeek 说错了,求解器能兜住;求解器跑不出来,DeepSeek 的分析还能给人工排产做参考。
3.1 阶段一:用 DeepSeek 生成排产规则与约束权重
先回答一个常见问题:既然已经有求解器,为什么还要 DeepSeek 在前面走一趟?因为求解器的约束是死的,权重是人工调的,而排产环境里最难的是“哪些冲突本周重要”。比如本周有一台关键设备要做精度保养,那么所有依赖这台设备的工序都应该降速处理;下周客户审计,那么特定工单的优先级要临时拉高。这些语义性约束放在传统 APS 里,要靠计划员手动改权重,改一次还要等求解器重跑一次。DeepSeek 在这里的作用是自动把语义转成约束。
阶段一的调用我用一个 Python 封装来做。要注意 DeepSeek 的 API 是 OpenAI 兼容的,base_url 指向你的网关即可。
import json from openai import OpenAI client = OpenAI( api_key="sk-...", base_url="https://your-llm-gateway/v1" ) def gen_rules(engine, input_json, model="deepseek-chat", temperature=0.2): prompt = PROMPT_TEMPLATE.format(days=14, input_json=input_json) resp = client.chat.completions.create( model=model, messages=[ {"role": "system", "content": "你是生产排产规则分析师,只输出 JSON。"}, {"role": "user", "content": prompt} ], temperature=temperature, max_tokens=2048, response_format={"type": "json_object"} ) content = resp.choices[0].message.content return json.loads(content)这段代码的关键在 response_format 参数。OpenAI 兼容接口里,声明 json_object 能极大降低格式漂移率。engine 参数这次没用到,是我预留的本地推理入口——如果你的车间不允许数据出内网,用 vLLM 部署一个 DeepSeek 模型,把 base_url 指到内网地址,engine 传给推理服务做模型路由。后续要接多智能体编排时,engine 字段也是模型分流的关键标记。temperature=0.2 是为了让规则输出尽量稳定,分析类任务不需要创造性。
拿到返回的 dict 后,我会先做三件事:检查 conflicts 里提到的 order_id 是否都在输入里存在;priority_suggestions 是否都在 0-9;rules 是否为空。任何一项异常,直接把阶段一结果丢弃,本次排产回退到旧的静态规则。这是个保命设计,宁可慢,不可错。
3.2 阶段二:与优化求解器联动约束槽位分配
阶段一输出的三条 rules 和优先级建议,要落进求解器。我默认的求解器是 OR-Tools 的 CP-SAT,因为它是开源里对工序级排产支持最顺的——它天然支持区间变量、开工结束时间、可选设备组约束。实际生产环境里,如果公司已经有商业 APS 引擎,也可以把 rules 翻译成该引擎的表单字段,思路一致。
下面这段代码演示把 DeepSeek 的输出转成 CP-SAT 的硬约束与软约束:
from ortools.sat.python import cp_model def build_cp_sat(job_input, llm_analysis): model = cp_model.CpModel() horizon = 14 * 24 * 60 # 分钟 # 为每个工序创建可选区间变量 job_intervals = {} for job in job_input["orders"]: for op in job["ops"]: dur = op["std_min"] start = model.new_int_var(0, horizon, f"start_{job['id']}_{op['seq']}") end = model.new_int_var(0, horizon, f"end_{job['id']}_{op['seq']}") interval = model.new_interval_var(start, dur, end, f"interval_{job['id']}_{op['seq']}") job_intervals[(job["id"], op["seq"])] = interval # 硬约束:同一设备上区间不重叠,在完整实现中通过 no_overlap 加入 # 软约束:优先级高的工单尽量提前 priority_map = { p["order_id"]: p["priority"] for p in llm_analysis.get("priority_suggestions", []) } obj_terms = [] for job in job_input["orders"]: first_seq = job["ops"][0]["seq"] interval = job_intervals[(job["id"], first_seq)] prio = priority_map.get(job["id"], 5) obj_terms.append(prio * model.new_int_var(0, horizon, f"via_{job['id']}")) model.minimize(sum(obj_terms)) return model, job_intervals这段代码略去了设备映射的细节,故意保留三个核心点:工序用 interval_var 表达,设备的互斥约束靠 no_overlap 加;优先级转成目标函数的系数;rules 数组里允许的硬约束必须能被翻译成求解器原生约束。实际写库的时候,llm_analysis 里 rules 数组会被逐个翻译成 add_no_overlap、add_cumulative 或 add_allowed_assignments。这里要特别小心:DeepSeek 的规则是自然语言,翻译成约束时需要白名单——只能映射到系统支持的那几种约束类型,遇见图上有、代码里没有的规则,直接忽略并写日志。
如果公司里没有 OR-Tools,退一步用遗传算法也能接。核心流程不变:DeepSeek 输出规则与权重,进化算法把规则编码到适应度函数里。差别只在求解速度和稳定性,CP-SAT 在 30 道工序这个规模上通常几秒钟就有可行解,遗传算法要调参数,花的时间更多。
3.3 落地示例:10 台设备 30 道工序的智能排产流程
把这套两阶段流程串起来,我做过的最小验证是:10 台设备、5 个工单、30 道工序,跑一个 14 天的排产窗口。完整流程是一个 Python 脚本,依次执行取数、归一化、阶段一、阶段二、回写。
def run_aps_pipeline(db_conn): # 步骤 1:取数并归一化 df_raw = load_aps_input(db_conn, horizon_days=14) input_json = normalize_to_json(df_raw) # 步骤 2:DeepSeek 规则分析 llm_analysis = gen_rules(engine="vllm-local", input_json=input_json) # 步骤 3:求解器求解 model, intervals = build_cp_sat(input_json, llm_analysis) solver = cp_model.CpSolver() solver.parameters.max_time_in_seconds = 30.0 status = solver.solve(model) # 步骤 4:解出结果,映射回设备,写入排产结果表 if status in (cp_model.OPTIMAL, cp_model.FEASIBLE): write_schedule_to_mes(solver, intervals, input_json) else: # 求解失败,走降级策略:沿用上一版可行方案 fallback_to_last_good_schedule()这个脚本是整套方案的主循环。参数上有几个值得注意的地方:max_time_in_seconds 设在 30 秒,是给求解器的硬上限,超过就接受当前可行解,不做优化;如果 30 秒连可行解都没有,直接走 fallback。normalize_to_json 和 write_schedule_to_mes 这两个函数其实是最费精力的,前者要处理 MES 里各种脏数据,后者要把求解器的时间区间映射回真实设备号和班次。
注意:30 道工序在这个规模下,CP-SAT 通常几秒能到可行解,几分钟后优化开始收敛变慢。所以 30 秒上限不是偷懒,是控制重排频率。排产是周期性任务,不是一次性的,每天晚上重排一次,每被插单触发一次,求解太长会让下游计划员等不下去。
4. 集成回写与兜底:让排产结果落进 MES 而不是一直停在 PPT 里
排产方案如果只停留在 Excel 或 PPT 里,等于没做。真正落地的一步是把求解结果写回 MES 的派工表,让班组长在终端上看到的是排好的任务,并能在异常时执行人工干预。这一章讲集成方式、接口设计与失败兜底。
4.1 三种集成方式:API 直连、中间表、事件消息
对接 MES 没有统一标准,常见做法是三种:API 直连、中间表、事件消息。选哪种取决于 MES 的开放程度和团队对数据库的掌控力。
| 集成方式 | 适合场景 | 优点 | 缺点 |
|---|---|---|---|
| API 直连 | MES 有完整 REST/WebService 接口 | 实时性强,字段清晰 | 需要 MES 厂商配合,联调周期长 |
| 中间表 | MES 和 APS 共用数据库或可访问只读库 | 实现最快,DBA 就能搞定 | 容易造成脏读,需加版本号控制 |
| 事件消息 | 排产结果写消息队列,MES 订阅 | 解耦彻底,支持多车间扩展 | 要消息中间件,运维成本增加 |
我建议刚起步的团队优先走中间表,因为排产本身是批量任务,不是高频事务,中间表完全够用。只有当你需要把排产结果实时推送到多个车间时,事件消息才值得上。API 直连的反而不推荐,除非 MES 厂商已经封装好了最适合的接口,否则对接文档能扯一个月。
还有一个细节:无论用哪种方式,回写必须是“全量覆盖加版本号”。每天重排后,先是把上次的派工全部标记为作废,再写入新的版本。如果不做这一步,车间终端上会看到一天中同一工单出现两条派工,工人在选任务时直接迷茫。
4.2 典型接口时序与回写字段设计
以中间表方式为例,我会在 MES 库里建一张计划派工表,核心字段如下:
CREATE TABLE mes_dispatch_plan ( plan_version VARCHAR(32) NOT NULL, -- 计划版本,如 20250701_1800 work_order_id VARCHAR(32) NOT NULL, seq_no INT NOT NULL, -- 工艺顺序号 op_code VARCHAR(32) NOT NULL, machine_id VARCHAR(32) NOT NULL, -- 分配到的设备 planned_start DATETIME NOT NULL, planned_end DATETIME NOT NULL, plan_source VARCHAR(16) DEFAULT 'DEEPSEEK_APS', status TINYINT DEFAULT 0, -- 0=新建 1=已下发 2=已开始 3=已完成 created_by VARCHAR(32) DEFAULT 'APS', created_at DATETIME DEFAULT NOW(), PRIMARY KEY (plan_version, work_order_id, seq_no) );这张表设计上有两个关键点。其一,主键是 plan_version 加工单加顺序号,意味着每个排产版本里每个工单的每道工序只能有一条计划,写入时用 REPLACE 或 INSERT ... ON DUPLICATE KEY UPDATE 保证幂等。其二,plan_source 字段用来区分方案来源,方便复盘时统计 DeepSeek 规则参与排产的覆盖率。后面做回溯验证时,靠这个字段筛数据。
写入时机也有讲究。求解器一结束就全量写,会造成一个问题:MES 里刚开工的工序被新版本覆盖。所以写库前要加判断,凡是 planned_start 已经过去的、并且作业状态是已开始的行,不能覆盖,要保留下来,重排时把这些工序当作“不可移动的锚点”。这个逻辑放在 write_schedule_to_mes 里,这也是 3.3 节里我提到这个函数费精力的原因。
4.3 求解失败与超时的降级策略
再好的方案也会遇到求解器跑不动、DeepSeek 服务超时的时候。降级策略不是可选项,是上线前的硬指标。我一般设计三级降级:
第一级,DeepSeek 阶段一失败。此时不要重试三次以上,直接跳过规则分析,用系统里最近一次保存的规则配置喂给求解器。规则库平时是落库缓存着的,所以这不是空跑。第二级,求解器超时但已有可行解。接受可行解,不做优化,并记录一条日志:本轮是 suboptimal。第三级,求解器连可行解都拿不到。此时绝不能写入空表,要保留上一版本派工计划不动,并通过企业微信机器人或钉钉机器人把冲突清单推给计划员,让他们人工决策。
第一级和第三级触发时,都不要自动把问题丢给大模型去“反思”。不能让 LLM 在失败循环里反复调优,因为每一次调用都在消耗时间和费用,而且往往没有实质改善。正确做法是把当时的输入快照、模型输出、求解状态打成包,存到一个排产诊断表里,第二天由实施工程师统一看。
降级策略还要配一个开关:可以在配置中心里手动关闭 DeepSeek 参与,回到纯求解器模式。为什么需要这个开关?因为如果某天规则分析出现了系统性偏差,比如它把一批本来不急的工单优先级调到 9,你会需要能一键回到旧逻辑。这个开关是排产系统的“后悔药”。
5. 排产落地避坑:5 条来自一线的踩坑记录
前面几章讲了怎么做,这一章把实践里反复踩的坑集中列出来。每一条都是“现象、原因、解决”的结构,照着排查能省掉大半的调试时间。
5.1 排产结果太完美,车间根本执行不了
现象:DeepSeek 输出的排产方案甘特图非常紧凑,设备利用率接近 90%,但计划员一看就摇头,说这没法干。原因:模型把两道工序之间的切换时间当成了 0,忽略了换刀、装夹、跨车间搬运。这是求解器里没有设置 setup time 的典型症状。解决:在归一化 JSON 里给每个工序加上 setup_min 字段,并把同一个设备上不同产品之间的切换时间映射成依赖上一工序的约束,而不是固定值。没有这个字段,光靠提示词告诉模型“考虑换型时间”是没用的。
这条坑在生产重排里尤其致命。因为重排时前序工序已经实际占用过设备,切换时间被压掉以后,新方案看起来比旧方案早结束,实际上只是把冲突后移到了班次交接点。我现在的习惯是每次排产完,把设备切换总时间单独拉出来和真实历史对比一次,偏差超过 20% 就说明模型或数据有问题。
5.2 交期怎么算都保不住,最后发现日历是错的
现象:排产结果看起来交期都满足,但实际执行时一半工单延期。原因:设备日历里默认每天 24 小时可用,没排班概念。求解器把凌晨三点也排上加工,实际车间根本没人开机。这是标准化输入里漏掉班次模型的坑。解决:在 machines 里增加 schedule 字段,用数组表达每天可用时段,比如两班制 08:00-20:00,满了就当设备不可用。注意节假日和月末盘点日也要维护进来,这通常需要从 ERP 的工厂日历表同步,而不是手工维护。
这个坑的隐蔽之处在于,单看甘特图看不出毛病,只有把排产结果按班次聚合才能发现设备被排到半夜。调试阶段我建议把每个设备的最终占用时段按小时画成热力图,一眼能看出哪些设备在深夜被排了活。这个图不要偷偷自己看,发给车间班组长,他们能告诉你这份排产能不能活过第一天。
5.3 提示词一长,模型就开始自由发挥
现象:把完整 JSON 塞进提示词,DeepSeek 回答出来一堆“建议”,字段对不上,甚至开始编造工单号。原因:提示词里数据部分太长,指令部分被稀释,模型对输出格式的注意力下降。解决:把输入拆成两块——把“角色、任务、输出格式”作为 system prompt,把 JSON 数据作为 user prompt,并且显式要求“只输出 JSON”。另外,把数据里不需要分析的字段删掉,只保留模型需要的最小集合。这一步看似简单,实际减少格式错误的幅度非常明显。
我在调试阶段见过最离谱的一次,模型在 conflicts 里编了一个根本没有的工单号,还煞有介事地描述了原因。后来排查发现,是因为输入 JSON 里工单号格式混用了带前导零和不带前导零的写法,模型在分析时自行补全成了不存在的编号。从那以后,进模型的数据统一清洗成同一套编码规则。
5.4 求解器在深夜把排程任务卡死
现象:每天晚上十一点的重排任务经常第二天早上才跑完,甚至报错。原因:排产窗口内新插单太多,设备组约束写松了,搜索空间爆炸;还有一个常见原因,是 OR-Tools 的 max_time_in_seconds 没设置,默认不限时,遇到难的实例就一直跑。解决:给求解器加硬上限,比如 60 秒;同时把“无法排进当前窗口的工单”过滤出来单独列成清单,而不是把所有工单都硬塞进窗口。我在 3.3 节里写 30 秒超时,就是为了避免这种卡死。
这类的坑还有一个更隐蔽的版本:同一台设备的不可用时间段发生了重叠,比如一个维护计划和一次换模计划都写进了 unavailable,求解器在解析时就出现了无解的空窗。所以每次重排前要做一次日历合法性校验,把所有 unavailable 时间段按设备合并、去重、排序,再进求解器。
5.5 token 费用失控,越排越贵
现象:排产功能上线一周,DeepSeek API 费用比预期高出了好几倍。原因:每次排产都要调用规则分析,加上开发调试期间的反复请求,token 量比想象中大。而且模型的输入是整份 JSON,工单一多,输入 token 成倍上涨。解决:把排产拆成增量分析——每天只对比增量工单和变更设备,不用全量重分析;调试阶段用离线的轻量模型跑,确认逻辑稳定后再切到正式模型;生产环境把 temperature 调低、max_tokens 收紧,避免模型输出多余的文本。所有规则分析结果做缓存,输入没变就不重新调用。
费用问题的另一个来源是失败重试。我在 4.3 节里强调过不要失败就自动重试,原因就在这。一次失败重试等于三倍费用,而且大概率还是同样的失败。实践里我所有调用都统一走一个代理层,代理层做三件事:缓存、超时、费用统计。每个工单排产的花费可以精确到分,计划员那边才好做预算。
6. 用回溯仿真验证排产质量:让 DeepSeek 越用越准
最后讲一个我每次上线前都会做的验证动作:回溯仿真。做法很简单,把过去 4 周已经执行完的工单、当时的 MES 数据、当时的设备状态作为输入,用当前这套 DeepSeek 加求解器流程重新排一遍,然后把排产结果与真实执行的交付日期、设备利用率、加班时长做对比。如果新方案的预计完工时间普遍早于实际交付时间,说明方案有优化空间;如果普遍比实际还晚,说明模型对产能过于乐观,要检查设备和班次模型。
def backtest(window_days=28): # 取历史工单与实际完成时间 hist = load_historical_orders(window_days) # 用当天的数据快照回放排产 replayed = run_aps_pipeline(hist.snapshot) # 对比指标:交期达成率、设备利用率、平均完工提前量 report = evaluate(replayed, hist.actual) return report.sort_values("order_id")这个脚本的价值不在代码,在反馈闭环。每季度跑一次,把偏差最大的前十条记录逐条看,会发现大部分问题出在输入数据没维护好,少数出在规则设置过度。我把这些经验固化成一条习惯:每次排产方案出现问题,先怀疑数据,再怀疑规则,最后才怀疑模型。因为大模型在这里只是翻译器,翻译错的前提是源语言有歧义。
回放的同时,把真实执行结果里计划员手动调整过的工序也记录到派工表里。这些人工调整是比任何提示词都准确的规则训练材料,后续可以让 DeepSeek 学习“哪类工序常被人工挪动”,从而在下轮规则建议里主动避开。这套闭环做到位,你会发现排产方案越来越接近车间真实可执行的上限。
希望帮到你。先把上面的回溯脚本跑通一次,你的 APS 落地方案就真正站住脚了。
本文还有配套的精品资源,点击获取