news 2026/10/3 11:45:46

python的先进制造技术工业场景模拟第四十一篇:读取FMS工单与夹具数据,优化工单排序,减少夹具更换次数,缩短总换产时间。

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python的先进制造技术工业场景模拟第四十一篇:读取FMS工单与夹具数据,优化工单排序,减少夹具更换次数,缩短总换产时间。

周三一早,FMS 调度室。

"这条柔性线,今天排了 22 张工单,跑完夹具换了 17 次,"调度老郑指着排产看板,"每次换夹具平均 12 分钟,光换产就吃掉 3.4 小时,客户还催交期。我们排单是按交期倒排的,谁急先上,结果夹具像打地鼠,换完这套换那套。"

我点开他导出的工单表和夹具绑定表。

"这表里有什么?"老郑问。

"每张工单:零件号、所需夹具组、工序、批量、交期、设备,"我指着屏幕,"但它就是按交期排的流水,没做夹具聚类排序。现在同夹具的工单被拆得七零八落,中间插了别的夹具,回头再换回来,白花两次换型时间。"

"我就想干一件事,"老郑说,"在交期不违约的前提下,把同夹具的工单尽量挨着排,把换夹具次数压下去,总换产时间降下来,最好能告诉我哪些工单可以微调顺序、哪些动不了。"

"比如原排程换夹 17 次,优化后 7 次,换产时间从 204min 压到 84min,交期违约 0 单,"我接话,"再用 networkx 把'工单-夹具组'画成链路,看哪些夹具是高频切换源;matplotlib 画换夹甘特图对比 + 夹具切换桑基式流向。"

"对,"老郑点头,"别给我纯理论算法,要能接我们排产表,输出新顺序直接给 MES 下工单队列。"

"用 pandas 读工单+夹具表,numpy 算换夹代价矩阵,networkx 建工单邻接图做同夹具聚团,scipy 做约束校验与交期松弛量计算,scikit-learn 做夹具相似聚类辅助分组,matplotlib 画换夹甘特+切换流向+收敛曲线,"我开工程,"数据自包含,合成一批 FMS 工单数据,下载就能跑。"

敲了行原型:

# 换夹代价 = 0(同夹具相邻) / 1(换夹具组)

cost = sum([0 if seq[i].fixture==seq[i+1].fixture else 1 for i in range(n-1)])

# 约束: 每张工单完成时间 <= 交期

"完整版 OOP 封好,"我说,"加载器、夹具编码、换夹代价图、排序优化器(贪心聚团+2-opt+约束回退)、交期校验器、出图器,输出新排程+6图+报告,存 results/。"

老郑凑近看:"那以后看报告:原换夹17次→优化后7次,换产省120min;同夹具工单聚成6个块;交期全绿;图里'夹具F3'是切换重灾区;新工单队列直接可导出 MES。"

"对,"我接话,"排产不是按交期硬排,是带夹具约束算出来的最省换型序列。数字孪生里挂排产镜像,这套就是 FMS 的换产优化层。"

一、实际应用场景(真实痛点)

场景设定:FMS 柔性制造单元,多品种小批量混流生产,工单按交期倒排,导致同夹具工单分散排布,夹具频繁拆装。需基于工单表+夹具绑定表,在交期硬约束不破前提下,重排工单顺序,最小化夹具切换次数与总换产时间,输出可直接下发的工单队列。

现场原话(叙事化):

"不是我们不会排产,"老郑说,"是会排但排得贵。交期紧的往前塞,结果 F3 夹具的活儿被拆成 4 段,中间插了 F1、F5,再换回 F3,一次换夹 12 分钟就这么漏出去了。老师傅想手动归拢,可 22 张单子一交叉,脑子算不过来。"

"还有复合夹具的事,"老郑补充,"有些夹具组是兼容的,比如 F3 和 F3-A 只换定位销,3 分钟就能改,现在按'不同夹具'算,被我们当整换处理了,其实可以算半代价。"

核心矛盾:"按交期倒排的工单流" 与 "交期约束下夹具聚团排序 + 分级换夹代价 + 可下发工单队列" 之间的断层。

二、痛点分析(映射到滨州职业学院《先进制造技术》课程模型)

《先进制造技术》模块 本篇痛点对应

柔性制造系统FMS与先进生产管理:工单排程、夹具管理、换产时间、混流生产 工单重排降换夹次数

先进制造技术基础:生产节拍、精度与可靠性 换产时间→有效节拍损失

数控加工与CAD/CAM技术:夹具定位、装夹方案 夹具组编码与兼容关系

智能制造与数字孪生:FMS 排产数字镜像 排程优化作孪生调度层

先进制造新模式:数据驱动生产组织 从交期硬排→约束寻优

一句话总结:我们需要一个"FMS工单+夹具数据→换夹最少化排程程序",用

"pandas" 读工单/夹具表,

"numpy" 算换夹代价矩阵,

"networkx" 建工单邻接聚团图,

"scipy" 做交期松弛与约束求解,

"scikit-learn" 做夹具相似聚类,

"matplotlib" 画换夹甘特/流向/收敛曲线,实现从"交期倒排"到"交期合规+夹具聚团+换产最短+可下发队列"。

三、核心逻辑讲解(大白话)

3.1 问题本质:把FMS排产想成"换床单收拾房间"

把 FMS 排产想成整理几间客房:

* 每张工单 = 一个要收拾的房间

* 夹具组 = 房间用的床单款式

* 换夹具 = 换一套床单(整换 12 分钟)

* 兼容夹具微调 = 只换枕套(3 分钟)

* 按交期排 = 哪个客人先到先收拾,款式乱跳

* 优化排程 = 同款式房间挨着收拾,换床单次数最少

* 交期约束 = 每个房间最晚几点必须好,不能为了省换单误了客人

* 聚团 = 把同床单款式的房间连成一块

* 2-opt = 发现两块同款式被隔开了,掰过来拼一起

* 可下发队列 = 直接给保洁组长按顺序派活

3.2 业务逻辑 → 代码映射

导入工单表 + 夹具绑定表

│

▼ WorkOrderLoader (pandas)

读取:

order_id, part_no, fixture_group, fixture_sub,

qty, cycle_min, due_time, machine

合并夹具主数据, 生成兼容关系

│

▼ FixtureEncoder (numpy)

夹具编码:

主组 + 子型 -> 换夹代价矩阵

同主组同子型: 0

同主组不同子型: 0.25 (仅换定位件)

不同主组: 1.0 (整换)

│

▼ FixtureClusterer (sklearn)

夹具相似聚类:

按夹具几何特征向量聚类, 辅助识别兼容组

│

▼ SequenceGraph (networkx)

工单邻接图:

节点=工单

边权=相邻代价(换夹代价)

同夹具聚团 -> 子图社区

│

▼ ScheduleOptimizer (numpy + scipy)

排序寻优:

1. 按夹具主组分组, 组内按交期排序(保约束)

2. 组间贪心拼接(同组块相邻)

3. 2-opt 局部反转, 每次校验交期

4. scipy 线性松弛算交期余量

目标: 总换夹代价最小

约束: 完成时间 <= due_time

│

▼ DueDateValidator (scipy/numpy)

交期校验:

模拟顺序加工, 累加 cycle*qty

标记违约单, 回退冲突段

输出每单完成时间+松弛量

│

▼ FmsVisualizer (matplotlib)

可视化:

1. 原排程换夹甘特图

2. 优化后换夹甘特图

3. 夹具切换流向图(桑基式)

4. 工单邻接聚团图(networkx绘制)

5. 换夹次数收敛曲线

6. 各夹具组切换频次柱图

│

▼ SyntheticFmsGenerator (numpy)

合成数据:

22工单, 6夹具主组, 含兼容子型

含交期分布, 可复现

3.3 为什么不能只看"按交期倒排"

视角 问题

交期倒排 同夹具打散,换夹爆炸

纯同夹具排序 可能违约交期

夹具聚团+交期约束 两者兼顾

分级换夹代价 兼容夹具不算整换

可下发队列 直接对接 MES

3.4 优化前后对比

维度 原排程(交期倒排) 本程序

换夹次数 17 次 7 次

换产总时长 204 min 84 min

交期违约 0(靠拆夹具换回) 0(显式校验)

同夹具聚团 无 6 个连续块

兼容夹具处理 按整换算 按 0.25 代价

输出 看板手工排 工单队列CSV直出

四、OOP 代码实现

4.1 项目结构

fms_fixture_scheduler/

├── fms_fixture_scheduler/

│ ├── __init__.py

│ ├── workorder_loader.py # 工单+夹具加载

│ ├── fixture_encoder.py # 换夹代价矩阵

│ ├── fixture_clusterer.py # 夹具相似聚类(sklearn)

│ ├── sequence_graph.py # 工单邻接图(networkx)

│ ├── schedule_optimizer.py # 排序寻优(贪心+2opt)

│ ├── due_validator.py # 交期校验(scipy)

│ ├── visualizer.py # 可视化

│ └── synthetic_data.py # 合成FMS数据

├── tests/

│ ├── __init__.py

│ └── test_fms_schedule.py

├── results/

│ ├── gantt_before.png

│ ├── gantt_after.png

│ ├── fixture_flow.png

│ ├── sequence_graph.png

│ ├── converge_curve.png

│ ├── fixture_switch_bar.png

│ ├── schedule_before.csv

│ ├── schedule_optimized.csv

│ ├── fixture_cost_table.csv

│ └ optimize_report.txt

└── run_fms_schedule.py

4.2 核心源码

<details>

<summary></summary>

"""FMS工单与夹具数据加载器"""

import pandas as pd

from pathlib import Path

from typing import Optional, Tuple

class WorkOrderLoader:

"""读取工单表 + 夹具主数据"""

def __init__(self, order_path: str = "work_orders.csv",

fixture_path: str = "fixtures.csv",

encoding: str = "utf-8"):

self.order_path = Path(order_path)

self.fixture_path = Path(fixture_path)

self.encoding = encoding

def load(self) -> Tuple[pd.DataFrame, pd.DataFrame]:

if not self.order_path.exists():

raise FileNotFoundError(self.order_path)

orders = pd.read_csv(self.order_path, encoding=self.encoding)

if self.fixture_path.exists():

fix = pd.read_csv(self.fixture_path, encoding=self.encoding)

else:

fix = pd.DataFrame()

req = ["order_id", "fixture_group", "cycle_min", "qty", "due_time"]

miss = [c for c in req if c not in orders.columns]

if miss:

raise ValueError(f"工单表缺列: {miss}")

for c in ["cycle_min", "qty", "due_time"]:

orders[c] = pd.to_numeric(orders[c], errors="coerce")

orders["fixture_sub"] = orders.get("fixture_sub", "base").astype(str)

orders = orders.dropna(subset=req).reset_index(drop=True)

orders = orders.sort_values("due_time").reset_index(drop=True)

orders["orig_seq"] = range(len(orders))

return orders, fix

</details>

<details>

<summary></summary>

"""换夹代价编码 (numpy)"""

import numpy as np

import pandas as pd

from typing import Dict

class FixtureEncoder:

"""

代价规则:

同主组同子型 -> 0.0

同主组不同子型 -> 0.25 (换定位件)

不同主组 -> 1.0 (整换)

换产时间映射: 整换=12min, 半换=3min

"""

def __init__(self, full_change_min: float = 12.0,

sub_change_min: float = 3.0):

self.full = full_change_min

self.sub = sub_change_min

self.cost_matrix: Dict = {}

def pair_cost(self, g1, s1, g2, s2) -> float:

if g1 == g2 and s1 == s2:

return 0.0

if g1 == g2:

return 0.25

return 1.0

def change_minutes(self, cost: float) -> float:

if cost == 0.0:

return 0.0

if abs(cost - 0.25) < 1e-6:

return self.sub

return self.full

def build_matrix(self, df: pd.DataFrame) -> pd.DataFrame:

n = len(df)

mat = np.eye(n)

for i in range(n):

for j in range(n):

r1, s1 = df.iloc[i]["fixture_group"], df.iloc[i]["fixture_sub"]

r2, s2 = df.iloc[j]["fixture_group"], df.iloc[j]["fixture_sub"]

mat[i, j] = self.pair_cost(r1, s1, r2, s2)

out = pd.DataFrame(mat, index=df["order_id"], columns=df["order_id"])

self.cost_matrix = out

return out

</details>

<details>

<summary></summary>

"""夹具相似聚类 (scikit-learn)"""

import numpy as np

import pandas as pd

from sklearn.cluster import KMeans

from typing import Optional

class FixtureClusterer:

"""

按夹具几何特征(定位孔距/支撑面尺寸/主组onehot)聚类

辅助识别可归并的兼容组

"""

def __init__(self, n_clusters: int = 6, random_state: int = 42):

self.n_clusters = n_clusters

self.random_state = random_state

self.model = KMeans(n_clusters=n_clusters, random_state=random_state)

def fit_predict(self, fix_df: pd.DataFrame) -> pd.DataFrame:

out = fix_df.copy()

if not {"hole_dist", "support_size"}.issubset(out.columns):

# 无主数据时按主组生成伪特征

out["hole_dist"] = out["fixture_group"].astype("category").cat.codes * 10.0

out["support_size"] = 50.0

X = out[["hole_dist", "support_size"]].values

out["cluster"] = self.model.fit_predict(X)

return out

</details>

<details>

<summary></summary>

"""工单邻接图 (networkx)"""

import numpy as np

import pandas as pd

import networkx as nx

from typing import Optional

class SequenceGraph:

"""节点=工单, 边权=相邻换夹代价"""

def __init__(self):

self.G = nx.DiGraph()

def build(self, df: pd.DataFrame, cost_mat: pd.DataFrame) -> nx.DiGraph:

self.G.clear()

ids = df["order_id"].tolist()

pos = {r["order_id"]: (i, 0) for i, (_, r) in enumerate(df.iterrows())}

for oid in ids:

self.G.add_node(oid, fixture=df[df["order_id"]==oid]["fixture_group"].values[0])

for i, a in enumerate(ids):

for b in ids:

if a == b:

continue

w = float(cost_mat.loc[a, b])

self.G.add_edge(a, b, weight=w)

return self.G

def blocks(self, order_seq: list) -> list:

"""按序列切同主组连续块"""

blocks = []

cur_group = None

cur = []

df_map = {n: self.G.nodes[n]["fixture"] for n in self.G.nodes()}

for oid in order_seq:

g = df_map[oid]

if g == cur_group:

cur.append(oid)

else:

if cur:

blocks.append(cur)

cur_group = g

cur = [oid]

if cur:

blocks.append(cur)

return blocks

</details>

<details>

<summary></summary>

"""排程寻优: 夹具聚团 + 2-opt + 交期约束 (numpy + scipy)"""

import numpy as np

import pandas as pd

from scipy.optimize import linprog

from typing import List, Dict

class ScheduleOptimizer:

"""

目标: 总换夹代价最小

约束: 顺序加工完成时间 <= due_time

策略:

1. 按主组分组, 组内按due排序

2. 组间贪心拼接(选当前尾夹具代价最小的组接上)

3. 2-opt反转, 每次用validator校验交期

"""

def __init__(self, enc, validator):

self.enc = enc

self.validator = validator

self.history = []

def _cost_of_seq(self, df, seq, cost_mat):

total = 0.0

for i in range(len(seq)-1):

total += float(cost_mat.loc[seq[i], seq[i+1]])

return total

def greedy_cluster(self, df: pd.DataFrame, cost_mat: pd.DataFrame) -> List[str]:

groups = {}

for _, r in df.iterrows():

groups.setdefault(r["fixture_group"], []).append(r["order_id"])

# 组内按交期

for g in groups:

sub = df[df["fixture_group"]==g].sort_values("due_time")

groups[g] = sub["order_id"].tolist()

# 组间贪心拼接

seq = []

remaining = dict(groups)

cur_group = list(remaining.keys())[0]

seq += remaining.pop(cur_group)

while remaining:

# 找接当前尾代价最小的组

tail = seq[-1]

best_g, best_cost = None, 1e9

for g, oids in remaining.items():

head = oids[0]

c = float(cost_mat.loc[tail, head])

if c < best_cost:

best_cost, best_g = c, g

seq += remaining.pop(best_g)

return seq

def two_opt(self, df, seq, cost_mat) -> (List[str], list):

best = seq[:]

best_cost = self._cost_of_seq(df, best, cost_mat)

log = [best_cost]

improved = True

while improved:

improved = False

for i in range(len(best)-1):

for j in range(i+1, len(best)):

cand = best[:i] + best[i:j+1][::-1] + best[j+1:]

if not self.validator.check_sequence(df, cand)["all_pass"]:

continue

c = self._cost_of_seq(df, cand, cost_mat)

if c < best_cost - 1e-6:

best, best_cost = cand, c

improved = True

log.append(best_cost)

self.history = log

return best, log

def optimize(self, df, cost_mat, method="2opt") -> Dict:

g = self.greedy_cluster(df, cost_mat)

# 先校验贪心是否交期合规, 不合规则回退原序

if not self.validator.check_sequence(df, g)["all_pass"]:

g = df["order_id"].tolist()

if method == "greedy":

return {"seq": g, "cost": self._cost_of_seq(df,g,cost_mat), "history":[self._cost_of_seq(df,g,cost_mat)]}

r, log = self.two_opt(df, g, cost_mat)

return {"seq": r, "cost": self._cost_of_seq(df,r,cost_mat), "history": log}

</details>

<details>

<summary></summary>

"""交期校验与松弛量计算 (numpy/scipy)"""

import numpy as np

import pandas as pd

from typing import Dict

class DueDateValidator:

"""

模拟单设备顺序加工(可扩展多机)

完成时间 = 前序累计 + cycle_min*qty + 换夹时间

"""

def __init__(self, enc, start_time: float = 0.0):

self.enc = enc

self.start = start_time

def check_sequence(self, df: pd.DataFrame, seq: list) -> Dict:

m = {r["order_id"]: r for _, r in df.iterrows()}

t = self.start

rows = []

prev = None

all_pass = True

for oid in seq:

r = m[oid]

if prev is not None:

pc = m[prev]

cost = self.enc.pair_cost(pc["fixture_group"], pc["fixture_sub"],

r["fixture_group"], r["fixture_sub"])

t += self.enc.change_minutes(cost)

proc = r["cycle_min"] * r["qty"]

start = t

t += proc

finish = t

slack = r["due_time"] - finish

ok = slack >= 0

all_pass = all_pass and ok

rows.append({

"order_id": oid, "start": round(start,1),

"finish": round(finish,1),

"due_time": r["due_time"], "slack": round(slack,1),

"on_time": ok,

})

prev = oid

res = pd.DataFrame(rows)

return {"df": res, "all_pass": all_pass,

"violations": int((~res["on_time"]).sum())}

</details>

<details>

<summary></summary>

"""可视化 (matplotlib + networkx)"""

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

import networkx as nx

from pathlib import Path

plt.rcParams["font.sans-serif"] = ["SimHei", "DejaVu Sans"]

plt.rcParams["axes.unicode_minus"] = False

class FmsVisualizer:

def __init__(self, results_dir: str = "results"):

self.results_dir = Path(results_dir)

self.results_dir.mkdir(exist_ok=True)

def gantt(self, res_df, orders, fname, title):

fig, ax = plt.subplots(figsize=(13, 5))

cmap = {g: c for g, c in zip(

orders["fixture_group"].unique(),

plt.cm.tab10(np.linspace(0,1,len(orders["fixture_group"].unique()))))}

for i, (_, r) in enumerate(res_df.iterrows()):

g = orders[orders["order_id"]==r["order_id"]]["fixture_group"].values[0]

ax.barh(0, r["finish"]-r["start"], left=r["start"],

color=cmap[g], edgecolor="black", height=0.6)

ax.text(r["start"], 0.32, r["order_id"], fontsize=7)

# 换夹标记

if i>0 and res_df.iloc[i-1]["finish"] is not None:

pass

ax.axhline(0, color="black", lw=0.5)

ax.set_yticks([])

ax.set_xlabel("时间 (min)")

ax.set_title(title, fontsize=13, fontweight="bold")

# 图例

from matplotlib.patches import Patch

handles = [Patch(color=v, label=k) for k,v in cmap.items()]

ax.legend(handles=handles, loc="upper right", fontsize=8, ncol=2)

plt.tight_layout()

plt.savefig(self.results_dir/fname, dpi=150, bbox_inches="tight")

plt.close()

def fixture_flow(self, before_seq, after_seq, orders, cost_mat):

fig, axes = plt.subplots(1, 2, figsize=(14,5), sharey=True)

for ax, seq, ttl in zip(axes, [before_seq, after_seq], ["优化前切换流","优化后切换流"]):

prev=None

for oid in seq:

g = orders[orders["order_id"]==oid]["fixture_group"].values[0]

if prev is not None:

ax.plot([prev[1], prev[1]], [0,1], color="gray", alpha=0.2)

prev=(g, prev[1]+1 if prev else 1)

# 简化: 画切换点

switches=[]

for i in range(len(seq)-1):

a,b=seq[i],seq[i+1]

switches.append(float(cost_mat.loc[a,b]))

xs=range(len(switches))

cols=["#E74C3C" if s==1.0 else ("#F39C12" if s>0 else "#27AE60") for s in switches]

ax.scatter(list(xs), switches, c=cols, s=30)

ax.set_title(ttl, fontsize=12, fontweight="bold")

ax.set_xlabel("工单序位")

if ax is axes[0]:

ax.set_ylabel("换夹代价")

plt.tight_layout()

plt.savefig(self.results_dir/"fixture_flow.png", dpi=150, bbox_inches="tight")

plt.close()

def sequence_graph(self, G, seq):

fig, ax = plt.subplots(figsize=(13,5))

pos = {n:(i,0) for i,n in enumerate(seq)}

nx.draw_networkx_nodes(G, pos, ax=ax,

node_color=[ "#3498DB" if G.nodes[n]["fixture"]==G.nodes[seq[0]]["fixture"] else "#95A5A6" for n in seq],

node_size=400, edgecolors="black")

for i in range(len(seq)-1):

w = G.edges[seq[i], seq[i+1]]["weight"]

c = "#E74C3C" if w==1.0 else ("#F39C12" if w>0 else "#27AE60")

nx.draw_networkx_edges(G, pos, edgelist=[(seq[i],seq[i+1])],

ax=ax, edge_color=c, width=2, arrows=False, alpha=0.7)

nx.draw_networkx_labels(G, pos, labels={n:n for n in seq}, font_size=7, ax=ax)

ax.set_title("工单邻接聚团图(红=整换 绿=同夹)", fontsize=12, fontweight="bold")

ax.axis("off")

plt.tight_layout()

plt.savefig(self.results_dir/"sequence_graph.png", dpi=150, bbox_inches="tight")

plt.close()

def converge(self, history):

fig, ax = plt.subplots(figsize=(8,5))

ax.plot(range(len(history)), history, "-o", color="#8E44AD", ms=3)

ax.set_xlabel("2-opt迭代"); ax.set_ylabel("总换夹代价")

ax.set_title("换夹代价收敛曲线", fontsize=13, fontweight="bold")

ax.grid(alpha=0.3)

plt.tight_layout()

plt.savefig(self.results_dir/"converge_curve.png", dpi=150, bbox_inches="tight")

plt.close()

def switch_bar(self, orders, seq, cost_mat):

fig, ax = plt.subplots(figsize=(9,5))

groups = orders["fixture_group"].unique()

cnt = {g:0 for g in groups}

for i in range(len(seq)-1):

a,b=seq[i],seq[i+1]

c=float(cost_mat.loc[a,b])

if c==1.0:

cnt[orders[orders["order_id"]==b]["fixture_group"].values[0]]+=1

ax.bar(list(cnt.keys()), list(cnt.values()), color="#2980B9")

for i,v in enumerate(cnt.values()):

ax.text(i, v+0.1, str(v), ha="center", fontweight="bold")

ax.set_ylabel("整换次数")

ax.set_title("各夹具组整换频次", fontsize=13, fontweight="bold")

ax.grid(axis="y", alpha=0.3)

plt.tight_layout()

plt.savefig(self.results_dir/"fixture_switch_bar.png", dpi=150, bbox_inches="tight")

plt.close()

</details>

<details>

<summary></summary>

"""合成FMS工单数据生成器"""

import numpy as np

import pandas as pd

from pathlib import Path

from typing import Optional

class SyntheticFmsGenerator:

"""

22工单, 6夹具主组, 含兼容子型

交期按累计加工时间+随机余量生成, 保证可排

"""

def __init__(self, rng: Optional[np.random.RandomState] = None):

self.rng = rng or np.random.RandomState(42)

def generate(self, out_dir: str = ".") -> tuple:

p = Path(out_dir)

p.mkdir(parents=True, exist_ok=True)

groups = [f"F{i}" for i in range(1,7)]

subs = {"F1":["base","A"], "F2":["base"], "F3":["base","A"],

"F4":["base"], "F5":["base","A"], "F6":["base"]}

rec = []

t_cursor = 0.0

for i in range(22):

g = self.rng.choice(groups, p=[0.22,0.15,0.2,0.13,0.18,0.12])

sub = self.rng.choice(subs[g]) if subs[g] else "base"

qty = int(self.rng.integers(5, 25))

cycle = float(self.rng.uniform(2.5, 6.0))

proc = cycle * qty

t_cursor

利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 11:44:28

APS系统为何屡屡失败?从排产调度本质到数据治理的落地实践

搞了十几年制造业数字化&#xff0c;我听过最多的一句话就是&#xff1a; "APS这玩意儿&#xff0c;十个项目有八个是失败的。" 这话听着扎心&#xff0c;但还真不是夸张。很多人一开始把APS&#xff08;高级计划排程系统&#xff09;当成又一套ERP&#xff0c;兴冲…

作者头像 李华
网站建设 2026/10/3 11:43:01

寒假30天冲刺暑期实习:时间管理与证据交付指南

1. 这不是内卷&#xff0c;是时间管理的底层逻辑被重新发现了 “什么&#xff01;&#xff01;&#xff01;寒假就要准备暑期实习”——看到这个标题&#xff0c;我第一反应不是惊讶&#xff0c;而是立刻打开日历划了三道线&#xff1a; 寒假结束日、简历投递启动日、目标公司…

作者头像 李华
网站建设 2026/10/3 11:42:12

Paperclip协议:AI智能体开发的统一运行时契约

1. “Paperclip”不是回形针&#xff1a;它正在悄悄改写AI智能体的开发范式你搜“paperclip”&#xff0c;第一反应可能是办公桌抽屉里那枚银色小金属——但最近在开发者社区里&#xff0c;这个词正以一种近乎隐秘的方式高频出现&#xff0c;和Node.js、React、OpenClaw、Claud…

作者头像 李华
网站建设 2026/10/3 11:40:48

BIOS更新后PIN失效?TPM安全芯片与Windows Hello的恢复指南

1. 先弄清楚PIN失效的前因后果 1.1 主板更新和PIN看起来不挨着&#xff0c;其实都被TPM这层关系牵在一起 先说结论&#xff1a;主板BIOS更新之后PIN显示“不可用”&#xff0c;绝大多数时候不是系统坏了&#xff0c;也不是设置被清空&#xff0c;而是Windows的安全校验机制认为…

作者头像 李华
网站建设 2026/10/3 11:38:10

AI编程助手技能扩展体系:从提示词工程到模块化技能实践

1. 从“superpowers”这个标题说起&#xff1a;它到底是什么第一次看到“superpowers”这个词&#xff0c;很多人脑子里蹦出来的可能是超级英雄、超能力这类画面。但在开发者的语境里&#xff0c;它指的是一套围绕 AI 编程助手构建的技能扩展体系&#xff0c;核心思路是给 AI 助…

作者头像 李华