AI敏感词过滤配置怎么做,先分清输入拦截与输出复检
AI敏感词过滤配置的核心不是找一份词表贴上去,而是决定在哪一层拦截、用什么方式匹配、命中之后怎么处理。
对大多数接入大模型的业务来说,比较稳妥的做法是输入和输出各过滤一次:用户提问先过一遍,模型返回内容再复查一遍,命中后按风险等级选择拦截、打码或转人工。
只做输入过滤挡不住模型自己生成违规内容,只做输出过滤则会白白消耗推理成本。
先确定过滤放在哪一层
常见有三个位置,可以叠加使用:
- 应用层:在调用模型接口的代码里加过滤函数,最灵活,能拿到用户ID、会话ID等上下文。
- 网关层:用 Nginx 的 Lua 模块或反向代理前置服务做初步拦截,适合挡住明显的批量请求。
- 模型服务层:部分推理框架支持输出回调,可在流式返回时逐段检查。
新手建议从应用层入手,改造成本低、调试直观。
如果业务已经有 Nginx 入口,可以在网关层补一道粗过滤,降低无效请求打到模型的概率。
词表怎么组织才不混乱
不要把敏感词全塞进一个文本文件。
建议按风险等级和匹配方式拆开:
- 高危词:命中即拒绝,比如明确的违法交易类词汇,用精确匹配。
- 中危词:命中后打码或要求改写,用包含匹配。
- 需要上下文的词:单看词本身没问题,结合前后文才敏感,这类不要进词表,交给规则或人工。
一个可维护的目录结构示例:
filter/
high.txt # 一行一个高危词
medium.txt # 中危词
regex.txt # 需要正则的规则
词表文件用 UTF-8 编码,每行一个词,加载时统一转小写并去重。
中文还要考虑全角半角、繁简和空格插字,比如“敏 感 词”这种拆开写的,需要在匹配前先做归一化。
匹配逻辑的写法示例
先做文本归一化,再匹配。
下面是一个 Python 思路示例,重点看处理顺序:
import re
def normalize(text):
text = text.lower()
text = re.sub(r"\s+", "", text) # 去掉空格和换行
return text
def load_words(path):
with open(path, encoding="utf-8") as f:
return [line.strip() for line in f if line.strip()]
def check(text, high_words, medium_words, regex_rules):
t = normalize(text)
for w in high_words:
if w in t:
return "block", w
for rule in regex_rules:
if re.search(rule, t):
return "review", rule
for w in medium_words:
if w in t:
return "mask", w
return "pass", None
几个容易踩的点:
- 先归一化再匹配,否则空格插字、大小写混写都能绕过。
- 正则不要写得太宽,像
.*这种会导致大量误杀和性能问题。 - 词表加载放在服务启动时做一次,不要每次请求都读文件。
命中之后怎么处理
过滤结果不要只有“通过”和“拒绝”两种。
更实用的分级是:
block:直接返回固定提示语,不调用模型,同时记录命中的词和用户ID。review:先返回安全版本,把原文写入待审核队列,由人工确认是否放行。mask:把命中片段替换成占位符,比如***,再继续走模型。
记录日志时不要原样存整段敏感原文,可以只存哈希值和命中位置,方便排查又降低二次泄露风险。
如果需要追溯,单独设审核库并限制访问权限。
验证和排查误杀
配置完成后至少做三类验证:
- 正常业务问句能通过,比如行业术语、产品名不被误拦。
- 故意插入空格、大小写、全角的变体能被识别。
- 命中后的返回内容符合预期,日志里有对应记录。
如果出现大面积误杀,先检查正则规则,再看词表里有没有过短的单字词。
单字词用包含匹配时误伤极高,建议长度小于两个字的词只做精确匹配或不进词表。
另外要注意,敏感词过滤只是内容安全的一环,无法覆盖语义层面的变体和隐喻表达。
对高风险业务,过滤规则要配合人工审核、模型输出评估和用户举报通道一起使用,不能把词表当成唯一防线。