1. 先把“可控性”讲清楚:AI原生应用为什么绕不开这道闸
做AI原生应用最绕不开的坎,就是可控性。我把“AI原生应用”拆开看,它和传统软件最大的区别在于:传统软件的每个分支都是人写死的,输入是什么、输出基本可预期;而AI原生应用的所有交互都经过一个概率模型,用户问一句、模型答一句,中间要是没有一道闸,出事的概率远比传统软件高。什么叫可控性?不光是内容安全,还包括模型会不会“胡说八道”、会不会越界执行危险操作、会不会在某个敏感话题上突然失控、以及线上出问题之后你能不能快速定位到底是哪条策略在起作用。可控性不是某一个模块,而是横跨数据、模型、推理、运营一整条链路的工程能力。
这个题目的后半句是“自动化实现路径”。为什么强调自动化?因为靠人盯是盯不住的。我见过不少团队,刚上线AI功能时全指望运营同学一条条刷对话记录,人工给badcase打标,再手动整理成规则。前一百条、一千条还能扛,等日活上来之后,一小时就有几千甚至上万条需要判断的对话,人工根本看不过来。更要命的是,模型版本一旦升级,之前人工积累的那套判断标准就可能失效一半。
所以“可控性的自动化”本质上是在回答一个问题:怎么把过去靠人肉做的审核、评测、监控、迭代,变成一套可以自动运行、可量化、可回归的工程体系。适合谁来参考?一类是正在做AI应用落地、被内容安全或回答质量折腾得睡不好觉的开发者,另一类是技术决策者,想把不确定性变成可管理的风险指标。这篇文章我会从整体设计、核心实现、落地细节到问题排查,把我踩过的坑和试过好用的方案一起讲清楚,让你看完之后能直接搭出一套属于自己的可控性闭环。
2. 整体设计思路拆解:三层防线加一条数据飞轮
2.1 先把可控性的边界定义清楚
很多团队一上来就急着写敏感词库,其实顺序反了。第一步不是写规则,而是先把“可控”这个词翻译成四项可度量的指标:内容安全,即不会生成违规、违法或存在明确风险的内容;行为边界,即模型不会执行超出授权范围的操作,不泄露系统提示词、不调用未授权的工具;质量稳定,即回答不是随机的,同一类问题在不同时间、不同用户下拿到的是同一量级、同一立场的答案;合规留痕,即每一次异常判定都有日志、有依据、可以回捞和复盘。
我建议把这四项指标写进项目PRD里,而不是把它们当成后台默默的“安全模块”。因为在AI原生应用里,可控性本身就是功能的一部分。就拿行为边界来说,一个助手如果能在对话里被诱导出系统提示词,那不是安全事件,而是功能缺陷,用户会直接失去信任。只有先把边界定义清楚,后面所有自动化手段才有评判标准。
2.2 为什么纯人工审核撑不住:从“做完”到“做对”的差距
我上一个项目做的是面向C端用户的AI问答助手,刚上线时一片岁月静好,直到某天凌晨有一条回答出现了严重的内容越界,第二天被反馈到管理层,团队才开始连夜补规则。那段时间我们每天人工review几千条对话,把一个不长的敏感词表扩充到上万条,但效果依然一般。因为漏网的不是明面上的词,而是变体、拼音、谐音、拆字,甚至是一段看起来无害但语义上明显越界的句子。
纯人工审核的另一个问题是标准漂移。A运营觉得这个回答不行,B运营觉得凑合能过,DEF三个人投票还可能有平票。没有统一的自动化标准,审核质量就不稳定。而自动化方案的最大价值不是替代人,而是把标准固定下来:规则怎么判、模型怎么评、策略怎么拦截,全部代码化、版本化,每次变更都走测试,出问题可以回滚。这就像给审核流程装上了CI/CD,质量是构建出来的,不是盯出来的。
2.3 三层防线与一条飞轮
我最后落地的一套体系,可以概括成“三层防线加一条数据飞轮”。
第一层是输入输出检测层,在请求进来和响应返回之前分别卡一道。这一层要非常快,几毫秒内完成,用轻量规则加文本分类模型处理绝大多数明确违规的内容。第二层是模型评测层,做上线前的离线验证,用一批经过标注的评测集去评估每个模型版本、每套Prompt配置是否满足可控性指标。第三层是运行时拦截与策略编排层,处理那些不走寻常路的复杂情况,结合多模型投票、向量相似度检索、动态策略路由给出最终判定。
这是三条横向的防线。纵向贯穿它们的是数据飞轮:线上拦截到的badcase、人工复核的结果、评测集里的badcase,全部回流到一个样本中心,定期自动生成新的规则候选、筛选新的训练数据、迭代评测集。这样三层防线不是三座孤岛,而是同一个系统在不同时机上的三道闸。这也是“自动化实现路径”里最关键的一环:让系统自己越用越准,而不是永远靠人写规则来喂。
3. 第一层防线:规则引擎与检测层的核心实现
3.1 敏感词库的建设:黑名单是底线,不是全部
规则引擎这一层最基础的是敏感词库。但我不建议一上来就堆词条,而是把词库拆成三个层次:基础层是那些无论什么场景都绝对不能出现的词,属于置顶规则,命中直接拦截;领域层是和你的业务场景强相关的词,比如做医疗问答,涉及诊疗方案的用词就要额外收紧;动态层是从线上badcase里自动挖掘出来的词或短语,每两天自动更新一次。
词库的存储我推荐放在独立的配置中心里,不改代码、不重新发版就能热更新。格式上做成纯文本或JSON都行,但要支持命中的命中位置、命中的词条ID。这样出现误杀时你能快速定位是哪条规则出了问题,而不是对着一段拦截日志发呆。
3.2 从关键词到正则和语义意图:躲避对抗怎么处理
只靠关键词远远不够。线上的对抗手段五花八门:插入特殊字符、全角半角混用、拼音替代、拆字重排、甚至故意把一句话倒着写。我的做法是三层叠加:
第一层是标准化清洗器。文本进来先做Unicode标准化,把全角转半角、繁体转简体、去掉零宽字符和干扰字符,然后再去匹配敏感词。第二层是正则模式库。敏感词库解决“词在不在”的问题,正则解决“变体能不能识别”的问题。我会为正则单独建一个库,每条正则有对应的风险类型和等级,比如针对拆字模式、拼音字母混插模式分别建模板。正则的坑是容易互相覆盖、顺序敏感,所以我会给每条正则加一个优先级字段,并且每次更新都在评测集上跑一遍回归,防止新正则误伤正常内容。
第三层是语义意图分类。这一步不依赖具体词,而是判断整句话的意图。比如“教我做一个危险的东西”这种句子可能一个违禁词都不含,但意图明显越界,就需要一个轻量文本分类模型来兜底。我建议用一个小型的预训练模型做微调,几百兆以内,延迟控制在20毫秒以内。这一层和关键词层是并行关系,任何一层命中都算违规。把三者配起来之后,对抗能力会明显提升,因为攻击者绕过了关键词层,还有语义层等着。
3.3 性能优化:别让安全系统拖垮主链路
检测层如果处理太慢,就会直接影响用户体感。我实测下来有一条经验:凡是能在请求前算好的,绝不在响应链路里现算。比如标准化后的文本、敏感词匹配结果、语义分类的embedding向量,这都属于可以在请求前置缓存或预计算的内容。
另外一定要做布隆过滤器做粗筛,把绝大多数完全正常的文本快速放行,不需要跑后面的正则库和分类模型。布隆过滤器判断“正常文本”的时间可以到微秒级,在服务里也只占很小的内存。粗筛通过之后才进入精细检测。这样设计之后,正常请求的额外延迟可以控制在5毫秒以内,而真正需要做深度检测的只是少数,不会成为瓶颈。
注意:规则引擎一定不要和业务逻辑耦合在一个服务里。哪怕前期规模小、图省事,也尽量拆成独立服务或独立的内部接口。否则每次策略更新都要跟着业务发版,发布频率会被拖慢到令人崩溃。
4. 第二层防线:模型评测与红线测试
4.1 评测集怎么建:别只测一个方向
模型评测这层,是很多团队最容易忽略也最不值得省的一步。评测集建设的核心原则是“一致性 + 覆盖度”。一致性指同一个badcase用统一的标注规范打标,比如“是否违规”“违规类型”“严重等级”;覆盖度指评测集必须覆盖正常问法、灰区问法、对抗问法、历史线上badcase、新发现的变体问法等等不同切片。
我建议把所有用例分成三个子集,起到不同作用:基础集固定不变,用来做每次发版前的冒烟验证,保证基本盘不崩;动态集从线上badcase和人工新增用例里定期补充,用来验证新规则是否有效;对抗集是从绕过案例中沉淀的,难度最高,专门用来压测模型和策略的鲁棒性。什么样的题目能进对抗集是有门槛的:必须是线上真实出现过的绕过方式,而不是拍脑袋想出来的。
4.2 评测执行与打分:用数据说话
评测执行我是放在CI流程里的。每次改动规则库、升级模型、调整Prompt模板,都自动跑一遍评测流水线,产出一份结构化报告。报告里最重要的不是“通过/不通过”,而是四个分数:违规内容拦截率(违规样本里有百分之多少被拦住了),正常内容误伤率(正常样本里有百分之多少被错杀),定向对抗绕过率(对抗集里还能溜过去几条),以及平均判定延迟。这四个指标分别对应可控性的四个维度,也对应上线之前要回答的四个问题:会不会出事、会不会误伤用户、攻击者能不能钻空子、系统会不会太慢。
打分还有一个细节要提:一定要看分类别的结果,不要只看整体分数。比如评测集里医疗类违规200条、一般辱骂类600条、对抗类200条,整体拦截率90%看着还行,但细看可能对抗类只拦了60%,那个才是需要重点关注的风险。我会在报告里给每个切片单独算分,并生成一个“最薄弱三项”列表,直接告诉团队下一步要补哪里。
4.3 评测集回流:让评测集持续进化
评测集不是攒一批就完事的。我见过有些团队建了一版评测集,半年都没更新过,结果模型迭代三轮之后,评测集跑出来分数一路绿灯,但线上badcase还是一堆。原因很简单,评测集已经过时了,它所代表的“风险分布”和线上真实情况对不上了。
我的做法是每周从线上抽取一个风险样本池:包括被拦截的、被用户举报的、被人工复核标记为误伤的、以及通过规则但来自低信誉用户的高风险对话。然后对这些样本做轻量自动标注,再合并进评测集的动态子集。这个过程能自动化到什么程度?我建议至少把“样本选取”自动化,标注可以人机配合。系统负责把候选样本按风险类型聚类,人工只需要快速确认聚类结果是否合理。这样两个人在半天内就能完成一次评测集的周度更新,效率比每天人工刷对话高得多。
5. 第三层防线:运行时拦截与策略编排的落地细节
5.1 拦截策略分级:先软后硬,别一上来就封
运行时拦截是最容易得罪用户的一层。如果一个正常用户在AI问答里提到某个中性话题,系统直接返回“该问题无法回答”,用户会对产品失去信任。所以我把拦截策略设计成六档,按严重程度递进:
- 放行:检测通过,正常返回。
- 警示:正常回答,但给提问方或运营方打一个可观测标记。
- 改写:模型重新生成回答,去掉风险部分。
- 转向:不直接回答,引导用户换一个更安全的话题或方式提问。
- 拒答:明确告知无法回答该问题。
- 阻断:不仅拒答,还触发账号维度的风控动作。
这里的关键技术点叫“策略编排器”。它不是简单地按命中数量来堆等级,而是把规则命中的风险类型、严重等级、用户的信誉分、上下文会话历史合并成一个综合判定矩阵,再决定走哪一档。举个实际例子:用户第一次问某个敏感边缘话题,我会选择警示加转向;如果同一会话里连续三次追问同类话题,等级就要升到拒答。同样的词,放在不同场景、不同频次下,处置策略是不同的。
提示:策略编排器的核心是“可解释”。每条决定都要记录命中了哪些规则、哪些权重参与了计算。出问题复盘的时候,你要能在几秒内回答“为什么这条对话被拒了”这个问题,而不是翻代码翻半天还说不清楚。
5.2 灰度发布与策略演练:先小流量验证
所有新策略上线前,我都会做一次离线回溯。方法是把线上过去一周的真实流量日志重新跑一遍新策略,看它会拦截多少原本放行的样本、放掉多少原本该拦的样本,以及误伤率有没有超过阈值。这一步完全不产生线上风险,成本也很低,却能提前筛掉绝大多数不成熟策略。
离线回溯通过之后才进灰度。我从1%流量开始,逐步放大到5%、20%、50%。每一步灰度都盯三个指标:badcase拦截数量有没有异常增多、用户投诉率有没有上升、回答正常率有没有下降。这三个指标必须一起看。拦截数量上升但投诉率没变,说明策略有效;拦截数量和投诉率同时上升,说明可能在误杀。
灰度期间有一个很容易被忽略的点:灰度策略和线上已有策略是同时生效的,可能出现“新策略没触发,但userId哈希变化导致旧策略判定结果不同”的假阳性问题。我会在灰度日志里单独标记策略版本号,做对比分析时只看同一条规则命中情况,不被全局数据波动带偏。
5.3 人工复核抽屉与反馈闭环
再自动化的系统也需要人工兜底。我的说法是“机器负责拦截,人负责救火”。在策略编排器里设置一个人工复核抽屉,凡是命中了多策略、但判定置信度低于阈值的样本,自动进入复核队列,由人工审核员做最终判断。这个队列不需要很大,控制在每天几百条以内就行,因为绝大部分高度确定的样本机器已经处理掉了。人工审核完之后,结果再回流到样本中心和评测集,形成闭环。
这里要给审核员建一套好用的工作台,不然效率会很低。工作台上必须一次性展示四个信息:原始对话上下文、机器判定结果和置信度、命中了哪些规则、以及历史相似case的处理结果。从我的经验看,这个工作台比审核员培训文档重要十倍。有了好的工作台,一个审核员每天能处理上千条样本,而且处理标准的稳定性会明显比只靠记忆和感觉高很多。
6. 数据飞轮:让系统越用越准的自动化引擎
6.1 样本回流与自动打标
三层防线日常跑起来之后,真正驱动整个系统变强的其实是数据飞轮。飞轮的输入是所有的拦截样本、人工复核记录、评测集跑分结果、用户反馈。这些数据不能散落在各个日志里,必须全部落到一个统一的样本中心,按统一的格式存储,带上来源标签(是线上拦截的、人工复核的、还是评测集新增的),并带上时间、策略版本、模型版本这些关键元信息。
自动打标这一步相对困难一些。我的做法是做“自动预打标 + 人工确认”。先用规则和旧模型对新样本做一次初步分类,给出“疑似违规类型A的概率是0.93”这样的输出,然后人工只需要做二选一确认:接受或修正。这样打标的效率至少提升三倍。积累两三个星期之后,这批数据就是活生生的训练语料和评测语料,比任何公开数据集都贴合你的业务场景。
6.2 自动化回归与策略自检
有了样本中心之后,每一次策略更新或模型升级,都跑一遍全量自动化回归。这里不是只跑固定评测集,我还会加一个动态回归,把过去三十天的线上样本随机抽取30%塞进回归集,专门用来检查新策略对历史流量会不会造成异常影响。这套自动化回归体系跑起来之后,团队吃下的定心丸非常大:因为任何一次改动,系统的“行为基线”都会自动对比,哪怕改动后正常率降了0.5%,系统也会在发布前亮出红牌。
6.3 一套看板盯住四个趋势
最后一定要做可视化看板,让可控性不只是写在文档里的概念,而是每天都能看到的数据趋势。我会把看板设计成四块:风险拦截趋势(拦截量按等级、按风险类型分布)、误伤趋势(在已拦截样本中,被人工复核纠正成正常样本的比例)、评测得分趋势(拦截率、误伤率、对抗绕过率的变化折线)、以及策略健康度(每条规则近期的命中量、误杀贡献量,自动标记出“命中量暴跌”或者“误杀突然升高”的规则)。
这块看板是可控性体系的“仪表盘”。它解决的问题不是“今天出没出事”,而是“风险有没有在悄悄抬头”。从我的实际经验看,绝大多数严重的线上问题都不是一瞬间爆发的,而是连续几天某条曲线在缓慢爬坡,只是没有人在看。有了自动化看板和阈值告警,你能在问题变成事故之前就介入。
7. 常见问题与排查技巧实录
7.1 误杀率突然升高
这是最频繁的问题。我的排查顺序是先回溯时间点变化,看误杀升高是从哪个版本开始的,是规则库更新、模型升级还是流量结构变化。然后按风险类型切分误杀样本,看集中度高不高。最后针对性检查对应规则的正则是否有兼容性问题。
最常见的原因是新增正则覆盖过广,比如一个针对拆字攻击的正则用“长度大于15且字母占比超过50%”当辅助特征,结果把大量正常翻译类文本也命中了。我建议每条新正则都要在三个数据切片上跑测试:正常文本、对抗文本、以及“最容易误杀”的边界文本(包含大量URL、编码字符、外语混排的文本)。
7.2 语义绕过屡禁不止
如果对抗集里总是有绕过的样本,说明语义意图分类这层需要补强。不要急着去堆规则,而是看绕过样本在embedding空间里是不是聚在一起。如果聚在一起,说明是一个稳定的攻击模式,把这部分样本加入训练集微调分类模型会有用;如果散得很开,说明是零散对抗,规则层补几条针对性的正则更划算。
7.3 模型升级后行为漂移
模型从V1升到V2,评测集分数全绿,线上却出了风格偏差的badcase。这种情况通常是评测集的动态子集没有覆盖到新模型最容易变化的区域。把新模型在两个版本的输出差异做一个diff分析,把差异大且涉及敏感领域的问题补进评测集,下次升级前就心里有底了。
7.4 拦截了但日志里查不到
查不到拦截日志大多数是因为你绑定的是响应阶段拦截记录,但实际触发的是输入阶段检测,两套日志没有用同一个traceId打通。我在设计日志时要求所有检测节点都带上同一个请求级traceId,从入口到出处罚策略,一条链路查到底。这个比事后花一整天翻日志划算得多。
| 问题现象 | 最常见原因 | 排查建议 |
|---|---|---|
| 误杀率升高 | 正则覆盖过广 | 先按版本切分,再按风险类型定位到具体规则 |
| 对抗绕过频发 | 语义分类模型滞后 | 看绕过样本的embedding分布,决定补数据还是补正则 |
| 升级后行为漂移 | 评测集未覆盖变化区域 | 做新旧模型输出diff,把差异大的敏感样本补进评测集 |
| 日志查不到拦截记录 | traceId未贯穿 | 统一全链路traceId,从入口开始串到底 |
| 人工复核效率低 | 工作台信息不全 | 一次展示上下文、机器判定、命中规则、相似历史 |
8. 关于工具选型与架构落地再补充几句
关于用现成服务还是自建,我给一个原则性的建议:核心检测能力能用成熟依赖就用成熟依赖,但策略编排层一定要自己掌控。原因很简单,策略编排本质上是你们产品的“价值观代码”,它需要跟着业务快速调整,不适合被某个现成平台的黑盒逻辑锁住。而底层的敏感词匹配、向量检索、文本分类跑分,这些在开源社区都有非常成熟的组件可以直接用。
架构上我会把整个体系拆成四个服务:detector(检测服务,负责标准化、布隆过滤、敏感词、正则、向量粗判)、judger(评测服务,解析策略编排,产出等级与处置建议,这里面向规则配置,业务不感知)、sampler(样本服务,统一收集所有节点的判定记录,做离线样本挖掘和回流)、dashboard(看板服务,汇总指标与告警)。四个服务之间全部走异步消息传递,检测链路本身保持串行同步,但样本收集完全异步,不影响主流程性能。
部署上比较推荐把detector和judger部署成无状态服务,可以横向扩容。样本中心和数据看板用云上的消息队列加分析库就能搞定,初期完全不需要上重型的实时计算平台。只要消息格式定义清楚,后面扩展接入其他策略源或数据源都很方便。整个体系的建设周期,一个三到五人的小团队,大概八到十周可以跑起来。
9. 我踩过坑之后的一点体会
整套体系做完之后再回头看,最大的体会是:可控性这件事,做的不是对抗,而是工程。不要指望一条规则、一个模型能解决所有问题,也不要指望一套系统上线之后就一劳永逸。它的本质是把“风险”当作一种需要持续观测、持续迭代的指标,用工程手段让风险保持在可控区间内。我最庆幸的是从第一天就把评测集和样本回流建了起来,后面每次模型迭代、策略更新都有数据兜底,团队内部吵架都少了很多。而如果一开始就埋头写规则、上线后靠人肉盯日志,现在大概率还在被各种线上事故追着跑。最后再补一个小技巧:规则引擎、评测流水线、灰度旁路这三样东西,是整套体系的地基,一定要最先搭好,越早做,后面的维护成本越低。