diff --git a/docs/my-website/docs/proxy/logging.md b/docs/my-website/docs/proxy/logging.md index 1c3b4f81c2..f583765bb9 100644 --- a/docs/my-website/docs/proxy/logging.md +++ b/docs/my-website/docs/proxy/logging.md @@ -17,6 +17,7 @@ Log Proxy Input, Output, Exceptions using Custom Callbacks, Langfuse, OpenTeleme - [Logging to Sentry](#logging-proxy-inputoutput---sentry) - [Logging to Traceloop (OpenTelemetry)](#logging-proxy-inputoutput-traceloop-opentelemetry) - [Logging to Athina](#logging-proxy-inputoutput-athina) +- [Moderation with Azure Content-Safety](#moderation-with-azure-content-safety) ## Custom Callback Class [Async] Use this when you want to run custom callbacks in `python` @@ -1003,4 +1004,87 @@ curl --location 'http://0.0.0.0:4000/chat/completions' \ } ] }' -``` \ No newline at end of file +``` + +## Moderation with Azure Content Safety + +[Azure Content-Safety](https://azure.microsoft.com/en-us/products/ai-services/ai-content-safety) is a Microsoft Azure service that provides content moderation APIs to detect potential offensive, harmful, or risky content in text. + +We will use the `--config` to set `litellm.success_callback = ["azure_content_safety"]` this will moderate all LLM calls using Azure Content Safety. + +**Step 0** Deploy Azure Content Safety + +Deploy an Azure Content-Safety instance from the Azure Portal and get the `endpoint` and `key`. + +**Step 1** Set Athina API key + +```shell +AZURE_CONTENT_SAFETY_KEU = "" +``` + +**Step 2**: Create a `config.yaml` file and set `litellm_settings`: `success_callback` +```yaml +model_list: + - model_name: gpt-3.5-turbo + litellm_params: + model: gpt-3.5-turbo +litellm_settings: + callbacks: ["azure_content_safety"] + azure_content_safety_params: + endpoint: "" + key: "os.environ/AZURE_CONTENT_SAFETY_KEY" +``` + +**Step 3**: Start the proxy, make a test request + +Start proxy +```shell +litellm --config config.yaml --debug +``` + +Test Request +``` +curl --location 'http://0.0.0.0:4000/chat/completions' \ + --header 'Content-Type: application/json' \ + --data ' { + "model": "gpt-3.5-turbo", + "messages": [ + { + "role": "user", + "content": "Hi, how are you?" + } + ] + }' +``` + +An HTTP 400 error will be returned if the content is detected with a value greater than the threshold set in the `config.yaml`. +The details of the response will describe : +- The `source` : input text or llm generated text +- The `category` : the category of the content that triggered the moderation +- The `severity` : the severity from 0 to 10 + +**Step 4**: Customizing Azure Content Safety Thresholds + +You can customize the thresholds for each category by setting the `thresholds` in the `config.yaml` + +```yaml +model_list: + - model_name: gpt-3.5-turbo + litellm_params: + model: gpt-3.5-turbo +litellm_settings: + callbacks: ["azure_content_safety"] + azure_content_safety_params: + endpoint: "" + key: "os.environ/AZURE_CONTENT_SAFETY_KEY" + thresholds: + Hate: 6 + SelfHarm: 8 + Sexual: 6 + Violence: 4 +``` + +:::info +`thresholds` are not required by default, but you can tune the values to your needs. +Default values is `4` for all categories +::: \ No newline at end of file diff --git a/litellm/proxy/hooks/azure_content_safety.py b/litellm/proxy/hooks/azure_content_safety.py index 2cea05c69a..2735a88394 100644 --- a/litellm/proxy/hooks/azure_content_safety.py +++ b/litellm/proxy/hooks/azure_content_safety.py @@ -59,16 +59,6 @@ class _PROXY_AzureContentSafety( except: pass - def _severity(self, severity): - if severity >= 6: - return "high" - elif severity >= 4: - return "medium" - elif severity >= 2: - return "low" - else: - return "safe" - def _compute_result(self, response): result = {} @@ -80,7 +70,7 @@ class _PROXY_AzureContentSafety( if severity is not None: result[category] = { "filtered": severity >= self.thresholds[category], - "severity": self._severity(severity), + "severity": severity, } return result @@ -148,10 +138,10 @@ class _PROXY_AzureContentSafety( content=response.choices[0].message.content, source="output" ) - #async def async_post_call_streaming_hook( + # async def async_post_call_streaming_hook( # self, # user_api_key_dict: UserAPIKeyAuth, # response: str, - #): + # ): # self.print_verbose(f"Inside Azure Content-Safety Call-Stream Hook") # await self.test_violation(content=response, source="output") diff --git a/litellm/tests/test_azure_content_safety.py b/litellm/tests/test_azure_content_safety.py index f7d9d82686..3cc31003a7 100644 --- a/litellm/tests/test_azure_content_safety.py +++ b/litellm/tests/test_azure_content_safety.py @@ -50,7 +50,7 @@ async def test_strict_input_filtering_01(): assert exc_info.value.detail["source"] == "input" assert exc_info.value.detail["category"] == "Hate" - assert exc_info.value.detail["severity"] == "low" + assert exc_info.value.detail["severity"] == 2 @pytest.mark.asyncio @@ -168,7 +168,7 @@ async def test_strict_output_filtering_01(): assert exc_info.value.detail["source"] == "output" assert exc_info.value.detail["category"] == "Hate" - assert exc_info.value.detail["severity"] == "low" + assert exc_info.value.detail["severity"] == 2 @pytest.mark.asyncio