🏠 总目录📚 本教程 19 · 合规、审计与模型卡
📑 本页目录(点开跳转)

19 · 合规、审计与模型卡

44 分钟 | 📋 不是走过场,是给自己留后路


🎯 一句话

当模型影响到人的钱、机会或权利时,「效果好」就不再是唯一标准。 这一章讲三件事:公平性怎么量、决策怎么解释、以及怎么写一份能救你的模型卡。


⚖️ 一、公平性:先想清楚你要哪一种

「公平」不是一个定义,是好几个互相冲突的定义

定义 含义 例子
群体公平(统计均等) 各群体的通过率相同 男女的贷款通过率一样
机会均等 各群体中真正合格的人通过率相同 有还款能力的人,不分性别都能过
预测均等 各群体的预测精度相同 对各群体的预测同样准
个体公平 相似的个体得到相似的结果

🔑 一个必须知道的数学事实除非各群体的基础率恰好相同,否则上面几个定义不可能同时满足。 这是被证明过的(fairness impossibility)。

实践含义你必须先选一个,并且说清为什么选它 —— 而不是笼统地说「我们的模型是公平的」。

为什么不可能同时满足?一个 30 秒能算完的例子

   两个群体,基础率不同:A 组 30% 真的合格,B 组 10% 真的合格
   假设模型对两组【同样准】:TPR = 0.8,FPR = 0.1   ← 机会均等 ✅

   A 组通过率 = 0.3×0.8 + 0.7×0.1 = 0.31
   B 组通过率 = 0.1×0.8 + 0.9×0.1 = 0.17   ⭐

   💀 「机会均等」一满足,「群体公平」自动就不满足(0.17 / 0.31 = 0.55)
      想把通过率拉平?只能对 B 组降门槛 —— 那又会破坏「预测均等」

这不是模型不够好,是数学上的必然基础率不同的两个群体,你只能选一个方向去对齐。 报告里要写的是「我们选了机会均等,因为……」,而不是「我们的模型公平」。

怎么量

import pandas as pd

def fairness_report(df, group_col, y_true, y_pred):
    """⭐ 给每个群体算一整排数字放在一张表里 —— 单看任何一个都会误导"""
    out = []
    for g, d in df.groupby(group_col):
        out.append({
            "群体": g, "样本量": len(d),
            "基础率": d[y_true].mean(),                        # ⭐ 冲突的根源,必须报
            "通过率": d[y_pred].mean(),                        # 群体公平看这个
            "TPR": d.loc[d[y_true] == 1, y_pred].mean(),       # ⭐ 机会均等看这个
            "FPR": d.loc[d[y_true] == 0, y_pred].mean(),
            "PPV": d.loc[d[y_pred] == 1, y_true].mean(),       # 预测均等看这个
        })
    t = pd.DataFrame(out)
    # ⭐ 四五分之规则:最低通过率 / 最高通过率 ≥ 0.8,否则要能解释清楚
    t["通过率之比"] = t["通过率"] / t["通过率"].max()
    return t

「四五分之规则」(80% rule)值得记住弱势群体的通过率 ÷ 优势群体的通过率 < 0.8 时,就要能拿出解释。 它不是数学定理,是一条被广泛引用的经验红线 —— 但它的价值在于:它是一条你今天就能算出来的、具体的数字。 上面那个例子里比值是 0.55直接触线

⚠️ 两个常见误区

误区 真相
「把敏感特征删掉就公平了」 其他特征会代理它(邮编 ≈ 种族,购物记录 ≈ 性别)⭐
「差异 = 歧视」 ❌ 差异可能来自真实的基础率不同;要看的是「同等条件下是否被区别对待」

第一条特别重要删掉敏感特征反而会让你失去检测偏差的能力 —— 你连"有没有偏差"都测不出来了。 正确做法通常是:不用它做预测,但保留它做审计。(具体受当地法规约束)

💀 一个案例:删掉了性别,却比带着性别更歧视

   场景:简历初筛模型
   合规要求:不得使用性别
   团队做法:删掉性别字段,顺便也删掉了姓名             ✅ 看起来很干净

上线半年后,外部审计(带着自己的数据)算出来

指标 数字
女性候选人通过率 ÷ 男性候选人通过率 0.61 💀(四五分之规则要求 ≥ 0.8)
团队自己在这半年里发现的问题 —— 因为他们没有性别字段,根本算不出这个比值

模型学到了三个强代理

   ① 毕业院校     —— 女子学院、师范类院校的分布差异
   ② 简历关键词   —— 社团、爱好、志愿经历的用词差异
   ③ 工作年限的【连续性】⭐ —— 生育带来的空档期被学成了负面信号

⭐⭐ 这个案例的核心结论,值得抄在合规评审的第一页删掉敏感特征不会消除偏见,只会消除你发现偏见的能力。 半年里唯一有能力做这个检测的,是外部审计——因为只有他们手上有性别标签。

🔍 上线前跑一次「代理检测」,20 行代码

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score
import pandas as pd

def proxy_audit(X_without_sensitive, sensitive, top_k=10):
    """⭐ 用【剩下的所有特征】去预测敏感属性 —— 预测得越准,代理越强"""
    clf = GradientBoostingClassifier(random_state=0)
    auc = cross_val_score(clf, X_without_sensitive, sensitive,
                          cv=5, scoring="roc_auc").mean()
    clf.fit(X_without_sensitive, sensitive)
    imp = pd.Series(clf.feature_importances_,
                    index=X_without_sensitive.columns).nlargest(top_k)
    return {"能多准地推出敏感属性(AUC)": round(auc, 3), "最强的代理": imp}
这个 AUC 说明
≈ 0.5 ✅ 基本没有代理,删掉敏感特征确实有效
0.65 – 0.85 ⚠️ 有明显代理,"删了字段"是自欺欺人
> 0.9 💀 敏感属性几乎被完整重建了,模型事实上"知道"每个人的性别/种族

这个检查的妙处在于:它不需要模型上线,也不需要标签。 只要有历史数据和敏感属性标签,半小时就能跑完 —— 而且它输出的 最强的代理 那张表,直接告诉你该去审查哪几个特征


📜 二、可解释性:给人看的解释

技术解释 ≠ 给用户的解释

   ❌ 「特征 f_23 的 SHAP 值是 −0.18」
   ✅ 「主要因为您近 30 天有 5 次贷款申请记录」

   ⭐ 好的对外解释要满足三条:
   ① 用业务语言,不用特征名
   ② 是【可行动的】—— 告诉他怎么做能改变结果
   ③ 数量不超过 3-4 条,按影响排序

🔗 技术侧怎么算在第 10 章 SHAP这一章关心的是怎么把它翻译成人能用的话。

⚠️ 一个法律与技术的落差: 很多法规要求「对自动化决策提供解释」, 但SHAP 给的是「模型为什么这么算」,不是「现实中你该怎么改」第 10 章的边界)。 如果解释要用于指导用户行动,需要额外确认因果方向第 13 章)。


📋 三、模型卡(Model Card)

一页纸,回答别人会问的所有问题

# 模型卡:<模型名> v<版本>

## 1. 基本信息
- 用途:解决什么业务问题
- 版本 / 上线日期 / 负责人
- 上游依赖、下游消费方

## 2. 预期用途与【不适用范围】⭐⭐
- 设计用于:______
- **不应用于**:______(这一条最重要)
- 已知失效场景:______

## 3. 训练数据
- 来源、时间范围、样本量
- 人群构成(各群体占比)⭐
- 已知的采样偏差

## 4. 评估结果
- 整体指标
- **分人群指标** ⭐(不只是总体)
- 公平性指标(选了哪个定义、为什么)

## 5. 局限与风险
- 已知的失效模式
- 分布外行为
- 反馈闭环风险

## 6. 运维
- 监控项与告警阈值
- 重训周期与触发条件
- 降级策略、回滚方式
- 联系人 / 值班

第 2 节的「不应用于」是整张卡最有价值的部分模型被滥用,绝大多数是因为使用者不知道它的边界。

💀 一个典型的滥用:给「用户流失预测」模型的分数, 被业务方拿去当作「用户价值分」来分配客服资源 —— 两者完全不是一回事,但分数看起来都像"用户好坏"。 模型卡写清楚「不应用于评估用户价值」,就能挡住它。

⚠️ 模型卡真正的难点不是写,是「不腐烂」

   💀 最常见的失败模式:
   模型卡在上线那天写得很好,然后【再也没有更新过】
   → 半年后它描述的是一个已经不存在的模型
   → 而所有人还在拿它当依据 —— 比没有模型卡更危险  ⭐

三条让它活下来的机制

机制 做法
和发布单元绑在一起 ⭐⭐ MODEL_CARD.md 放进第 17 章的发布目录,每个版本一份
关键字段自动生成 训练数据时间范围、样本量、人群构成、分人群指标 —— 这些都该由训练脚本写出来,不靠人手填
过期即告警 模型卡的 last_reviewed 超过 6 个月 → 进值班列表

「自动生成」这条最有效需要人手填的部分越少,模型卡越不容易腐烂。 真正需要人写的其实只有两节:「不应用于」「已知的失效模式」 —— 而这两节恰好也是最有价值的两节。


🔍 四、审计要能回答的五个问题

   ① 这个决策是怎么做出的?        → 第 17 章的日志 + 第 10 章的 SHAP
   ② 模型用了哪些数据训练?        → 数据快照 + 模型卡
   ③ 有没有对某群体系统性不利?     → 分人群评估 + 公平性指标
   ④ 出问题时怎么发现和纠正?       → 监控 + 回滚 + 申诉通道
   ⑤ 谁负责?                    → 模型卡里的负责人

④ 里的「申诉通道」常被忽略自动化决策必须有人工复核的入口。 这既是很多法规的要求,也是发现模型系统性错误的重要来源 —— 申诉数据本身就是一份高质量的错误样本集


🧭 五、一个务实的分级

不是所有模型都需要这一整套

影响 该做的
内部工具、无个人影响 模型卡(简版)+ 基础监控
影响用户体验(推荐、排序) + 分人群评估 + 申诉通道
影响机会(信贷、招聘、定价) + 完整公平性评估 + 可解释 + 人工复核
影响安全/健康 + 外部审计 + 强制人工确认

判据是「模型的错误会给个人造成什么后果」, 不是模型有多复杂、也不是用了什么算法。


⚠️ 六、一张坑表

后果 怎么修
说「我们的模型是公平的」 没说清是哪种公平,等于什么都没说 明写选了哪个定义、为什么
删掉敏感特征就算完事 💀 代理照样歧视,而你失去了检测能力 不用于预测,保留用于审计;上线前跑 proxy_audit
只报整体指标 分人群的问题永远看不见 分人群评估进闸门(第 16 章闸3)
只看通过率差异,不看基础率 把真实的基础率差异当成歧视 基础率必须报,它是所有冲突的根源
模型卡写完不再更新 半年后它描述的是一个不存在的模型,比没有更危险 绑进发布单元 + 关键字段自动生成 + 过期告警
模型卡不写「不应用于」 分数被拿去做完全不同的决策 那一节是整张卡最有价值的部分 ⭐⭐
自动化决策没有申诉入口 既违规,又丢掉了最好的错误样本来源 申诉通道 + 人工复核
申诉数据只用来处理个案 浪费了一份高质量的标注 定期把申诉样本喂回评估集 ⭐
对外解释直接吐 SHAP 值 用户看不懂,且可能给出错误的行动建议 翻译成业务语言 + 先确认因果方向(第 13 章
所有模型都上全套合规 成本高到没人执行,最后一起摆烂 按影响分级,判据是「错误对个人的后果」

🔗 七、和站内其他章的关系

相关的地方 和这一章的关系
第 10 章 SHAP 技术解释的来源
第 13 章因果 「可行动的解释」需要它
第 17 章回溯 审计问题 ① 的基础
全景导论 14 LLM 场景的合规
全景导论 12 · 对齐与AI安全 治理那一侧:模型该不该做某件事,是在训练阶段用对齐解决的。本章管的是「做完之后怎么留证据、怎么应付审计」——同一件事的前后两半
智能体工程 15 Agent 的安全边界

✅ 检查点

  1. 四种公平性定义分别是什么?为什么必须先选一个?用那个 30 秒的例子说明它们为什么冲突。
  2. 什么是四五分之规则?上面那个例子里的比值是多少?
  3. 「删掉敏感特征就公平了」错在哪?用那个简历初筛的案例说明。正确做法通常是什么?
  4. 代理检测怎么做?AUC 落在哪个区间说明"删字段是自欺欺人"?这个检查为什么特别划算?
  5. 对外解释要满足哪三条?SHAP 用于对外解释时有什么落差?
  6. 模型卡里最有价值的是哪一节?举那个滥用的例子。
  7. 模型卡真正的难点是什么?哪三条机制能让它不腐烂?其中最有效的是哪一条、为什么?
  8. 审计要回答哪五个问题?哪一项常被忽略、为什么它重要?
  9. 分级的判据是什么?为什么不该所有模型都上全套?
👀 答案
  1. 群体公平(通过率相同)、机会均等(真正合格的人通过率相同)、预测均等(预测精度相同)、个体公平。必须先选一个是因为:除非各群体基础率恰好相同,否则这些定义不可能同时满足(已被证明)。例子:A 组 30% 合格、B 组 10% 合格,模型对两组同样准(TPR=0.8、FPR=0.1,机会均等成立)→ A 组通过率 0.31、B 组 0.17群体公平自动就不成立;想拉平通过率只能对 B 组降门槛,那又破坏预测均等。这不是模型不够好,是数学上的必然。
  2. 弱势群体的通过率 ÷ 优势群体的通过率不低于 0.8,否则要能拿出解释。它不是数学定理,是一条被广泛引用的经验红线,价值在于今天就能算出来。上面那个例子里是 0.17 / 0.31 = 0.55,直接触线
  3. 因为其他特征会代理它(邮编≈种族、购物记录≈性别)。案例:简历初筛模型删掉性别和姓名,半年后外部审计算出女性通过率是男性的 0.61 倍,而团队自己发现的问题是零——因为没有性别字段,他们根本算不出这个比值。模型学到的三个代理是:毕业院校简历关键词(社团/爱好用词)、以及工作年限的连续性(生育空档期被学成负面信号)。核心结论:删掉敏感特征不会消除偏见,只会消除你发现偏见的能力。正确做法通常是:不用它做预测,但保留它做审计(受当地法规约束)。
  4. 用剩下的所有特征去预测敏感属性,预测得越准说明代理越强。AUC 0.65–0.85 说明有明显代理、"删了字段"是自欺欺人;接近 0.5 才算真的没代理;超过 0.9 意味着敏感属性几乎被完整重建了。划算是因为不需要模型上线也不需要标签,有历史数据和敏感属性标签半小时就能跑完,而且它输出的「最强的代理」那张表直接告诉你该去审查哪几个特征
  5. ①用业务语言不用特征名 ②是可行动的(告诉他怎么做能改变结果)③不超过 3-4 条、按影响排序。落差在于:SHAP 给的是「模型为什么这么算」,不是「现实中你该怎么改」;如果解释要用于指导用户行动,需要额外确认因果方向
  6. 第 2 节的「不应用于」。因为模型被滥用绝大多数是使用者不知道边界。例子:「流失预测」的分数被拿去当「用户价值分」分配客服资源——两者完全不是一回事但分数看起来都像"用户好坏"。
  7. 难点不是写,是不腐烂:最常见的失败是上线那天写得很好、然后再也没更新,半年后它描述的是一个不存在的模型,而所有人还拿它当依据——比没有模型卡更危险。三条机制:和发布单元绑在一起(每个版本一份)、关键字段由训练脚本自动生成last_reviewed 超过 6 个月就告警。最有效的是自动生成——需要人手填的部分越少,模型卡越不容易腐烂;真正需要人写的只有「不应用于」和「已知失效模式」两节,而这两节恰好也最有价值。
  8. ①决策怎么做出的 ②用了哪些数据训练 ③有没有对某群体系统性不利 ④怎么发现和纠正 ⑤谁负责。④里的「申诉通道」常被忽略——它既是法规要求,申诉数据本身也是一份高质量的错误样本集,应该定期喂回评估集。
  9. 模型的错误会给个人造成什么后果——不是模型有多复杂、用了什么算法。不该所有模型都上全套,是因为成本高到没人执行,最后会一起摆烂

🛑 可以停在这里

走神救援

「公平」不是一个定义是好几个互相冲突的定义:群体公平(通过率相同)、机会均等(真正合格的人通过率相同)、预测均等、个体公平;⭐⭐已被证明:除非各群体基础率恰好相同,否则不可能同时满足你必须先选一个并说清为什么。⚠️两个误区:⭐「删掉敏感特征就公平了」是错的——其他特征会代理它(邮编≈种族),而且删掉后你连有没有偏差都测不出来,正确做法通常是不用它预测但保留它做审计;「差异=歧视」也错,要看的是同等条件下是否被区别对待对外解释三条:用业务语言、可行动、不超过3-4条;⚠️落差:SHAP 给的是"模型为什么这么算"不是"现实中你该怎么改",要指导行动得先确认因果方向。⭐⭐模型卡最有价值的是「不应用于」那一节——滥用绝大多数是因为使用者不知道边界(典型:流失预测分数被拿去当"用户价值分"分配客服资源)。审计五问:怎么做出的/用了什么数据/有无群体不利/怎么发现纠正/谁负责;⭐「申诉通道」常被忽略——它既是法规要求,申诉数据本身也是高质量的错误样本集。⭐分级判据是「错误会给个人造成什么后果」,不是模型多复杂(全都上全套的结果是成本高到没人执行、最后一起摆烂)。⭐30 秒看懂"为什么不可能同时满足":A 组 30% 合格、B 组 10% 合格,模型对两组同样准(TPR=0.8/FPR=0.1,机会均等成立)→ A 组通过率 0.31、B 组 0.17,群体公平自动就不成立;想拉平只能对 B 组降门槛,那又破坏预测均等。这不是模型不够好,是数学上的必然。四五分之规则:弱势群体通过率 ÷ 优势群体通过率 不低于 0.8,上面这个例子是 0.55,直接触线——它的价值在于今天就能算出来。💀真实案例:简历初筛模型删掉性别和姓名,半年后外部审计算出女性通过率是男性的 0.61 倍,而团队自己发现的问题是零——因为没有性别字段,他们根本算不出这个比值;模型学到的三个代理是毕业院校、简历关键词、以及工作年限的连续性(生育空档期被学成负面信号)。⭐⭐该抄在合规评审第一页的一句:删掉敏感特征不会消除偏见,只会消除你发现偏见的能力。 🔍上线前跑 20 行的代理检测:用剩下的特征去预测敏感属性,AUC 0.65–0.85 就说明"删了字段"是自欺欺人,超过 0.9 意味着敏感属性几乎被完整重建;不需要上线也不需要标签,半小时跑完,还直接告诉你该审查哪几个特征。⚠️模型卡的难点不是写是不腐烂——上线那天写得很好然后再没更新,半年后它描述的是一个不存在的模型,比没有更危险;三条机制:绑进发布单元、⭐关键字段自动生成(人手填的越少越不容易腐烂)、过期告警;真正需要人写的只有「不应用于」和「已知失效模式」两节,而这两节恰好最有价值

下一节 👉 20-实战与挑战项目.md

打卡记录保存在你的浏览器里,首页能看到总进度