1. 从车间里的那束手电光说起如果你在冷轧精整线的出口段站过一个班大概会记住这样一个画面带钢以每秒十几米的速度从眼前掠过质检员站在操作台上手里拿着强光手电眼睛盯着钢带表面靠反光的变化去捕捉那些一闪而过的麻点、划伤和折印。一个班下来眼睛是花的判断标准也在悄悄漂移——同一条划痕上班第一小时判为降级第六小时可能就放行了。这不是人的态度问题是生理极限问题。钢铁缺陷识别这件事本质上要解决的就是人眼看不住、规则写不完两个矛盾。人眼看不住是因为速度太快、时间太长、注意力有限规则写不完是因为传统机器视觉靠的是人工设计特征——阈值分割、形态学运算、纹理统计量、边缘检测这些方法在实验室打好光的样片上跑得很漂亮一到现场就崩原因很简单钢铁表面的背景纹理太复杂了轧制纹、氧化铁皮、乳化液残留、水渍、反光带全都在干扰你而缺陷本身的形态又变化多端同一种划伤有细如发丝的有宽如指甲盖的有沿轧向的也有斜向的光照稍微偏一点灰度分布就面目全非。深度学习进这个场景靠的不是高级而是它把特征怎么提这件事从工程师手里拿走交给了数据。你给它几千张带标注的缺陷图它自己去找那些人类说不清楚但确实存在的纹理模式。这也是为什么这几年从热轧到冷轧、从镀锌到中厚板越来越多的产线开始尝试这条路线。这篇内容面向的是准备动手做这件事的人可能是刚接到任务的算法工程师可能是产线上负责质量信息化的技术员也可能是想搞清楚这套东西到底靠不靠谱的工艺人员。我会把从类别体系设计、成像链路搭建、模型选型、训练调参到现场部署的完整链路讲一遍重点放在那些文档里不会写、但现场一定会遇到的问题上。先说一个结论可能有点反直觉在钢铁缺陷识别项目里模型往往不是最难的环节最难的是缺陷类别怎么定、图像怎么采、误报怎么收场。这三件事决定了项目的上限模型只是把上限兑现出来。后面几节会反复回到这个判断上。2. 缺陷类别体系没定清楚后面全是返工2.1 类别不是越细越好而是越可执行越好我见过不少项目一上来就列了三十多个缺陷类别热轧的结疤、麻点、压印、辊印、边裂、夹层、氧化铁皮压入、塔形、镰刀弯冷轧的孔洞、折印、乳化液斑、锈斑、划伤、擦伤、平整纹镀锌的锌粒、锌疤、漏镀、镀层脱落……列得挺全问题是标注的人分不清模型也学不动。正确的做法是回到业务本身问一个问题这些缺陷在下游工序里处理方式是否真的不同如果划伤和擦伤在判定上走的是同一套降级规则、同一个客户接受标准那它们在模型里就应该合并成一个线性机械损伤类。反过来如果氧化铁皮压入需要单独统计反馈给热轧工序做工艺追溯那它就必须独立成类哪怕它和麻点在图像上高度相似。我在一个模拟项目里做过这样的对照初始类别体系有 21 类训练出来的模型整体准确率看着还行但混淆矩阵显示有 6 组类别互相串得厉害人工复核发现这 6 组里有 4 组本来就是同一个工艺成因、同一个处置方式。合并成 15 类之后模型的有效识别率提升了接近 8 个百分点标注速度也快了一截。这不是模型的功劳是类别体系理顺了。所以在项目启动的头两周我会坚持做一件事拉上质检、工艺、下游工序三方一起把缺陷字典写出来。每个类别必须包含四样东西——典型图像、边界定义、与其他类别的区分要点、判定阈值。缺一样后面标注就会出分歧。2.2 一份能落地的缺陷字典长什么样下面这张表是我习惯用的格式字段不多但每个字段都在解决一个具体的分歧点字段作用举例说明类别编码唯一标识用于标注工具和数据库D-LIN-01类别名称现场通用叫法线性划伤典型图像至少 5 张不同光照、不同严重程度的样片存档在共享目录形态定义长宽比、走向、边缘特征长宽比大于 8走向与轧向夹角小于 15 度区分要点和最容易混的类别怎么分与折印的区别折印有周期性重复且伴随轻微厚度变化严重度分级轻、中、重三档的判定依据长度小于 50mm 为轻50 至 300mm 为中超过 300mm 为重处置规则判级、降级、切除、需人工复核中度及以上降级重度需切边处理这张表看起来是管理工作实际上直接决定了标注质量和模型的收敛速度。我踩过的坑是项目做到一半工艺那边更新了客户接受标准轻微锈斑从可接受变成了需记录结果之前的标注全得重来一遍因为当时的标注根本没区分严重度。严重度这个维度一定要在第一天就加上哪怕模型一开始只做类别判断后面要做分级时也不用重新标。2.3 类别不平衡这件事从标注阶段就要开始管钢铁缺陷的分布极度倾斜。正常表面占 99% 以上剩下的 1% 里麻点和划伤可能又占了一大半真正稀有的边裂、夹层可能几千张图里才出几例。这种长尾分布不是训练阶段靠损失函数就能完全拉平的标注阶段就得有意识地补。我的做法是建一个样本台账按类别记录当前样本数设定最低样本门槛——比如每个类别至少 500 个独立实例不是 500 张图因为一张图里可能有多处缺陷。达不到门槛的类别要么去产线上主动找比如调整排产计划专门跑一批容易出边裂的规格要么用合成的方式补后面会讲要么就诚实地承认这一类暂时不做先上线能做的类不要让一个只有 30 个样本的类别拉低整体表现。提示稀有类别的样本宁可少而准不要多而糊。我见过为了凑数把相似类别的图硬塞进来的结果模型学到的是一团模糊的中间态误报率反而更高。3. 成像链路决定天花板模型只能在下面跳舞3.1 分辨率、行频、视场这三个数是算出来的不是猜出来的很多人接手项目第一件事是找模型我的习惯是先算三个数最小可检缺陷尺寸、相机分辨率、行频。算法很简单但算错一个后面全废。假设现场要求能稳定检出 0.2mm 的麻点。按工程经验一个缺陷至少要被 3 到 5 个像素覆盖模型才能稳定学到它的形状特征取中间值 4 像素那么空间分辨率就是单像素对应实际尺寸 0.2mm / 4 0.05 mm/px再假设这条产线的带钢宽度是 1250mm如果只用一台线扫相机覆盖全宽需要的像素数就是1250mm / 0.05mm/px 25000 px两万五千像素的线扫相机在市面上不是没有但价格和后续的算力压力都很可观。更常见的工程做法是分成 4 台 8K 相机拼接每台覆盖约 320mm 幅宽像素数留一点重叠余量。这时候视场宽度就是 320mm分辨率 0.04mm/px比要求更宽松一些属于合理的设计余量。行频的计算同样直接。产线速度按 1.5 m/s也就是 1500 mm/s算纵向分辨率要和横向保持一致同样是 0.04mm行频 1500 mm/s ÷ 0.04 mm/px 37500 Hz三万七千五百赫兹,这个数超过了大部分常规线扫相机的行频上限真按这个配置去做要么降低速度、要么放宽分辨率要求、要么用多台相机做纵向分区。我列这个计算过程是想说明一件事成像参数的确定是产线速度和检出精度之间的硬约束博弈我想要更高的精度这句话在现场是要付出代价的。实际项目里我见过一种折中的方案横向用高分辨率保证能看清细节纵向分辨率适当放宽到 0.08mm行频降到 18750 Hz同时把检测目标调整为长度方向的连续性——因为水平划伤这类缺陷在纵向是贯穿的纵向分辨率低一点不影响判断只有垂直方向的点状缺陷会受影响。这种按缺陷走向分配分辨率的思路是省成本又能保住效果的做法。3.2 打光方式选错再好的模型也白搭钢铁表面缺陷的成像难点在于它是一个高反光的金属曲面缺陷有凸起的锌粒、结疤、有凹陷的麻点、压印、有纯色差的锈斑、乳化液斑、有纯几何的划伤、折印。这四类缺陷对光照的响应完全不同用一种打光方式通吃是不可能的。我一般会把光源方案拆成几路高角度漫射光整个表面被均匀照亮适合看颜色和反射率差异比如锈斑、乳化液残留。缺点是凸起和凹陷的对比度会被抹平。低角度暗场光光线以很小的角度掠射表面只有凸起或凹陷的边缘会亮起来划伤、压印、锌粒这类几何缺陷在这路光下非常明显。这是钢铁表面检测里最常用也最有效的一路。同轴光适合镜面程度高的冷轧板能抑制反光不均。条形光加偏振片对付水膜、油膜造成的干扰偏振片能压掉一部分镜面反射。多路光不是简单叠加而是每一路配一个独立的检测通道各自跑各自的模型或者共享骨干网络、分开输出头。这个设计的理由是不同缺陷在不同光照下的信噪比差异太大混在一起训练等于让模型自己去解一个光照混叠的谜题白白浪费容量。提示光源的稳定性比光源的亮度更重要。恒流驱动、定期校准、灯珠老化的衰减曲线要记录。我遇到过一次批量误报最后查出来是某一路条形光的一个灯珠坏了导致该区域整体偏暗模型的归一化被带偏了。3.3 触发与同步一个容易被忽略的隐性故障源线扫相机靠编码器触发编码器信号来自产线的测速辊或者电机编码器。如果触发信号不稳图像会出现纵向拉伸或者压缩缺陷的形状就变了模型自然认不出。这个问题在现场的典型表现是同一卷钢头部检测正常中段开始误报增多。原因往往是产线在加速或减速段测速辊打滑或者编码器分辨率不够导致实际行频和图像行数不匹配。解决办法有两个层面硬件上编码器尽量选高分辨率的装在不会打滑的辊子上信号线走屏蔽软件上在预处理阶段做一次行间距校验用图像里已知的周期性特征比如轧制纹或者标记线反推实际的行间距做一次轻微的纵向重采样。这个校验模块代码不多但能救回不少莫名其妙的误报。4. 分类、检测还是分割三条路线的真实取舍4.1 先把问题拆成找得到和认得准两件事新手常犯的错误是把缺陷识别当成一个单任务。实际上它至少包含两个子问题缺陷在哪里定位和缺陷是什么类别分类。这两个子问题的难度和评价标准完全不同。定位难在召回——漏掉一处缺陷后面分类再准也没用。分类难在精度——定位框里到底是不是真缺陷、是哪一类误判会直接变成误报。所以工程上我更倾向于两阶段或者多任务的架构而不是一个端到端的检测模型硬扛所有事情。4.2 三条路线的适用边界路线代表方法适用场景主要代价图像分类ResNet、EfficientNet、ConvNeXt缺陷位置已经由前道工序或粗定位给出只需要判类别依赖 ROI 裁剪质量无法处理多缺陷共存目标检测YOLO 系列、Faster R-CNN、DETR需要同时给出位置和类别缺陷尺寸差异不太极端小目标召回是难点标注成本高语义/实例分割U-Net、DeepLab、Mask R-CNN缺陷边界不规则、需要算面积占比、需要精细判级标注成本最高推理慢边缘像素精度难保证无监督异常检测PaDiM、PatchCore 一类缺陷样本极少、冷启动阶段、类别尚未定义只能判异常不能判类别对光照变化敏感我在实际项目里的组合通常是这样的先用一个轻量的候选区提取模块做粗筛再用分类网络做细判。粗筛可以是一个小分辨率的检测模型也可以是基于传统方法的对比度分析——后者在很多场景下依然有效因为缺陷区域和背景的局部对比度差异是客观存在的用积分图做局部均值方差分析速度快、不用训练、不会过拟合。细判阶段的分类网络输入是从原图裁出来的 ROI尺寸归一化到 224 或 288。这里有个细节裁剪时要留足够的上下文。只裁缺陷本身模型看不到周围的正常纹理反而难以判断我一般会按缺陷外接框的 1.5 到 2 倍扩边让模型能看到缺陷和背景的对比关系。import cv2 import numpy as np def crop_with_context(img, box, scale1.8, out_size288): x1, y1, x2, y2 box w, h x2 - x1, y2 - y1 cx, cy (x1 x2) / 2.0, (y1 y2) / 2.0 half max(w, h) * scale / 2.0 H, W img.shape[:2] nx1 int(max(0, cx - half)) ny1 int(max(0, cy - half)) nx2 int(min(W, cx half)) ny2 int(min(H, cy half)) patch img[ny1:ny2, nx1:nx2] # 保持长宽比的前提下缩放空白处用边缘像素填充 patch cv2.resize(patch, (out_size, out_size), interpolationcv2.INTER_AREA) return patch这段代码没什么高深的东西但扩边系数scale是个需要调的参数。我试过 1.2、1.5、1.8、2.2 四档在模拟项目的数据集上1.5 到 1.8 之间效果最稳1.2 的上下文太少2.2 以上缺陷在图中占比太小分类头容易忽略它。4.3 冷启动阶段无监督方法值得一试很多产线刚上线时根本没有缺陷样本库——设备刚改造完历史数据全是正常品。这时候硬着头皮去标几百个缺陷是不现实的。无监督异常检测在这个阶段能救场。它的思路是只用正常样本训练学出一个正常表面的分布推理时任何偏离这个分布的局部区域都标为异常。这类方法不需要缺陷标注几十张正常图就能跑起来。但它有几个明显的局限必须提前知道第一它只能告诉你这里不对劲不能告诉你这是什么缺陷第二它对光照和材质的整体漂移非常敏感换一个钢种、换一批轧辊正常表面的纹理变了模型就开始大面积误报第三阈值很难定定高了漏检定低了满屏框。我通常把它定位成上线初期的过渡方案和长期运行的兜底方案——前者的意思是用它先跑起来攒数据等有标注了再切到监督模型后者的意思是监督模型总有覆盖不到的稀有缺陷用一个异常检测通道做补充至少能把它捞出来交给人工复核而不是彻底漏掉。5. 训练阶段的参数与技巧哪些真有用哪些是玄学5.1 数据增强在这里是个高风险动作通用视觉任务里那套增强手段——随机旋转、颜色抖动、随机裁剪、MixUp——搬到钢铁缺陷上有一半是帮倒忙的。原因在于缺陷的语义和方向、颜色是绑定的。划伤基本都是沿轧向的你把它随机旋转 90 度它就变成了一个现实中不存在的形态模型学到的是噪声。锈斑的颜色是它最重要的判别特征你做一个强力的 HSV 抖动等于把这个特征毁了。我实际用下来比较安全的增强组合是import albumentations as A from albumentations.pytorch import ToTensorV2 train_tf A.Compose([ # 小角度旋转模拟相机安装的轻微偏差 A.Rotate(limit8, border_modecv2.BORDER_REFLECT_101, p0.5), # 亮度对比度微调模拟光源衰减和曝光波动 A.RandomBrightnessContrast( brightness_limit0.12, contrast_limit0.12, p0.6), # 轻微高斯噪声模拟传感器噪声 A.GaussNoise(var_limit(3.0, 12.0), p0.3), # 轻度模糊模拟对焦漂移 A.GaussianBlur(blur_limit(3, 5), p0.2), # 弹性形变非常轻微模拟带钢张力变化 A.ElasticTransform(alpha1, sigma8, p0.2), A.Resize(288, 288), ToTensorV2(), ])注意几个细节旋转限制在 8 度以内超过这个范围就不符合现场的实际分布了亮度和对比度的调整幅度都压在 0.12因为产线的光源是恒流的实际波动不会太大增强过头反而制造了不存在的困难样本弹性形变的参数调得很温和只是想模拟张力带来的轻微几何畸变。有一个增强我是明确禁用的水平翻转。初看好像没什么问题但如果你仔细想过缺陷的物理成因会发现某些类别的分布是有方向偏好的比如边部的缺陷通常在一侧更密集翻转之后这个统计特性就被破坏了。除非你能确认左右对称否则不要开。真正有效的增强不在通用库的列表里而在缺陷合成上。Copy-Paste 的思路是从已有缺陷图里抠出缺陷区域贴到正常背景的不同位置上生成新的训练样本。这个东西对稀有类别特别有用一个只有 50 个样本的类别通过合成能扩到 500 个以上。副作用是合成边界的融合痕迹可能被模型当成特征学到所以贴的时候要用泊松融合或者羽化不要硬贴。5.2 损失函数和采样策略先看数据长什么样类别极度不平衡的情况下交叉熵会倾向于把所有样本判成多数类。常见的对策有三类重采样、类别加权、Focal Loss。我的经验是先看少数类的绝对数量够不够。如果稀有类别有 300 个以上的独立实例用类别加权交叉熵权重按类别频率的倒数开方不要直接用倒数太激进就够了如果只有几十个那问题不是损失函数能解决的得靠合成数据或者两阶段训练——先在平衡的子集上预训练再在全量数据上微调。Focal Loss 我一般只在检测模型里用因为检测任务的正负样本比例更极端一张图里可能有上万个候选框只有几个是正的。分类任务里用它超参 α 和 γ 调起来太费劲收益不明显。还有一个细节验证集必须按卷划分不能按图片随机划分。同一卷钢上的缺陷高度相似同一个轧辊造成的辊印会在整卷上重复如果按图片随机划分训练集和验证集里出现来自同一卷的相似样本验证指标会虚高你以为模型泛化得很好上线之后才发现完全是另一回事。这个坑我在早期项目里踩得很实在验证集准确率 96%上线第一周误报率高得让操作工直接把系统关了。5.3 阈值怎么定用业务指标反推不要用准确率模型输出的是概率概率到判定之间有一道阈值。这道阈值怎么选是整个项目里最需要和现场对齐的地方。准确率在这个场景下几乎没有指导意义。假设缺陷占比 1%一个永远输出正常的模型准确率是 99%但它完全没用。真正要盯的是三个数漏检率Recall有多少真实缺陷没被检出。这个数直接对应质量风险越低越好。误报率单位长度或单位卷上的误报次数。这个数直接决定操作工愿不愿意用。每卷平均报警数这是操作工最直观的感受指标。这三者之间是此消彼长的关系。阈值调低召回上去误报也上去阈值调高误报下来漏检上去。我的做法是画一条 DET 曲线然后在曲线上找一个业务可接受点而不是数学上的最优点。具体来说先问清楚两个问题现场每卷能容忍多少次误报漏检的后果有多严重如果漏检会导致客户投诉甚至批量退货那就要偏保守宁可误报多一点如果误报多了操作工会直接关掉系统那就要偏激进。这个决策不是算法工程师能单方面定的必须和质检主管一起定而且定完之后要把这条曲线的数据留存下来后面再有争议拿数据说话。提示给操作工留一个一键复核的入口非常重要。模型报警之后让人在两秒内能确认或否认否认的结果自动回流成训练样本。这个闭环是系统能长期活下去的关键没有它模型只会随着时间推移越来越不准。6. 从实验室到产线部署链路上的硬约束6.1 延迟预算是倒着算出来的产线的速度决定了你的推理时间上限。这条约束是硬的没有商量的余地。假设带钢速度 15 m/s单台相机横向视野 320mm纵向按 0.5m 一段做检测这个长度是留给后处理融合的那么一段图像在相机视野中停留的时间是0.5m ÷ 15 m/s ≈ 33 ms33 毫秒这就是你从拿到完整一段图像到输出结果的极限。这里面还要扣掉图像传输、预处理、后处理、结果上报的时间留给模型推理的预算大概只有 20ms 左右。20ms 能做什么在一张中端工业级显卡上一个 ResNet-50 级别的分类网络跑单张 288×288 的图大概 3 到 5ms如果要做 20 个 ROI 的批量推理可以用 batch 并行摊到每个 ROI 上更便宜。但如果换成一个大分辨率的检测模型跑全图20ms 就非常紧张了。这就是为什么我前面说粗筛加细判的两阶段架构在工程上更划算粗筛用的是小模型或者传统方法成本极低细判只对少数候选区做批量推理。整体延迟可控。6.2 加速手段的优先级部署阶段的加速我一般按这个顺序做先确认是不是模型的问题。很多时候瓶颈在数据拷贝、图像解码、颜色空间转换上不在推理上。用 profiling 工具看一眼各阶段耗时别一上来就想着量化。转成推理引擎格式。ONNX 是中间态再转成目标硬件对应的引擎通常能拿到 1.5 到 2 倍的加速。做 FP16 或 INT8 量化。FP16 基本无损可以直接上INT8 需要校准集校准集必须来自真实产线图像不能用随机噪声否则精度掉得莫名其妙。我一般会保留两套引擎量化版跑常规检测原始精度版在离线复核时用。批处理和流水线并行。相机采集、预处理、推理、后处理做成四个阶段用队列串起来各阶段并行跑整体吞吐能提升不少。裁剪模型的思路也要考虑。钢铁缺陷分类这个任务其实不需要太深的网络——缺陷的判别特征主要是局部纹理和形状感受野不需要太大。我试过把骨干换成轻量级的结构参数量降了七成精度只掉了一个多点延迟降了一半多这笔账很划算。6.3 结果怎么呈现比模型精度更影响使用体验这一点很多人忽略。模型输出一个框和一个类别这只是原始数据。操作工需要的是这卷钢有没有问题、问题在哪、严重程度如何、要不要处理。所以后处理层要做的融合工作包括同一位置的多帧结果去重线扫是连续采集的同一处缺陷会在相邻几帧里重复出现、按缺陷字典做严重度分级、按卷汇总生成报告、把缺陷位置映射回带钢的实际米数坐标这样现场才能找到它。坐标映射这件事有个容易出错的地方图像坐标到实际米数的换算依赖编码器计数而编码器计数在换卷、停机、倒车的时候会跳变。必须有一套校验机制用卷号和米数做双重索引不能只信编码器。7. 现场跑起来之后真正的麻烦才开始7.1 模型漂移是常态不是意外实验室里 95% 的准确率上线三个月掉到 80%这是常态。原因不是什么玄学是很具体的物理变化镜头积灰导致对比度下降、光源灯珠老化导致亮度分布改变、换了新轧辊导致表面纹理变化、换了钢种导致反光特性不同、季节变化导致车间温度湿度改变影响成像。应对这个问题的核心不是让模型更强而是建立监控。我一般会在系统里埋三类监控指标监控项采集方式异常判定处置动作图像质量每千帧统计一次全局均值、方差、梯度能量偏离基线超过 3 个标准差触发镜头清洁或光源检查工单报警分布按类别统计每小时报警数某类报警数突增 5 倍以上抽样人工复核判断是真实缺陷还是误报模型置信度分布统计预测概率的直方图高置信度样本占比明显下降说明输入分布漂移考虑增量训练这三类指标跑起来之后很多问题能在爆发之前被发现。我印象比较深的一次是图像质量的梯度能量指标连续两天缓慢下降运维按提示去检查发现是一路光源的驱动电流在漂肉眼完全看不出来但模型的误报已经在悄悄上升了。7.2 误报的闭环处理决定了系统能活多久误报是必然会发生的无法消除只能管理。管理的关键是让每一次误报都变成一次数据回流。具体做法是给操作工一个极简的复核界面——报警弹出来两个按钮确认和误报。点了误报之后这张图连同模型输出一起进到一个待处理队列。算法侧每周清一次队列把确认的误报整理成负样本加入训练集重新训练一版。这个循环跑起来之后你会发现一个有意思的现象误报率的下降不是线性的前两个月降得特别快因为模型在快速学习现场那些你在实验室里根本想不到的假缺陷——水渍、反光、标记笔迹、捆带压痕、甚至飞虫落在镜头上造成的阴影。这些东西没有任何一个公开数据集里有只能靠现场喂。我一般会把这个闭环的周期定成两周一次小版本更新三个月一次大版本更新。小版本只做负样本补充不动模型结构大版本才考虑换骨干、加类别、改架构。这样风险可控。7.3 几个用血换来的小经验不要相信单一光照通道的稳定性。任何一路光源出问题如果只有这一路在判整个区域就瞎了。多路冗余不是为了提精度是为了容错。标注规范要版本化。缺陷字典改了标注规范就得跟着改版本号每张图的标注记录要带上版本号。否则半年后你根本分不清哪些标注是按老标准做的。上线初期不要把阈值调得太激进。先用一个保守的配置跑两周让操作工建立信任再逐步收紧。一上来就追求高召回满屏报警人的第一反应是关掉它后面再想让他们重新打开就难了。留一个手动标注入口。让质检员能在系统里直接框出模型漏掉的缺陷这些样本的价值比任何合成数据都高因为它们是真实的漏检案例。训练集和验证集的划分要按时间或者按卷不要按图片随机。前面提过一次这里再强调一遍这是我在多个项目里验证过的最容易导致验证集虚高的错误。记录每一次模型更新对应的数据版本和代码版本。出问题的时候能回滚能复现。这个在项目后期模型迭代频繁的时候尤其重要没有版本管理的模型迭代最后一定是一团乱麻。我自己在这个方向上做了几年最大的体会是这套系统的价值不在于模型有多准而在于它能不能稳定地、可解释地、可持续地跑下去。一个 88% 准确率但每天稳定运行、误报可追溯、能自我迭代的系统比一个实验室里 96% 准确率但上线两周就被关掉的系统有价值得多。技术选型的时候把这句话放在心里很多决策会变得清晰。