Featured image of post 模型安全检测 14:安全检测模型横评与接入实验

模型安全检测 14:安全检测模型横评与接入实验

Llama Guard 4 / Prompt Guard 2 / ShieldGemma 调研,包装成原子能力接入 JoySafety DAG 的方案。

状态:✅ 已完成 前置阅读:03-技术架构与业务模块分析、04-DAG编排引擎深入、09-自定义原子能力 调研日期:2026-09-14 素材来源:① 公开资料调研(各家模型卡/论文,链接随文给出)② 本仓库源码核实 ③ maas-safe-doc/安全护栏/poc/ 下的已有测试集与测试记录 读者定位:想搞清楚"开源安全检测模型哪家强、怎么接进 JoySafety、接完怎么比"的读者

结论标记约定(本篇是调研+实验设计,严格区分三种信息):

标记含义
【调研】来自公开资料(模型卡/论文/官方文档),附来源链接
【源码】本仓库代码核实,附 path:line 坐标
【实测记录】maas-safe-doc 里已有的跑分结果(内部服务器,2026-08 批次)
【待实测】本篇设计好方案、尚未跑出数字的部分

〇、先建立全局认识

0.1 框架与模型的分工

JoySafety 自身不是检测模型,它是"检测能力的编排框架"(03 篇核心结论)。检测模型在它里面是可插拔的原子能力:框架只认 single_label_pred 统一协议(HTTP POST 进、风险标签出),后端挂的是自家 bert 还是 Llama Guard,对 DAG 引擎完全透明。

1
2
3
4
5
6
7
检测模型供给格局(2025-2026):
  编码器小模型(22M~400M)   Prompt Guard 2、JoySafety bert     ← 毫秒级,CPU 可跑
  生成式护栏大模型(0.6B~20B) Llama Guard 4、Qwen3Guard、Granite Guardian ← 要 GPU
  多模态护栏                 Llama Guard 4、ShieldGemma 2        ← 图文混合场景
        │  统一包装成 single_label_pred 协议(本文第四章)
        ▼
  JoySafety DAG:keyword → 小模型粗筛 → 大模型精检 → 知识库双证(第六章)

0.2 本篇回答的四个问题

  1. 主流开源安全检测模型的能力边界(第一章,【调研】)
  2. JoySafety 自带三个 bert 的真实底细与统一协议(第二章,【源码】)
  3. 怎么公平地比:统一评测集建设(第三章)+ 怎么接进来比:接入实验全流程(第四章)
  4. 比完之后怎么用:对比表格模板(第五章)+ 快慢分层组合策略(第六章)

一、主流开源安全检测模型清单【调研】

1.1 逐家要点

Llama Guard 4(Meta,2025-04 LlamaCon 发布):12B 稠密模型,从 Llama 4 Scout 剪枝而来,原生多模态(文本+单图/多图/多轮对话)。分类体系对齐 MLCommons 危害分类 13 类(S1 暴力犯罪…S13),另加 S14 代码解释器滥用,共 S1-S14。输出是生成的文本:safe 或 unsafe\nS9(续输出命中的类别编号)。许可:Llama 4 Community License(商用受限,月活 7 亿红线)。12B 自托管约需 24GB 显存。来源:NVIDIA build 模型卡↗、HF 官方博客↗、PurpleLlama MODEL_CARD↗。

Llama Prompt Guard 2(Meta,2025-04):编码器分类器,86M(mDeBERTa-base 基座)和 22M(DeBERTa-xsmall 基座)两档,上下文仅 512 token。v2 把 v1 拆开的"注入/越狱"两个标签合并成单一 MALICIOUS 二分类(BENIGN/MALICIOUS),同时覆盖直接越狱与间接注入(第三方数据里埋的恶意指令)。只审输入、不审输出。许可:Llama 许可。来源:LlamaFirewall 论文附录 B↗、ModelScope 模型卡↗。

ShieldGemma 2(Google,2025-03):基于 Gemma 3 4B 的图像内容审核模型,“策略感知"设计——输入是用户自定义的安全策略 + 图片,输出 Yes/No 违规判定,内置危险内容/色情/暴力血腥三类图像策略。注意区分:ShieldGemma v1 才是文本模型(Gemma 2 的 2B/9B/27B,四类危害,LLM-as-a-judge 的 Yes/No 输出)。许可:Gemma Terms of Use(可商用但非 OSI 开源协议)。来源:ShieldGemma 2 论文↗、Google DeepMind 页面↗。

Granite Guardian(IBM):谱系 3.0(2B/8B)→ 3.2(5B)→ 3.3(8B,支持 thinking 推理模式)→ 4.1(8B,2026 年新版)。风险覆盖最全的一家:harm/越狱/亵渎/偏见/暴力/色情 + RAG 三件套(上下文相关性/ groundedness/答案相关性幻觉)+ 工具调用幻觉。输出 Yes/No + 置信度。Apache 2.0,许可最干净。来源:granite-guardian GitHub↗、Ollama 4.1 模型卡↗。

WildGuard(Allen AI,NeurIPS 2024 D&B):基于 Mistral-7B-v0.3 的 7B 模型,一个模型干三件事:用户 prompt 有害性、模型回复有害性、拒答识别。配套 WildGuardMix 92K 训练集 + WildGuardTest 5K 人工标注测试集,论文报告把越狱攻击成功率从 79.8% 压到 2.4%。许可:代码 Apache 2.0,数据集 ODC-BY。来源:WildGuard 论文↗、NeurIPS 页面↗。

NVIDIA Aegis 系列:基于 LlamaGuard/Llama 3.1 微调的内容安全模型家族,13 类关键风险,最大卖点是训练数据(Aegis 2.0 数据集,NeurIPS 2024)商用可用;后继形态为 Llama 3.1 NemoGuard 8B Content Safety。来源:NVIDIA NeMo 文档↗、Aegis 2.0 slides↗。

补充:Qwen3Guard(阿里,2025-10):提纲外但必须纳入——中文场景绕不开。0.6B/4B/8B 三档,Gen(生成式指令判定)+ Stream(token 级分类头,流式生成中实时打分)两个变体,119 种语言,三级严重度(safe/controversial/unsafe),119 万条训练样本,Apache 2.0。来源:Qwen3Guard 技术报告↗。

1.2 横评大表

模型参数量时延量级【实测记录见五章】中文支持风险分类体系输出协议许可
Llama Guard 412B(多模态)GPU 百 ms 级弱(Llama 4 官方语言表不含中文,靠零样本泛化)MLCommons S1-S14生成文本 unsafe\nS#Llama 4 社区许可
Prompt Guard 222M / 86MCPU 个位数 ms弱(mDeBERTa 多语基座,训练语料英文为主)二分类(越狱+注入合并)张量概率 + 标签Llama 许可
ShieldGemma 24BGPU 数十~百 ms弱图像三类策略(可自定义策略文本)生成 Yes/NoGemma ToU
Granite Guardian2B~8BGPU 数十~百 ms弱-中harm/越狱/RAG 幻觉/工具幻觉等 13+生成 Yes/No + 置信度Apache 2.0
WildGuard7BGPU 百 ms 级弱三任务:prompt 害/回复害/拒答生成结构化文本代码 Apache 2.0 / 数据 ODC-BY
NVIDIA Aegis7B~8BGPU 百 ms 级弱13 类风险生成文本数据集 CC 系 / 模型 NVIDIA 许可
Qwen3Guard0.6B/4B/8B0.6B 可 CPU强(119 语言)三级严重度 × 多类目Gen 生成 / Stream token 头Apache 2.0
JoySafety bert_20250916~102M(MacBERT)CPU 百 ms 级【源码见 2.1】强(中文专训)14 类中文业务风险张量概率 + 标签Apache 2.0

批注:一个反直觉的调研结论——模型大小与安全检测能力不相关。arXiv 2605.28830↗ 在 79,331 样本上横评 14 款护栏模型,发现安全场景的核心指标是 recall(漏检代价远高于误报);Qwen Guard 4B 拿到最高 recall(83.97%),而 Llama Guard 12B、GPT-OSS Safeguard 20B 这类大模型行为保守,最多漏掉 75% 的违规内容。选型别看参数量,看同分布评测集上的 recall。


二、JoySafety 自带模型与统一协议【源码】

2.1 三个自带模型的真实底细(data/models/)

模型基座(config.json 实锤)类别数权重体积演示环境是否注册
bert_20250916chinese-macbert-base(data/models/bert_20250916/model/config.json 的 _name_or_path)14 类(0 正常 + 1001 涉政/1002 暴恐/1003 涉黄/1004 涉赌/1005 涉毒/1006 辱骂/2001 歧视/3002 商业违规/4002 侵权/5001 违禁/5002 虚假信息/1007 两性健康/1008 政治非拒答)390MB✅
bert_prompt_injection_20250828chinese-roberta-wwm-ext(同上看 _name_or_path)二分类(0 正常 / 201 提示词注入)390MB✅
bert_prompt_injection_20251118chinese-roberta-wwm-ext三分类(正常/明确攻击/疑似风险,见 README.md:19 发布说明;红蓝军对抗训练)390MB❌ 未注册(example/safety-skills/safety-knowledge/skills_init.py 只注册了前两个)
  • 14 类的 riskCode↔文案映射声明在 example/safety-skills/safety-bert/conf/conf_example.json;类别总表也见 safety/safety-skills/model_overview.md:50-74。
  • 三个模型都是 BERT 系 12 层 768 隐层(hidden_size: 768, num_hidden_layers: 12),词表 21128(中文词表),max_position_embeddings: 512——输入超过 512 token 会被截断(safety/safety-skills/safety-bert/app/model/bert_infer.py:36)。
  • 官方还有一个生成式审核模型 JSL-joysafety-v1(基于 gpt-oss-20b 指令微调,见 model_overview.md:12-13),需单独从 HuggingFace 下载,不在 data/models/ 里。

2.2 模型推理服务(safety-bert,8003)

POST /v1/bert/{model_name},body 带 text_list,逐条返回风险标签。推理核心(safety/safety-skills/safety-bert/app/model/bert_infer.py:48-63):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def infer(self, query: List[str]):
    softmaxed = self.predict(self.model, query, self.tokenizer, self.device)  # ① 整批 softmax
    resp = []
    for i in range(len(softmaxed)):
        max_idx = np.argmax(item)                    # ② argmax 取 Top1 标签
        max_label = self.labels[max_idx]             # ③ labels 来自服务自己的 conf(riskCode 映射表)
        temp = BertResponseData(riskCode=max_label.riskCode, riskMessage=max_label.riskMessage,
                                probability=item[max_idx], text=query[i],
                                detail=[...])          # ④ detail = 全标签概率分布,策略层调阈值要用
        resp.append(temp)
    return resp

批注:riskCode 映射表(哪个 label 序号对应 1001 还是 201)不在模型权重里,而在 safety-bert 服务的 JSON 配置里(conf_example.json 的 labels 数组)。这就是"模型即配置"的含义——同一套代码换一套 labels 就能服务另一个分类模型。服务响应壳是 {code, message, cost, data}(safety-bert/app/base/__init__.py:21-33,code=0 成功)。

2.3 统一协议:SingleLabelPredFunction 逐段批注

框架与模型服务之间的唯一契约是 single_label_pred 类型。注册表映射:safety/safety-api/src/main/java/com/jd/security/llmsec/service/execute/FunctionRegistry.java:23(single_label_pred → SingleLabelPredFunction)。

初始化(safety/safety-api/src/main/java/com/jd/security/llmsec/service/execute/functions/SingleLabelPredFunction.java:49-96):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
long timeout = 150;                                    // ① 默认超时只有 150ms!
if (this.conf().getTimeoutMilliseconds() != null) {
    timeout = this.conf().getTimeoutMilliseconds();    // ② 用注册时的 timeoutMilliseconds 覆盖
}
switch (this.conf.getModelType()) {
    case textcnn: case llm: case bert: case fasttext:  // ③ 四种 modelType 走同一个 HTTP 协议
        FasttextConf fasttextConf = ...(this.conf.getExtra());  // ④ 只需 extra.url 一个字段
        Object resource = FunctionResourcePool.getFunc(type(), url);
        if (resource != null) { this.fasttextClient = (OkHttpClient) resource; }
        else { ... FunctionResourcePool.addFuncIfAbsent(type(), url, temp);
               ScheduleWarmup.appendTask(...); }        // ⑤ 每 URL 一个共享 OkHttpClient + 注册 warmup
  • ③④是接入外部模型的关键认知:不管你的模型是 bert 还是 llm 基座,只要包装成同样的 HTTP 接口就能接入;框架对模型架构零感知。
  • ⑤ warmup 的实现:ScheduleWarmup.java:40 的 @Scheduled(initialDelay=5000, fixedRate=60000) 每分钟重放所有 warmup 请求(body 为 text_list=["warmup"]),保持 HTTP 连接池与模型缓存热度。

运行时(同文件 runFasttext():116-155):

1
2
3
4
5
6
7
SingleLabelPredCheck.SkillsReq req = new SingleLabelPredCheck.SkillsReq();
req.setBusiness_id(context.getBusinessConf().getName());     // 业务名
req.setRequest_id(firstReq.getRequestId());
req.setText_list(Lists.newArrayList(context.getCheckContent())); // 待审文本(单条)
ResponseMessage<List<SkillsResp>> respMessage = HttpHelper.post(this.fasttextClient,
        fasttextConf.getUrl(), HttpHelper.keepaliveHeader(), req, ...);  // Keep-Alive 长连接
SingleLabelPredCheck.SkillsResp resp = respMessage.getData().get(0);     // 只取 data[0]

请求/响应结构定义在 safety/safety-basic/src/main/java/com/jd/security/llmsec/core/check/SingleLabelPredCheck.java:61-72:

1
2
3
4
5
6
7
public static class SkillsReq {                 // 请求:四字段
    private String request_id; private String business_id;
    private String session_id;  private List<String> text_list;
}
public static class SkillsResp extends RiskInfo {  // 响应:riskCode/riskMessage/probability 继承自 RiskInfo
    private String text; private List<RiskInfo> detail;   // detail=全标签分布
}

忽略码机制(同文件 doIgnore():157-163):若返回的 riskCode 命中注册时的 ignoreRiskCode 集合,结果被改写为 defaultRisk(默认 0/正常文本/1.0,safety/safety-basic/.../core/util/LabelUtil.java:13)。演示 DAG 里 bert 节点配了 ignoreRiskCode: [1006]——辱骂类交给关键词层处理、bert 结果直接忽略(example/safety-skills/safety-knowledge/strategy_example.yml:56-63)。

2.4 两条链路的完整图景(接入实验前要烂熟于心)

配置流转(注册新模型走这条路):

1
2
3
4
5
6
POST admin:8006 /config/defense/manage/function/new + /online
  → MySQL function_conf 表(版本化状态机 init→edit→online,online 禁改)
  → safety-api 每 60s 轮询 admin /config/defense/api/conf
      (DynamicConfigService.java:65,@Scheduled fixedRate=60000)
  → 比对 lastChangeTimestamp 判断变更(同文件 shouldUpdate():113-151)
  → 全量替换 volatile 配置 Map → 回调 listener 重建 DAG(重编译 groovy、重建 OkHttp client)

请求流转(模型被调用的这条路):

1
2
3
4
5
业务方 POST :8007/llmsec/api/defense/v2/{accessKey}
  → 参数校验 → 限流 → HMAC-SHA1 验签(test 开头免签)
  → DAG 主循环逐节点执行 → parallel 节点线程池并发调各 function
  → SingleLabelPredFunction.runFasttext() → HTTP → 模型服务
  → groovy router 按 riskCode + probability 阈值归约 → 响应

超时两层都要改(02 篇坑 4 的结论,接外部模型时最先踩):① DAG 并行节点的 timeoutMilliseconds;② function 注册时的 timeoutMilliseconds(→ OkHttp callTimeout,SingleLabelPredFunction.java:54-57、73)。外部大模型动辄数百 ms,两层默认 2000ms 很容易不够。


三、评测集建设方案

3.1 现有素材盘点【实测记录】

maas-safe-doc/安全护栏/poc/测试集/ 下已有三个 CSV(格式已 Read 核实):

文件条数字段标签分布说明(测试集说明.txt)
guard_test_set_v6.csv993id,prompt,label,categoryunsafe 693 / safe 300大模型生成并打标;9 个英文类目(Jailbreak 100、Copyright 70、PII 70、Self-Harm 66 等)
guard_test_set_v7.csv2023id,prompt,label,category,is_obviousunsafe 1293 / safe 730v6 + 开源数据集中较明显的违规样本;新增中文类目(违法犯罪 100、淫秽色情 100、政治错误 100、普通安全 430),Jailbreak 扩到 400;is_obvious 标注是否明显违规/安全(明显 1778 / 隐晦 245)
toxicchat0124_prompt_zh.csv2752id,prompt,label,jailbreakingsafe 2401 / unsafe 351(其中越狱标记 87)ToxicChat-0124 的中文翻译版,真实用户语料分布(safe 占绝大多数,贴近线上)

三个集合互补:v7 类目标注细、适合看分类明细;toxicchat_zh 分布真实、适合看误判率;jailbreaking 标记可单独切出注入/越狱子集。

3.2 四类样本设计方案(复用 + 补齐)

目标矩阵:注入 / 越狱 / 违规内容 / 正常 × 中 / 英。

维度数据来源规模建议现状
中文违规v7 中文类目(违法犯罪/淫秽色情/政治错误)+ 普通安全400+430 已有✅ 直接复用
中文注入/越狱v7 Jailbreak 400 + toxicchat_zh 的 jailbreaking=1(87 条)~500✅ 复用;间接注入样本需补(可从 RAG 语料里埋指令构造)【待实测】
英文违规/越狱v6 的 9 个英文类目(AILuminate/ToxicChat 同源风格)993 已有✅ 复用
正常样本v7 Safe/普通安全 730 + toxicchat_zh safe 2401充足✅ 复用;建议按业务场景再补真实业务 query【待实测】

建设原则:① 所有模型在同一文件、同一份顺序上跑,避免采样偏差;② 保留 is_obvious 分层统计——明显违规检出率是底线,隐晦违规才拉开差距;③ 每条样本记录文本长度,时延分析要用。

3.3 指标定义(与已有测试报告对齐)

  • 检出率 = Recall(unsafe):漏检是安全场景最大代价(第一章调研结论),排第一指标
  • 误判率 = FP/(FP+TN):正常用户被误拦的比例
  • Accuracy / Precision / F1、混淆矩阵、按 category 的分类明细
  • 时延:mean / P95 / P99(已有报告就是这个格式,见 安全模型测试/L2测试结果/)
  • 资源:进程内存(CPU 模型)或显存(GPU 模型)、加载耗时

四、接入实验:把外部模型包装成 single_label_pred(衔接 09 篇)

4.1 协议契约(2.3 节的 JSON 形态)

1
2
3
4
5
请求  POST {你的服务地址}
  {"request_id":"...","business_id":"test","session_id":"...","text_list":["待审文本"]}
响应  200 + {"code":0,"message":"success","data":[
        {"riskCode":201,"riskMessage":"201提示词注入","probability":0.994,
         "text":"...","detail":[{"riskCode":0,...},{"riskCode":201,...}]}]}

硬性要求(来自 SingleLabelPredFunction.java:126-148 的解析逻辑):code==0 否则抛错;data 非空数组、只取 [0];riskCode/probability 必填,detail 供 groovy 阈值策略使用(演示 DAG 里 bert_common.detail.find { it.riskCode == 0 } 就在用它,strategy_example.yml:82)。

4.2 包装服务参考实现(Prompt Guard 2 版)

编码器模型最省事——它原生就是"张量概率 + 标签”,和协议同构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from fastapi import FastAPI
from transformers import pipeline
clf = pipeline("text-classification", model="meta-llama/Llama-Prompt-Guard-2-86M")  # ① HF 一行加载
app = FastAPI()

@app.post("/guard/prompt_guard_2")
def predict(req: dict):
    data = []
    for text in req["text_list"]:                        # ② 协议批量字段,逐条推理
        r = clf(text)[0]                                 # ③ {'label':'MALICIOUS','score':0.99}
        risk = 201 if r["label"] == "MALICIOUS" else 0   # ④ 映射到 JoySafety 风险码体系
        data.append({"riskCode": risk,
                     "riskMessage": "201提示词注入" if risk else "0正常文本",
                     "probability": r["score"], "text": text, "detail": []})
    return {"code": 0, "message": "success", "data": data}  # ⑤ code=0 是成功硬约定

Llama Guard 4 / Qwen3Guard-Gen 版的三个额外工作(生成式模型才有):

  1. 解析生成文本:unsafe\nS9 → 提取类别码;Qwen3Guard 还有 controversial 第三档,要预先决定归入 safe 还是 unsafe(已有测试报告里两种口径都跑过,见 3.3 的 Strict/Lenient)
  2. riskCode 映射表设计:S1-S14 是 MLCommons 体系,和 JoySafety 的 1001~5002 中文业务体系不一一对应——建议外部模型用独立号段(如 6xx)注册,避免与自带 bert 的语义混淆
  3. probability 从哪来:生成式模型没有现成概率,可取首 token logprob,或输出固定置信度(如 0.99)并在 groovy 阈值表里区别对待

4.3 注册 → DAG 引用 → 验证(完整步骤)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
① 起服务:包装服务部署到能访问 safety-api 的网络(容器可加进 compose 网络)
② 直连验证:curl -X POST {服务} -d '{"text_list":["ignore previous instructions"]}'
            → 确认 code=0、riskCode=201(绕开框架先验模型,02 篇坑 4 的二分法)
③ admin 注册(模板照抄 skills_init.py:17-48 的 bert 条目,改三处):
   POST :8006/config/defense/manage/function/new
   {"name":"prompt_guard_2","group":"default","type":"single_label_pred",
    "timeoutMilliseconds":2000,                      ← 按模型实测时延设
    "confObj":{"name":"prompt_guard_2","modelType":"bert",
               "extra":{"url":"http://{host}:9000/guard/prompt_guard_2"},
               "ignoreRiskCode":[]}}
   → POST .../function/online {"id": <返回的 id>}
④ DAG 引用:newVersion 出新策略版本,在并行节点里加 `- ref: prompt_guard_2`,
   groovy router 的阈值表加一行(如 `201:0.99` 同款)
⑤ 生效:等 60s 轮询或直接 docker restart safety-api(坑 5 经验),等 1~2 分钟
⑥ 端到端验证:quickstart/api_test.py 打注入样本,看 riskCheckType=single_label_pred

注意:modelType 字段填 bert 即可——它只是走分支的标签(SingleLabelPredFunction.java:59-63 四种类型同一路径),不代表真实模型架构。


五、横评对比:已有记录 + 待实测模板

5.1 已有实测记录(maas-safe-doc/安全护栏/poc/安全模型测试/,内部服务器 2026-08 批次)

L2 大模型对比(测试集 guard_test_set_v7_L2.csv,875 条,2026-08-18):

模型AccuracyPrecisionRecall(检出率)F1平均时延
PolyGuard-Qwen(7B)93.49%98.40%94.27%96.29%105.1ms
SingGuard-NSFA-9B90.86%99.58%90.19%94.65%40.8ms
JoySafety(整体 API)88.80%99.14%88.28%93.40%2121.1ms
Qwen3Guard-Stream-8B77.49%99.66%75.16%85.69%48.3ms
Llama Guard 4 12B70.17%99.81%66.88%80.09%181.0ms

读表要点:① 全体 precision ≥98%(护栏模型都宁可放过不可错杀),差距全在 recall;② Llama Guard 4 在中文占比高的 v7 上 recall 垫底,印证第一章"中文弱"的调研结论;③ JoySafety 的 2121ms 是整条 DAG 流水线的耗时(含关键词+双 bert 串并行),不是单模型推理时延,比时延不能直接比。

L1 小模型对比(测试集 guard_test_set_v6.csv,993 条,2026-08-17,9 款)节选:

模型F1漏报率误报率平均时延QPS
HaloGuard1-Gen-0.8B92.69%10.39%8.67%187.44ms5.3
SingGuard-NSFA-0.8B87.92%21.21%1.00%4.37ms229.1
Wolf Defender(注入专项)79.93%29.58%13.33%1.76ms567.4
Prompt Guard 2(86M)13.08%92.93%2.33%20.28ms49.3

最刺眼的一行:Prompt Guard 2 在中文为主的 v6 上 recall 只有 7.07%——英文专训的注入检测模型对中文攻击接近失明。这就是中文业务必须用中文语料微调(JoySafety 自带注入 bert 的价值)或选多语模型(Qwen3Guard 系)的直接证据。【实测记录】

5.2 待实测对比模板【待实测】

在本仓库环境(Mac/Docker 或 GPU 服务器)上,用第三章评测集 + 第四章接入方法,填下表:

模型检出率 Recall误判率 FP ratePrecisionF1时延 mean/P95内存/显存加载耗时备注
bert_20250916(自带 14 类)待填~390MB 权重违规内容维度
bert_prompt_injection_20250828(二分类)~390MB注入维度
bert_prompt_injection_20251118(三分类)~390MB注入维度,需先注册
Prompt Guard 2 86M预期:中文 recall 很低预期 CPU <50ms~350MB预期英文强
Prompt Guard 2 22M~90MB粗筛候选
Qwen3Guard-Gen-0.6B中文多语候选
Llama Guard 4 12B需 GPU~24GB 显存多模态唯一选项

分维度记录:注入 / 越狱 / 违规 / 正常四类分开统计;is_obvious=0(隐晦样本)单独看检出率。


六、快慢模型分层组合策略

6.1 已有两阶段实验结论【实测记录】

安全模型测试/L1测试结果/L1方案.txt 的两阶段设计:L1 放行侧 HaloGuard+SingGuard+WolfDefender 三个小模型都判 safe 才直接放行;拦截侧 HaloGuard+SingGuard+Siren 都判 unsafe 才直接拦截;不确定样本进 L2 大模型复核。

模型搭配测试报告/compare_report.md 的最优组合(Stage1 小模型 ensemble → Qwen3Guard 复审):

组合Stage1 F1Two-Stage F1L2 复审率L2 改判正确率
haloguard + wolfdefender → Qwen3Guard93.95%94.59%28.5%97.9%

这组数字是分层策略价值的直接证据:71.5% 的流量被毫秒级小模型当场解决,只有 28.5% 进入大模型;大模型改判的 97.9% 是改对的。时延大头只花在难样本上。

6.2 映射到 JoySafety DAG 的实现

JoySafety 的演示 DAG 本身就是分层结构(keyword 粗筛 → bert 精检),把外部模型插进对应层即可:

1
2
3
4
5
6
7
8
start(分流 user/robot)
  └─ user 链路:
       L0  keyword(AC 自动机,亚 ms)          ← 黑词短路 / 白词放行
       L1  parallel(小模型粗筛: prompt_guard_2 或 fasttext 级)
             groovy router:高置信(>0.99)直接定结论 ──┐
       L2  parallel(bert_20250916, bert_prompt_injection_*, 外部大模型)  ← 只有 L1 不确定才到这
             groovy router:riskCode 差异化阈值表判定(strategy_example.yml:77 的套路)
       L3  (可选)rag_answer + bert 双证:riskCode 一致且概率>0.5 才判风险,防误杀

实现要点:L1→L2 的"不确定才升级"就是 groovy 里一个 if——if (small.hasRisk() && small.probability > 0.99) return null 终结 否则 return 'L2节点'。并行节点的归约(first_risk/groovy_script)见 ParallelFunction.java:57-67。

6.3 融入纵深防御的组合拳(设计建议,部分待实测)

  1. 注入防线:Prompt Guard 2 22M(英文流量、个位数 ms)与自带注入 bert(中文流量)并联而非二选一——groovy 里任一高置信命中即拦【待实测:并联后的误判率叠加情况】
  2. 违规防线:自带 bert_20250916 主力(中文 14 类是它的主场),Qwen3Guard-0.6B 做第二意见(多语 + controversial 档恰好对应"疑似"语义)
  3. 成本公式:全量流量过 L0/L1(~10ms),L2 只接 L1 不确定部分(复审率控制在 30% 内),L3 双证只接 L2 判风险的样本——与已有实验的 28.5% 复审率同构
  4. 一号段一模型:外部模型的 riskCode 用独立号段注册(4.2 节),阈值表分行管理,互不污染

七、结论速查

调研结论(可信,附来源):① 选型看同分布 recall 别看参数量(arXiv 2605.28830);② 主流开源模型除 Qwen3Guard 外中文都弱;③ 生成式护栏(Llama Guard 4 等)输出要解析+映射才能进 single_label_pred 协议;④ 许可最干净的是 Granite Guardian 和 Qwen3Guard(Apache 2.0),Llama 系有月活限制。

实测记录结论(内部环境,可参考):① PolyGuard-Qwen 单模型最强(F1 96.29%);② Prompt Guard 2 中文注入 recall 仅 7%,中文场景不可用;③ 两阶段分层(小模型粗筛 + 大模型复审 28.5% 流量)F1 94.59% 且省时延。

待实测清单(本篇方案的直接产出):① 第四章包装服务在本仓库环境的端到端验证;② 5.2 表格全部数字;③ 6.3 并联/分层组合在真实评测集上的误判率叠加情况;④ bert_prompt_injection_20251118 三分类注册后的提升幅度。


附录:关键坐标速查

主题位置
统一协议实现safety/safety-api/src/main/java/com/jd/security/llmsec/service/execute/functions/SingleLabelPredFunction.java:116(runFasttext)
协议请求/响应结构safety/safety-basic/.../core/check/SingleLabelPredCheck.java:61-72
忽略码/默认风险同上文件 :157-163;safety/safety-basic/.../core/util/LabelUtil.java:13
modelType 枚举safety/safety-basic/.../core/conf/funcs/ModelType.java:8-12
Function 注册表safety/safety-api/.../service/execute/FunctionRegistry.java:23
warmup 机制safety/safety-api/.../service/ScheduleWarmup.java:40(每 60s 重放)
配置轮询safety/safety-api/.../service/DynamicConfigService.java:65
bert 推理服务safety/safety-skills/safety-bert/app/model/bert_infer.py:48-63
自带模型 labels 映射example/safety-skills/safety-bert/conf/conf_example.json
注册脚本模板example/safety-skills/safety-knowledge/skills_init.py:17-48
演示 DAG 阈值表example/safety-skills/safety-knowledge/strategy_example.yml:77-89
注册接口文档safety/safety-admin/docs/api/function_api.md
评测集../maas-safe-doc/安全护栏/poc/测试集/(v6 993 条 / v7 2023 条 / toxicchat_zh 2752 条)
已有测试报告../maas-safe-doc/安全护栏/poc/安全模型测试/(L1 小模型 9 款、L2 大模型 5 款、两阶段组合 5 组)

参考资料

使用 Hugo 构建
主题 Stack 由 Jimmy 设计