评估护栏与检测器。
市面上每一个注入分类器都靠召回率来卖,而召回率恰恰是那个完全说不出「它会把你的生产流量弄成什么样」的数字——因为在真实的攻击基础发生率下,一个 99% 召回、1% 误报的检测器,大约每抓到一次真攻击就要附送一百次假警报,而团队会在两周之内彻底不看它。要评估的是操作点在你的基础发生率下的表现,而不是检测器在一个均衡基准上的表现;并且在看任何一张厂商曲线之前,先用两类错误的代价比推出阈值。
先把基础发生率的算术做一遍,通常这就把讨论结束了。
取一个数字确实漂亮的检测器——99% 召回、1% 误报——把它放到一天的流量上跑,其中真正是攻击的请求是一万分之一。这不算悲观的基础发生率;对多数内部智能体而言,这已经算慷慨了。
100,000 requests/day, base rate 1 in 10,000 → 10 attacks, 99,990 benign true positives = 10 x 0.99 = 9.9 false positives = 99,990 x 0.01 = 999.9 precision = 9.9 / (9.9 + 999.9) = 0.98% → 101 alerts per real attack, 1,000 blocked users per day
这个检测器本身没有任何毛病。造成伤害的是算术,而一个由 500 条攻击和 500 条良性提示构成的基准——50% 的基础发生率——把这个算术彻底掩盖了。均衡集上公布的 F1 是关于那个打分函数的陈述;你自己基础发生率下的精确率,才是关于你周一早上的陈述。
在任何选型评比之前,先用你自己的数字算这一遍。它会把问题从「哪个检测器最准」重构成「这条工作流能吸收多高的误报率」,而第二个问题有一个你真能问出来的答案:去问将来处理这些告警的人,一天他们愿意读多少条。
评估的单位是一个操作点,而不是一个检测器。
几乎所有护栏都是一个打分函数加一个阈值,而阈值属于你。按两家的默认设置去比较两个检测器,比的是两家厂商对你风险偏好的猜测。
- 先报曲线,再挑点。可比的数字是「固定召回率下的误报率」——先挑一个风险负责人肯签字的召回率,再按候选者为达到它要让你付出多少假警报来排名。单一的准确率数字在不同检测器之间不可比,在同一个检测器的不同版本之间也很少可比。
- 阈值从代价比推出来,不是从曲线拐点上挑出来。如果一次漏掉的提示注入在只读摘要智能体上的代价是一份糟糕的摘要,而一次误报的代价是一个被拦下的用户加一张工单,那么这个比值并不明显偏向「宁可全抓」。而在一个握着写权限凭据的智能体上,它会强烈反转。同一个检测器、两个阈值,这个决定是产品决定。
- 按接触面分别定阈值。整个平台一个阈值,是没人做过这道题的标志。按「智能体拿这段输入能干什么」来分档,这与自主性等级是同一根轴。
- 对你会分别处置的类别分别打分。一个只会报「不安全」的检测器在运维上近乎无用;一个会报「不安全:检索内容中夹带指令」的检测器则可以路由。按类别评估,因为各类别的召回率差异极大,而汇总数字会把它抹平——这与失败分类法是同一个论证。
你的基础发生率不是基准的,而且你必须去测它。
没有发生率估计就算不出精确率,而拿到它只有一条诚实的路:给一份生产流量的均匀随机样本打标。不是被标记出来的那份样本——被标记的那份,正是检测器已经看过的地方。
- 均匀抽样、盲标、并把样本留着。随机抽几百条请求,交给一个看不到检测器分数的人来标,你同时拿到发生率和一个无偏的漏报估计。你测的其他一切,都是以检测器自己的意见为条件的。
- 按计划重新估计。当你进入一个新市场、把一个新接触面公开暴露,或者被人写进一篇文章时,基础发生率就会移动。在某个发生率上调好的阈值,换一个发生率就是失调的,而系统里没有任何东西会告诉你。
- 要有心理准备:置信区间会很难看。如果发生率真是万分之一,一份 500 条的样本里将一条攻击都没有,你的区间是「低于千分之六的某处」。这是一个真结果:它告诉你误报那一侧主导了整个设计,你该停止争论召回率了。
- 按事件数来计算一次漏报到底值多少。能为收紧阈值提供理由的,不是某个基准上的召回率,而是「首个出错步骤是本该被这个检测器抓住的一段输入」的生产事件数。如果这个数在两个季度里是零,那么真正在干活的控制并不是它。
冻结的基准所测的那个分布,攻击者有权移动它。
护栏评估有一个普通质量评估没有的性质:输入分布是由一个希望你的数字出错的人挑的。公开的注入语料,恰恰是每家厂商都拿去调过、每个攻击者都读过的那一批,这使得在它们上面的高分成为最弱的一种证据。
- 留两套集合,永不混用。一套冻结的回归集,带版本、不改动,它的存在是为了发现一次升级把事情弄糟了;作为绝对度量它毫无意义。一套轮换的对抗集,由红队每个周期针对当前阈值刷新,它是唯一能估计当下召回率的东西。
- 给对手的投入打分,而不只是给结果打分。「三次尝试就绕过」和「两百次尝试才绕过」在同一个召回率下是两件不同的产品。记录「首次绕过所需尝试次数」;随着检测器老化,这个指标会肉眼可见地衰减。
- 把你买来的载荷留出去。如果某厂商的基准已经进了他们的训练集,他们在上面的分数测的是记忆——这是护栏版本的基准污染。留一套私有集,永远不发给他们。
- 把无聊的负样本放进去。生产中一半的误报来自看起来像对抗、实则正当的文本:安全文档、提示工程的讨论、引用了报错的缺陷报告、客户粘贴过来的一段日志。把这些放进良性那一半,否则你的误报率是虚构的。
如果你的检测器是一个在判文本的 LLM,那它也是一个带提示词的模型,裁判校准里的一切都适用:它会在模型升级时漂移、对格式敏感,而且它自己也可被注入。把它的版本和阈值一起钉住,任何一方变动都重跑回归集。
检测器有延迟预算,也有失效模式,而这两样通常都没被测过。
护栏坐在每一个请求的关键路径上;如果输入输出都扫,就是两次。它的质量数字只是评估的一半,另一半是它对被它保护的那套系统做了什么。
- 测新增的 p95,不是新增的均值。一个均值 80 ms、长尾 900 ms 的分类器,会把一个利落的智能体变成一个偶尔坏掉的智能体;而在多步运行里,这条长尾你要付好几次。见度量智能体延迟。
- 明确决定 fail-open 还是 fail-closed,然后去测它。多数技术栈是「不小心」fail-open 的——检测器超时、异常被吞掉、请求未经筛查就放行,而没有任何指标记录下「这次没筛」。为「未评估」发一个独立计数器并对它告警;护栏的一次宕机是安全事件,不是延迟毛刺。
- 按每个受保护请求来定价。输入与输出都上模型检测器,可能吃掉账单中不小的一块;而用一个便宜的确定性前置过滤先滤掉 90% 的流量再进昂贵那一层,通常是更好的架构,并且它在任何准确率对比里都不可见。相关:智能体成本控制。
- 追踪一次拦截的人力代价。被拦后申诉的请求数、支持工单数,以及一个被告知「不行」的用户的重试率。正是这个数字决定这项控制能不能熬过它的第一个季度。
先影子上线,再把它当作一项有明确职责的控制来治理。
上线次序是团队最容易跳过的一段,而阈值恰恰是在这一段里真正被选定的——在真实流量上,而不是在一页幻灯片上。
- 先跑影子模式,至少完整一个自然周。全部打分、一律不拦,然后人工逐条读分数最高的一百条。你只能用这个办法找到误报的聚集,别无他法;顺带还免费拿到了发生率估计。
- 先在窄接触面上启用强制。把它开在爆炸半径最大、流量最小的地方——那个握着写权限凭据的智能体,而不是公开的聊天框。
- 把操作点纳入版本控制,配上负责人与复核日期。阈值是一次带安全后果的配置变更;它该走与权限变更相同的评审通道,并且在基础发生率估计刷新时重新推导。
- 在风险登记册里如实写清它的职责。内容检测器降低的是被攻陷的发生率,它约束不了持续时间,因为它的漏报是无声的。能约束持续时间的控制是行为型的——见发现智能体被攻陷。把一个召回率数字当成覆盖率来引用,正是一套技术栈最后只剩一层防御、却对此自我感觉良好的由来。
在比较任何一家厂商之前先做两件事:拿他们数据表上的数字,按你自己的基础发生率算一遍精确率;然后去问将来接收这些告警的团队,一天他们真正会读多少条。这两个数钉住误报预算,预算钉住阈值,而阈值决定了哪些检测器还有资格参赛——这与大多数评估实际的进行次序恰好相反。
相关:生产中的护栏——本文所度量的那套分层设计;质量回归检测——这门功夫里「冻结集」的那一半;以及校准——一个分数要先有意义,压在它上面的阈值才有意义。