一、凌晨两点有人在村论坛刷屏
村里的论坛本来是给村民问政策、约农机、找走失牲口用的,日均发帖四百条上下,回帖两千六百条。运营只有两个人,白天的量还能看完,问题出在夜里。有天凌晨两点,一个账号在两小时里发了七十多条带站外联系方式的帖子,第二天早上村民在群里问,说论坛是不是没人管了。我们翻后台,那七十条要一条条点开、判断、驳回,两个人处理完已经十点。
再往前看一周的数据,人工审核的漏网率大概在百分之六,漏掉的多半是夜里发出来的,以及图片里带字的那些。帖子是同步发布、事后巡查的模式,也就是说,内容在被判定有问题之前,村民已经能看到了,删除只是事后补救。这条链路必须改,改成什么形态是我们要回答的第一个问题。
二、同步审核卡住发布,异步审核带来状态
最直接的做法是把审核塞进发布接口,发帖请求先过一遍词表,命中就拒绝返回。这条路的代价很实在,图片和视频的检测要几百毫秒到几秒,用户点了发布站在那里等,弱网情况下直接超时,村民会以为没发出去然后重发三次。视频更夸张,要走一遍抽帧检测,一次十几秒,放在同步链路里完全不可接受。
另一条路是异步。发帖请求只做一次快速的词表校验,通过就把帖子按待审状态入库,立刻返回成功,用户看到的是已提交待审核。检测在后台慢慢跑,跑完再决定放行还是驳回。这样发布体验回来了,代价是论坛里多了一种状态,所有读取内容的地方都得先想清楚,待审的帖子该不该出现在这个入口。我们当时低估的正是这一条。
三、两条路子和我们付的学费
审核策略本身也有两条路。一条是全量人审,所有帖子和回帖都进人工队列,最稳妥但两个运营扛不住每天三千条。另一条是机审优先、人工兜底,机审通过的直接放行,命中的转人工,误杀靠申诉纠正。我们选第二条,并且把发帖和回帖的审核开关做成后台可配,开学季那种发帖高峰可以临时把回帖调成免审。
代价是机审的误判会真实地伤害用户。有一段词库里收了几个常用词,村民讨论家禽行情时被整段丢掉了,当天就有人在意见反馈里问为什么发不出去。我们后来把策略从一律丢弃改成按命中词分档,一般敏感词只做打码,只有明确的违规词才整段拦下,命中边界的情况统一转人工,让人来判。分档之后误杀确实少了,可人工队列的量涨了大约三成,两个运营的活儿反而更满,这是当时没算到的一笔账。
四、状态机怎么落进服务里
帖子的状态我们定义成六个,待审、申诉中、已通过、已驳回、已隐藏、已归档。发帖写入时是待审,机审通过直接进已通过,命中就留在待审等人工;人工驳回时附带一个原因枚举,作者可以在驳回后七天内提一次申诉,状态转申诉中,由另一名运营复核。已通过的帖子被举报达到阈值会转回待审,也就是二次审核。
内容安全做成两段,一段是文本的词表匹配,用多模式匹配算法一次扫完整篇,另一段是图片和视频的异步检测,回调回来再更新判定结果。词表命中带着位置信息,便于前端在编辑页高亮提示作者自己改。审核服务属于万村乐数字乡村,发帖和回帖共用同一套状态判定,两个入口不再各写一份。
五、几个必须写死的字段
帖子表上跟审核相关的字段有八个,状态码、审核方式、驳回原因、审核人、审核时间、命中词快照、根帖标识、是否删除。状态码用两位数整数,不存字符串,方便加索引和范围查询;审核方式分免审、机审、人审三种,用来回溯一条帖子是被哪一层放行的。命中词快照存的是当时命中的词和位置,词库更新之后仍然能还原当初的判断依据。
根帖标识是给回帖用的,主帖的根标识等于自己的主键,回帖的根标识指向主帖。所有可见性判断都以根帖为准,主帖不可见时整棵回帖树一起不可见。删除一律用软删,物理删除只在归档任务里按保留策略执行。黑名单账号的发帖不进待审队列,直接进隔离表,避免它占用人工审核的额度。
六、踩过的三个坑
第一个坑是状态过滤漏入口。现象是手机端的搜索接口能搜出一条被驳回的帖子,点进去还能看到全文。根因是全站有九处拼查询条件的地方,只有六处老老实实加了状态过滤,搜索那处是后来加的功能,直接漏了。改法是把可见性条件收进一个统一的查询构造器,业务代码不许直接查帖子表,只允许调构造器,并补上覆盖全部入口的回归用例。
第二个坑是编辑免审。现象是有账号先把一条正常内容发出来过审,过几个小时再把它编辑成带站外联系方式的推广。根因是编辑接口直接复用了更新字段的逻辑,状态原样保留了已通过。改法是编辑正文一律把状态重置回待审,并且把上一版正文存进版本快照,运营驳回时能顺手对比两版差异,判断是不是恶意改稿。
第三个坑是级联隐藏。现象是主帖被删之后,回帖还能通过历史链接直接访问,等于删了个寂寞。根因是回帖按自己的主键做了软删标记,但根帖标识那一列的关联没有跟着更新。改法是软删主帖时按根帖标识批量把整棵回帖树标成隐藏,读取时以根帖状态为准做二次校验,两条路同时兜住。
七、这条链路解决不了什么
词表挡不住谐音、拼音首字母和拆字,也挡不住写在图片里的文字。前者我们靠人工转审兜底,后者靠图片检测,但检测模型本身有误判,把菜地里的竹架认成违规物的情况也发生过。我们最后的做法是给误判留一条反馈通道,运营可以把一条判定标成误判,误判样本每周回看一次,用来调整阈值。
申诉环节也没法自动化。谁来判一条被驳回的内容是不是真的违规,这件事本身带主观性,我们只能做到复核人和初审人不是同一个人,并且驳回原因必须从枚举里选,不能手写自由文本,否则用户拿到一句含糊的理由,申诉也没法针对性回答。申诉的处理时长我们也定了上限,超过四十八小时没有复核的会升级到负责人那一层,免得一桩申诉压在队列里没人管。审核的公平性靠流程约束,不靠算法。
八、小结
改完之后,论坛的可见内容里违规帖的存活时间从小时级压到了分钟级,夜里那批刷屏的帖子在入库后平均四十秒内被机审拦下,没进过任何人的时间线。真正花时间的不是词表和检测模型,而是补上那三处漏掉的状态过滤,以及把编辑和删除的级联逻辑理顺。万村乐数字乡村 在村里跑了一年多,这一条条结论背后都对应着一次村民的投诉。