工时估算模型:把经验写成可解释的规则
车间里最有价值的东西往往是某个人脑子里的判断:同样一张图,他瞥一眼就知道大概要几个工时。把这种判断写成代码,难点不是算得准,而是算错了以后能查得清。
一、先放弃"一把梭"的公式
最开始我想得很天真:找几个老工程师问出公式,乘一乘就出来了。问了之后发现,他们给的从来不是一个公式,而是一串条件分支——
"这个东西啊,看材料,看最薄的地方,看有多少个孔要攻丝,看要不要热处理。要是薄壁件,后面还得加一刀校形。"
这是一套规则体系,不是一条曲线。所以数据结构不应该是"参数表 + 回归",而应该是一棵可以被逐条解释的判定树。
二、把输入分成三类
估算的输入其实来自完全不同的来源,混在一起就必然写成一团。我按可信度分了层:
| 类别 | 来源 | 可信度 | 例子 |
|---|---|---|---|
| 图纸事实 | 解析图纸得到 | 高 | 外形尺寸、孔数、公差等级、粗糙度 |
| 工艺决策 | 由规则推导 | 中 | 装夹次数、走刀路径、是否需要基准转换 |
| 环境参数 | 人工配置 | 低(会变) | 设备效率、材料切削性、批量 |
这个划分带来一个很好的副作用:只要环境参数变了,只有第三层需要重算,前两层的结果可以缓存。工厂换了一台设备,不必把历史图纸全部重新解析一遍。
三、规则要写成数据,不要写成 if
规则一旦写进代码,改一次就要发一次版,这是很多内部工具最后没人用的原因。我的做法是把规则做成表结构,运行时加载:
{
"id": "thin_wall_extra_pass",
"when": {"min_wall_thickness": {"lt": 2.0}, "material": {"in": ["aluminum", "stainless"]}},
"then": {"add_hours": 0.3, "reason": "薄壁件需增加校形与轻切削走刀"},
"priority": 20
}
每条规则都带 reason。这不是给用户看的装饰,而是给自己留的调试线索:估算结果旁边能列出"命中了哪几条规则、各贡献多少",一旦和老师傅的判断差得远,直接看哪条规则被误触发。
四、结果必须可追溯,包含版本号
这一条是我吃过亏之后加的。同一张图纸,三个月前算出来 12 个工时,现在算出来 15,中间只改过几条规则和一个设备参数。如果没有版本记录,这种事根本没法解释。
所以每次估算的结果都带三样东西:
- 输入快照:当时解析出的几何特征与参数值,冻结存下来。
- 规则版本:命中规则集的哈希。
- 命中明细:每条规则贡献的增量。
代价是存储变大,收益是任何一次"为什么是这个数"都能当场答出来。在制造行业,能解释比算得准更有说服力——因为最终签字的是人。
五、边界条件比主流程更难
真正花时间的不是标准件,是那些不标准的输入:
- 图纸上缺尺寸,或者标注自相矛盾(公差大于基本尺寸)。
- 单位不统一,同一张图里混着公制和英制。
- 多层嵌套的装配图,零件重复引用。
- 解析出来的孔数明显不合理(比如 3000 个孔),多半是识别错了。
对这些情况,正确做法不是"尽力猜一个数",而是标记为不可靠并说明原因。一个诚实的"这张图有 3 处标注缺失",比一个看起来很专业的错误数字有用得多。
六、要不要上机器学习
短期内没有。原因有三个:
- 样本量不够。一个中小工厂一年也就几千张图,而且分布极度不均。
- 不可解释。估算结果要用来报价,报价要签字,签字的人需要理由。
- 规则版可以冷启动。没有历史数据也能跑,这是能落地的关键。
比较现实的做法是:先用规则跑起来,把每次"人工修正"的差值记下来。这些修正值本身就是标注数据。等积累到一定量,再用它来反向调整规则里的系数,甚至拟合出一个只在特定材料/工艺上生效的修正项。这条路径不需要一开始就承诺"AI 定价"。
七、小结
把经验写成代码,本质上是一次知识结构化的过程。写完之后最好问自己一句:如果这个人离职了,别人能不能靠这套规则复现他的判断?
如果答案是"能,而且能看出他为什么这么判断",那这套模型就算成功了,哪怕它只覆盖了 70% 的常见件。