尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

供应商质量评分自动化:MySQL+Python实现CPK、PPM与8D闭环

供应商质量评分自动化:MySQL+Python实现CPK、PPM与8D闭环 简介围绕供应商质量管理与控制这一供应链核心议题这份文档面向采购、质量与供应链管理人员梳理了可落地的管控方法与实施要点。内容从制定联合质量计划切入分经济、技术、管理三个维度展开涵盖价值分析、成本与质量平衡、产品与工艺设计协同、检验测试标准化及责任分配并说明向供应商派遣常驻代表与质检组的监督机制以及定期或不定期监督检查、变更报告的处理思路。文档还给出定期排序评估的具体准则如质量保证批合格率、进货批合格率、投入后工序直通合格率、纠正行动报告响应速度、交货期履行与审核分数等并讨论帮助供应商导入 ISO9000、6Sigma 体系的方法兼及供应商关系管理的基本框架。资源包内含 1 个 doc 文档约 265KB层次清晰、便于检索查阅已有 104 人学习。适合需要搭建供应商质量管控流程、完善评估指标与内外协同机制的从业者参考。1. 供应商质量管理不是一份躺在共享盘里的 .doc很多公司共享盘里都躺着这样一份文档来料检验、8D、年度审核写得挺全可旺季一来问题照旧IQC 判了不合格采购说供应商已经在整改质量说没收到整改单月底谁也算不清这家供应商是 A 级还是 C 级。失效的原因不在文字而在它没有和数据、流程挂上钩——评分靠人填合格率靠各自的手工表整改单超期没人催。下面按一条能落地的路径推先定指标口径和评分模型再用数据库搭数据底座然后用脚本把 CPK 计算、月度评分、超限告警每天自动跑一遍最后收在 8D 闭环和复评验证上。适合 SQE、质量工程师以及被拉来做质量看板的开发。2. 供应商质量指标体系与分级模型的搭建方法2.1 先定口径再谈系统同一个供应商采购说合格率 99%质量说 94%差出来的五个点通常是口径打架一边把让步接收算成合格一边算成不合格一边按批次算一边按件数算。系统化之前必须先把口径写死写进字段定义里而不是写在制度文档的附件里。否则脚本跑得再快也只是一个自动产出争议的工具。判断口径是否合格有个很实用的检验方式随便挑三家供应商让两个人各自按口径手工算一遍结果必须完全一致。做不到就说明定义还有歧义比如来料批到底指一次送货单还是一个物料号一个到货日。常见做法是把检验批定义为「物料号 到货日期 供应商」的最小组合落到表里就是一个唯一键。2.2 五个可落地的核心指标与取数口径指标不在多在于每个都能自动取到数、都能对应一个动作。下面这五个是制造业里最通用的一组。指标计算口径数据来源更新频率对应动作IQC 批次合格率判定 PASS 的批次 / 当期检验批次让步接收单独打标来料检验单每批加严或放宽抽检PPM不良件数 / 收货总件数 × 10^6来料检验 产线退货每日触发 SCARCPK 达标率CPK ≥ 1.33 的关键特性数 / 送检关键特性数SPC 测量数据每月现场审核SCAR 按期关闭率到期前关闭的整改单 / 当期到期整改单8D 记录每周供应商约谈重复问题复发率同失效模式 90 天内再发次数 / 问题总数缺陷明细每月降级、冻结新项目几个容易被忽略的细节PPM 的分母必须是收货总件数不是抽检件数抽样检验里用抽检数当分母会把 PPM 放大几十倍批次合格率要有最小样本门槛一个月只交过一批货的供应商不该拿 100% 去拉高均分让步接收既不能算合格也不能算不合格要用第三种状态单独统计因为它对应的是风险不是质量水平。2.3 供应商分级评分卡的权重与阈值设计2.3.1 权重分配与归一化方式五项指标量纲不同直接加权没意义必须先各自归一化到 0100 分。越大越好的指标批次合格率直接用比例映射越小越好的指标PPM、复发率用目标值到最差值做线性映射目标值得满分最差值得 0 分。权重建议按「结果类 40%、过程类 35%、闭环类 25%」的大框架分配避免全压在结果指标上那会导致供应商只救火不改善。# supplier_scorecard.yaml —— 权重合计必须为 1.0改完用校验脚本跑一遍 weights: lot_pass_rate: 0.15 # 结果类批次合格率 ppm: 0.25 # 结果类百万件缺陷数 cpk_rate: 0.20 # 过程类关键特性过程能力达标率 scar_ontime: 0.15 # 闭环类整改单按期关闭 recurrence: 0.25 # 闭环类重复问题复发反向指标 targets: # 归一化的满分点与零点 ppm: {best: 200, worst: 3000} recurrence: {best: 0, worst: 0.3} grade_cutoffs: {A: 85, B: 70, C: 60} # D 为 60 分以下2.3.2 阈值别拍脑袋用历史分位数校准分级线最容易犯的错是按感觉定比如 90 分以上算 A结果全年没有一家达标分级失去区分度。稳妥做法是拉过去 12 个月的数据算分位数前 25% 对应的分数作为 A 线中位数附近作为 B 线后 25% 作为 C 线再结合业务容忍度上下浮动 23 分。分级的意义在于区分对待而不是给所有供应商发奖状。阈值确定后要固化成配置而不是写死在代码里。每次调整阈值都留一次版本记录否则三个月后没人说得清为什么这家供应商从 B 掉到了 C。3. 用 MySQL 搭供应商质量数据底座3.1 三张核心表来料批次、缺陷明细、整改单数据底座不需要多复杂三张事实表加一张供应商主数据基本够用。重点是字段定义要和第 2 章的口径一一对应特别是结果状态和数量字段。CREATE TABLE iqc_lot ( lot_id BIGINT PRIMARY KEY AUTO_INCREMENT, supplier_id VARCHAR(32) NOT NULL, material_no VARCHAR(64) NOT NULL, receive_qty INT NOT NULL, -- 收货总件数PPM 的分母 defect_qty INT NOT NULL DEFAULT 0, -- 判定不良件数 inspect_date DATE NOT NULL, result ENUM(PASS,FAIL,CONCESSION) NOT NULL, -- 让步接收单独打标 UNIQUE KEY uk_lot (supplier_id, material_no, inspect_date), KEY idx_sup_date (supplier_id, inspect_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE defect_detail ( defect_id BIGINT PRIMARY KEY AUTO_INCREMENT, lot_id BIGINT NOT NULL, failure_mode VARCHAR(64) NOT NULL, -- 失效模式复发率靠它聚合 defect_qty INT NOT NULL, source ENUM(IQC,LINE,CUSTOMER) NOT NULL, KEY idx_lot (lot_id), KEY idx_mode (failure_mode) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE scar ( scar_id VARCHAR(32) PRIMARY KEY, supplier_id VARCHAR(32) NOT NULL, failure_mode VARCHAR(64) NOT NULL, created_at DATETIME NOT NULL, due_at DATETIME NOT NULL, closed_at DATETIME DEFAULT NULL, status ENUM(OPEN,D5_DUE,CLOSED) NOT NULL DEFAULT OPEN ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;result用三值枚举而不是布尔是为了让步接收能单独统计defect_detail独立成表复发率才有的算否则只能统计总量、看不出是不是同一个问题反复发生scar.due_at显式存到期时间比每次用created_at 30 天现算更稳因为不同等级的问题时限本来就不同。3.2 批次合格率与 PPM 的查询写法月度汇总是最常跑的一条查询难点全在分母和边界条件上。SELECT l.supplier_id, DATE_FORMAT(l.inspect_date, %Y-%m) AS ym, COUNT(*) AS lot_cnt, SUM(l.result PASS) AS pass_lot_cnt, ROUND(SUM(l.result PASS) / COUNT(*) * 100, 2) AS lot_pass_rate, ROUND(SUM(l.defect_qty) / NULLIF(SUM(l.receive_qty), 0) * 1000000, 1) AS ppm FROM iqc_lot l WHERE l.inspect_date 2024-01-01 AND l.result CONCESSION -- 让步接收不进合格率分子分母单独走风险统计 GROUP BY l.supplier_id, ym HAVING COUNT(*) 5; -- 样本不足 5 批的月份不参与评分MySQL 里SUM(condition)会把布尔值当 0/1 求和比SUM(CASE WHEN ... THEN 1 ELSE 0 END)短但只适用于 MySQL换到 PostgreSQL 要改回COUNT(*) FILTER (WHERE ...)。NULLIF是防除零的某个月只有退货没有正常收货时分母是 0。HAVING COUNT(*) 5这条门槛值得坚持否则一家每月只交一批货的供应商会频繁拿满分把整体分布拉歪。3.3 汇总表落库把月度评分固化下来评分结果要落成表不要每次从明细现算否则看板和 API 都被慢查询拖死。CREATE TABLE supplier_month_score ( supplier_id VARCHAR(32) NOT NULL, ym CHAR(7) NOT NULL, lot_pass_rate DECIMAL(5,2), ppm DECIMAL(10,1), cpk_rate DECIMAL(5,2), scar_ontime DECIMAL(5,2), recurrence DECIMAL(5,2), score DECIMAL(5,2), grade CHAR(1), PRIMARY KEY (supplier_id, ym) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;主键用(supplier_id, ym)是为了后面INSERT ... ON DUPLICATE KEY UPDATE能幂等重跑脚本中途失败重来不会产生重复月份。写入时按 3.2 的查询结果逐项更新score和grade由 Python 侧算好再写回权重和阈值改动只影响脚本不动表结构。4. Python 自动化CPK 计算、评分刷新与超限告警4.1 从库里拉数据算 CPK 的最小脚本CPK 是整个评分里最容易算错的一项错在标准差的取法和样本量门槛上。import pandas as pd def cpk(values, lsl, usl, min_sample30): 单边规格传 None 即可样本不足直接返回 None不参与达标率统计 s pd.Series(values).dropna() if len(s) min_sample: return None # 样本太少CPK 波动极大宁可判为未知 mu, sigma s.mean(), s.std(ddof1) # ddof1 为样本标准差 if sigma 0: return None # 全部测量值相同通常是记录错误 upper (usl - mu) / (3 * sigma) if usl is not None else float(inf) lower (mu - lsl) / (3 * sigma) if lsl is not None else float(inf) return round(min(upper, lower), 2)min取的是上下限里较差的那一侧这正是 Cpk 与 Cp 的区别所在——Cp 只看离散程度Cpk 还要看中心偏了多少供应商把均值调偏一点就能骗过 Cp骗不过 Cpk。ddof1用样本标准差和多数 SPC 软件的口径一致如果供应商报告和我们算出来差一点先对样本量和标准差口径再怀疑数据造假。单边规格只有上限或只有下限很常见比如粗糙度、杂质含量这时传None函数按单边处理。4.2 评分卡落地与分级告警评分就是把归一化和加权串起来告警则是把评分结果变成人能看见的动作。def norm_lower_better(value, best, worst): 越小越好的指标达到 best 得 100 分达到 worst 得 0 分中间线性插值 if value is None: return 0.0 # 无数据按 0 分处理倒逼供应商补数据 if value best: return 100.0 if value worst: return 0.0 return (worst - value) / (worst - best) * 100 def score_supplier(row, w, targets): s (row[lot_pass_rate] * w[lot_pass_rate] norm_lower_better(row[ppm], **targets[ppm]) * w[ppm] row[cpk_rate] * w[cpk_rate] row[scar_ontime] * w[scar_ontime] norm_lower_better(row[recurrence], **targets[recurrence]) * w[recurrence]) grade A if s 85 else B if s 70 else C if s 60 else D return round(s, 2), grade告警要能直接推给人不要只写进日志。import requests def push_alert(webhook, supplier, grade, reasons): text f[供应商质量告警] {supplier} 本期评级 {grade}\n \n.join(reasons) resp requests.post(webhook, json{msgtype: text, text: {content: text}}, timeout5) resp.raise_for_status() # 非 2xx 直接抛异常交给外层重试不吞掉失败raise_for_status()这行不要省。很多脚本把推送失败静默吞掉结果质量周报发了三天没人收到也没人知道。4.3 幂等写入与告警去重定时任务必然会重跑重跑不能产生副作用。落库用INSERT ... ON DUPLICATE KEY UPDATE告警用去重键控制。参数建议值说明CPK 最小样本量30低于此值返回 None不计入达标率CPK 达标线1.33关键特性常用 1.67按物料分级设置PPM 预警线500超过即触发 SCAR可按品类上下浮动批次合格率预警线98%低于即通知 SQE复发统计窗口90 天同失效模式在此窗口内二次发生计复发告警去重窗口24 小时同一供应商同一原因只推一次去重实现很简单把supplier_id grade 原因哈希拼成 key写进 Redis 并设置 24 小时过期写入成功才推送。这样脚本被定时器重复触发、或者手工补跑历史月份都不会让群里刷屏。补跑历史月份时记得把去重开关关掉否则回补的告警全被吞了。5. 8D 闭环与供应商复评的进阶技巧5.1 SCAR 触发规则与 8D 时效校验整改单不能靠人想起才开。把触发规则写成 SQL每天扫一遍命中即建单。-- 触发条件单批不良件数占比超过 5%或同一失效模式 90 天内已出现两次 SELECT l.supplier_id, l.material_no, d.failure_mode, SUM(d.defect_qty) AS bad_qty FROM defect_detail d JOIN iqc_lot l ON l.lot_id d.lot_id WHERE d.source IQC AND l.inspect_date DATE_SUB(CURDATE(), INTERVAL 90 DAY) GROUP BY l.supplier_id, l.material_no, d.failure_mode HAVING bad_qty 3;建单之后要卡时限否则 8D 会永远停在 D3。SELECT scar_id, supplier_id, DATEDIFF(NOW(), created_at) AS age_days, CASE WHEN status CLOSED AND DATEDIFF(NOW(), created_at) 30 THEN OVERDUE WHEN status CLOSED AND DATEDIFF(NOW(), created_at) 7 THEN D5_DUE ELSE ON_TRACK END AS flag FROM scar WHERE status CLOSED;常见时限设置是D1D3围堵48 小时内提交D4D5根因与对策7 天内D6D8验证与预防30 天内。超期就自动把该供应商当月闭环类指标扣分指标和流程绑在一起催单才有人理。注意age_days用的是自然日跨节假日多的月份可以改成工作日计算但要和供应商约定清楚否则月底又是一轮扯皮。5.2 用加严检验与回溯验证确认控制真的生效整改单关闭不等于问题消失必须做效果回溯。可操作的规则是SCAR 关闭后该供应商该物料连续 3 批加严检验抽检比例提到正常的两倍3 批全合格才恢复常规抽检期间再出一次同类问题直接升格为现场审核并冻结新项目导入。这条路子比整改关闭即结束严但正是它能挡住复发。回溯验证用数据说话对比整改前后各 90 天的 PPM 和 CPK。SELECT s.supplier_id, CASE WHEN l.inspect_date s.closed_at THEN 整改前 ELSE 整改后 END AS phase, ROUND(SUM(l.defect_qty) / NULLIF(SUM(l.receive_qty), 0) * 1000000, 1) AS ppm, COUNT(*) AS lot_cnt FROM iqc_lot l JOIN scar s ON s.supplier_id l.supplier_id AND s.failure_mode 尺寸超差 WHERE l.inspect_date BETWEEN DATE_SUB(s.closed_at, INTERVAL 90 DAY) AND DATE_ADD(s.closed_at, INTERVAL 90 DAY) GROUP BY s.supplier_id, phase;如果整改后 PPM 没降下来说明 D4 根因分析是走过场对策打在了症状上而不是原因上这时候该退回去重开 D4而不是继续往下走 D5 的永久对策。复评结果写回supplier.grade之后下一轮定时任务跑完IQC 工单上的抽检档位就自动换了档——控制从这里开始自己转起来。本文还有配套的精品资源点击获取
返回列表