Two different failures
| What you see | Where it was filtered |
|---|---|
HTTP 400, "code": "content_filter", "innererror": {"code": "ResponsibleAIPolicyViolation", "content_filter_result": {...}} | The prompt (input) was blocked; the model never ran |
HTTP 200, but "finish_reason": "content_filter" and a truncated or empty answer | The completion (output) was blocked partway |
1. Read the annotations
The response includes content_filter_result (prompt) or content_filter_results (completion) with each category:
"content_filter_result": {
"hate": {"filtered": false, "severity": "safe"},
"self_harm": {"filtered": false, "severity": "safe"},
"sexual": {"filtered": false, "severity": "safe"},
"violence": {"filtered": true, "severity": "medium"},
"jailbreak": {"filtered": true, "detected": true}
}
Log this object for every blocked call. Without it, you can't tell which category fired.
2. Common false positives in IT support bots
| Trigger | Example | Fix |
|---|---|---|
| Violence | "kill the process", "terminate the zombie", "execute the child" | Usually low severity and allowed with the default filter. If blocked, review the filter threshold. |
| Jailbreak / prompt shields | Retrieved documents that contain "ignore previous instructions" text (for example, a security KB) | Pass retrieved text as documents, mark it clearly, or adjust the indirect attack shield for that deployment |
| Self-harm | Healthcare or HR content | A custom filter configuration agreed with your Responsible AI reviewer |
3. Adjust the filter (with approval)
In Azure AI Foundry → Guardrails + controls → Content filters, create a configuration:
- Set the threshold per category, for input and output separately (low / medium / high).
- Turn prompt shields on or off for direct and indirect attacks.
- Assign the configuration to the specific deployment.
Fully turning filters off, or "annotate only" mode, needs approval from Microsoft (a modified content filtering application). Document the business reason.
4. Handle it in code
try:
resp = client.chat.completions.create(model=deployment, messages=messages)
choice = resp.choices[0]
if choice.finish_reason == "content_filter":
log.warning("output filtered", extra={"filters": choice.content_filter_results})
return FRIENDLY_FALLBACK
except openai.BadRequestError as e:
if getattr(e, "code", None) == "content_filter":
log.warning("prompt filtered", extra={"body": e.body})
return "I can't help with that request. Please rephrase or contact support."
raise
Don't retry the same prompt in a loop; it will be blocked again.
5. Streaming
With streaming, the output is checked in chunks. A filtered stream ends with a content_filter finish reason after some text was already sent. The UI should replace the partial text with the fallback message.
Tip
Build a small test set of 30–50 real support prompts that were wrongly blocked. Run it every time you change filter settings or switch model versions, so you know the effect before customers do.