security_testing_model

4.1K downloads 19 likes on ModelScope updated

Model card

引言

随着人工智能技术的飞速发展,生成式大模型在各个领域的应用日益广泛。然而,随之而来的信息安全问题也日益凸显。国家对AI生成式大模型的要求和出台的政策,旨在促进其健康发展与规范应用,同时确保其不会危害国家安全、公共利益以及公民权益。

背景

近年来,生成式大模型如GPT-4等在自然语言处理、图像识别等领域取得了显著进展。这些模型能够根据输入数据生成高质量的文本、图片等内容,为各行各业带来了巨大的创新潜力。然而,随着模型规模的扩大和应用范围的拓展,其潜在的安全风险也逐渐显现。

政策要求

为了应对这些挑战,国家出台了《生成式人工智能服务管理暂行办法》等一系列政策,旨在规范生成式大模型的研发和应用。这些政策强调了以下几个方面的重要性:

  1. 促进健康发展与规范应用:鼓励技术创新的同时,确保技术应用不会对社会造成负面影响。
  2. 维护国家安全和公共利益:通过制定相关法规和标准,防止技术被用于危害国家安全和社会公共利益。
  3. 保护公民权益:在技术应用过程中,必须尊重和保护公民的个人信息和隐私权。
  4. 提升透明度和可靠性:要求服务提供商提高服务的透明度,确保生成内容的准确性和可靠性。
  5. 强化监管:实施包容审慎和分类分级监管,对提供者进行有效的监督和管理。
  6. 鼓励创新与合作:支持技术在各行业的创新应用,并鼓励国内外的技术交流与合作。
  7. 数据安全与质量控制:要求使用合法来源的数据,并采取措施提高训练数据的质量。
  8. 法律责任明确:明确了提供者和使用者的法律责任,确保各方遵守法律法规。
  9. 未成年人保护:特别关注未成年人用户,防止他们过度依赖或沉迷于技术。
  10. 国际规则参与:鼓励中国参与生成式人工智能相关国际规则的制定,以促进全球范围内的技术标准统一。

消息

  • 【2025-11-10】:支持MCP服务

    • 调用地址:https://taian-mcp-safe.rencaidanao.com
    • 类型:StreamableHTTP
  • 🚀【2025-11-25】:第一版本模型宣布开源: 模型还存在很多的不足,注意甄别,效果远不如第二代模型!!体验链接为:数据安全检查模型:数据安全检查模型-1

  • 🚀【2025-11-25】:第二版本安全检查模型已完成,目前处于测试阶段,体验链接为---数据安全检查模型:数据安全检查模型-AI

    • 第二版本安全检查模型比第一版本有了更大的升级,对于高风险的指标能做到100%拦截。具体详细可见 第二代安全模型介绍部分。
    • 更安全、更准确

第一代模型介绍

指标维度

  • 指标总共有52个

模型微调

  • 定义

    NSFW(Not Safe for Work)文本分类【NSFW-text-detection】:其主要预期用途就是对不适合在工作场合阅读的文本内容进行分类识别。这类文本可能包含色情低俗、暴力血腥、极端冒犯性的话语、过度粗俗的表述等违背公序良俗、不适合在正式工作环境(比如办公室、商务会议等场所)出现的内容。同样可以通过专门为此目的进行了优化调整的模型或系统,来对这些不适宜的文本进行筛选、标记或处理,以确保在相应的应用场景中呈现出符合规范和适宜大众阅读的文本内容。

  • 数据分布情况

    • small模型样本量:60872条【去重(4374条)】(多标签分类,1条可能包含多个标签)
    • base模型样本量:148181条【去重(34597条)】(多标签分类,1条可能包含多个标签)

![安全数据分布](fig/安全数据分布2.png)


快速使用

  • 下载(前往页面进行申请 模型申请链接 ,通过后即可下载模型)

    • 验证SDK token
    from modelscope.hub.api import HubApi
    api = HubApi()
    api.login({your_sdk_token})
    
    • 模型下载
    from modelscope import snapshot_download
    model_dir = snapshot_download('xiaolv/security_testing_model')
    
    • 指定类型下载(只需要加载.pth的文件即可,再对原始模型的参数进行替换)
    from modelscope import AutoModel,AutoTokenizer
    import torch.nn as nn
    # 1. 定义原始模型
    class MultiLabelClassifier(nn.Module):
        def __init__(self):
            super(MultiLabelClassifier, self).__init__()
            model_base = "AI-ModelScope/xlm-roberta-base"
            n_classes = 52
            self.bert = AutoModel.from_pretrained(model_base)
            self.drop = nn.Dropout(p=0.3)
            self.out = nn.Linear(self.bert.config.hidden_size, n_classes)
        def forward(self, input_ids, attention_mask):
            _, pooled_output = self.bert(
                input_ids=input_ids,
                attention_mask=attention_mask,
                return_dict=False
            )
            output = self.drop(pooled_output)
            return self.out(output)
    
    # 2. 加载微调参数
    from modelscope import snapshot_download
    import os
    import torch
    best_model_name = ""    ## 选择哪个模型,.pth
    model =MultiLabelClassifier()
    ## 替换掉参数
    model_dir = snapshot_download('xiaolv/security_testing_model',allow_file_pattern =["*.pth"],cache_dir="./")
    model_dir = model_dir
    checkpoint_model = os.path.join(model_dir,best_model_name)
    print(f"checkpoint_model:{checkpoint_model}")
    # 用cpu加载,如果在GPU加载的话,去掉:map_location=torch.device('cpu')
    checkpoint = torch.load(checkpoint_model,map_location=torch.device('cpu'))
    model.load_state_dict(checkpoint['model_state_dict'])
    

gradio页面代码示例

# !/usr/bin/env python
# -*-coding:utf-8 -*-

import os
import numpy as np
from modelscope import AutoModel,AutoTokenizer
import torch
import torch.nn as nn
import gradio as gr
import logging
import pandas as pd
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=logging.WARNING)
os.environ['CUDA_VISIBLE_DEVICES'] = ''
from modelscope import snapshot_download
from modelscope.hub.api import HubApi
api = HubApi()
app_key = os.getenv('appKey')
api.login(app_key)
best_model_name = str(os.getenv('best_model'))

# os.system("pip install --upgrade gradio fastapi pydantic")
# os.system("pip install urllib3==1.26.15")
# 2. 定义模型
class MultiLabelClassifier(nn.Module):
    def __init__(self):
        super(MultiLabelClassifier, self).__init__()
        model_base = "AI-ModelScope/xlm-roberta-base"
        n_classes = 52
        self.bert = AutoModel.from_pretrained(model_base)
        self.drop = nn.Dropout(p=0.3)
        self.out = nn.Linear(self.bert.config.hidden_size, n_classes)
    def forward(self, input_ids, attention_mask):
        _, pooled_output = self.bert(
            input_ids=input_ids,
            attention_mask=attention_mask,
            return_dict=False
        )
        output = self.drop(pooled_output)
        return self.out(output)

class Cheak_data_safe():
    def __init__(self):
        self.safety_indicators_list = [
            "不安全1","不安全2", "不安全3",
            "不安全4", "不安全5", "不安全6", "不安全7", "不安全8",
            "不安全9", "不安全10", "不安全11", "不安全12", "不安全13",
            "不安全14", "不安全15", "不安全16", "不安全17", "不安全18",
            "不安全19", "不安全20", "不安全21", "不安全22", "不安全23",
            "不安全24", "不安全25", "不安全26", "不安全27", "不安全28",
            "不安全29", "不安全30", "不安全31", "不安全32", "不安全33",
            "不安全34", "不安全35", "不安全36", "不安全37", "不安全38",
            "不安全39", "不安全40", "不安全41", "不安全42", "不安全43",
            "不安全44", "不安全45", "不安全46", "不安全47", "不安全48",
            "不安全49", "不安全50", "不安全51",
            "安全"
        ]
        self.max_length = 512
        model_base = "AI-ModelScope/xlm-roberta-base"
        ## 加载模型
        # 初始化BERT tokenizer
        ## 1. 加载原始模型
        self.tokenizer = AutoTokenizer.from_pretrained(model_base)
        self.model =MultiLabelClassifier()

        ## 替换掉参数
        model_dir = snapshot_download('xiaolv/security_testing_model',allow_file_pattern =["*.pth"],cache_dir="./")
        self.model_dir = model_dir
        checkpoint_model = os.path.join(model_dir,best_model_name)
        print(f"checkpoint_model:{checkpoint_model}")
        self.pth_files_sys = [checkpoint_model]
        checkpoint = torch.load(checkpoint_model,map_location=torch.device('cpu'))
        self.model.load_state_dict(checkpoint['model_state_dict'])

        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.device = "cpu"

        self.pth_files = self.list_pth_files()
        print(self.pth_files)


    def change_model_ft(self,path_file):
        ## 替换掉参数
        checkpoint = torch.load(path_file,map_location=torch.device('cpu'))
        self.model.load_state_dict(checkpoint['model_state_dict'])
        logging.warning(f"修改模型为:{path_file}")

    def list_pth_files(self):
        pth_files = []
        for root, dirs, files in os.walk(self.model_dir):
            for file in files:
                if file.endswith(".pth") and "best" not in str(file):
                    pth_files.append(os.path.join(root, file))

        pth_files_end = self.pth_files_sys + pth_files
        return list(dict.fromkeys(pth_files_end))


    def chat(self,sample_text, max_length,threshold_slider):
        if isinstance(sample_text,str):
            sample_text = [sample_text]

        # 预测示例
        self.model.eval()
        encoding = self.tokenizer.batch_encode_plus(
            sample_text,
            add_special_tokens=True,
            max_length=max_length,
            return_token_type_ids=False,
            padding='max_length',
            return_attention_mask=True,
            return_tensors='pt',
            truncation=True
        )
        input_ids = encoding['input_ids'].to(self.device)
        attention_mask = encoding['attention_mask'].to(self.device)

        with torch.no_grad():
            output = self.model(input_ids=input_ids, attention_mask=attention_mask)
            predictions = (torch.sigmoid(output) > threshold_slider).float()
            logging.warning(f"Predictions for test sample: {predictions.cpu().numpy()}")
            probability = torch.sigmoid(output)
            resu = self.find_candi(predictions.cpu().numpy(),probability)
            resu_df = pd.DataFrame(resu)
            # 将列标题转换为字符串类型
            resu_df.columns = resu_df.columns.astype(str)
            print(f"sample_text:{sample_text}")
            print(f"resu:{resu}")
            print(f"==" * 100)
        return resu,resu_df

    def find_candi(self,arr,probability):
        arr = np.array(arr)
        indices = np.where(arr == 1)
        unique_values, counts = np.unique(indices[0], return_counts=True)
        safety_indicators_name = [self.safety_indicators_list[ids_i] for ids_i in indices[1]]
        probability_name  = probability[np.where(arr == 1)].numpy().tolist()
        probability_name  = [str(round(pmn_i,4)) for pmn_i in probability_name]
        result_split = []
        statr_i = 0
        counts_list = list(counts)
        for qie_i in counts_list:
            result_split.append([safety_indicators_name[statr_i:statr_i+qie_i],probability_name[statr_i:statr_i+qie_i]])
            statr_i = statr_i+qie_i

        return result_split





if __name__=="__main__":
    safe_model = Cheak_data_safe()
    with gr.Blocks(title='小吕数据安全检查模型') as demo:
        with gr.Tab("小吕数据安全检查模型"):
            gr.HTML("""<h1 align="center">数据安全检查模型——小吕</h1>""")
            with gr.Accordion("🔥模型相关介绍", open=False):
                gr.HTML(
                    """
                        <p> 1.模型链接介绍:<a href="https://modelscope.cn/models/xiaolv/security_testing_model/summary">🔥大模型安全测试基座模型</a></p>
                    """)

                gr.Markdown(
                    """
---
NSFW(Not Safe for Work)文本分类【NSFW-text-detection】:其主要预期用途就是对不适合在工作场合阅读的文本内容进行分类识别。这类文本可能包含色情低俗、暴力血腥、极端冒犯性的话语、过度粗俗的表述等违背公序良俗、不适合在正式工作环境(比如办公室、商务会议等场所)出现的内容。同样可以通过专门为此目的进行了优化调整的模型或系统,来对这些不适宜的文本进行筛选、标记或处理,以确保在相应的应用场景中呈现出符合规范和适宜大众阅读的文本内容。

### 体验链接
 - 数据安全检查模型:[数据安全检查模型-1](https://modelscope.cn/studios/xiaolv/security_testing_model/summary)
 - 数据安全检查模型:[数据安全检查模型-AI](https://www.modelscope.cn/studios/xiaolv/security_testing_model_ms/summary)


### 2025-11-10:支持MCP服务
- 调用地址:https://taian-mcp-safe.rencaidanao.com
- 类型:StreamableHTTP


### 数据分布情况

- **small**模型样本量:130940条(多标签分类,1条可能包含多个标签)
- **large**模型样本量:持续生成中

![安全数据分布](安全数据分布2.png)
### 模型微调
- 基座模型
  使用xlm-roberta-base模型作为基座模型进行微淘
  - 达摩(modelscope[modelscope](https://modelscope.cn/)):[xlm-roberta-base]([xlm-roberta-base · 模型库 (modelscope.cn)](https://modelscope.cn/models/AI-ModelScope/xlm-roberta-base))
  - HF([huggingface](https://huggingface.co)):[xlm-roberta-base]([xlm-roberta-base · Hugging Face](https://huggingface.co/FacebookAI/xlm-roberta-base))
- 数据来源
  微调的数据基于以下开源数据收集而来
  - hhhwssjmy-text-safety:[文本安全检测 · 数据集 (modelscope.cn)](https://modelscope.cn/datasets/hhhwssjmy/text-safety)
  - PKU-Alignment-PKU-SafeRLHF:[PKU-SafeRLHF](https://huggingface.co/datasets/PKU-Alignment/PKU-SafeRLHF)
- 模型性能
  - `Val Accuracy(全对): 0.5486`
  - `Val Accuracy2(1 的 位置 至少对1个): 0.8972`
  
###**注意** 
在实际应用程序中实施此模型时,必须负责任且合乎道德地使用此模型,并遵守内容准则和适用法规,尤其是那些涉及潜在敏感内容的应用程序。
---
"""
                )

            with gr.Row():
                with gr.Column():
                    input_text = gr.Textbox(label="输入文本框")
                    submit_button = gr.Button("提交")

                    max_length_slider = gr.Slider(minimum=1, maximum=512, value=512, label="最大长度")
                    # 新增的阈值滑块组件
                    threshold_slider = gr.Slider(minimum=0.1, maximum=1, value=0.5, step=0.05, label="阈值")

                    gr.HTML("""  <hr> """)
                    with gr.Accordion("非专业人员勿点",open=False):
                        file_dropdown = gr.Dropdown(choices=safe_model.pth_files, label="下拉框:选择不同模型")
                        submit_button2 = gr.Button("更换模型")
                # 右侧输出部分
                with gr.Column():
                    output_text = gr.Textbox(label="输出数据返回文本框")
                    output_text_df = gr.Dataframe(label="输出数据返回文本框")

            submit_button.click(fn=safe_model.chat, inputs=[input_text, max_length_slider,threshold_slider], outputs=[output_text,output_text_df])
            submit_button2.click(fn=safe_model.change_model_ft, inputs=[file_dropdown])

            # 添加示例
            gr.HTML("""  <hr> """)
            gr.HTML(
                """
                    <p>数据实例来源开源数据集:thu-coai-Safety-Prompts:<a href="https://huggingface.co/datasets/thu-coai/Safety-Prompts">thu-coai-Safety-Prompts</a></p>
                """)

            with gr.Accordion("示例", open=False):
                examples = [
                    ["不便展示,自己想吧", 512, 0.5],
                    ["不便展示,自己想吧?", 512, 0.5]
                ]
                gr.Examples(examples, [input_text, max_length_slider, threshold_slider])

    demo.queue(api_open=False).launch(show_error=True,share = False,show_api=False)

注意

在实际应用程序中实施此模型时,必须负责任且合乎道德地使用此模型,并遵守内容准则和适用法规,尤其是那些涉及潜在敏感内容的应用程序。

体验链接


第二代模型相关介绍(2025-11-25更新)

  • 第二代指标总共有升级到个69个

  • 接口返回格式如下:

    • 返回两个json字典的检测,可以根据具体的情况,选择合适的策略进行判断。

    • 第一个json的字段判断较为严格,对于要求不高的情况下,第一个字典可以适当采用。

    • 第二个json字段由于涉及不安全内容较多,所以不显示具体的指标,而是只输出对应的不安全指标编号。

      • {
          "安全性": "**",
          "风险等级": "**",
          "涉及风险指标": [
            "**"
          ],
          "检测技巧": [
            "***"
          ],
          "置信度": [
            "0.5545",
            "0.5545"
          ],
          "理由": {
            "code": "200",
            "msg": "操作成功",
            "messageId": "**",
            "data": {
              "promptResult": [
                {
                  "label": "**",
                  "confidence": 0.5545,
                  "riskWords": [
                    "**"
                  ],
                  "subResult": [
                    {
                      "label": "***",
                      "confidence": 0.5545,
                      "riskWords": [
                        "小傻瓜"
                      ]
                    }
                  ]
                }
              ],
              "promptCategory": "违规",
              "contentCategory": "未识别"
            }
          }
        }
        
        {
          "安全性": "安全/不安全",
          "风险指标": ["指标编号"]
        }
        
  • 体验链接:数据安全检查模型:数据安全检查模型-AI

联系我们

如果你想给我们的研发团队和产品团队留言,请通过邮件(2240560729@qq.com)联系我们。