Logo花火漫画开发文档
函数详情

AI 内容审核

ai-comment-moderator 与 ai-username-moderator 的触发机制、审核逻辑与处理流程

本页面描述两个由数据库触发器自动调用的 AI 审核函数。它们不接受客户端直接请求,而是在数据写入时通过 supabase_functions.http_request / pg_net 异步触发。

函数对比

ai-comment-moderatorai-username-moderator
触发表commentsprofiles
触发时机AFTER INSERTAFTER UPDATE
JWT 校验是(触发器携带 Service Role JWT)否(verify_jwt: false
AI 模型x-ai/grok-4.1-fast(via OpenRouter)x-ai/grok-4.1-fast(via OpenRouter)
审核对象评论文本 content昵称 display_name
违规处理修改评论 status回滚昵称 + 发送通知

ai-comment-moderator

触发流程

用户发表评论
  → INSERT INTO comments
    → 触发器 review-new-comment (AFTER INSERT)
      → supabase_functions.http_request 调用 ai-comment-moderator
        → AI 分析评论内容
          → 更新 comments.status 和 moderation_meta

触发器 review-new-commentcomments 表每次 INSERT 后触发,通过 supabase_functions.http_request 以 POST 方式调用函数,超时 5000ms。

评论在插入时 status 默认为 public,审核是后置异步的——用户提交后评论立即可见,审核完成后才可能被修改状态。

审核维度

AI 会对评论内容进行分析并返回以下结构:

Prop

Type

各等级的判定标准:

等级含义示例
low安全或无伤大雅正常讨论、善意灌水、轻微擦边
medium轻度违规阴阳怪气、轻微引战、疑似广告
high严重违规明确色情、暴力、仇恨言论、诈骗广告

状态映射

审核结果会映射为 comment_status 枚举值并更新到 comments.status

risk_level→ status效果
lowpublic正常展示,所有人可见
mediumshadow_banned影子禁言——评论仅发布者自己可见,其他用户看不到
highrejected直接拒绝(隐藏),所有人不可见

comment_status 枚举共有四个值:publicshadow_bannedrejectedpending。AI 审核只会产出前三种。

moderation_meta 示例

审核完成后,comments.moderation_meta(JSONB)会被更新为:

{
  "ai_reviewed": true,
  "provider": "OpenRouter:x-ai/grok-4.1-fast",
  "reviewed_at": "2025-06-15T08:30:00.000Z",
  "risk_level": "medium",
  "reason": "疑似广告内容",
  "tags": ["spam"]
}

异常处理

当 AI 返回的 JSON 无法解析时(例如模型输出了 Markdown 包裹的 JSON),函数会回退为 medium 等级处理,reason 标记为 AI_PARSE_ERROR。这意味着解析失败时评论会被影子禁言而非放行,属于偏保守策略。


ai-username-moderator

触发流程

用户修改昵称
  → UPDATE profiles SET display_name = '新昵称'
    → 触发器 review-new-username (AFTER UPDATE)
      → supabase_functions.http_request 调用 ai-username-moderator
        → AI 分析新昵称
          → 通过:记录审核结果
          → 违规:回滚昵称 + 发送系统通知

触发器 review-new-usernameprofiles 表每次 UPDATE 后触发。

防无限循环机制

由于违规处理本身也会 UPDATE profiles(回滚 display_name + 写入 moderation_meta),函数在入口处检查 moderation_meta 是否发生变化。如果变化了,说明本次 UPDATE 是由审核回滚引起的,直接跳过,避免无限递归。

收到触发 → moderation_meta 有变化?
  → 是:跳过(这是审核自身触发的更新)
  → 否:继续检查 display_name
    → display_name 无变化?跳过
    → display_name 有变化 → 调用 AI 审核

审核维度

与评论审核不同,用户名审核仅关注两个维度,其他内容一律视为安全:

AI 返回结构:

Prop

Type

审核原则是宁可放过也不要误判——普通昵称、二次元名、表情符号等均视为安全。

处理方式

仅在 profiles.moderation_meta 记录审核通过信息,不改变 display_name

{
  "last_name_review": {
    "ai_reviewed": true,
    "provider": "OpenRouter: x-ai/grok-4.1-fast",
    "reviewed_at": "2025-06-15T08:30:00.000Z",
    "result": "pass"
  }
}

两步操作同时执行:

  1. 回滚昵称:将 display_name 恢复为修改前的值,并在 moderation_meta 中记录被驳回的昵称和原因
  2. 发送系统通知:向 notifications 表插入一条类型为 system 的通知,告知用户昵称被撤回及原因

通知内容示例:您的昵称「加我vx:xxx」因违反用户名使用规范被系统自动撤回(原因:推广引流)。请注意账号合规使用。如有疑问,请提交工单反馈。

moderation_meta 示例:

{
  "last_name_review": {
    "ai_reviewed": true,
    "provider": "OpenRouter: x-ai/grok-4.1-fast",
    "reviewed_at": "2025-06-15T08:30:00.000Z",
    "result": "rejected",
    "rejected_name": "加我vx:xxx",
    "is_violation": true,
    "reason": "推广引流",
    "tags": ["promotion"]
  }
}

相关数据表

Prop

Type

Prop

Type

Prop

Type

Secrets 依赖

两个函数共用以下 Secrets:

Secret用途
OPENAI_API_KEYOpenRouter API Key,用于调用 AI 模型
OPENAI_BASE_URLAPI 端点(当前指向 OpenRouter)
SUPABASE_URL项目 URL(系统自带)
SUPABASE_SERVICE_ROLE_KEYService Role Key,用于绕过 RLS 更新数据

这两个函数使用 SERVICE_ROLE_KEY 是必要的——触发器上下文没有用户 JWT,且需要修改其他用户的数据(回滚昵称、修改评论状态)。

注意事项

  • 评论审核是后置的:评论发布后立刻可见,AI 审核通常在数秒内完成。极端情况下(AI 响应慢或失败),违规评论可能短暂暴露
  • 昵称审核也是后置的:用户修改昵称后会短暂看到新昵称,违规时才被回滚
  • AI 解析失败:评论审核回退为 medium(影子禁言);昵称审核回退为 pass(放行)。两者策略不同——评论偏保守,昵称偏宽松
  • 模型更换:如需更换 AI 模型,修改函数中的 model 字段并确保 OPENAI_BASE_URL 指向正确的兼容端点
  • 触发器超时supabase_functions.http_request 设置的超时为 5000ms,超时后不会重试

On this page