一、前言
针对UGC内容安全审核,之前主流的解决方案是阿里云或腾讯云的安全审核产品这一套,但是这两个平台主要通过自定义词库进行违规词校验,人工维护成本较高、产品对上下文语义理解不足,且还需要通过人工进行二次审核,借用大语言模型能力恰好可以弥补这些问题,通过大幅度提高内容安全审核的准确性,可以极大减轻人工审核压力(甚至可以直接释放人力成本)。
业务场景问题:通过腾讯云/阿里云内容安全审核产品 + 大语言模型,提高UGC内容自动审核准确度(达到85%以上),从而减轻人工审核成本。
本篇的核心目标是:通过调用多个第三方平台提供的大语言模型API找出和业务场景设计的prompt匹配度(准确度)最高的模型!
业务整体架构如下:
二、术语
-
UGC内容:用户发布的内容,如练笔、评论、个性签名、昵称等;
-
安全审核产品:阿里云、腾讯云等安全审核产品,主要维护自定义违规词词库,并有一定的语义理解能力(但效果不佳且很难根据业务需求调整策略);
-
Prompt: 通过特定格式的文本输入引导大语言模型生成符合需求的输出;
-
通过样本:指经过大语言模型审核,且预期应该是[审核通过]的测试样本;
-
不通过样本:指经过大语言模型审核,且预期应该是[审核不通过]的测试样本;
三、大语言模型API调用示例
3.1 腾讯云hunyuan-turbos-latest模型
我们经过腾讯云DeepSeek R1、DeepSeek V3、混元T1模型、混元turbos模型等多轮测试(包括测试样本和不通过样本),其中混元turbos是准确率最高的,且样本测试结果比较稳定,响应速度约4秒/条。
- 不通过样本:总数:80,第1轮不通过69,准确率86.25%;第2轮不通过67,准确率83.75%
- 通过样本:总数50,第1轮通过41,准确率82%;第2轮通过41,准确率82%
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-hunyuan</artifactId>
<version>3.1.1085</version>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-lkeap</artifactId>
<version>3.1.1228</version>
</dependency>
static String SYSTEM_PROMPT = "# 角色 \n" +
"中国工信部认证AI内容审核专家,依据最新《生成式人工智能服务管理暂行办法》及《人工智能生成合成内容标识办法》进行三重审查:\n" +
"\n" +
"**审核维度**\n" +
"1. **合法性**(违反即驳回) \n" +
" - 危害国家安全(宪法/网络安全法禁止内容) \n" +
" - 宣扬恐怖/极端主义、民族仇恨、邪教迷信 \n" +
" - 传播色情(含变体)、暴力、赌博、谣言 \n" +
" - 篡改历史、侮辱英烈 \n" +
"\n" +
"2. **价值观**(违反即驳回) \n" +
" - 攻击社会主义制度 \n" +
" - 传播封建迷信/历史虚无主义 \n" +
" - 煽动地域/性别/职业对立 \n" +
" - 宣扬拜金主义、畸形审美、消极躺平 \n" +
"\n" +
"3. **未成年人保护**(违反即驳回) \n" +
" - 诱导自残/厌世/校园霸凌 \n" +
" - 美化早恋/同性恋(含耽美作品) \n" +
" - 无价值追星/游戏内容 \n" +
" - 逻辑混乱的无效文本 \n" +
"\n" +
"**输出格式** \n" +
"仅返回: [审核通过] 或 [审核不通过]和理由";
static String SECRET_ID = "你的API ID";
static String SECRET_KEY = "你的API KEY";
private static HunyuanClient hunyuanClient = null;
private static HunyuanClient getHunyuanClient() {
if (hunyuanClient != null) {
return hunyuanClient;
}
synchronized (HunyuanClient.class) {
if (hunyuanClient != null) {
return hunyuanClient;
}
Credential cred = new Credential(SECRET_ID, SECRET_KEY);
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("hunyuan.tencentcloudapi.com");
httpProfile.setConnTimeout(10);
httpProfile.setReadTimeout(60);
httpProfile.setWriteTimeout(60);
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
hunyuanClient = new HunyuanClient(cred, "", clientProfile);
}
return hunyuanClient;
}
public static String getTencentDeepSeekCheckResult (String content) {
try {
ChatCompletionsRequest req = new ChatCompletionsRequest();
req.setModel("hunyuan-turbos-latest");
Message[] messages = new Message[2];
Message message1 = new Message();
message1.setRole("user");
message1.setContent(SYSTEM_PROMPT);
messages[0] = message1;
Message message2 = new Message();
message2.setRole("user");
message2.setContent(content);
messages[1] = message2;
req.setMessages(messages);
// 返回的resp是一个ChatCompletionsResponse的实例,与请求对象对应
ChatCompletionsResponse resp = null;
resp = getHunyuanClient().ChatCompletions(req);
// 输出json格式的字符串回包
if (resp.isStream()) { // 流式响应
log.warn("内容修正异常不支持流式响应!");
} else { // 非流式响应
String requestId = resp.getRequestId();
Choice[] choices = resp.getChoices();
String result = null;
if (null != choices && choices.length > 0) {
Choice choice = choices[0];
String finishReason = choice.getFinishReason();
Message _message = choice.getMessage();
if (null != _message && "stop".equals(finishReason)) {
return result;
}
}
}
} catch (Exception e) {
log.error("程序异常", e);
}
return null;
}
public static void main(String[] args) {
String checkResult = getTencentDeepSeekCheckResult("滚蛋啊");
System.out.println("审核结果:" + checkResult);
}
3.2 腾讯云DeepSeek R1模型
DeepSeekR1测下来的结果和预期偏差较大,反而是效果最差的,而且因为要输出思维链整个请求耗时较长(大约20秒/一次请求),且每次请求结果不一致,另外价格也贵,相比豆包和混元模型来说显然不是一个很好的选择。
- 不通过样本测试结果(总数68条,测试2轮): 第1轮67.6%、第2轮69.1%,准确率不一致,各case审核结果部分不一致;
- 通过样本测试结果(总数50条,测试2轮): 第1轮94%、第2轮90%,准确率不一致,各case审核结果部分不一致;
static String SYSTEM_PROMPT = "# 角色 \n" +
"中国工信部认证AI内容审核专家,依据最新《生成式人工智能服务管理暂行办法》及《人工智能生成合成内容标识办法》进行三重审查:\n" +
"\n" +
"**审核维度**\n" +
"1. **合法性**(违反即驳回) \n" +
" - 危害国家安全(宪法/网络安全法禁止内容) \n" +
" - 宣扬恐怖/极端主义、民族仇恨、邪教迷信 \n" +
" - 传播色情(含变体)、暴力、赌博、谣言 \n" +
" - 篡改历史、侮辱英烈 \n" +
"\n" +
"2. **价值观**(违反即驳回) \n" +
" - 攻击社会主义制度 \n" +
" - 传播封建迷信/历史虚无主义 \n" +
" - 煽动地域/性别/职业对立 \n" +
" - 宣扬拜金主义、畸形审美、消极躺平 \n" +
"\n" +
"3. **未成年人保护**(违反即驳回) \n" +
" - 诱导自残/厌世/校园霸凌 \n" +
" - 美化早恋/同性恋(含耽美作品) \n" +
" - 无价值追星/游戏内容 \n" +
" - 逻辑混乱的无效文本 \n" +
"\n" +
"**输出格式** \n" +
"仅返回: [审核通过] 或 [审核不通过]和理由";
static String SECRET_ID = "你的API ID";
static String SECRET_KEY = "你的API KEY";
public static String getTencentDeepSeekCheckResult (String content) {
try{
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
// 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性
// 以下代码示例仅供参考,建议采用更安全的方式来使用密钥
// 请参见:https://cloud.tencent.com/document/product/1278/85305
// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
Credential cred = new Credential(SECRET_ID, SECRET_KEY);
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("lkeap.tencentcloudapi.com");
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
LkeapClient client = new LkeapClient(cred, "ap-guangzhou", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
ChatCompletionsRequest req = new ChatCompletionsRequest();
req.setModel("deepseek-r1");
Message[] messages1 = new Message[2];
Message message1 = new Message();
message1.setRole("system");
message1.setContent(SYSTEM_PROMPT);
messages1[0] = message1;
Message message2 = new Message();
message2.setRole("user");
message2.setContent(content);
messages1[1] = message2;
req.setMessages(messages1);
req.setStream(false);
req.setTemperature(0.1F);
req.setMaxTokens(1024L);
// 返回的resp是一个ChatCompletionsResponse的实例,与请求对象对应
ChatCompletionsResponse resp = client.ChatCompletions(req);
return resp.getChoices()[0].getMessage().getContent();
} catch (TencentCloudSDKException e) {
log.error(e.getMessage(), e);
}
return "服务异常";
}
public static void main(String[] args) {
String checkResult = getTencentDeepSeekCheckResult("滚蛋啊");
System.out.println("审核结果:" + checkResult);
}
3.3 火山引擎 doubao-1-5-pro-32k-250115模型
豆包doubao-1-5-pro-32k-250115测下来的准确性和混元hunyuan-turbos-latest基本差不多,
样本测试结果比较稳定,响应速度约2秒/条;
- 不通过样本(总数68条,测试2轮): 第1轮79.4%、第2轮79.4%;
- 2.通过样本(总数50条,测试2轮): 第1轮94%、第2轮94%;
<dependency>
<groupId>com.volcengine</groupId>
<artifactId>volcengine-java-sdk-ark-runtime</artifactId>
<version>0.1.157</version>
</dependency>
<dependency>
<groupId>com.volcengine</groupId>
<artifactId>volcengine-java-sdk-core</artifactId>
<version>0.1.157</version>
</dependency>
static String SYSTEM_PROMPT = "# 角色 \n" +
"中国工信部认证AI内容审核专家,依据最新《生成式人工智能服务管理暂行办法》及《人工智能生成合成内容标识办法》进行三重审查:\n" +
"\n" +
"**审核维度**\n" +
"1. **合法性**(违反即驳回) \n" +
" - 危害国家安全(宪法/网络安全法禁止内容) \n" +
" - 宣扬恐怖/极端主义、民族仇恨、邪教迷信 \n" +
" - 传播色情(含变体)、暴力、赌博、谣言 \n" +
" - 篡改历史、侮辱英烈 \n" +
"\n" +
"2. **价值观**(违反即驳回) \n" +
" - 攻击社会主义制度 \n" +
" - 传播封建迷信/历史虚无主义 \n" +
" - 煽动地域/性别/职业对立 \n" +
" - 宣扬拜金主义、畸形审美、消极躺平 \n" +
"\n" +
"3. **未成年人保护**(违反即驳回) \n" +
" - 诱导自残/厌世/校园霸凌 \n" +
" - 美化早恋/同性恋(含耽美作品) \n" +
" - 无价值追星/游戏内容 \n" +
" - 逻辑混乱的无效文本 \n" +
"\n" +
"**输出格式** \n" +
"仅返回: [审核通过] 或 [审核不通过]";
static String apiKey = "你的API KEY";
static ConnectionPool connectionPool = new ConnectionPool(5, 1, TimeUnit.SECONDS);
static Dispatcher dispatcher = new Dispatcher();
static ArkService service =
ArkService.builder()
.dispatcher(dispatcher)
.connectionPool(connectionPool)
.apiKey(apiKey)
.build();
public static String getDouBaoCheckResult(String content) {
if ($.isBlank(content)) {
return "异常";
}
try {
// 构造消息
List<ChatMessage> messagesForReqList = new ArrayList<>();
// system
ChatMessage elementForMessagesForReqList0 =
ChatMessage.builder()
.role(ChatMessageRole.SYSTEM)
.content(SYSTEM_PROMPT)
.build();
// user
ChatMessage elementForMessagesForReqList1 =
ChatMessage.builder()
.role(ChatMessageRole.USER)
.content(content)
.build();
messagesForReqList.add(elementForMessagesForReqList0);
messagesForReqList.add(elementForMessagesForReqList1);
ChatCompletionRequest req =
ChatCompletionRequest.builder()
.model("doubao-1-5-pro-32k-250115")
.messages(messagesForReqList)
.temperature(0.1)
.build();
ChatCompletionResult chatCompletion = service.createChatCompletion(req);
System.out.println("AI响应结果:" + JSONObject.toJSONString(chatCompletion));
StringBuilder checkResult = new StringBuilder();
chatCompletion.getChoices().forEach(choice -> checkResult.append(choice.getMessage().getContent()));
return checkResult.toString();
}catch (Exception e) {
e.printStackTrace();
}
return "服务异常";
}
public static void main(String[] args) {
String checkResult = getDouBaoCheckResult("累了就来吸根烟吧");
System.out.println("审核结果:" + checkResult);
}
四、一点思考
- 选择哪个模型并不是拍脑袋决定的事情,正如我们一开始下意识是先选择的DeepSeek R1模型,但实际测下来效果却是最差的,比较合理的做法是通过样本测试去实际评估下,从准确性、响应时长、价格等多个角度去评估。 关于大模型成本和技术的评估可以参考:内容安全审核接入大语言模型的成本和技术评估-CSDN博客