fruiter / ai-moderation
AI 内容合规审核扩展:基于任意 OpenAI 兼容 API 自动检查用户发布的内容(Flarum 1.8+ / PHP 7.4+)。
Package info
github.com/CNFruiter/flarum-ai-moderation
Type:flarum-extension
pkg:composer/fruiter/ai-moderation
Requires
- php: >=7.4.0
- flarum/core: ^1.8.0
- guzzlehttp/guzzle: ^6.0 || ^7.4
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
一个用于 Flarum 1.8.x 的扩展:使用任意 OpenAI 兼容 API(OpenAI、DeepSeek、Moonshot、智谱、通义、Ollama、LM Studio、vLLM、OneAPI 等)在用户发布内容时自动进行合规审核,支持隐藏、标记待审核、拒绝发布三种处理方式。
- 兼容环境:Flarum 1.8.12 / PHP 7.4.33 / MySQL 8.4(已按该组合开发验证,PHP 7.4+、8.x 均可)
- AI 来源完全由你自己配置:只需填写
API 基础地址、API 密钥、模型名称三项 - 纯 PHP 后端 + 轻量管理后台(含"测试连接"按钮),无需改动论坛前端
- 开源协议:MIT
功能特性
- ✅ 覆盖所有用户发布场景:
- 新建讨论(标题 + 首帖内容一起检查)
- 回复帖子(检查内容)
- 编辑帖子(检查修改后的内容)
- 重命名讨论(单独检查新标题)
- ✅ 内置中文合规审核提示词(政治敏感、色情、暴力、赌博诈骗、人身攻击、广告引流等),并支持在后台追加自定义规则
- ✅ 三种违规处理动作(后台可切换):
动作 行为 hide_and_flag(推荐)立即隐藏,并在"标记"(Flags)里生成 AI 审核标记供管理员复核 hide仅隐藏内容 flag仅生成标记,内容保持可见 reject直接拒绝发布,作者看到错误提示 - ✅ AI 服务不可用时默认放行(避免 AI 故障影响社区正常发帖),可切换为拒绝发布
- ✅ 长短文本分流:短内容先审核后发布;长内容(可配置阈值)先发布后审核,进入延迟审核队列后台补审,用户无需等待
- ✅ 审核超时先发布后审核:AI 响应过慢(如推理型模型)时先放行发布、稍后补审,避免用户在发布页干等
- ✅ 多 AI 来源(提供商)负载均衡:后台可配置多个提供商(DeepSeek、Moonshot、OpenAI 等,各带独立地址/密钥/模型),请求随机轮换,分摊并发与限流
- ✅ 违规通知作者:内容被隐藏/标记时,向作者发送站内通知说明类别与原因
- ✅ 帖子被 AI 隐藏后,作者将其修改为合规内容会自动恢复并清除标记
- ✅ 管理后台"测试连接"按钮 +
php flarum ai-moderation:test命令,方便配置自己的 AI 来源
环境要求
- Flarum
^1.8.0(在 1.8.12 上验证) - PHP
>= 7.4(兼容 8.x) - 一个 OpenAI 兼容的 Chat Completions 接口(见下方兼容列表)
安装
方式一:通过 Packagist 安装(推荐)
在你的 Flarum 根目录执行:
composer require fruiter/ai-moderation php flarum extension:enable fruiter-ai-moderation php flarum assets:publish php flarum cache:clear
方式二:通过 VCS 仓库安装(Packagist 未收录时)
# 把 GitHub 仓库加入 composer 源
composer config repositories.fruiter vcs https://github.com/CNFruiter/flarum-ai-moderation
composer require fruiter/ai-moderation:@dev
php flarum extension:enable fruiter-ai-moderation
php flarum assets:publish
php flarum cache:clear
若需锁定稳定版本,可在仓库打 tag(如
v1.0.0),然后composer require fruiter/ai-moderation:^1.0。
方式三:本地路径安装(开发调试)
composer config repositories.ai-moderation path "<扩展所在路径>" composer require fruiter/ai-moderation:@dev php flarum extension:enable fruiter-ai-moderation php flarum assets:publish && php flarum cache:clear
配置
后台配置(推荐)
管理后台 → 扩展 → AI Moderation,主要设置:
| 设置项 | 说明 | 示例 |
|---|---|---|
| API 基础地址 | OpenAI 兼容接口地址,不含 /chat/completions |
https://api.deepseek.com/v1 |
| API 密钥 | 服务商提供的 Key(单密钥) | sk-xxxx |
| 多 AI 来源(提供商) | JSON 数组,每项含 api_base_url/api_key/model,随机负载均衡,优先于单来源设置 |
[{"api_base_url":"https://api.deepseek.com/v1","api_key":"sk-a","model":"deepseek-chat"},{"api_base_url":"https://api.moonshot.cn/v1","api_key":"sk-b","model":"moonshot-v1-8k"}] |
| 模型名称 | 服务商支持的模型 ID | deepseek-chat、gpt-4o-mini、moonshot-v1-8k |
| 违规处理方式 | 见上表 | hide_and_flag |
| 自定义指令 | 追加审核规则(选填) | 如:禁止发布包含微信号的内容 |
| 严格 JSON 模式 | 仅服务商支持 response_format 时开启 |
默认关 |
| AI 服务出错时放行 | 默认开(放行) | — |
| 长文本阈值(字符) | 超过该长度先发布、后台延迟审核(默认 300) | 300 |
| 长文本先发布后审核 | 默认开 | — |
| 审核超时也先发布后审核 | 默认开(超时不再阻塞发帖) | — |
| 违规时通知作者 | 默认开,向作者发送站内通知 | — |
配置完成后点击测试连接,确认能正常返回审核结果。
延迟审核队列(长文本 / 超时内容)
长文本与审核超时的内容先发布,随后进入延迟审核队列(数据库表 ai_moderation_queue),由两种方式处理:
-
后台即时处理(默认):帖子保存后,PHP 在响应返回后(shutdown 阶段)立即补审该帖;适合流量不大的站点。
-
定时任务兜底(推荐):配置 cron 每分钟执行一次,确保后台处理失败(如进程被终止)时内容也会被补审:
* * * * * php /path/to/flarum ai-moderation:process
也可手动执行:
php flarum ai-moderation:process --limit=50
延迟审核命中违规时,执行与同步一致的"隐藏 / 标记 / 通知作者"(reject 动作在延迟场景下降级为隐藏 + 标记 + 通知,因为内容已发布、无法撤回)。
CLI 配置(无后台时使用)
# 配置 OpenAI 兼容接口 php flarum ai-moderation:configure \ --base-url=https://api.deepseek.com/v1 \ --api-key=sk-xxxx \ --model=deepseek-chat \ --action=hide_and_flag # 测试连接 php flarum ai-moderation:test # 手动检查一段文本(可用真实模型试一下内置提示词的效果) php flarum ai-moderation:check "这段话是否违规?" php flarum ai-moderation:check "我这里有赌博网站,大家快来下注" php flarum ai-moderation:check "根据新闻报道,最近警方打击了一批网络赌博团伙" # 处理延迟审核队列(建议 cron 每分钟执行) php flarum ai-moderation:process # 停用 / 启用 php flarum ai-moderation:configure --disabled php flarum ai-moderation:configure --enabled
安全说明
- API 密钥存储:默认保存在 Flarum 的
settings表(仅管理员可见)。生产环境建议把密钥放到config.php,避免密钥进入数据库:// config.php return [ // ... 其他配置 'ai-moderation' => [ // 单来源(可选) 'api_key' => 'sk-xxxx', // 优先于后台设置 'api_base_url' => 'https://api.deepseek.com/v1', 'model' => 'deepseek-chat', // 或多来源负载均衡(可选,优先级更高) 'providers' => [ ['api_base_url' => 'https://api.deepseek.com/v1', 'api_key' => 'sk-a', 'model' => 'deepseek-chat'], ['api_base_url' => 'https://api.moonshot.cn/v1', 'api_key' => 'sk-b', 'model' => 'moonshot-v1-8k'], ], ], ];
config.php 中的值优先于后台设置,此时后台的密钥/地址/模型字段留空即可。 - 密钥不对外暴露:
ai-moderation.*设置不会被序列化到论坛前端,普通用户无法读取;日志中也不会记录密钥。 - 测试接口鉴权:
/api/ai-moderation/test仅管理员可访问,未登录或非管理员一律 403,避免匿名用户滥用你的 AI 额度。 - 失败放行策略:默认 AI 服务异常时放行内容(不阻塞发帖);如需严格模式,关闭"AI 服务出错时放行"。
- 建议:管理后台使用 HTTPS 访问,避免密钥在传输中被窃取。
OpenAI 兼容服务配置示例
| 服务商 | API 基础地址 | 示例模型 | 备注 |
|---|---|---|---|
| OpenAI | https://api.openai.com/v1 |
gpt-4o-mini |
官方 |
| DeepSeek | https://api.deepseek.com/v1 |
deepseek-chat |
国内直连,价格低 |
| Moonshot(月之暗面) | https://api.moonshot.cn/v1 |
moonshot-v1-8k |
|
| 智谱 GLM | https://open.bigmodel.cn/api/paas/v4 |
glm-4-flash |
|
| 通义千问 | https://dashscope.aliyuncs.com/compatible-mode/v1 |
qwen-plus |
兼容模式 |
| 小米 MiMo | https://api.xiaomimimo.com/v1 |
mimo-v2.5 |
推理型模型,单次审核较慢(约 20 秒+),建议调大"请求超时" |
| Ollama(本地) | http://localhost:11434/v1 |
qwen2.5:7b |
无需密钥;需 OLLAMA_HOST 允许局域网时注意地址 |
| LM Studio(本地) | http://localhost:1234/v1 |
本地模型 ID | 无需密钥 |
| vLLM / OneAPI / NewAPI 等 | 服务商提供的 OpenAI 兼容地址 | 其模型 ID |
提示:若某个服务商报错,优先检查
API 基础地址是否以/v1结尾(按服务商文档),以及是否需要在后台开启"严格 JSON 模式"。
内置审核提示词说明
扩展内置了一份中文审核提示词,覆盖:政治敏感、色情淫秽、暴力血腥、违法活动(赌博/毒品/诈骗等)、侮辱攻击、垃圾信息等类别。提示词设计上:
- 要求模型结合上下文判断——新闻报道、科普、讨论、举报语境下提及敏感词不算违规;
- 要求识别谐音字、变体词、隐晦暗示等规避手段;
- 无明确违规证据时判定为合规,降低误杀;
- 严格输出 JSON,供程序解析。
你可以通过后台"自定义指令"追加规则,或用 php flarum ai-moderation:check "..." 配合你的真实模型验证效果。
📖 自定义指令完整指南:原理、写法、宽松/标准/严格三档示例、判定差异对比、验证方法,详见 docs/custom-instructions.md。
工作原理
用户发帖/回复/编辑
│
▼
Flarum Post\Event\Saving(保存前)
│ 读取内容(首帖附带标题),发送给 OpenAI 兼容接口
│ {"compliant": true/false, "category": "...", "reason": "..."}
▼
┌─ 合规 ───────────────► 正常发布
│
└─ 违规(按动作处理)
├─ reject ─────────► 抛 ValidationException,发帖失败并提示作者
├─ hide/hide_and_flag ► 帖子保存时即处于隐藏状态(作者和管理员可见)
└─ flag/hide_and_flag ► 在"标记"中生成 AI 审核标记(管理员复核)
要点:
- 基于
Flarum\Post\Event\Saving与Flarum\Discussion\Event\Saving事件,在内容入库前完成审核,违规内容不会对普通用户可见。 - 新建讨论时,Flarum 会先保存讨论再通过
PostReply创建首帖并派发Post\Event\Saving,因此"标题 + 首帖内容"会一起提交审核。 - 帖子在保存前还没有 ID,无法直接写
flags表;扩展会在帖子保存完成(Posted/Revised事件)后自动补建 AI 标记。 - 长短文本分流:短内容走同步审核(发帖即判);长内容(> 长文本阈值)或审核超时(AI 响应超过"请求超时")时跳过同步阻塞,帖子先发布,进入
ai_moderation_queue延迟队列,由后台(shutdown 阶段)或php flarum ai-moderation:process(cron)补审——命中违规则隐藏 + 标记 + 通知作者。 - 审核请求为同步时每次发帖会多一次 AI 调用(通常 1~3 秒);延迟审核不阻塞发帖,适合模型较慢(如 mimo-v2.5 约 20 秒+)的场景。
常见问题
Q:AI 误判把正常内容隐藏了怎么办? 管理员在后台"标记"页查看 AI 标记及原因,可一键恢复;作者把内容改为合规后再次保存也会自动恢复。
Q:flags 扩展没启用会怎样?
hide_and_flag 中的"标记"部分会被自动跳过(仅隐藏),不会报错;建议启用自带的 flarum/flags 扩展以获得完整的标记审核流程。
Q:AI 服务挂了/超时,用户还能发帖吗? 默认可以。短内容失败放行("AI 服务出错时放行"默认开);长内容与超时内容先发布、进入延迟队列补审。如需严格模式,关闭"AI 服务出错时放行",此时 AI 不可用会拒绝发帖并提示"审核服务暂时不可用"。
Q:长文本的延迟审核需要额外配置吗?
不需要额外配置即可工作(默认在响应后后台补审);建议再配一条 cron:* * * * * php /path/to/flarum ai-moderation:process,确保后台处理失败时也能兜底补审。
Q:作者会收到哪些通知? 内容被判定违规(隐藏/标记)时,作者会收到站内通知,包含违规类别与原因;可在后台关闭"违规时通知作者"。
Q:后台"测试连接"报错怎么办?
先确认基础地址、密钥、模型三项正确;再运行 php flarum ai-moderation:test 查看详细错误;Ollama/LM Studio 等本地服务请确认已开启 OpenAI 兼容端点。
Q:如何避免重复审核? 编辑时未修改内容、仅隐藏/恢复帖子的操作不会触发审核;每次"内容变化"只调用一次 AI。
目录结构
ai-moderation/
├── composer.json
├── extend.php # 扩展注册
├── locale/ # 语言包(en / zh)
├── src/
│ ├── Api/Controller/ # 后台测试连接 API(仅管理员)
│ ├── Console/ # ai-moderation:configure / test / check
│ ├── Listener/ # 审核监听器(帖子、讨论标题、补建标记)
│ ├── Moderation/ # AI 客户端、提示词协调器、结果解析、标记创建
│ └── Support/ # 日志工具
└── js/
├── admin.ts # 后台 JS 入口
├── webpack.config.js
└── src/admin/index.tsx # 后台设置页(含测试连接按钮)
重新构建后台 JS(修改 js/ 后):
cd js
npm install
npm run build