aps-agent/docs/product/flex-simulation-guide.md

178 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 柔性排产 · 全流程模拟操作手册
> **面向**:产品演示、方案讲解、验收。
> **场景**:康尼芜湖「多品种小批量 + 设备可移动」柔性排产(高压线束 / PDU 共线)。
> **两种走法**:A 一键脚本(最快看全貌)|B 逐接口操作(贴近真实系统)。
> **现场真实单**:先跑 `python scripts/load_kangni.py`(或口令「导入完整生产路线」)替换演示 flex*,再用柔性排产;口径见 [demand-data-intake.md](./demand-data-intake.md) 附「完整生产路线」。
> 数据口径见 [demand-data-intake.md](./demand-data-intake.md);需求背景见 [demand-kangni-wuhu.md](./demand-kangni-wuhu.md)。
---
## 第一部分 · 自然语言:一次排产到底发生了什么
用大白话把整条链讲一遍。假设计划员接到一张订单「高压线束总成 100 套,7 天后交」。
### 1)设备不再绑死产线——「设备虚拟化」
传统做法:这条活固定走「线束产线」。但芜湖的现实是压接机今天在线束区、明天被调去 PDU 区。所以系统里**每台设备是一份独立档案**,记录它「能干哪几道工序、能不能移动、移动要多久、当前在哪个区、能装哪些模具」。产线不再是固定的钢筋水泥,而是**用的时候临时拼出来的**。
### 2)同类设备汇成一个「产能池」
系统不问「哪条线」,只问「哪道工序」。所有能做压接的设备(4 台可移动压接机)汇成一个**压接能力池**;所有能焊接的(1 台激光焊接机)汇成**焊接池**。排产时从池子里**动态取设备**,谁空闲、谁装了合适模具就用谁。
### 3)为这张订单临时拼一条「虚拟产线」
系统把订单按工艺路线展开成工序序列(来料检验→下线→压接→装配→测试→包装),然后逐道工序去对应能力池取一台设备,拼出一条**虚拟产线 VL-FO-001**:
- 压接这道是瓶颈工序,从压接池挑一台负载最轻的压接机,并确认它装了适配模具(没装就算换型时间);
- 如果这台压接机需要从别的区调过来,就把「移动耗时」插进时间轴(移动时不能生产);
- 每道工序占用设备的一个时间槽,前道没干完后道不能开始。
排完这条虚拟产线就「拼完即用、用完即散」,设备回到池子等下一单。
### 4)产能到底有多少——「瓶颈产能法」
不再用「设备台数×理论工时×拍脑袋 70%」。系统只认最慢那道工序:
> 全厂日产能 = 瓶颈工序可用工时 ÷ 单件工时。
本场景里 PDU 的激光焊接只有 1 台(≈88 件/天),它就是天花板;而压接池 4 台并行看着能做 1920 件/天,那是虚高,没意义。**哪道最慢,产能就由它说了算。**
### 5)销售问「这批什么时候能交」——「交期承诺模拟」
系统不回答「按产能算 X 天」,而是把这张询单**试着插进当前排程**,给三个数:
- 乐观(独占资源):最早能哪天完成;
- 预计(和在制订单抢资源):大概率哪天完成;
- 资源缺口:要更早,得加哪台设备 / 外包哪道工序。
### 6)计划总在变——「动态重排」
- **紧急插单**:来一张 VIP 急单,冻结当前窗口重排,急单优先占瓶颈资源,其余顺延;
- **设备故障**:某台设备停机,系统**实时把它从能力池剔除**,用剩下的重排。这里有个关键区别:可移动压接机坏一台,池子还有 3 台冗余,交期几乎不受影响;但激光焊接机就 1 台,一坏 PDU 直接停摆,系统立刻报「无可用设备」,提示上备机 / 外包 / 重新议交期。
**一句话总结**:任何时刻,系统都能回答计划员那三个问题——**现在能做什么、做多少、什么时候做完**。
---
## 第二部分 · 走法 A:一键脚本模拟(最快)
不用起服务、不用点页面,一条命令把上面 6 步全跑出来,全中文可读输出。
### 前置
```powershell
# 仓库根目录,已建好 .venv 并 pip install -r requirements.txt
cd <aps-agent-repo>
```
### 运行
```powershell
.venv\Scripts\python.exe scripts\flex_simulation.py
```
### 输出会分 7 段(对应上面的业务流程)
| 阶段 | 你会看到 | 怎么读 |
| --- | --- | --- |
| 阶段 0 主数据/产能池 | 区域、每个能力池的设备清单(★=瓶颈)、模具、订单 | 确认「压接池 4 台可移动 / 焊接池 1 台」这类池结构 |
| 阶段 1 初始排产 | 5 条虚拟产线,每条逐工序打印:设备·模具·换型/移动/加工耗时·时间段 | 看「★瓶颈」那行是不是占了压接/焊接设备并挂了模具 |
| 阶段 2 瓶颈产能法 | 各池日产能表 + 限制性瓶颈 | 看「限制性瓶颈=激光焊接 88 件/天」,对照台账法虚高 1920 |
| 阶段 3 三模式对比 | 正排/倒排/瓶颈锚的延迟、准时单、最晚完工 | 压力下倒排明显更差(295h/0 准时),说明模式选择有意义 |
| 阶段 4 交期承诺 | PDU 500 套的乐观/预计完工 + 缺口提示 | 看两个日期差多少,缺口指向焊接工序 |
| 阶段 5 紧急插单 | 插单前后虚拟产线数、最晚完工、急单排入时段 | 看急单是否优先占了瓶颈 |
| 阶段 6 设备故障 | 案例①压接机故障(有冗余)|案例②焊接机故障(停摆报错) | 对比「池化韧性」与「单点瓶颈」两种结局 |
> 脚本是**内存态确定性**运行(种子固定),任何机器任何时间跑结果一致,适合反复演示。改数据后重跑即可。
---
## 第三部分 · 走法 B:逐接口操作(贴近真实系统)
先起后端,再按「看主数据 → 排产 → 看产能 → 问交期」的顺序调接口;或直接打开前端右侧「柔性工作台」点选同一条链路。
### 0)起服务
```powershell
.venv\Scripts\python.exe -m uvicorn server.main:app --reload --port 8000
```
以下命令用 PowerShell 的 `Invoke-RestMethod`(另起一个终端)。
### 1)看柔性主数据与产能池(P0 只读)
```powershell
Invoke-RestMethod http://localhost:8000/api/flex/world | ConvertTo-Json -Depth 6
```
返回:`zones` 区域、`pools` 能力池(含是否瓶颈/设备清单)、`equipment` 设备、`molds` 模具、`orders` 订单、以及最近一次排产的 `virtualLines` / `workOrders` / `conflicts`。
### 2)执行一次柔性排产(P1 直通,写草稿)
```powershell
$body = @{ sortMode = "BOTTLENECK" } | ConvertTo-Json
Invoke-RestMethod -Method Post -ContentType "application/json" `
-Uri http://localhost:8000/api/flex/schedule -Body $body
```
- `sortMode` 可选 `ASC`(正排) / `DESC`(倒排) / `BOTTLENECK`(瓶颈锚),不传取默认瓶颈锚;
- 可加 `orderIds=@(1,2)` 只排指定订单;
- 返回摘要:`vlCount` 虚拟产线数、`woCount` 工单数、`makespan` 最晚完工、`onTimeCount` 准时单、`conflictCount` 冲突、`bottleneck` 瓶颈工序。
排完再调一次 `GET /api/flex/world` 看 `virtualLines`(每条虚拟产线的工序-设备-模具-时间)。
### 3)瓶颈产能法分析(P0 只读)
```powershell
Invoke-RestMethod http://localhost:8000/api/flex/capacity | ConvertTo-Json -Depth 5
```
返回各池 `dailyCapacity` 日产能、`workDays` 本版本工作量折合天数、`bottleneckPool` 限制性瓶颈池。
### 4)交期承诺模拟(P0 只读沙盒,不改主干)
```powershell
$body = @{ productCode = "PDU-UNIT"; quantity = 500 } | ConvertTo-Json
Invoke-RestMethod -Method Post -ContentType "application/json" `
-Uri http://localhost:8000/api/flex/simulate-due -Body $body
```
返回 `optimisticFinish` 乐观完工、`expectedFinish` 预计完工、`bottleneck` 瓶颈提示。
### 接口速查
| 步骤 | 方法 | 端点 | 权级 |
| --- | --- | --- | --- |
| 看主数据/产能池/最新排产 | GET | `/api/flex/world` | P0 |
| 执行柔性排产 | POST | `/api/flex/schedule` | P1 |
| 瓶颈产能分析 | GET | `/api/flex/capacity` | P0 |
| 交期承诺模拟 | POST | `/api/flex/simulate-due` | P0(沙盒) |
---
## 第四部分 · 走法 C:换成你的真实数据
模拟数据都在种子的 `flex*` 键里(`server/state/seed.py` 的 `_seed_flex`)。换真实数据**不用改引擎**,只需:
1. 按 [demand-data-intake.md](./demand-data-intake.md) 的 11 张表准备数据(P0 五张必填:区域 / 设备 / 工序 / 模具 / 工艺路线);
2. 逐表替换 `_seed_flex` 里对应的 `flexZones` / `flexEquipment` / `flexOperations` / `flexMolds` / `flexRoutings` / `flexBom` / `flexMaterials` / `flexTeams` / `flexCalendar` / `flexOrders` / `flexParams`;
3. 删除 `server/data/world.json`(若存在)让种子重播,或重启后端;
4. 重跑走法 A 或 B 即可。
字段口径一致即可,编码自定;**不要**把工厂名/产品名写进引擎或意图,保持行业无关。
---
## 第五部分 · 验收清单(照着勾)
- [ ] 阶段 0 能看到「压接池 4 台可移动 / 焊接池 1 台」的池结构与★瓶颈标记
- [ ] 阶段 1 每条虚拟产线工序顺序正确、压接工序挂了适配模具、可移动设备有移动耗时痕迹
- [ ] 阶段 2 限制性瓶颈=激光焊接(约 88 件/天),且明显低于压接池
- [ ] 阶段 3 倒排在压力场景下延迟明显高于正排/瓶颈锚(模式选择有意义)
- [ ] 阶段 4 交期给出乐观/预计两个日期 + 缺口指向焊接
- [ ] 阶段 5 急单优先占瓶颈、其余顺延
- [ ] 阶段 6 压接机故障影响小(池化韧性)、焊接机故障 PDU 停摆并报 NO_CAPABILITY
- [ ] `pytest tests/golden -q` 全绿(当前 48 passed)
---
## 常见问题
- **必须起后端吗?** 走法 A 不用,纯内存跑;走法 B/前端需要 `uvicorn`。
- **为什么三模式有时结果一样?** 交期宽松、产能有余时三模式趋同;只有产能吃紧才分化(脚本阶段 3 / 工作台「三模式对比」会压缩交期制造压力)。
- **重排是局部还是全量?** 故障与急单当前为**全量重排**(L4);缩池体现 L1;窗内 L2/L3 为后续切片。
- **前端在哪看?** 右侧「柔性工作台」+ 视口柔性甘特/产能池;也可继续用脚本/接口。
变更登记见 [`../CHANGELOG.md`](../CHANGELOG.md)。