Skip to main content

Alibaba Cloud Content Moderation

Alibaba Cloud Content Moderation grades content with a risk level through the TextModerationPlus API, and AISIX blocks requests whose returned level reaches your configured threshold. Requests can be checked before they reach the upstream model, and responses can be checked before they reach callers.

This is a different Alibaba Cloud product from Alibaba Cloud AI Guardrails (aliyun_ai_guardrail, the MultiModalGuard API). Use AI Guardrails when you manage policy in its console, need composite checks such as prompt-attack detection and sensitive-data masking, or want the calls visible in the AI Guardrails console's records.

In this guide, you will create an Alibaba Cloud Content Moderation resource, send one allowed request, and send one blocked request that AISIX rejects before it reaches the upstream model.

Prerequisites

Before starting, prepare the following:

  • Review Guardrail Behavior for hook points, enforcement modes, and remote failure handling.
  • One of these configuration paths:
    • AISIX Cloud with an environment, an attached gateway, and a write-scoped admin token. For On-Premises, follow the AISIX Cloud Quickstart. To request Hybrid Cloud access, contact API7.
    • An open-source AISIX gateway that loads a declarative resources.yaml file.
  • A working model alias and caller API key that can send Chat Completions requests.
  • Alibaba Cloud Content Moderation enhanced-edition APIs activated in the region you want to use.
  • An Alibaba Cloud AccessKey ID and AccessKey secret allowed to call the TextModerationPlus API action.
  • curl. The AISIX Cloud path also uses jq.

Export the gateway and provider values used by both paths:

# AISIX_PROXY has no trailing slash or endpoint path.
# The local quickstarts use http://127.0.0.1:3000.
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export AISIX_MODEL="gpt-4o-mini"
export ALIBABA_CLOUD_ACCESS_KEY_ID="YOUR_ALIBABA_CLOUD_ACCESS_KEY_ID"
export ALIBABA_CLOUD_ACCESS_KEY_SECRET="YOUR_ALIBABA_CLOUD_ACCESS_KEY_SECRET"

Create an Alibaba Cloud Content Moderation Guardrail

Choose one configuration path to create the guardrail, then use the shared verification procedure.

AISIX Cloud

Export the control-plane connection details:

# AISIX_CP includes /api and has no trailing slash.
# The local On-Premises quickstart uses http://localhost:8080/api.
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_BASE_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"

Create an Alibaba Cloud Content Moderation resource in the environment and capture its ID:

export GUARDRAIL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/guardrails" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "aliyun-review",
"enabled": false,
"hook_point": "both",
"fail_open": false,
"enforcement_mode": "block",
"kind": "aliyun_text_moderation",
"config": {
"region": "cn-shanghai",
"access_key_id": "'"${ALIBABA_CLOUD_ACCESS_KEY_ID}"'",
"access_key_secret": "'"${ALIBABA_CLOUD_ACCESS_KEY_SECRET}"'",
"output_fail_open": false,
"risk_level_threshold": "medium",
"timeout_ms": 3000
}
}' | jq -r '.guardrail.id')

both checks caller requests and model responses. See Guardrail Hook Point.

fail_open: false blocks the request if Alibaba Cloud Content Moderation fails or times out. The default is true.

enforcement_mode: block rejects matching content. This is the default. See Enforcement Modes.

output_fail_open: false blocks unscanned model output during an Alibaba Cloud outage. This is the default.

risk_level_threshold blocks returned risk levels at or above the configured threshold.

timeout_ms bounds how long AISIX waits for the guardrail decision.

AISIX derives the moderation endpoint from region (green-cip.<region>.aliyuncs.com). Set endpoint in config to a full URL only when you need to override that host.

Attach the guardrail to the environment so it applies to all traffic:

curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/guardrails/$GUARDRAIL_ID/attachments" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope_type": "env"
}'

The env scope omits scope_id and covers every request in the environment. To narrow enforcement, set scope_type to model, api_key, or team and pass the resource ID as scope_id.

Enable the guardrail after its attachment exists:

curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/guardrails/$GUARDRAIL_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'

The enabled configuration projects to attached gateways automatically.

Open-Source AISIX Gateway

Add the guardrail to the resources file that already defines the example model and caller API key. The example reads credentials from ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET. A running quickstart container does not inherit these variables from later host exports.

resources.yaml
guardrails:
- name: aliyun-review
enabled: true
hook_point: both
fail_open: false
enforcement_mode: block
kind: aliyun_text_moderation
region: cn-shanghai
access_key_id: ${ALIBABA_CLOUD_ACCESS_KEY_ID}
access_key_secret: ${ALIBABA_CLOUD_ACCESS_KEY_SECRET}
output_fail_open: false
risk_level_threshold: medium
timeout_ms: 3000

The provider fields sit directly on the guardrail entry rather than under config. AISIX derives the endpoint from region; set endpoint only when the gateway should use another full URL.

Every enabled guardrail in the resources file applies to every request handled by that gateway. Apply the change by validating the complete file before reloading or recreating the gateway. If you are extending the open-source quickstart, follow Reload a Resources File to recreate the container only after validation succeeds and pass the additional credential variables.

Verify the Guardrail

AISIX Cloud projection is asynchronous. If the first request does not reflect the guardrail, wait for the gateway to apply the latest revision and retry. See Resource Projection for convergence checks.

Send a benign request through AISIX:

curl -sSi -X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "'"${AISIX_MODEL}"'",
"messages": [
{
"role": "user",
"content": "What is the capital of France?"
}
]
}'

A successful response starts with HTTP/1.1 200 OK and returns an OpenAI-compatible chat-completions body.

For a repeatable check, use content that your Alibaba Cloud Content Moderation configuration classifies at or above the configured AISIX threshold.

Then send a request containing that content:

curl -sSi -X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "'"${AISIX_MODEL}"'",
"messages": [
{
"role": "user",
"content": "YOUR_POLICY_VIOLATING_TEXT"
}
]
}'

A blocked response starts with HTTP/1.1 422 Unprocessable Entity and includes an OpenAI-compatible error:

{
"error": {
"message": "request blocked by content policy (guardrail 'aliyun-review')",
"type": "content_filter"
}
}

AISIX blocks the request before dispatching to the upstream model when Alibaba Cloud Content Moderation returns a blocking risk level.

Tune Risk Threshold

Alibaba Cloud returns a risk level for each moderation decision. Alibaba Cloud determines the level from its moderation result and configured score thresholds. AISIX does not recalculate it.

AISIX can block the low, medium, or high levels:

ThresholdEffect
highBlocks only high-risk verdicts. This is the default.
mediumBlocks medium-risk and high-risk verdicts.
lowBlocks low-risk, medium-risk, and high-risk verdicts.

Use a stricter threshold when the application should reject more uncertain content, or a less strict threshold when you want Alibaba Cloud to block only the strongest matches.

Trace a Blocked Request to Alibaba Cloud

A blocked response tells the caller only that content policy rejected the request. To find out why a specific request was blocked, correlate it with the moderation record in the Alibaba Cloud console.

Every AISIX proxy response carries an x-aisix-request-id header, including the 422 above:

HTTP/1.1 422 Unprocessable Entity
x-aisix-request-id: 12179fb5-5c3c-4a2a-a411-d73746379cc6

Ask the caller for that ID, then search the gateway log for it:

grep 12179fb5-5c3c-4a2a-a411-d73746379cc6 /path/to/aisix.log

The moderation decision is logged at info level. Both IDs appear on the same log line, so one search finds them together. The example below is wrapped to fit the page; in your log it is a single line:

INFO request{request_id=12179fb5-5c3c-4a2a-a411-d73746379cc6}: aisix_guardrails::aliyun:
aliyun text moderation blocked content row=aliyun-review service="llm_query_moderation"
aliyun_request_id=019F6EF3-6F9A-5A25-9EED-256CB0E26448 aliyun_code=200
aliyun_risk_level=high aliyun_labels=inappropriate_oral,violent_incidents

Two different IDs appear here, and they are not interchangeable:

FieldMeaning
request_idThe gateway request ID, equal to the caller's x-aisix-request-id.
aliyun_request_idAlibaba Cloud's own RequestId for the moderation call. Use it to look up the record in the Alibaba Cloud console or to open a ticket with Alibaba Cloud support.
aliyun_risk_levelThe risk level Alibaba Cloud returned, which is compared against your threshold.
aliyun_labelsThe categories Alibaba Cloud matched. One request commonly matches several.

Requests that pass moderation log the same fields at debug level, so raise the gateway log_level to debug when you need the Alibaba Cloud RequestId for a request that was not blocked.

When Alibaba Cloud cannot be reached at all, such as a timeout or a connection failure, aliyun_request_id is logged empty because Alibaba Cloud never issued one. The accompanying failure field names the cause. This example is also wrapped:

WARN request{request_id=...}: aisix_guardrails::aliyun: aliyun text moderation call failed
row=aliyun-review aliyun_request_id= failure=Timeout fail_open=false

When a 422 Is a Configuration Error

With fail_open: false, a guardrail that cannot get a decision from Alibaba Cloud blocks the request. A wrong credential therefore reaches the caller as the same 422 content_filter as a genuine policy hit. The log tells them apart: a configuration error logs at error level, with aliyun_code naming the cause.

aliyun_codeCause
SignatureDoesNotMatchThe access_key_secret is wrong.
InvalidAccessKeyId.NotFoundThe access_key_id is wrong, or the key is disabled.
InvalidAction.NotFoundThe region or endpoint does not serve this API.

Alibaba Cloud returns other codes for other failures; its error reference resolves any code by name.

AISIX logs the code but never the body Alibaba Cloud returns with it. On a signature error, that body quotes the entire signed request back. The quoted request carries the caller's prompt and your AccessKey ID, so echoing it would put both in your logs.

Two things are deliberately kept out of this path:

  • Alibaba Cloud's RequestId is never returned to the caller. Callers receive only x-aisix-request-id, and you resolve the rest from the log.
  • The text that Alibaba Cloud matched is never logged. Alibaba Cloud returns the offending words in its RiskWords and RiskPositions fields, but AISIX records only the category labels, so gateway logs cannot leak caller content.

Next Steps

You have now enforced Alibaba Cloud Content Moderation through AISIX. Use these guides to tune behavior or compare related guardrails: