输入过滤器的设计:正则表达式、关键词列表、分类器——多层过滤怎么组合

假设你正在做一个社区论坛,刚上线一个月,用户就开始会整活了。有人在评论区发“草泥马”,紧接着一堆人开始刷“卧槽”“法克鱿”“马勒戈壁”。你手忙脚乱地维护了一个敏感词列表,把看到的脏话全塞进去,然后每天都能发现新变体。这种猫鼠游戏持续了两周,你终于意识到——单纯靠关键词列表,永远追不上人类造词的速度。

AI technology illustration

更头疼的是,你听说了正则表达式可以匹配各种变形,又听说机器学习分类器能理解语义。但真正让你困惑的是:这三者到底该怎么组合?是全部堆上去,还是选一个?这篇文章我想用我踩过的坑,聊聊多层过滤的设计逻辑。

关键词列表:简单,但脆弱得令人心碎

关键词列表的本质是子串匹配。你把需要拦截的词放进一个字典,用户输入进来,逐个查一遍,命中就拦截。它的优点很突出:实现简单、延迟低、逻辑透明。哪怕用最朴素的字符串哈希,处理一篇文章也在微秒级。

但它的缺点同样赤裸裸。语言是活的,关键词却是死的。“小可爱”可以是昵称,也可以是反讽。“废物”可能是在骂人,也可能是在描述一件物品。更别提变体了——同音字、谐音、谐音字加空格、拆字、emoji 替代,每一种都能轻松绕过你的字典。

我记得有一次,我的过滤器被“身寸米青”这种拆字梗绕过了。当时我第一反应是把这个词也加进黑名单,但马上意识到,用户能造出成千上万种拆法,我根本加不过来。

正则表达式:更灵活,但也是一个无底洞

正则表达式把“固定字符串”升级成“模式”。你可以写 f\s*u\s*c\s*k 来匹配中间带空格的脏话,也可以用 [b8]itch 来匹配数字替代字母的变体。听起来很美,但正则不是银弹。

第一个问题是可读性。一个月后你回来看自己写的过滤正则,就像看一幅抽象画。第二个问题是维护成本。用户的想象力无限,你的正则有限,任何一个没覆盖到的变体都会成为漏网之鱼。

第三个问题最致命:灾难性回溯。某些正则表达式(比如 (a+)+$ 这种嵌套量词)在处理长字符串时,会进入指数级的回溯计算。攻击者可以利用这一点来进行 ReDoS,让你的过滤服务直接卡死。这不是危言耸听,OWASP 将 ReDoS 列为常见攻击手段。你原本想过滤恶意输入,结果正则本身变成了漏洞。

更深层的问题在于,正则依然是黑名单思维。你是在列举“我知道哪些是坏的”,而用户总在制造“你不知道的那些”。

分类器:能理解语义,但成本很高

到了机器学习时代,你可能会想:我用一个文本分类模型,让模型自己判断“这算不算辱骂”。这就是第三类方案:分类器。常见的实现是基于 BERT 的文本分类模型,输入一段文字,输出它属于各个类别的概率。

分类器的优势在于它能处理语义和上下文。“你真是个天才”在讽刺语境下是攻击,“我恨你”可能只是情绪发泄。它不需要穷举变体,因为它学的是“语言使用模式”。Hugging Face 的文本分类任务说明可以作为入门参考。

但分类器也有自己的问题。首先,它需要高质量的训练数据,而且要对齐你的审查标准。你定义“违规”的方式直接决定模型行为。其次,推理成本比字符串匹配高几个数量级——在大流量的入口处跑一个 Transformer 模型,GPU 账单会告诉你什么叫现实。第三,它不可解释。模型为什么拦了这句话?你只能回看训练集,完全无法像正则那样一句话说清楚。

所以你看,三种技术各有利弊。关键词便宜但脆弱,正则灵活但难维护且可能反噬,分类器聪明但昂贵且不透明。那怎么组合?这才是真正有价值的问题。

多层过滤:让每一层只解决它最擅长的问题

我见过不少团队的做法是“把所有方案全上”,结果体验灾难。关键词拦一次,正则拦一次,分类器再拦一次,误报叠加,用户发什么都发不出去。正确的做法不是堆叠,而是分工。

核心原则是:每层只做自己擅长的事,并为下一层降低难度

层级 技术 职责 成本
0 预处理 大小写归一、全半角转换、去除零宽字符 极低
1 白名单 确定合法的内容直接放行 极低
2 关键词 确定性违规词,如硬核色情、违禁品 极低
3 正则 已知变体,如带空格、谐音字
4 分类器 语义模糊、需要上下文判断

为什么这个顺序?因为匹配类技术(关键词、正则)快,可以迅速处理掉大部分流量;语义模型慢,所以放在最后,只处理前两层筛过之后的长尾内容。这样分类器的计算压力也小得多。

把“命中”分级:从“直接拦截”到“送审”

最常见的错误是把所有命中都当成相同级别的威胁。实际上,你应该为每个过滤器定义它的“置信度”和“后果”。一个简单的分级:

  • 确定违规:如“出售枪支”的链接,直接拦截,不给用户任何反馈。
  • 疑似违规:命中关键词但语境不确定,交给分类器打分,低分放行,高分拦截。
  • 需要人工:分类器也无法确定的高风险内容(比如逃杀类游戏攻略),进入人工队列。

这套分级的核心是:不要用一把尺子量所有内容。关键词列表可以作为“触发器”,而不是“最终仲裁者”。比如“傻逼”这个词,在“你真是个傻逼”和“他说傻逼这个词很粗鲁”中,前者违规,后者是引用。正则命中后,把整句话传给分类器,让模型根据上下文判断。

这比单独用正则或关键词要聪明得多,因为关键词提供了召回(把可疑内容都捞出来),分类器负责精确(判断哪些是真正违规的)。这恰好利用了两种技术的互补性。

一个简化的流程示意:

  1. 用户输入
  2. 预处理:大小写归一、全半角转换
  3. 白名单命中?是 → 放行
  4. 黑名单命中?是 → 拦截
  5. 正则/关键词弱信号命中?是 → 送入分类器
  6. 分类器概率 > 0.9 → 拦截;> 0.6 → 人工审核;否则放行

我的踩坑记录:过滤器不是用来“零误杀”的

我最早以为,多层过滤的目标是“一个坏人都放不进来”。于是我疯狂提高每一层的敏感度,结果正常用户哀嚎遍野。后来我想通了:过滤器本质上是一个风险管理工具,你要在误报和漏报之间找一个你的业务能承受的平衡点。

比如金融社区的评论,宁可误报也不能漏报,所以分类器阈值要低;普通娱乐论坛,误报会杀死用户的表达欲,所以阈值要高,把不确定的内容交给用户举报机制去处理。这个平衡只能通过真实数据不断调优,没有任何静态方案能一劳永逸。

结论:多层过滤的边界在哪

写到这里,你应该明白了,多层过滤不是三个技术叠罗汉,而是一个各司其职的流水线。关键词负责过滤确定性的垃圾,正则处理已知变体,分类器判断语义模糊的长尾,人工审核兜底。每一层都有明确的职责和出口,而不是简单地把内容扔进一个“违规”或“合法”的二分桶。

但也要清醒:这套系统的边界同样明显。只要用户想绕过,总能找到新的角度——用零宽字符拼接、用二维码分享链接、甚至用语音转文字再翻译成奇怪的语言。对抗性攻击是无限的游戏,多层过滤的目标不是“不可绕过”,而是提高绕过的成本,让大多数普通用户遵守规则,让恶意用户付出足够高的代价。

如果你正在设计这样一套系统,我的建议是:从关键词起步,把正则当成辅助,把分类器当成最后的仲裁者,并且永远要有人工审核的逃生通道。别追求完美,追求可控。

原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/577.html

(0)
上一篇 2天前
下一篇 1天前

相关推荐