--- topic: 审核台运营 canonical: true date: 2026-06-22 --- # 运营域 · 审核台与内容安全运营 > **这是什么**:绘境AI 平台每天怎么把生成出来的内容审一遍、违规了怎么处置、运营在后台用什么台子干这摊活——也就是"审核台"这一整套机制的设计。它回答"双层审核怎么判、锁风三档怎么跟 IP 库绑、处置怎么联动信息流和创作者信用、人审队列怎么走 BPM、admin 审核台长什么样"。 > **给谁看**:写 compliance / feed / admin 后台的工程师、做内容安全运营的同事、对接律所聊审核制度的人,以及创始人。 > **怎么读**:先看 §1 它和[合规闸门](合规闸门.md)的分工——一个管"能不能上线这件事的法定门槛",一个管"上线之后每天怎么把内容守住";再按 §3 各小节看具体设计。 > **边界**:合规闸门那 12+1 道法定上线门(ICP/版号/大模型登记…)在[合规闸门](合规闸门.md),本页不重复。本页只讲"内容安全运营"——审、处置、台子。 --- ## 1. 审核台和合规闸门是两件事 [合规闸门](合规闸门.md)讲的是绘境AI 作为一个平台,要合法地公开经营,必须先穿过哪些**法定资质门**:ICP 备案、版号、大模型登记、算法备案这些。那是一次性的、日历驱动的、过了就不用再过的前置条件,卡的是"平台能不能开门"。 审核台讲的是另一件事:门开了以后,平台上每天有人用一句话生成新游戏、传新素材、发新内容,这些**用户产生的内容(UGC)+ AI 生成的内容(AIGC)**得有人(和机器)一条条审过去,违规的要拦下来、要处置。这是持续运转的日常运营,卡的是"每一条内容能不能放出去、放出去之后表现不对怎么收回来"。 两者的关系可以这样讲:合规闸门是把平台这台机器**通上电的总开关**,审核台是机器跑起来之后的**质检线和安全阀**。它们在一个点上交汇——合规闸门里有一道门(A1 看板 #8 内容合规材料)要求平台"拿得出一套内容审核制度文本 + 审核记录留存机制",而这套制度文本描述的就是审核台怎么运转、审核记录从哪来。所以审核台不只是运营工具,它本身是法定合规材料的实现物;渠道提审、ICP 经营性升级都会要它。 ```mermaid flowchart LR subgraph 闸门["合规闸门(法定上线门 · 一次性)"] G["ICP / 版号 / 大模型登记 / 算法备案
过了平台才能开门"] end subgraph 审核台["审核台(内容安全运营 · 持续)"] A["每条 UGC/AIGC 内容
双层审核 + 锁风三档 + 违规处置"] REC["审核记录留存"] end G ==>|开门后| A REC -.->|实现物| MAT["#8 内容合规材料
(渠道提审 / ICP 升级要)"] MAT -.->|是闸门的一道| 闸门 ``` 还有一条法定义务直接落在审核台上:AIGC 显式标识。绘境AI 上几乎每款游戏都是 AI 生成的,《人工智能生成合成内容标识办法》要求显著标注"AI 生成"。这道标识不是审核动作,但它和审核台共用同一批生成元数据(promptHash、生成来源),后面 §3.6 会讲它怎么和审核记录、隐式水印一起挂在内容溯源这条线上。 --- ## 2. 现状:框架在、判定为空、处置半通 把审核台拆开看,它落在 compliance、feed、community 三个模块里,而这三处的现状很不一样——有的已经把骨架建好了,有的连桩都没有。设计要落在这个现状上,不能假装从零开始。 **compliance 模块:锁风门框架真、判定原子全是桩、封禁链路半通。** 锁风门 `ComplianceGateApi.evaluate` 已经是现行真相:它聚合各合规原子,按 `block > review > pass` 取最严裁决,落一条 `game_compliance_gate_result` 审计台账,顺带 upsert 一个内容分级(`all/8+/12+/16+`),裁决结果在 project 发布前检查(T-PRJ-05)里被真注入。但是——聚合进来的两个原子(`StyleComplianceAtom` 风格、`IpComplianceSeam` IP)**目前都是桩,恒返回 pass**。意味着今天的发布链对违规内容**零自动拦截,纯靠人工兜底**。封禁台账(`UserBanDO` + `BanStatusEnum`)和申诉状态机(`AppealStatusEnum`:0 待处理→1 通过/2 驳回)是真的,admin 侧 `compliance:appeal:handle` 能处理申诉,权限位现有 `compliance:ban:create` / `:cancel` / `:query`。 封禁的下游联动只通了一半。封禁单个**游戏**目标时,`UserBanServiceImpl.createBan` 会调 `ProjectApi.unlistIfPublished(gameId)`,走 project 权威状态机把那一款 PUBLISHED 游戏下架(Phase C 已收口,真实现非桩)。但封禁**账号(创作者)**这条断着:`createBan` 只写 `game_user_ban` 台账,既不置 `game_player.status=DISABLE`,也不遍历下架该创作者已发布的全部内容;而创作入口的 `validateCreator`(passport)只查 `game_player.status` 和 `creator_flag`、**不查 `game_user_ban` 表**。结果是封了一个创作者账号后,他的 `game_player` 仍是启用态,`validateCreator` 照样放行——封号拦不住本人继续创作。"封号连带全部内容下架"目前是零实现。本设计要补这条断链(§3.5)。 **feed 模块:降权/下架的字段和管理端都在,但缺一个供 compliance 调的跨模块降权接缝。** 现状是:`FeedRankDO` 上有 `exposureLimit`(限曝光降权因子,`>=9999` 是硬剔除哨兵,出流时直接踢掉)和 `status`(`0` 屏蔽,注释明写"举报降权/下架联动"),排序分公式是 `sort_score = quality_score + boost − exposureLimit`;运营在 admin 侧有一个 `setExposureLimit` 端点(`AdminFeedController`,权限位 `feed:featured:update`)能手动调降权。但要注意——`setExposureLimit` 是**管理端 HTTP 端点**,不在 feed 对外的跨模块 `FeedApi` 契约上;`FeedApi` 目前只暴露 `upsertRank`(发布基线/算分回灌)和 `offlineRank`(按 gameId 全分区下架,status=0)两个方法。也就是说,compliance 现在能调 feed 的只有 `offlineRank` 这条**下架**接缝(已用于封禁联动下架),**没有一个跨模块的降权接缝**让 compliance 去调 `exposureLimit`。 而且这个降权接缝是上一波**刻意没建**的:封禁联动的代码注释(`UserBanServiceImpl`,R5 降权出流屏蔽)写明"P1 本波不生效——不注入 feed、不建 FeedDownweightApi 孤儿 seam"。所以处置联动 feed 这件事,**下架**走现有 `offlineRank` 就够,**降权**则要么新建一个 feed 降权 `-api`(把 `setExposureLimit` 提升到跨模块契约),要么改走"下架 + 内容安全处置台账"的组合而不单独做降权——这是 §3.5 要定的事,别声称接缝已经焊好。 **community 模块:创作者信用的宿主是等级引擎,但信用本身零实现。** "创作者信用"这个概念目前没有独立实体。community 有一个等级引擎(`LevelDO`,表 `game_community_level`,T-CMU-11),现有字段是 `level/publishedCount/lastMilestone` 这些,**没有 `credit_score`**,MVP 只维护发布计数 + 新人里程碑、分层留 P1;`CommunityNotifyApi` 也没有任何扣分端点。信用分要么挂上这条等级线(加列),要么另立一张独立扣分台账——两条路在 §3.5 里展开,创始人 2026-06-22 定放第一期、建简单扣分台账。 **完全没有的:** 双层机审的两层都没接——既没有自部署快检模型,也没有阿里云内容安全客户端(全仓只有 OSS 用到阿里云);人审队列只有"申诉"这一种工单,没有"内容初审/复审"的工作队列(带认领、分派、SLA);锁风三档强度只有分级(rating)这个结果字段,没有"按 IP 敏感度选标准/严格/人工复核档"的策略配置,IP 库本身还是 seam(寄宿 compliance,授权链未建)。 ```mermaid flowchart TB subgraph 真["已建成(真 / 框架真)"] GATE["锁风门聚合 + 台账 + 分级
(原子是桩,恒 pass)"] BAN["封禁台账 + 申诉状态机
(封游戏→下架那一款;封账号未联动)"] EXP["feed exposureLimit + status 字段
+ admin setExposureLimit + 跨模块 offlineRank"] LV["community 等级引擎
(信用宿主)"] end subgraph 缺["待建(本设计补)"] L1["自部署快检(第一层)"] L2["阿里云内容安全(第二层兜底)"] QUEUE["人审工作队列 + BPM 流转"] STR["锁风三档策略 + IP 库绑定"] DRIVE["feed 降权 -api + 封账号联动 + 信用扣分"] end ``` --- ## 3. 设计 ### 3.1 目标 把上面这堆"框架在、判定空、处置半通"补成一套能日常运转的内容安全运营机制,具体要做成: 1. **一条贯通的审核判定流**:任何要对外的内容(发布的游戏、上传的素材),先过自部署快检挡掉大面,拿不准的送阿里云兜底,再拿不准的进人审队列,人审走 BPM 工作流。三层各有明确的放行/拦截/转人工阈值,任何一条内容的最终裁决都能追到是哪一层、为什么判这个结果。 2. **锁风三档是一个可配的运营旋钮**:标准/严格/人工复核三档,按 IP 敏感度和内容类型选,和 IP 库绑定——给迪士尼这种高敏 IP 创作的内容自动走严格档甚至人工复核,UGC 原创走标准档。 3. **违规处置真联动**:封禁、举报降权、分级标签三类处置动作,真的去改 feed 的曝光权重、真的去扣创作者信用,而不是只在 compliance 自己库里记一笔。 4. **admin 审核台是运营的工作台**:队列(看什么待审)、详情(看一条内容的全部判定证据)、处置(一键封禁/降权/打标)、锁风档位配置(调三档策略),权限分清楚谁能审、谁能配策略、谁能封号。 **审核状态的唯一权威在 compliance**。project 只持有游戏的生命周期状态(draft/published/…),审核结论(pass/review/block、人审队列状态、锁风裁决)归 compliance 拥有,project 只接收回写、不自己写审核态。这是为了避免"两个模块都在写审核状态"的脑裂——历史上 Wave3 评审就拍过这个归属切分,这里继承。 ### 3.2 双层审核的判定流:快检挡大面、兜底定生死、人审兜疑难 审核判定的主干是一个**三段瀑布**:自部署快检 → 阿里云兜底 → 人审队列。设计的核心不在"调用三个检测器",而在**路由——什么内容在哪一层被放掉、什么内容必须往下一层送**。路由对了,既能把绝大多数内容用最便宜的方式放行,又不会让真正有问题的内容漏过去。 **第一层 · 自部署快检(safe-content-ai)。** 自己部署的轻量内容安全模型,对文本/图片做一遍快、免费、低延迟的扫描。它的职责是**挡掉大面**——明显没问题的直接放行(占绝大多数),明显违规的直接拦截,只把**落在中间灰带的样本**往下送。这一层的价值是成本:阿里云内容安全是按调用量收费的,如果每条内容都送阿里云,成本会随产能线性涨(三向审计早就点名"成本表漏了审核 API")。快检把大部分流量在本地消化掉,只让灰带样本花阿里云的钱。 **第二层 · 阿里云内容安全(兜底)。** 灰带样本送阿里云的文本/图像内容安全 API,拿它**有合规背书的权威结论**。这一层不是每条都过,是快检拿不准时才过。阿里云返回的标签(色情/暴恐/政治等)映射成平台的 `block/review/pass`:确定违规 → block,确定无问题 → pass,它也拿不准或返回需人工复核的标签 → review,转人审。 > **接入时点(创始人 2026-06-21 定)**:阿里云兜底在**接真实公开流量之前**接入——也就是渠道线③上线前。自有端邀请制内测阶段(②),内容面向的是邀请来的种子用户、量小可控,快检 + 人审已经够用;等真的要面向陌生公众放量(渠道线),阿里云的权威背书才成为合规刚需。所以这一层的代码接缝现在就留好(检测器抽象 + 一个本地快检实现),阿里云实现挂在 feature flag 后面,放量前接通。 **第三层 · 人审队列。** 两道机审都判 review(拿不准),或者锁风三档策略直接要求人工复核的,进人审队列。人审给出 approve/reject 的人工终裁,这一裁决是最高权威,覆盖机审结论。人审怎么组织成队列、怎么走 BPM,在 §3.4 单独讲。 下面这张图画的是**单条内容的运行时路由**。注意:第二层走不走阿里云,不是按内容逐条决策的,而是一个**部署时点的 feature flag**——放量前(渠道线③)把 flag 打开、灰带样本接通阿里云,放量前 flag 关着、灰带直接进人审。所以图里灰带出口标的是"flag 开 → 阿里云 / flag 关 → 人审",而不是一道按内容判的运行时分支。 ```mermaid flowchart TB IN["待审内容
(发布游戏 / 上传素材)"] --> STR{"锁风三档策略
(按 IP/类型选档)"} STR -->|"人工复核档:直接送人审"| QUEUE STR -->|"标准/严格档:走机审"| L1["第一层 自部署快检
safe-content-ai"] L1 -->|明显 OK| PASS["pass 放行"] L1 -->|明显违规| BLOCK["block 拦截"] L1 -->|"灰带·拿不准
(flag 开→阿里云 / flag 关→人审)"| ALY["第二层 阿里云内容安全
(仅 flag 开 · 放量前接通)"] L1 -.->|"灰带 · flag 关(内测期)"| QUEUE["第三层 人审队列"] ALY -->|确定 OK| PASS ALY -->|确定违规| BLOCK ALY -->|仍拿不准| QUEUE QUEUE -->|人工 approve| PASS QUEUE -->|人工 reject| BLOCK PASS --> GATE["写锁风门台账
game_compliance_gate_result"] BLOCK --> GATE ``` 落到代码上,这套瀑布是对现有锁风门的**扩展而非重建**。今天 `ComplianceGateServiceImpl.evaluate` 已经在做"聚合原子 → max 取最严 → 落台账 → 出 verdict"。要做的是: - 在 `StyleComplianceAtom` / `IpComplianceSeam` 之外,新增**内容安全原子**(文本/图像),内部就是"先快检、灰带再阿里云"这条瀑布,产出 `ComplianceAtomResult{verdict, reason}`,和现有原子同构地塞进 `evaluate` 的聚合列表。这样三层瀑布的结果天然进了 max 聚合——任一层判 block,聚合就是 block。 - review 的处理要扩。今天 `GateVerdict` 只是返回 verdict,没有"转人审后挂起、等人审回来再定"的环节。要补一个**人审挂起态**:聚合裁决为 review 时,不立即放行也不立即拦截,而是**建一条人审工单**(§3.4)、把 project 的发布卡在"待人审"上,人审终裁回来再驱动后续。 - 阿里云调用是外部 API,必须按工程铁律处理超时/失败/重试:阿里云超时或报错时**降级到 review(转人审),绝不降级到 pass**——内容安全的降级口径只能往严格走,放行型降级等于把没审过的内容当审过了放出去。这条和变现侧"打款降级要 fail-fast"是同一个道理:涉及安全和钱的降级,方向永远朝保守。 ### 3.2.1 事中召回:举报率超阈值把已上线内容拎回人审(创始人 2026-06-22 历史回收判定捡回) 上面那条三段瀑布管的是"内容上架前先审一遍",§3.5 的举报降权管的是"判定违规之后怎么处置"。这两者之间漏了一环:内容已经过审上线、在 feed 里正常跑,但它后来变坏了,或者一开始就擦着边没被机审拦住,玩家开始大量举报——这种情况下没有任何机制把它重新拎回审核。审核台只画了"事前审"和"事后处置"两端,中间"内容在线上由信号触发重审"这一环是空的。补上它,审核闭环才从"只防得住新内容"变成"也防得住上线后才变坏、才被举报的内容"。 触发信号取**举报率**,定义为 `report_rate = 举报数 / 曝光数`,是一个负向质量信号——分母用曝光而非绝对举报数,是为了不让高曝光的热门内容仅因为基数大就被误判,也不让冷门内容靠几次举报就轻易翻车。当一条内容的举报率在统计窗口内冲过阈值,系统自动给它建一条人审工单,把它**反向召回**到 §3.4 的人审队列,由人来定它该继续跑、降权还是下架。这条路径和上架前送审方向相反:一个是上线前主动送审拦截,一个是上线后被舆情反向召回;但它们汇入的是同一个人审队列、走同一套审核工单状态机,人审终裁同样是最高权威。 它接的是两个已有的点。一头接 feed 的举报埋点——举报本身是 feed/community 侧已有的玩家互动信号,事中召回要做的是把这个信号按曝光归一成举报率、并设一个可配阈值的监测;另一头接 §3.4 的人审队列,召回产出的工单和机审 review 产出的工单同构,只是 `触发原因` 标成"举报率超阈值"、证据里带上当前举报率和窗口内的举报样本。这样事中召回不另起一套人审基础设施,复用审核工单这一条主干。 阈值的高低和窗口长短是运营旋钮,要随真实举报分布调:定太低会把正常内容频繁拎回人审、加重人力;定太高则起不到事中拦截的作用,坏内容在被召回前已经伤害了一批玩家。这和快检阈值一样是运营常态、不是一次性调好的参数,落点是锁风档位配置那一类策略配置(§3.7)。 **contract-first 清单(待落地)**:① 监测口径——举报率的计算依赖"举报数"和"曝光数"两个量,举报数在 community/feed 的互动埋点里、曝光数在 feed 的出流统计或 telemetry 里,要先确认这两个量能按 `gameId` 聚合取到(若现有埋点不足,需补一个按游戏聚合举报数/曝光数的只读查询,别新建写接缝);② 触发器——新增一个周期扫描的 job(或挂在现有 feed/compliance 的定时任务上),扫超阈值的内容、调 §3.4 的建工单入口,工单 `触发原因` 枚举加一个"举报率超阈值"值;③ 阈值配置——`report_rate` 阈值和统计窗口作为可配项落 admin 策略配置(复用 §3.7 锁风档位配置页那套策略表,不单建一张表),权限位沿用 `compliance:lock-policy:config`;④ 幂等——同一条内容在一个窗口内只召回一次,别让它每轮扫描都重复建工单(以 `gameId + 窗口` 为幂等键)。这一环放在第一期人审队列建成之后接,因为它依赖人审工单这条主干先在。 ### 3.3 锁风三档与 IP 库怎么绑 锁风门(Gate)裁决的是"这条内容的风格/版权/内容安全过不过",而**锁风三档**调的是"用多严的力度去裁"。同一条内容,标准档可能放行、严格档可能转人审、人工复核档直接送人。这三档不是写死的,是个**按内容的 IP 归属和类型动态选出来的策略**。 三档的语义: - **标准档**:默认档,UGC 原创、低敏内容走这档。机审瀑布正常跑,只有灰带和违规才转人审/拦截。绝大多数内容在这档。 - **严格档**:中高敏内容(知名 IP 授权创作、品牌方营销内容)。降低机审放行的阈值——快检判"大概 OK"的也要送阿里云复核,阿里云判 review 的一律转人审。宁可多花成本和人力,也不让擦边内容溜过。 - **人工复核档**:最高敏(头部 IP、强约束授权、政治敏感题材)。跳过机审放行路径,**所有内容直接进人审队列**,人没点头就不放行。 **和 IP 库怎么绑——这是三档的输入来源。** 三档不该让运营对每条内容手动选,而该由内容的 IP 归属自动推导。绘境AI 的 IP 库(ip 模块,目前以 seam 寄宿 compliance、授权链待建)管的是"哪些 IP 形象、谁授权的、授权范围多大"。设计的终态是:锁风档位作为 IP 的一个**授权属性**挂在 IP 库上,每个注册 IP 带一个 `lockStrength`(标准/严格/人工复核),录入 IP 授权时由运营按 IP 方的敏感度和合同约束定下来。 但要说清现状——**IP 库目前只是个 seam,授权链还没建,没有承载 `lockStrength` 的 IP 实体**。所以 `lockStrength` 现阶段不挂在 IP 实体上,而是先落一张轻量的过渡表 `lock_strength_policy`(按 ipId 或题材关键词映射档位,admin 可配,详见下面的范围依赖说明),等 IP 授权模型成熟再把它收敛进 IP 实体。一条内容生成时声明了用哪个 IP,审核就拿这个 IP 去过渡表查档位,据此选档;没声明 IP 的纯 UGC,默认标准档。内容类型再叠一层兜底规则(比如题材黑名单——棋牌/捕鱼即便纯 UGC 也强制拉到人工复核档,对应历史回收 020 的生成侧题材审查)。 ```mermaid flowchart LR subgraph IPLIB["档位源(现阶段=过渡表 lock_strength_policy
终态收敛进 IP 实体授权属性)"] IP1["迪士尼 IP
lockStrength=严格"] IP2["王蓝莓 IP
lockStrength=标准"] IP3["敏感题材
lockStrength=人工复核"] end CONTENT["待审内容
声明 ipId"] --> SEL["选档器"] IPLIB --> SEL TYPE["内容类型/题材黑名单
(兜底拉档规则)"] --> SEL SEL -->|无 IP/低敏| STD["标准档"] SEL -->|IP 中高敏| STRICT["严格档"] SEL -->|IP 最高敏/黑名单| MANUAL["人工复核档"] STD --> FLOW["机审瀑布(§3.2)"] STRICT --> FLOW MANUAL --> Q["直接人审队列"] ``` > **范围依赖(创始人 2026-06-21 定)**:锁风三档**和 IP 库绑定、随素材/IP 授权模型一起做**。也就是说三档的策略落地依赖 IP 库把"IP 注册 + 授权链 + lockStrength 属性"这套建起来。在 IP 库授权模型落地前,三档可以先用一张轻量的 `lock_strength_policy` 配置表过渡(按 ipId 或题材关键词映射档位,admin 可配),等 IP 授权模型成熟再把 `lockStrength` 收敛进 IP 实体。这样三档不被 IP 库的进度卡死,又不产生两套并行的策略源。 锁风三档的裁决记录要能回答"为什么这条走了严格档",落点是现有的 `game_compliance_gate_result` 台账。但现状要讲清:这张表(`GateResultDO`)目前只有 `id/gameId/versionId/verdict/rating/details/traceId` 这几列,**没有 `lock_strength` 或 `ip_id` 字段**。补记档位和命中 IP 有两条路: - **优先**:写进已有的 `details` JSON 列。`details` 现在存的是各原子明细数组(`[{atom,verdict,reason}]`),给它再加两个键 `lockStrength` 和 `ipId` 即可,不改表结构、不加迁移,溯源时从 JSON 里读。 - **若要按列查询/统计**(比如按档位聚合审核量):则需 contract-first 补一次迁移——在 `game_compliance_gate_result` 上 `ADD COLUMN lock_strength VARCHAR / ip_id BIGINT`(均 nullable、对存量行无影响,向后兼容),同步改 `GateResultDO` 加两个字段、`GateResultMapper` 不动(MyBatis-Plus 自动映射)。迁移版本号按落地时仓内最新版顺延分配(现仓已到 V25)。 MVP 阶段建议走第一条(写 `details`),只有在确有按档位做报表的需求时才升列。 ### 3.4 人审走 BPM:从申诉单一队列到内容审核工作流 今天 compliance 只有"申诉"这一种人工工单——用户被处置后不服,提个申诉,admin 在 `compliance:appeal:handle` 里通过或驳回。但**内容审核本身的人工环节(机审判 review → 人来定)还没有队列**。这是人审要补的主体。 人审队列设计成一个**审核工单(review task)的工作流**。每当机审瀑布产出 review、或锁风三档要求人工复核,就建一条审核工单进队列。工单带:目标内容(gameId/versionId 或 materialId)、触发原因(哪层判的 review、命中什么)、机审证据(各原子的 verdict 和 reason、阿里云返回的标签)、锁风档位、优先级。审核员从队列认领工单,看完证据给 approve/reject,工单流转到终态,终裁回写驱动后续(放行则推进发布、拦截则触发处置)。 **为什么走 BPM 而不是一个简单的 status 字段。** 内容审核的人工流转比"待处理→通过/驳回"复杂:有认领(避免两个审核员审同一条)、有分派(高敏内容派给资深审核员)、有升级(初审拿不准升级到复审/主管)、有超时(舆情内容要求 2 小时内处置,超时要告警甚至自动升级)、有 SLA 统计(平均审核时长、积压量)。这些用裸 status 字段管会越写越乱,正是 BPM(业务流程引擎)擅长的——把"谁能干、干完去哪、超时怎么办"声明成一张流程图,引擎来驱动。 **MVP 的务实形态:轻量状态机起步,Flowable 留远期。** 这和 project 发布审核(T-PRJ-06)的口径一致——MVP 先用**轻量审核状态机 + admin 审核队列**把"建工单→认领→裁决→回写"这条主干跑通,认领用乐观锁(CAS 抢占,防双审)、超时用定时任务扫描告警。重型 BPM 引擎(Flowable)等审核复杂度真的上来了(多级审核、复杂分派规则)再引入。这样不在 MVP 阶段背一个重引擎,又给将来留了演进位——状态机的状态和流转设计成能平滑映射到 BPM 流程定义。 审核工单状态机: ```mermaid stateDiagram-v2 [*] --> 待认领: 机审 review / 锁风人工档建单 待认领 --> 审核中: 审核员认领(CAS 抢占) 审核中 --> 已通过: approve(终裁放行) 审核中 --> 已拒绝: reject(终裁拦截→触发处置) 审核中 --> 已升级: 拿不准,升级复审/主管 已升级 --> 审核中: 上级接手 待认领 --> 超时告警: 超 SLA 未认领 审核中 --> 超时告警: 超 SLA 未裁决 超时告警 --> 审核中: 介入处理 已通过 --> [*] 已拒绝 --> [*] ``` 这套审核工单和现有的申诉工单是两条独立的人工流。但要说清现状:今天并不存在一套可复用的"队列基础设施"——申诉侧建成的只是 `AppealStatusEnum`(0 待处理→1 通过/2 驳回)状态机加一个 `compliance:appeal:handle` 处理端点,没有带认领/分派/SLA 的队列底座。所以准确说法是:这两条流将**共用同一套将要新建的队列 UI 框架和 RBAC 模式**——审核工单这条先把队列底座(认领、超时、列表筛选)建起来,申诉那条沿用同一套模式接进去。两者都是"待处理→终态"的人工裁决,但状态机和权限位分开(`compliance:review:handle` vs `compliance:appeal:handle`),其中 `compliance:review:handle` 是本设计新增、`compliance:appeal:handle` 已建。 人审工单落一张新表 `game_compliance_review_task`(继承 `TenantBaseDO` 拿审计列),关键字段:目标(`target_type` 游戏/素材 + `target_id`)、`status`(状态机)、`assignee_id`(认领人)、`priority`、`lock_strength`、`evidence`(机审证据 JSON)、`sla_deadline`(超时锚点)、`verdict`(人工终裁)、`operator_id`(终裁人,审计)。 ### 3.5 违规处置怎么联动 feed 曝光与创作者信用 处置是审核链的最后一环——判定违规之后,平台要做出反应。三类处置动作,每一类都要真的联动到下游,而不是只在 compliance 自己库里记一笔。 **封禁。** 针对账号(创作者)的最重处置。封禁台账(`UserBanDO` + `BanStatusEnum`)已建,被封用户可走申诉(`AppealDO.banId` 已关联封禁台账)。封禁要联动两处,而这两处现状都不到位,是本设计要补的: - **鉴权侧**:被封账号要在 `validateCreator`(见[鉴权与权限](../后端/鉴权与权限.md) §5)里被拦,创作写入口直接拒。现状是 `validateCreator` 只查 `game_player.status`(禁用态拒)和 `creator_flag`,**不查 `game_user_ban` 表**,而 `createBan` 又**不置 `game_player.status=DISABLE`**——所以封一个创作者账号后他照样能创作。要补的机制二选一:封禁时同步把 `game_player.status` 置 `DISABLE`(走 passport 的 -api,复用既有禁用态判定),或让 `validateCreator` 在判定时多查一次生效中的 ban 记录。前者改动小、复用现有禁用态链路,推荐;两条路都要定义解封时的状态恢复、幂等(重复封/解封不出错)、审计留痕。 - **内容侧**:封号要连带把该创作者**已发布的内容全部下架**。现状只通了"封禁单个游戏目标 → 下架那一款"(`UserBanServiceImpl` 调 `ProjectApi.unlistIfPublished(gameId)`,仅 PUBLISHED 生效),**封禁账号目标时不会遍历该创作者的全部游戏逐个下架**,这条级联是零实现。要补一个"按 creatorId 查其全部已发布游戏 → 逐个走 `offlineRank`/`unlistIfPublished` 下架"的批量联动,并处理好部分失败的补偿(下架是封禁的附带副作用,不应回滚封禁主操作)。 封禁分级(警告/限制创作/永久封禁)和封禁期限挂在台账上。 **举报降权 + 下架。** 针对内容的处置,这是和 feed 联动最直接的一类。处置动作落到 feed 的两个既有字段(`exposureLimit` 降权因子、`status` 屏蔽态),但能不能跨模块调到它们,两条路现状不一样(§2): - **下架/屏蔽**(内容违规,彻底踢出流):compliance 调 feed 现有的跨模块接缝 `FeedApi.offlineRank(gameId)`,把该游戏全分区排序行 `status` 置 `0`,`buildStream` 出流时直接踢掉。这条**现成可用**,封禁联动下架已经在走它。 - **降权**(内容有问题但不到下架,压低曝光):理想效果是把 `exposureLimit` 调高、`sort_score = quality + boost − exposureLimit` 自动下沉,内容还在流里但排得很后。但 `setExposureLimit` 现在只是 `AdminFeedController` 的**管理端 HTTP 端点**(给运营手动调用),**不在跨模块 `FeedApi` 上**,compliance 调不到。要让 compliance 自动降权,得 contract-first 新建一个 feed 降权 `-api`(把 `setExposureLimit` 的能力提升到跨模块契约层)。 降权这条创始人 2026-06-22 定**放第一期、单独做**:新建 feed 降权 `-api`(契约面新增,见下)让 compliance 能自动降权,不只靠"`offlineRank` 下架"——"降权但不下架"这种中间态第一期就有。代价是现在就给 feed 开一个新的跨模块写入口(contract-first 补 FeedApi 降权方法 + compliance-server 补 feed-api 依赖)。 若采用新建降权 `-api` 这条路,contract-first 清单是:在 `game-module-feed-api` 的 `FeedApi` 上加一个方法(如 `downweight(gameId, exposureLimit)`)+ 对应 DTO,`FeedApiImpl` 委托既有 `FeedService.setExposureLimit`(实现已在,不重写);compliance-server 的 pom 补 `game-module-feed-api` 依赖(现在没有,见 §2 编译缺口)。无 DB 迁移(`exposure_limit` 列 V25 已落)。 设计纪律不变:**compliance 是处置的发起方,feed 是执行方,跨模块只走 feed 的 `-api`**,不让 compliance 直接写 feed 的表(守模块边界)。 **分级标签。** 内容分级(`all/8+/12+/16+`,`ContentRating` 已建)既是处置结果也是展示依据。审核判定一款游戏适龄 16+,这个标签一方面在 feed/详情页对用户展示(青少年模式据此过滤),一方面喂给防沉迷——未成年用户的 feed 候选集要按分级过滤掉不适龄内容(对应历史回收 014:识别未成年后禁广告 + 禁付费 + 限时长 + 按分级最小化内容)。 **创作者信用——把处置转成对人的长期影响。** 单次处置是对单条内容的,但一个反复违规的创作者应该受到累积的约束。信用分就是这个累积器:每次违规处置(降权/下架/封禁)按严重度扣创作者信用分,信用分低于阈值的创作者,反向影响审核档位(自动拉到严格档,他的新内容审得更严)和分发(feed 基线曝光降低),形成"越违规越受限"的负反馈。 这套是**全新待建合同,现在一点没有**:community 的等级引擎 `LevelDO`(表 `game_community_level`)现有字段是 `id/creatorUserId/level/publishedCount/lastMilestone/lastMilestoneTime`,**没有 `credit_score`**;`CommunityNotifyApi` 只有通知投递和奖励发放方法,**没有扣分端点**。要让信用机制成立,contract-first 清单是: - **DB**:补一次迁移(在 `game_community_level` 上 `ADD COLUMN credit_score INT DEFAULT 100`,nullable/带默认、对存量行无影响,向后兼容);或另立一张独立的信用扣分台账表(每次处置记一条 + 累计分),与等级表解耦,二选一。迁移版本号按落地时仓内最新版顺延分配(现仓已到 V25,§3.3 那条若也落库会占一个号,别和它撞)。 - **跨模块 `-api`**:在 `community-api` 的 `CommunityNotifyApi`(或另立一个信用专用 api)上加一个扣分方法,**带幂等键**(同一处置事件重复投递不重复扣分);compliance 处置后调它注入扣分。 - **compliance 编译依赖**:compliance-server 的 pom 补 `game-module-community-api` 依赖(现在没有,见 §2 编译缺口)。 信用模型创始人 2026-06-22 定**放第一期**:第一期就把"简单扣分台账(只记不连带)"建起来——它牵涉新表 + 新跨模块端点(带幂等键)+ 误伤治理。第一期取保守形态(只扣分、不做激进连带封禁),复杂规则(信用分联动曝光基线等)留后细化,和等级引擎"MVP 仅计数、分层留 P1"的口径相容。 ```mermaid flowchart TB V["违规判定(机审 block / 人审 reject)"] --> DISPATCH{"处置类型"} DISPATCH -->|账号| BAN["封禁台账 UserBanDO(已建)"] DISPATCH -->|内容降权| DOWN["feed 降权 -api(待建)
exposureLimit↑ → sort_score 下沉"] DISPATCH -->|内容下架| OFF["FeedApi.offlineRank(已有)
status=0 出流剔除"] DISPATCH -->|分级| RATING["ContentRating 标签
→ 青少年模式/防沉迷过滤"] BAN -.->|连带下架全部内容(待建)| OFF BAN -.->|拦截创作:置 player DISABLE 或查 ban 表(待建)| AUTH["validateCreator 拒"] BAN -.-> CREDIT["创作者信用扣分(待建)
(community 等级体系/独立台账)"] DOWN -.-> CREDIT OFF -.-> CREDIT CREDIT -.->|信用低→拉严档| STR["锁风档位上调"] CREDIT -.->|信用低→降基线曝光| FEEDBASE["feed 基线曝光↓"] BAN -->|不服| APPEAL["申诉 AppealDO
(已建状态机)"] ``` 处置和审核状态的权威归属:**处置决策由 compliance 拥有并发起,处置效果落在各下游模块的既有字段上**。compliance 记"对谁、什么处置、什么原因、谁操作的"的处置台账(审计 + 申诉溯源用),feed/community 各自承载处置在自己域的效果。这样既守住"审核状态单一权威在 compliance",又不让 compliance 越界去写别人的业务表。 ### 3.6 内容溯源:AIGC 标识 + 隐式水印 + 审核记录 审核链路天然沉淀一批内容溯源数据,把它们串起来能同时满足三个需求:AIGC 法定标识、版权追责、审核记录留存(合规闸门 #8 要的那套)。 - **AIGC 显式标识**:每款生成游戏带"AI 生成"的显式标记,数据上挂在生成元数据(promptHash、生成来源)上,展示上在游戏卡片/详情页/分享页显著标注。这是《标识办法》的硬义务,在所有发行面都要带。 - **隐式水印**:给生成内容嵌入不可见的溯源标记(implicit watermark),是个全新工程件(历史回收 021)。它和显式标识互补——显式标识是给用户看的、可被去除,隐式水印是给追责用的、藏在内容里。MVP 可后置,随渠道线/放量排期。 - **审核记录留存**:锁风门台账(`game_compliance_gate_result`)+ 审核工单 + 处置台账,合起来就是"每条内容审了什么、谁审的、什么结论、怎么处置的"完整记录,留存 ≥180 天(对应 T-CMP 审计日志要求)。这套记录是合规闸门 #8 内容合规材料的实现物,也是渠道提审和被监管问询时的证据。 ### 3.7 admin 审核台前端 审核台的运营出口是 game-admin(Vue3 + Element Plus,见[前端域](../前端/README.md))上的一组页面。它服务运营和管理员,落在 admin 的 `/admin-api/compliance/*` 端点上。四块页面对应创始人定的四件事: **审核队列页。** 审核台的主屏。展示待审工单列表(机审转 review 的 + 锁风人工档的)和申诉工单列表,支持按优先级/锁风档位/触发原因/超时状态筛选,标红超 SLA 的工单。审核员从这里认领工单进详情。队列数据来自审核工单台账分页 + 申诉台账分页(`compliance:appeal:query` 已建,新增 `compliance:review:query`)。 **审核详情页。** 一条工单的全部判定证据摊开:目标内容(游戏可试玩/素材可预览)、机审逐层结论(快检判了啥、阿里云返回什么标签、各原子 reason)、锁风档位和命中的 IP、历史处置记录。审核员在这页给 approve/reject。 **处置操作页(或详情内嵌处置区)。** 一键发起三类处置:封禁(选分级 + 期限 + 原因)、降权/下架(调 feed 曝光)、打分级标签。处置即时联动下游(§3.5),操作落审计台账。这些是重权限动作,封禁复用现有权限位 `compliance:ban:create`/`:cancel`;降权/下架和打分级标签是新端点,要新增对应权限位(见下表)。 **锁风档位配置页。** 运营在这里维护锁风三档策略:给 IP 配 `lockStrength`、维护题材黑名单的兜底拉档规则、调各档的机审阈值。这是策略配置而非单条处置,要新增权限位 `compliance:lock-policy:config`,只给高级运营/管理员。 **权限模型**承 [鉴权与权限](../后端/鉴权与权限.md):admin 端走 B 端 RBAC,每个端点 `@PreAuthorize("@ss.hasPermission('compliance:资源:动作')")`,角色-菜单交集裁决、超管短路。要先讲清现状:compliance 现有的权限位只有 `compliance:ban:create` / `:cancel` / `:query` 和 `compliance:appeal:handle` / `:query`。审核台新增的页面要配套新增一批权限位,每个都得 contract-first 同步四处——端点上的 `@PreAuthorize`、admin 菜单种子(`system_menu`)、角色种子(把新权限位挂到对应角色)、验收用例(无权限 token 直连被 403)。下表里标"(新增)"的就是当前不存在、要随本设计建的: | 角色 | 能干什么 | 关键权限位 | |---|---|---| | **审核员** | 看队列、认领工单、approve/reject、打分级标签 | `compliance:review:query`(新增) / `:handle`(新增)、`compliance:rating:set`(新增) | | **处置专员** | 在审核员基础上 + 封禁、降权/下架、处理申诉 | `compliance:ban:create` / `:cancel`(已有)、`compliance:exposure:handle`(新增)、`compliance:appeal:handle`(已有) | | **合规管理员** | 在处置专员基础上 + 配锁风三档策略、配 IP lockStrength | `compliance:lock-policy:config`(新增) | 权限的强制在后端可信边界(服务侧 `@PreAuthorize`),admin 前端的按钮显隐只是体验,不算数——这条铁律承自鉴权域,审核台尤其要守:能封号、能改曝光的端点,前端藏了按钮但 API 直连仍可达,必须后端拦死。 ```mermaid flowchart TB subgraph ADMIN["game-admin 审核台(Element Plus)"] Q["审核队列页
待审工单 + 申诉"] D["审核详情页
试玩 + 机审证据 + 锁风档"] DISP["处置操作
封禁/降权/下架/打标"] CFG["锁风档位配置
IP lockStrength + 题材黑名单"] end subgraph API["/admin-api/compliance/* (B 端 RBAC)"] R1["review:query/handle"] R2["appeal:handle/query"] R3["ban:create/cancel(已有) · exposure:handle/rating:set(新增)"] R4["lock-policy:config"] end Q --> R1 & R2 D --> R1 DISP --> R3 CFG --> R4 R3 -.->|联动| FEED["feed -api(曝光)"] R3 -.->|联动| CMU["community(信用)"] ``` --- ## 4. 分期落地 创始人定了"全做",但四块有依赖先后,不是平铺并行。落地分三期,排序的依据是"什么先成立、什么被什么卡住"。 **第一期 · 把判定流和处置联动跑通(自有端内测够用)。** 这一期不依赖任何外部资质,可以马上动: - 内容安全原子(文本/图像)落地为**自部署快检 + 桩位的阿里云接缝**——快检真跑,阿里云实现挂 feature flag。原子接进现有锁风门聚合。 - 审核工单台账 + 轻量状态机 + admin 审核队列/详情/处置页。把"机审 review → 建工单 → 人审认领裁决 → 回写驱动"主干打通。 - 违规处置联动:下架走 feed 现有的 `FeedApi.offlineRank`(现成);封禁联动补两块断链——封账号时置 `game_player.status=DISABLE`(让 `validateCreator` 拦得住)+ 按 creatorId 批量下架其全部已发布内容。**feed 自动降权与创作者信用模型也放第一期(创始人 2026-06-22 定)**:新建 feed 降权 `-api` 让 compliance 自动降权、建简单信用扣分台账(只记不连带),两者都 contract-first 补新跨模块写入口 / 新表(见 §3.5)。 - 锁风三档用过渡的 `lock_strength_policy` 配置表起步(admin 可配),先按题材黑名单 + 手配 IP 映射选档。 - 事中召回(§3.2.1,创始人 2026-06-22 历史回收判定捡回)接在人审队列建成之后:把举报率按曝光归一成负向信号、设可配阈值,超阈值的已上线内容自动建工单反向召回到人审队列。复用审核工单主干,不另起人审基础设施。 这一期做完,自有端邀请制内测就有了一套能日常运转的内容安全运营——机审挡大面、人审兜疑难、违规真下架真拦创作,且上线后变坏/被举报的内容也能被举报率信号拎回重审。 **第二期 · 阿里云兜底接入(放量前的合规刚需)。** 依赖"接真实公开流量"这个时点(渠道线③临近):把第一期留的阿里云接缝接通,灰带样本真送阿里云、按工程铁律处理超时/失败/降级(降级朝 review 走)。同时补内容溯源——AIGC 显式标识在各发行面带上,审核记录留存机制成文(喂合规闸门 #8 材料)。 **第三期 · 锁风三档收敛进 IP 授权模型 + 隐式水印。** 依赖 IP 库把"IP 注册 + 授权链 + lockStrength 属性"建起来(随素材/IP 授权模型一起做):把过渡配置表里的档位策略收敛进 IP 实体的授权属性,三档按 IP 授权敏感度自动选。隐式水印作为全新工程件,随这一期或渠道线排期落地。BPM 重引擎(Flowable)在审核复杂度真上来时再评估引入,不在前三期硬约束内。 ```mermaid flowchart LR P1["第一期
快检+人审队列+处置联动+三档过渡表
(零外部依赖,内测够用)"] P2["第二期
阿里云兜底+AIGC标识+审核记录留存
(依赖:接公开流量/渠道线③)"] P3["第三期
三档收敛进IP授权+隐式水印
(依赖:IP库授权模型)"] P1 --> P2 --> P3 ``` --- ## 5. 验收与风险 ### 5.1 怎么算做对了 - **判定流可追溯**:任取一条审过的内容,能从台账还原它走了哪一档、哪层判的、机审给了什么结论、是否进人审、谁终裁、最终 verdict——全链证据齐全。 - **机审真拦截**:接进内容安全原子后,造一批已知违规样本(色情/暴恐/政治测试集),自部署快检对明显违规的能拦下来(不再像现在恒 pass);灰带样本能正确转下一层。这是从"零自动拦截"到"机审兜底"的硬验收。 - **处置真联动**:封一个号,该创作者已发布内容在 feed 出流被剔除、`validateCreator` 拒其再创作;降权一条内容,feed 排序真下沉;这些要在 staging 上 e2e 验到(feed 联动排序历史上 B2′ 已经在浏览器里 e2e 翻转过——2026-06-09 真人试玩玩过的游戏从第 2 位窜登顶,复用同套验法)。 - **降级朝保守**:阿里云接入后,模拟阿里云超时/报错,验证内容降级到 review 转人审、绝不放行。 - **权限不可绕**:审核台的封禁/改曝光端点,用无权限的 token 直连 API 被 403 拦(不靠前端藏按钮)。 - **状态单一权威**:验 project 不写审核态、只接 compliance 回写,不存在两处都改审核状态的脑裂。 ### 5.2 风险 - **快检模型的准确率是成本与漏判的平衡点**。快检放得太松,违规内容漏到下游甚至漏过;判得太严,大量正常内容涌进人审,人力成本爆掉(历史回收 026:人审是台阶函数,月新增超 2000 款就要 +6000 元/月)。快检阈值要随真实样本持续调,这是个运营常态,不是一次性调好。 - **阿里云内容安全是花钱的外部依赖**,成本随放量线性涨,而 ¥4,300/月 那张成本表压根没算它(三向审计点名)。放量前要把审核 API 成本单列进成本台账,否则单位经济测算偏乐观。 - **锁风三档依赖 IP 库,IP 库授权链还没建**。三档用过渡配置表起步缓解了卡死风险,但如果 IP 授权模型迟迟不落地,三档会长期停在"手配映射"的粗糙形态,高敏 IP 的自动严审落不了地。这块的真正成熟绑在素材/IP 授权模型的进度上。 - **人审是真正随产能咬人的成本**,且舆情内容有"2 小时内下架"的 SLA(历史回收 021)。MVP 轻量状态机能不能扛住放量后的审核积压、SLA 告警够不够及时,要在放量灰度时压测,必要时提前引 BPM。 - **创作者信用是新机制,要防误伤**。信用扣分若规则太硬,一次误判处置可能连累创作者的长期曝光,而申诉救济的时效要跟上。信用规则若做,MVP 也要保守(只扣分、不做激进的连带封禁),复杂规则留 P1 再细化。 ### 5.3 拍板结论与剩余开放项 原本三件待拍板,创始人 2026-06-22 已定前两件(feed 自动降权 + 创作者信用模型都放第一期、单独做);剩第三件(锁风记录升不升列)是工程细节,倾向写 JSON: 1. **feed 自动降权(创始人 2026-06-22 定:放第一期、单独做)。** contract-first 新建 feed 降权 `-api`(FeedApi 加降权方法 + DTO、compliance-server 补 feed-api 依赖)让 compliance 能自动降权,而非只靠 `offlineRank` 下架——"降权但不下架"的中间态第一期就有。 2. **创作者信用模型(创始人 2026-06-22 定:放第一期)。** 第一期建简单扣分台账(只记不连带,保守形态),contract-first 补新表(独立台账或 `LevelDO` 加 `credit_score` 列)+ community-api 带幂等键的扣分端点 + compliance-server 补 community-api 依赖。 3. **锁风裁决记录升不升列(§3.3)。** 现状:`game_compliance_gate_result` 没有 `lock_strength`/`ip_id` 列。取舍:MVP 把档位和命中 IP 写进已有的 `details` JSON(不改表),还是补一次 Flyway 迁移加两列(为了按档位做报表查询)。倾向写 JSON,但若确有报表需求需创始人点头升列。 --- ## 6. 相关文档 | 文档 | 关系 | |---|---| | [合规闸门](合规闸门.md) | 法定上线门(本页 §1 讲清与它的分工);#8 内容合规材料由本页的审核记录留存实现 | | [鉴权与权限](../后端/鉴权与权限.md) | admin 审核台的 B 端 RBAC 模型、封禁联动 validateCreator 的承接点 | | [13 模块](../架构/13模块.md) | compliance(T-CMP-12 锁风门 / -06 状态机 / -09 人审队列)、ip(seam @ compliance)、feed(曝光联动)、community(等级=信用宿主)的模块边界与现状 | | [前端域](../前端/README.md) | game-admin 前端体系(Element Plus),审核台页面在其上 | | [运营域 README](README.md) | 审核台在运营域的位置(上线/变现/发行之外的"内容安全运营"这一摊) | > **纪律**:本页只讲"内容安全运营怎么运转"——审、处置、台子。法定上线门在[合规闸门](合规闸门.md),模块边界在[13 模块](../架构/13模块.md),钱怎么分在[变现与单位经济](变现与单位经济.md),各域各司其职、互不重复。审核状态的唯一权威在 compliance,这条贯穿全页,任何模块都只读回写、不双写审核态。