Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

feat(ai-aws-content-moderation): moderate LLM responses, including streams#13735

Open
shreemaan-abhishek wants to merge 1 commit into
apache:masterapache/apisix:masterfrom
shreemaan-abhishek:feat/aws-content-moderation-responseshreemaan-abhishek/apisix:feat/aws-content-moderation-responseCopy head branch name to clipboard
Open

feat(ai-aws-content-moderation): moderate LLM responses, including streams#13735
shreemaan-abhishek wants to merge 1 commit into
apache:masterapache/apisix:masterfrom
shreemaan-abhishek:feat/aws-content-moderation-responseshreemaan-abhishek/apisix:feat/aws-content-moderation-responseCopy head branch name to clipboard

Conversation

@shreemaan-abhishek

Copy link
Copy Markdown
Contributor

Description

ai-aws-content-moderation only moderated requests, while its sibling ai-aliyun-content-moderation moderates both directions. AWS Comprehend DetectToxicContent scores response text just as well, so this was a plugin gap rather than an API limitation. It builds on #13647, which moved the plugin to the access phase with protocol-aware content extraction.

What changed — a new check_response option plus a lua_body_filter:

Case Behavior
non-streaming (ai_chat) the assembled completion is moderated in one call; a hit returns deny_code with a provider-compatible refusal body
streaming, stream_check_mode: realtime batches are moderated as they arrive, bounded by stream_check_cache_size (chars) and stream_check_interval (seconds); a hit replaces the rest of the stream with the refusal
streaming, stream_check_mode: final_packet (default) the assembled response is moderated once and the last chunk's SSE data events are annotated with risk_level

New schema fields: check_response (default false), stream_check_mode (default final_packet), stream_check_cache_size (default 128), stream_check_interval (default 3). All default to the previous behavior, so existing configurations are unaffected.

The verdict is published on ctx.var.llm_content_risk_level as high or none. Comprehend grades nothing, it only scores against the configured thresholds, so the verdict is binary; reusing the same ctx var the aliyun plugin sets keeps logging and downstream consumers uniform.

Deny reasons now name the side that tripped (request body exceeds ... / response body exceeds ...).

A Comprehend failure on the response side is logged and the content passes through: once bytes are on the wire there is no fail-closed option, and buffered responses behave the same way for consistency. This matches ai-aliyun-content-moderation. The request side is unchanged and still fails closed with a 500.

Testst/plugin/ai-aws-content-moderation.t TEST 18-30 cover non-streaming deny and pass-through, the provider-compatible deny body with a custom deny_message at the default deny_code, check_response off leaving a toxic response untouched, final_packet annotation, realtime cutting the stream off mid-flight, the upstream-error skip, and schema validation of the new fields. New fixtures live under t/fixtures/aws/. The Comprehend mock gained a fallback for free-form response text, since response content is not a fixture key; exact-key lookup still runs first, so every existing test is unchanged.

Docsdocs/en/latest/plugins/ai-aws-content-moderation.md updated with the new attributes and the response-moderation description.

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (If not, please discuss on the APISIX mailing list first)

…reams

The plugin only moderated requests, while ai-aliyun-content-moderation
moderates both directions. AWS Comprehend `DetectToxicContent` scores
response text just as well, so this was a plugin gap, not an API limit.

Adds `check_response` and a `lua_body_filter`:

- non-streaming: the assembled completion is moderated in one call
- streaming `realtime`: batches are moderated as they arrive
  (`stream_check_cache_size` / `stream_check_interval`), and the rest of
  the stream is replaced with a provider-compatible refusal on a hit
- streaming `final_packet`: the assembled response is moderated and the
  last chunk annotated with `risk_level`

The verdict is reported on `ctx.var.llm_content_risk_level` (`high` or
`none`) so logging matches the aliyun plugin. Comprehend failures on the
response side are logged and let the content through: once bytes are on
the wire there is no fail-closed option, and buffered responses behave
the same way for consistency.
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. enhancement New feature or request labels Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Morty Proxy This is a proxified and sanitized view of the page, visit original site.