跳到主要内容

ai-aliyun-content-moderation

ai-aliyun-content-moderation 插件支持集成 阿里云内容安全增强版,在代理 LLM 请求时检查请求体的风险等级(如涉黄、涉政、辱骂、暴力等),如果评估结果超过配置的阈值,则拒绝该请求。

请确保已在插件中正确配置 access_key_secret。如果配置错误,所有请求都会绕过插件并直接转发到 LLM 上游,同时你会在网关错误日志中看到插件输出的 Specified signature is not matched with our calculation

ai-aliyun-content-moderation 插件应与 ai-proxyai-proxy-multi 插件配合使用,用于代理 LLM 请求。

演示

以下演示展示了如何在 API7 企业版控制台中完成审查请求内容毒性示例:你可以审查请求内容是否含有毒性,并自定义拒绝状态码和消息。

按请求格式处理

该插件使用各协议的原生内容结构审核 Chat Completions、Responses API、Embeddings、Anthropic Messages 和 Bedrock Converse 请求。

网关会先检查 URI 特定规则,再检查仅基于请求体的规则,以识别请求格式:

  • Bedrock Converse 要求 URI 以 /converse 结尾且包含 messages 数组。
  • Anthropic Messages 要求 URI 以 /v1/messages 结尾。
  • Responses API 要求 URI 以 /v1/responses 结尾且包含 input 字段。
  • Chat Completions 使用 messages 数组。
  • 当前面的规则均不匹配时,Embeddings 使用 input
  • 当前面的规则均不匹配时,其他非空 JSON 对象使用透传格式。
请求格式可审核的内容
Bedrock Conversesystemmessages 中的文本。
Anthropic Messagesmessages 中的文本。
Responses APIinstructionsinput 中的文本。
Chat Completionsmessages 中的文本。
Embeddingsinput 中的字符串或字符串数组。
其他 JSON(透传)不提取请求格式特定文本。

APISIX 会审核表中列出的所有已提取内容。API7 企业版 3.9.16 或 3.10.3 起支持按角色选择内容,默认审核最近一轮用户消息。使用 request_check_roles 选择用户、工具或系统内容,使用 request_check_mode 选择最近一轮或所有匹配轮次。

按角色选择内容时,选择系统角色即可审核 Anthropic 顶层 system 提示词。当请求格式使用独立的工具角色或条目表示工具输出时,插件可以审核工具结果。Anthropic Messages 和 Bedrock Converse 将工具结果嵌套在用户消息中,因此仅选择工具角色时不会提取这些结果。

要审核支持范围内尽可能广的请求内容,请在插件配置中选择所有可用角色和全部轮次:

{
"request_check_roles": ["user", "tool", "system"],
"request_check_mode": "all"
}

此配置会扫描检测到的协议为这些角色暴露的所有文本,但不会恢复为原始请求体审核:嵌套的 Anthropic 和 Bedrock 工具结果仍属于用户内容,而不是独立的 tool 消息;不支持的非 AI 结构则遵循 fail_mode

如果 Responses 内容被拒绝,插件会以 Responses API 格式返回配置的消息。流式请求会收到以 response.completed 结尾的类型化服务器发送事件。

Embeddings 没有对话角色或轮次。启用按角色选择后,其 input 由用户角色选中。被拒绝的请求会收到 OpenAI 风格的错误响应。

如果向阿里云发起的审核请求失败,插件会记录错误,并在没有审核结论的情况下放行内容。fail_mode 只控制不支持的请求格式或非 AI 请求,不会让阿里云服务故障转为故障关闭。当该插件作为强制执行控制时,请监控内容审核错误和阿里云服务可用性。

示例

以下示例将使用 OpenAI 作为上游模型服务提供方。

在开始之前,请创建一个 OpenAI 账号 并获取 API Key。如果你使用其他模型服务提供方,请参考该提供方的文档获取 API Key。

此外,请创建一个 阿里云账号,开通内容安全增强版服务,并获取 endpoint、region ID、access key ID 和 access key secret。

你可以选择将这些信息保存到环境变量中:

# 替换为你的数据
export OPENAI_API_KEY=YOUR_OPENAI_API_KEY
export ALIYUN_ENDPOINT=https://green-cip.cn-shanghai.aliyuncs.com
export ALIYUN_REGION_ID=cn-shanghai
export ALIYUN_ACCESS_KEY_ID=YOUR_ALIYUN_ACCESS_KEY_ID
export ALIYUN_ACCESS_KEY_SECRET=YOUR_ALIYUN_ACCESS_KEY_SECRET

审核请求内容毒性

以下示例演示了如何使用该插件审查请求内容的毒性,并自定义拒绝状态码和消息。

使用 ai-proxy 插件创建一个通往 LLM 聊天完成端点的路由,并在 ai-aliyun-content-moderation 插件中配置集成详情以及拒绝代码和消息:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
--data-binary @- <<EOF
{
"id": "ai-aliyun-content-moderation-route",
"uri": "/anything",
"plugins": {
"ai-aliyun-content-moderation": {
"endpoint": "$ALIYUN_ENDPOINT",
"region_id": "$ALIYUN_REGION_ID",
"access_key_id": "$ALIYUN_ACCESS_KEY_ID",
"access_key_secret": "$ALIYUN_ACCESS_KEY_SECRET",
"deny_code": 400,
"deny_message": "Request contains forbidden content, such as hate speech or violence."
},
"ai-proxy": {
"provider": "openai",
"auth": {
"header": {
"Authorization": "Bearer $OPENAI_API_KEY"
}
}
}
}
}
EOF

❶ 配置拒绝 HTTP 状态码。

❷ 配置拒绝消息。

向该路由发送一个 POST 请求,请求体中包含系统提示词和一个带有脏话的用户问题:

curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4",
"messages": [
{ "role": "system", "content": "You are a mathematician" },
{ "role": "user", "content": "Stupid, what is 1+1?" }
]
}'

你应该收到 HTTP/1.1 400 Bad Request 响应,并看到以下消息:

{
"object": "chat.completion",
"usage": {
"completion_tokens": 124,
"prompt_tokens": 31,
"total_tokens": 155
},
"choices": [
{
"message": {
"role": "assistant",
"content": "Request contains forbidden content, such as hate speech or violence."
},
"finish_reason": "stop",
"index": 0
}
],
"model": "gpt-4",
"id": "c9466bbf-e010-469d-949a-a10f25525964"
}

向该路由发送另一个请求,请求体中包含一个正常的问题:

curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "system", "content": "You are a mathematician" },
{ "role": "user", "content": "What is 1+1?" }
]
}'

你应该收到 HTTP/1.1 200 OK 响应,并看到模型输出:

{
...,
"model": "gpt-4-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "1+1 equals 2.",
"refusal": null
},
"logprobs": null,
"finish_reason": "stop"
}
],
...
}

调整风险等级阈值

以下示例演示了如何调整风险等级阈值,以控制是否允许请求或响应通过。

使用 ai-proxy 插件创建一个通往 LLM 聊天完成端点的路由,并将 ai-aliyun-content-moderation 中的 risk_level_bar 配置为 high

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
--data-binary @- <<EOF
{
"id": "ai-aliyun-content-moderation-route",
"uri": "/anything",
"plugins": {
"ai-aliyun-content-moderation": {
"endpoint": "$ALIYUN_ENDPOINT",
"region_id": "$ALIYUN_REGION_ID",
"access_key_id": "$ALIYUN_ACCESS_KEY_ID",
"access_key_secret": "$ALIYUN_ACCESS_KEY_SECRET",
"deny_code": 400,
"deny_message": "Request contains forbidden content, such as hate speech or violence.",
"risk_level_bar": "high"
},
"ai-proxy": {
"provider": "openai",
"auth": {
"header": {
"Authorization": "Bearer $OPENAI_API_KEY"
}
},
"model": "gpt-4"
}
}
}
EOF

向该路由发送一个 POST 请求,请求体中包含系统提示词和一个带有脏话的用户问题:

curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4",
"messages": [
{ "role": "system", "content": "You are a mathematician" },
{ "role": "user", "content": "Stupid, what is 1+1?" }
]
}'

你应该收到 HTTP/1.1 400 Bad Request 响应,并看到以下消息:

{
"object": "chat.completion",
"usage": {
"completion_tokens": 124,
"prompt_tokens": 31,
"total_tokens": 155
},
"choices": [
{
"message": {
"role": "assistant",
"content": "Request contains forbidden content, such as hate speech or violence."
},
"finish_reason": "stop",
"index": 0
}
],
"model": "gpt-4",
"id": "c9466bbf-e010-469d-949a-a10f25525964"
}

将插件中的 risk_level_bar 更新为 max

curl "http://127.0.0.1:9180/apisix/admin/routes/ai-aliyun-content-moderation-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"ai-aliyun-content-moderation": {
"risk_level_bar": "max"
}
}
}'

向该路由发送相同的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "system", "content": "You are a mathematician" },
{ "role": "user", "content": "Stupid, what is 1+1?" }
]
}'

你应该收到 HTTP/1.1 200 OK 响应,并看到模型输出:

{
...,
"model": "gpt-4-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "1+1 equals 2.",
"refusal": null
},
"logprobs": null,
"finish_reason": "stop"
}
],
...
}

请求会被转发,因为单词 "stupid" 的风险等级为 high,低于配置的 max 阈值。

插件不再将原始审核请求或成功审核响应写入调试日志。请结合客户端可见的拒绝状态和阿里云监控数据排查审核结果,避免在网关日志中暴露提示词内容。