Files
cmhub/docs/moderation.md
T

5.2 KiB
Raw Blame History

内容安全与本地敏感词过滤

T-604 的实施口径与实现记录。目标是先做「中文 prompt 本地敏感词快筛」,命中在扣点和调上游之前拦截;云内容安全与输出审核不在本任务做实。

定位

  • 本地敏感词过滤是免费快筛和运营自定义黑名单,不替代合规内容审核。
  • T-604 只处理输入 prompt 的关键词拦截;图片审核、输出文本审核、输出图片审核、云厂商内容安全属于后续任务。
  • 默认关闭:MODERATION_ENABLED=false 时必须 no-op,现有生成接口行为不变。
  • 打开后使用 MODERATION_PROVIDER=keyword;未配置或配置错误时按 fail-closed 处理。

请求时序

生成接口必须按这个顺序执行:

  1. DRF serializer 校验基础字段。
  2. 先审核 prompt 文本,不得先下载 image_url 或预扣点。
  3. prompt 命中敏感词:返回 400 content_blocked,不下载图片、不解析别名、不计费、不写 CallRecord / PointsLedger、不调上游。
  4. prompt 通过后,才允许读取 image_base64 或下载公网 image_url,并继续 SSRF 防护。
  5. 别名解析、能力校验、计费规则查询。
  6. 预扣点、写 pending 调用和 consume 流水。
  7. 调上游,成功后写成功记录;失败走既有退点路径。

说明:T-604 已清理早期骨架里的 moderate_output_* 钩子和云厂商 provider stub,只保留 moderate_prompt() 本地关键词入口。输出审核若后续落地,必须重新定义「命中是否退点」的产品策略,并让对应配置真的生效;在 T-604 中不要暴露一个未实现的配置。

数据模型

新增 SensitiveWord 模型:

字段 说明
word 原始敏感词,唯一或按 category 唯一;不能为空
normalized_word 归一化后的词,用于构建 matcher;保存时生成,便于排查和唯一约束
category 分类,如 politics / violence / porn / custom
action MVP 只支持 block;后续再扩展 review / flag
is_active 是否启用
created_at / updated_at 时间戳

admin 要求:

  • 支持按 word / normalized_word / category 搜索。
  • 支持按 category / action / is_active 过滤。
  • 修改词库后触发 matcher 版本失效。

归一化

匹配前对 prompt 与词库统一归一化:

  • Unicode NFKC,把全角转半角。
  • 去零宽字符。
  • 去空白和常见分隔标点,用于拦截「敏 感 词」「敏-感-词」这类低级绕过。
  • 英文字母小写。
  • 繁简转换可选;如果 opencc 安装或运行失败,跳过繁简,不影响其他归一化。

风险:过度归一化会提高误伤概率。测试必须包含至少一条例外/普通文本样例,避免明显正常内容被误拦。

匹配与缓存

  • 使用 Aho-Corasick 自动机做多词匹配;ahocorapy 作为候选依赖,但实现前必须验证 PyPI 包可用性和 API 形状。
  • 禁止每请求重建 matcher。
  • 每个 worker 进程内缓存 matcher;生产多 worker 下不能只依赖 Django post_save / post_delete signal,因为 signal 只影响当前进程。
  • 采用共享版本号失效:词库变更后把 moderation:sensitive_words:version 写入共享 cache;每次请求只做轻量版本检查,版本不一致时当前进程重建 matcher。
  • 生产必须使用共享 cache(DatabaseCache / Redis / Memcached),不能依赖 LocMemCache 完成跨 worker 失效。

错误与留痕

命中后对外响应:

{
  "error": {
    "code": "content_blocked",
    "message": "输入内容未通过安全审核"
  }
}

留痕原则:

  • 不保存违规 prompt 原文。
  • 可记录分类、命中词 ID、请求用户、API Key 前缀、时间、阶段、处理结果。
  • MVP 若不建 ModerationRecord,至少测试中确认不会把 prompt 原文写入日志或数据库的新字段。

验收

当前实现状态:DONE。已落地 apps.moderation、SensitiveWord 模型/admin/迁移、ahocorapy keyword provider、归一化管线和共享 cache 版本号失效;生成接口已改为 serializer 后先审 prompt,命中时不会下载 image_url、不会扣点、不会写调用/流水、不会调上游。

T-604 完成前至少覆盖:

  • MODERATION_ENABLED=false 时生成接口 no-op,既有用例不变。
  • MODERATION_PROVIDER=keyword 且命中 prompt 时返回 400 content_blocked。
  • 命中时不扣点、不创建 CallRecord、不写 PointsLedger、不调用上游 provider。
  • 命中时不会下载 image_url。
  • 归一化命中:空格/分隔符/全半角/零宽字符。
  • 繁简归一化若启用则有测试;未安装 opencc 时测试跳过或断言 graceful fallback。
  • 词库变更后 matcher 版本号变化,当前进程下一次请求能重建 matcher。
  • 多 worker 口径在文档和测试中说明:跨进程刷新依赖共享 cache 版本号,不依赖本地 signal。

不在 T-604 范围

  • 云内容安全真实厂商接入。
  • 输出内容审核与输出命中退点/照扣策略。
  • 图片内容审核。
  • 脱敏、人工复审、灰度放行。
  • 大规模开源词库入库;可提供导入命令,但真实词库数据不进仓库。