ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

生成式AI上线评审:风险登记、脱敏留痕与证据包落地

生成式AI上线评审:风险登记、脱敏留痕与证据包落地

简介:《2023 生成式人工智能发展与监管白皮书》由南财合规科技研究院与观韬中茂律师事务所联合出品,面向关注AI产业、合规治理与政策研究的从业者、研究者及公众,系统梳理生成式AI的发展现状、政策导向、应用风险与各国监管路径,重点呈现中国在发展与安全之间的治理思路。资源包为1个PDF文件,约4.22MB,按“发展—风险—借鉴—实践”四部分展开,涵盖算力、大模型与应用市场,知识产权侵权、算法黑箱与歧视、数据安全与个人信息保护、伦理道德风险,以及美国、欧盟和中国的治理框架与商业化实践思考。目前已有153人学习下载,适合快速建立生成式AI监管议题的全景认知,也可作为报告写作、合规研判、课堂研讨与政策比较的参考资料。内容兼顾产业观察与法律合规视角,对理解生成式AI落地中的风险边界和治理工具具有较高参考价值。

1. 生成式人工智能落地评审的三个追问:这份白皮书到底能当什么用

做人工智能功能上线评审的团队,多半被这三句话问住过:训练语料从哪来、有没有授权凭证、用户输入会不会被拿去继续训练。问的人不一定懂模型,答的人常常只剩一句"行业里都这么做"。这份《2023 生成式人工智能发展与监管白皮书》的价值,不在于给你一份标准答案,而在于它把"发展现状、风险清单、域外观察、落地实践"四块拆得足够细,细到你能把里面的条目直接翻译成需求池里的检查项。适合三类人看:要拍板上不上生成式功能的产品负责人、负责语料和日志的后端与算法同学、以及需要在评审会上拿出证据的合规同学。翻完不一定能直接抄,但能少走不少弯路。

2. 四段骨架拆开看:发展、风险、域外观察、实践各喂给工程侧什么

很多人拿到这种几十页的材料,第一反应是从头读到尾,读完记住几个数字就放下了。实际用起来更高效的方式是把它当四份不同的输入:发展篇喂给你模块边界和成本量级,风险篇喂给你验收线,域外观察篇喂给你分级方法,实践篇喂给你研发与上线之间的那条界线。四份材料用途不同,读法也不该一样。

2.1 发展篇:数据、算力、模型、应用四层,正好对应四个模块边界

白皮书把生成式人工智能的产业链拆成数据层、算力层、模型层、商业化应用层,这个拆法对工程侧最大的好处是它天然对应了责任边界。数据层负责语料来源、清洗、标注;算力层负责训练与推理的容量;模型层负责选型、微调、评测;应用层负责交互形态和兜底。一个常见的翻车场景是:项目上线出了问题,大家围着模型层吵,最后发现是数据层的抓取没留授权凭证。按四层划分责任人,比按"前后端"划分更贴合这类系统的实际结构。

白皮书里给了几个可以拿来定量的锚点。它提到某个早期大模型的训练语料在 45TB 文本量级、包含 8000 亿词、模型参数 1750 亿;也给了算力口径:训练一次 13 亿参数规模的模型大约需要 27.5 PFlop/s-day,而单月运营所需的算力在数千 PFlop/s-day 量级。这两个数字放在一起看,结论很直接——推理侧的量级远高于训练侧,容量规划如果只按训练峰值买卡,上线一个月就会被打爆。

卡时换算的方法我一般这么走:把 PFlop/s-day 乘 86400 换成总浮点运算量,再除以单卡有效算力。单卡有效算力等于峰值乘利用率,训练场景利用率取 0.35 到 0.45 比较稳,推理场景因为批处理波动大,取 0.2 到 0.3 更保守。以主流训练卡 FP16 峰值 300 TFLOPS 为例,27.5 PFlop/s-day 折合约 5500 卡时,差不多是 229 张卡跑一天,这个量级对多数团队来说是要提前排队的。

产业链层白皮书给的事实锚点工程侧应产出的东西
数据层语料规模可达 45TB 量级语料台账、授权凭证目录、清洗版本记录
算力层训练 27.5 PFlop/s-day、月运营数千 PFlop/s-day容量模型、卡时预算表、降级预案
模型层通用模型与垂直模型两条路线选型决策记录、模型卡、评测集与基线分数
应用层办公、文娱、营销、家庭、金融等场景交互形态说明、人工兜底流程、抽检方案

模型层那一节提到通用模型和垂直模型的分野,这个判断对选型很关键。垂直模型成本低、部署灵活,但它对行业语料的质量要求反而更高,而且要能接进企业自己的知识库才能持续迭代。如果业务场景窄、数据又在自己手里,走垂直路线通常更划算;如果场景宽、迭代快、团队没有持续预训练的资源,接成熟接口再叠加检索增强是更现实的做法。选型时我会强制写一页决策记录,把"为什么不选自研"写清楚,评审会上这一页比任何 PPT 都好使。

2.2 风险篇:四类风险其实是四条验收线

风险章节罗列了知识产权侵权、算法风险、数据安全与个人信息保护、伦理道德四类。单看标题很容易滑过去,真正有用的是它把每一类下面的具体形态都点到了:输入端语料复制、输出端与原作品实质性近似、员工把内部资料贴进对话框导致商业秘密外泄、算法黑箱导致无法向用户解释结论、训练数据本身有偏导致分群体验不一致、模型在关键决策上给出错误判断。这些不是法律问题,是设计问题。

我的做法是把四类风险翻译成四条验收线,每条线配一个可检查的证据物。知识产权线看两个东西:语料授权覆盖率,以及输出端与原作品的近似检测报告。算法线看三样:决策留痕是否可回溯、分群评测集上各组的通过率差异、高风险场景是否有人工复核节点。数据与个人信息线看脱敏覆盖率、留存期限配置、以及有没有把用户输入默认纳入训练。伦理线看内容分级策略和生成内容标识。这四条线跑完,评审会上大部分追问都能当场翻到对应文件。

风险类典型现象可落地的控制点验收证据
知识产权输出与某段已有文本高度重合语料授权台账 + 输出近似检测授权覆盖率报表、重合度抽检记录
算法同一问题对不同人群给出不同质量答案分群评测集 + 决策留痕分组通过率差异表、trace 样本
数据与个人信息用户对话原文进了训练集输入侧脱敏 + 训练开关默认关闭脱敏日志、开关配置快照
伦理生成内容缺少标识、被二次传播显式标识 + 内容分级标识覆盖率、拦截记录

这里有个容易忽略的点:白皮书在知识产权那一节特别提到,模型训练的语料越匮乏,输出内容侵权风险越高;提示词写得越精准、越限缩,生成结果越容易贴近某个具体作品。这条对做提示词模板的团队是直接的警告——把模板写得过于具体,等于在帮模型复现某个来源。我的习惯是模板里保留风格描述,去掉具体作品名、角色名和段落引用。

2.3 域外观察篇:借的是分级方法,不是条文

域外观察那一章讲了两个法域在立法和风险治理框架上的进展,读的时候容易陷进条文对比里出不来。对工程团队真正有用的只有一件事:它们都在用"按风险分级"而不是"按技术分级"的思路。也就是说,判断一个功能该被多严格地对待,看的是它面向谁、处理什么数据、输出会不会被直接使用,而不是它用了多大的模型。

把这套方法搬到自己的项目上,我一般列五个判断项:是否面向公众开放注册、是否涉及未成年人、是否处理敏感个人信息、输出内容是否直接对外发布不经人工、是否用于影响个人权益的决策。五项里命中两项及以上,走高强度评审;命中一项,走常规评审;一项不中,登记备案即可。这套打分表写进需求模板后,产品同学提需求时自己就先分好级了,省掉大量来回。

要注意的是,域外框架里的具体条目和阈值是跟着当地立法走的,直接搬过来做合规判定会闹笑话。白皮书本身也是观察性质,不是规范性文件,条文口径必须以正式发布的文本为准。这一点在后面避坑那章还会展开。

3. 把风险章翻成风险登记表:九个字段、一套分级口径、一个生成脚本

风险清单如果只停留在文档里,三个月后一定没人看。让它活着的方式是变成一张可查询、可派工、可统计的表。这一章讲的是怎么把白皮书的风险条目落成登记表,以及怎么用一个小脚本把它变成评审会上能直接投屏的清单。

3.1 登记表的九个字段

字段设计的原则是:任何一个风险条目,扫一眼就知道谁负责、什么时候必须闭环、闭环的判据是什么。字段太少会变成一句空话,太多没人填。九个字段是我试过之后比较稳的一组。

字段说明填写要求
id全局唯一编号形如 R-001,按模块分段
category风险大类只能取知识产权、算法、数据与个人信息、伦理四值
scene触发场景写到具体功能点,如"客服问答自动回复"
risk风险描述一句话,包含触发条件和后果
likelihood可能性1 到 5,按 3.2 的口径打
impact影响1 到 5,按 3.2 的口径打
control现有控制措施写已有的,没有就写"无"
owner责任人必须是具体的人,不接受团队名
status状态待处理、缓解中、已闭环、已接受

likelihood和impact是全表唯一需要主观判断的地方,也是唯一容易吵架的地方。解决办法是把打分口径写死在表头注释里,谁打分谁负责解释。owner字段强烈建议做成必填校验,一张没有责任人的风险表,最后一定烂在共享盘里。

3.2 分级口径:可能性乘影响,落到处置时限

分级不用加权平均,加权平均的权重永远吵不完。直接用可能性乘影响,最高 25 分,然后按分数段映射到处置动作和时限。这个口径粗暴但好用,因为任何人都能在十秒内复算出结果。

分值区间处置等级动作要求时限
15 到 25阻断上线前必须闭环,或降级功能范围0 天
8 到 14缓解提交缓解方案并排期,允许带条件上线14 天
1 到 7接受登记观察,纳入季度复核90 天

打分的锚点要具体,否则每个人心里的"3 分"都不一样。我的锚点是这样:可能性 5 代表在当前流量下每天都会出现,3 代表每月出现若干次,1 代表理论上可能但从未观测到;影响 5 代表会直接导致对外内容错误或个人信息外泄,3 代表影响单个用户的体验但可人工纠正,1 代表内部可感知、用户无感。锚点写进模板,争议能少一半。

3.3 一个脚本把登记表跑成评审清单

登记表用 JSON 存,方便进版本库做 diff。下面这个脚本读取登记表,算出分值、等级和截止日期,渲染成一张 Markdown 表,直接贴进评审文档。

# risk_register.py —— 把风险登记表渲染成评审用的 Markdown 清单 import json from datetime import date, timedelta # 分级口径:score = 可能性 × 影响,最高 25 分 # 三元组含义:(分数下限, 处置等级, 时限天数) BANDS = [ (15, "阻断", 0), # 上线前必须闭环 (8, "缓解", 14), # 两周内提交缓解方案 (0, "接受", 90), # 登记观察,季度复核 ] def band_of(score): """按分值返回处置等级与时限,BANDS 必须按门槛从高到低排列""" for threshold, level, sla_days in BANDS: if score >= threshold: return level, sla_days return "接受", 90 def load(path): with open(path, encoding="utf-8") as f: data = json.load(f)["items"] # 无主风险直接拦截,避免登记表演变成许愿池 missing = [it["id"] for it in data if not it.get("owner")] if missing: raise ValueError(f"以下条目缺少责任人: {missing}") return data def render(items): rows = [] for it in items: score = it["likelihood"] * it["impact"] level, sla = band_of(score) due = date.today() + timedelta(days=sla) # 阻断级即时到期 rows.append( f"| {it['id']} | {it['scene']} | {it['risk']} | " f"{it['likelihood']} | {it['impact']} | {score} | " f"{level} | {it['owner']} | {due} |" ) head = ("| 编号 | 场景 | 风险描述 | 可能性 | 影响 | 分值 | 处置 | 责任人 | 截止 |\n" "|---|---|---|---|---|---|---|---|---|") return head + "\n" + "\n".join(rows) if __name__ == "__main__": print(render(load("risk_register.json")))

配套的登记表片段长这样,直接放进仓库跟代码一起走评审:

{ "items": [ { "id": "R-001", "category": "数据与个人信息", "scene": "客服问答自动回复", "risk": "用户输入含手机号时被原样写入训练样本", "likelihood": 4, "impact": 4, "control": "无", "owner": "某后端同学", "status": "待处理" } ] }

脚本逻辑很直白:likelihood乘impact得到分值,band_of按门槛从高到低匹配第一个满足的档位,所以BANDS的顺序不能乱,写反了会把阻断级降成接受级。时限用timedelta从当天起算,阻断级是 0 天即当天到期,这是刻意的——阻断级条目本来就不该有缓冲期。

参数上有三处可以按团队情况调。BANDS的门槛值,团队风险偏好保守可以调成 12 就阻断;sla_days按迭代周期调整,两周一个迭代的团队把缓解期设成 14 天刚好压在一个迭代内;owner校验从必填改成"必填且必须在通讯录里存在",能进一步减少无效填写。缺责任人就抛异常这个设计,是从一次事故里学来的——当时一张表里七条风险有五条责任人写的是"研发组",出事之后没人认。

4. 上线前卡三道闸:语料脱敏、交互留痕、输出抽检的落地参数

风险表和脚本解决的是"知道有什么风险",这一章解决"每天怎么防"。三道闸分别卡在数据进入模型之前、用户与模型交互之中、模型输出流向业务之后。三道都做成本会很高,但每道都有低成本的最小实现,关键是先有,再谈全。

4.1 第一道闸:输入侧的 PII 预处理

用户输入里带手机号、身份证号、邮箱、银行卡号是常态,这些东西一旦进了日志和训练样本,后面很难收场。最小实现是一个统一的脱敏入口,所有进入模型服务、日志系统和样本池的文本都先过一遍。

import re ID_CARD = re.compile(r"(?<!\d)(\d{17}[\dXx])(?!\d)") PHONE = re.compile(r"(?<!\d)(1[3-9]\d{9})(?!\d)") EMAIL = re.compile(r"([\w.+-]{1,64})@([\w-]+\.[\w.-]+)") BANK = re.compile(r"(?<!\d)(\d{16,19})(?!\d)") ID_W = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] ID_CHECK = "10X98765432" def valid_id(s): """校验身份证末位,避免把 18 位订单号误判成身份证""" total = sum(int(c) * w for c, w in zip(s[:17], ID_W)) return ID_CHECK[total % 11] == s[17].upper() def luhn(s): """银行卡 Luhn 校验,同样用于降低误杀""" total, alt = 0, False for ch in reversed(s): d = int(ch) if alt: d *= 2 if d > 9: d -= 9 total += d alt = not alt return total % 10 == 0 def mask(s, head=3, tail=3): if len(s) <= head + tail: return "*" * len(s) return s[:head] + "*" * (len(s) - head - tail) + s[-tail:] def scrub(text): text = ID_CARD.sub(lambda m: mask(m.group(1)) if valid_id(m.group(1)) else m.group(1), text) text = PHONE.sub(lambda m: mask(m.group(1)), text) text = BANK.sub(lambda m: mask(m.group(1)) if luhn(m.group(1)) else m.group(1), text) text = EMAIL.sub(lambda m: m.group(1)[0] + "***@" + m.group(2), text) return text

重点不在正则本身,而在两个细节。(?<!\d)和(?!\d)是前后边界,防止从一串长数字中间截取出 11 位当成手机号,没有这对断言,日志里一半的流水号都会被误掩。校验位判断是第二道过滤,身份证和银行卡都先验后掩,不合法就原样放行——这一步牺牲了一点漏检率,换回来的是排障时不用面对满屏星号。实际参数上,head和tail各留 3 位是我试出来的平衡点:留太少无法定位用户,留太多等于没掩。

如果业务需要"能还原",掩码就不够了,得用加盐哈希。做法是对原始值拼一个固定的盐再做 SHA-256,盐存在密钥管理里,不落代码库。代价是哈希后无法做模糊匹配,只能精确比对,所以通常只对身份证和银行卡这类强标识符用,手机号还是掩码更方便客服排查。

4.2 第二道闸:交互留痕的最小字段集

留痕不是把所有东西都记下来。全量记录对话原文,等于把个人信息风险从模型里搬到了日志里,风险没消失只是换了地方。最小字段集的原则是:能还原"谁在什么时候问了什么类型的问题、系统怎么响应的",但不保留可识别到人的原文。

字段是否必存说明
trace_id必存单次请求唯一标识,用于串联上下游
用户标识必存用内部 uid,不用手机号或邮箱
时间戳必存精确到毫秒,方便对齐告警
输入摘要必存脱敏后的前 N 字符,N 建议 200
输入哈希必存用于去重和相同问题聚类
输出摘要必存脱敏后内容,命中拦截规则时存全文片段
命中规则必存规则编号列表,空表示未命中
模型版本必存版本号加提示词模板版本
原始输入条件存仅命中高风险规则且进入人工复核时存
用户反馈选存点赞点踩,用于抽检加权

留存期限要跟业务场景挂钩,一般对话日志 90 天,进入人工复核的样本 180 天,训练样本池单独走审批。这组数字不是拍脑袋,是按"能不能在用户投诉的有效期内查到"倒推的。字段定完之后,落盘入口必须收敛成一个函数,任何绕过入口直接写日志的行为都要在代码评审里拦下来——我见过最典型的翻车是某个 SDK 自带的 debug 日志把完整请求打到了本地文件,上线三个月后才被发现。

4.3 第三道闸:输出抽检的分层方案

抽检的意义是给模型行为做持续采样,不是找茬。分层维度至少三个:场景、输出长度、是否命中敏感话题。每个层按固定比例抽,总量控制在人工可承受的范围内。

分层维度分层方式抽样比例判定重点
场景客服、营销文案、内部助手客服 5%,其余 2%事实性、承诺性表述
长度短于 100 字、100 到 500 字、长于 500 字短 1%,中 3%,长 10%长文本更易出现自相矛盾
敏感话题命中规则库的请求30%拒答是否恰当、有无越权建议
用户负反馈点踩或投诉100%必须逐条归因

抽检样本的随机种子要固定并记录,否则每周抽出来的样本没法比较,趋势图全是噪声。判定维度建议只留四项:事实是否可溯源、有无侵权近似、有无歧视性表述、有无超出业务范围的承诺。四项各打通过或不通过,不搞五分制,五分制的评分者一致性太差,最后没人信。

抽检发现的问题要回流到两个地方:一是规则库,把新发现的高频问题变成拦截规则;二是评测集,把确认的坏案例加进回归测试。这条回流路径不通,抽检就变成每周写一份没人看的报告。

5. 避坑记录:拿这份材料做落地时翻车的五个瞬间

5.1 把观察性材料当条文逐条对照

现象是评审会上有人拿着白皮书里的某句话问"这条我们算不算违反",然后全场沉默。原因是把行业观察材料当成了规范性文本,白皮书本身是研究性质,它描述的是趋势和框架,条文口径要以正式发布的文本为准。解决办法很简单:白皮书只用来做风险识别和分级,凡是涉及"是否合规"的判断,一律回到正式文本,并且把引用出处写进评审记录。

5.2 只做输出端过滤,输入端一本糊涂账

现象是上线两个月后被追问语料来源,翻遍仓库只有一个data_final_v3.zip。原因是团队把精力全放在输出审核上,输入端只留了一个文件名。解决方式是建语料台账,字段至少包含来源标识、获取方式、授权凭证路径、抓取时间、页面条款快照、是否含个人信息、清洗版本号。抓取时同步存一份条款快照这件事特别容易被跳过,等条款改了再回头找证据,基本找不回来。

5.3 把研发豁免理解成"内测随便搞"

现象是小范围灰度被认定为对外提供服务,团队一脸懵。原因是"研发"和"对外提供"之间没有定义边界。资源在实践部分记录的那条边界值得抄进内部规范:不向公众提供服务的研发、测试场景与正式对外服务要分开。落到工程上就是三件事——灰度环境走白名单邀请、不开放公开注册、输出内容加水印和"测试中"标识。这三件事做了,边界就清楚了。

5.4 脱敏脚本一把梭,把业务字段也掩了

现象是线上排障时日志里订单号全变星号,客服没法核对。原因是正则只卡了长度没做校验,把 18 位订单号当成身份证掩了。解决办法是第 4 章那套"先校验后掩码",再加一层字段白名单:明确列出哪些字段永不脱敏,比如内部订单号、trace_id。上线前用一周真实日志跑一遍,人工抽查 200 条,统计误杀率和漏检率,两个数字都写进验收报告。

5.5 抽检只挑好案例,坏案例进不了评测集

现象是抽检报告每周都是"整体良好",上线后投诉集中爆发。原因是抽检样本来自手工挑选,天然避开了长尾场景。解决办法是固定随机种子、按场景分层抽样、把点踩和投诉样本 100% 纳入。更进一步,把确认的坏案例回流成回归测试用例,每次模型或提示词变更都跑一遍,这一条比任何流程文档都管用。

6. 进阶:攒一页合规证据包,把评审会一次过掉

评审会开到第三轮还在扯皮的团队,问题通常不是没做,而是拿不出证据。我的做法是给每个生成式功能配一个"证据包"目录,跟代码仓放在一起,按版本归档。目录结构固定成六项,每项对应一个验收人,缺项就不允许提评审。

证据项内容对应验收人
语料台账来源、授权凭证、条款快照、清洗版本数据负责人
模型卡选型理由、版本号、评测集与基线分数算法负责人
风险登记表分值、处置等级、责任人、闭环记录项目负责人
留痕样本脱敏后的请求响应样本各 20 条后端负责人
抽检报告分层抽样结果、四项判定通过率质量负责人
处置记录拦截规则变更、坏案例回流清单合规对接人

这六项不需要一次做全,第一版可以只做台账、模型卡、登记表三项,剩下的随版本补齐。关键是每项都要有版本号,能回答"上个版本是什么样"这个问题。评审会上最有说服力的一句话不是"我们做了",而是"这是上周三的抽检报告,通过率 94%,两个不通过项已经进了回归集"。

验证这套东西有没有真的跑起来,有个很土但有效的办法:随机挑一个上周的用户投诉,从 trace_id 一路查到语料来源和当时的模型版本,全程不超过十分钟,说明链路是通的;超过半小时或者中间断了一环,说明证据包只是摆设。我一般每个季度做一次这样的反向抽查,抽查记录本身也归档。

说个自己的教训。早前做一个内部问答助手,风险表填得很漂亮,二十多条风险一个不落,责任人也都写了。上线前一周我把表拉出来复核,发现"已闭环"那一列里,有六条的控制措施写的是"提示词里加了约束"。提示词当然算控制措施,但它不是可验证的控制措施——没人知道约束有没有生效,也没人测过绕过的情况。从那以后我每次填风险表,只要控制措施里出现"提示词"三个字,就强制要求补一条对应的评测用例,跑不出结果的当未闭环处理。这个习惯后来救过两次场,都是模型换了版本、约束悄悄失效的情况。

希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进