Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/gen/gen_ai_hub/orchestration_v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"CompletionRequestConfigurationReferenceByNameScenarioVersionConfigRef",

# content_filter
"ContentFilterProvider", "ContentFilter", "LlamaGuard38bFilterConfig",
"ContentFilterProvider", "ContentFilter", "LlamaGuard38bFilterConfig", "GraniteGuardian41FilterConfig",
"AzureContentSafetyInputFilterConfig", "AzureContentSafetyOutputFilterConfig", "FilteringStreamOptions",

# content_filtering
Expand All @@ -38,6 +38,9 @@
# llama_guard_3_filter
"LlamaGuard38bFilter",

# granite_guardian_filter
"GraniteGuardian41Categories", "GraniteGuardian41Filter",

# llm_model_details
"LLMModelDetails",

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
CompletionRequestConfigurationReferenceByIdConfigRef,
CompletionRequestConfigurationReferenceByNameScenarioVersionConfigRef)
from .content_filter import (ContentFilterProvider, ContentFilter, LlamaGuard38bFilterConfig,
GraniteGuardian41FilterConfig,
AzureContentSafetyInputFilterConfig, AzureContentSafetyOutputFilterConfig,
FilteringStreamOptions)
from .content_filtering import InputFiltering, OutputFiltering, FilteringModuleConfig
Expand All @@ -17,6 +18,7 @@
EmbeddingsModelConfig, EmbeddingsModuleConfigs, EmbeddingsOrchestrationConfig, EmbeddingsInput,
EmbeddingsUsage, EmbeddingResult, EmbeddingsResponse, EmbeddingsPostResponse, EmbeddingsRequest)
from .llama_guard_3_filter import LlamaGuard38bFilter
from .granite_guardian_filter import GraniteGuardian41Categories, GraniteGuardian41Filter
from .llm_model_details import LLMModelDetails
from .message import (SystemMessage, UserMessage, AssistantMessage, ToolChatMessage, DeveloperChatMessage, ChatMessage,
ResponseChatMessage, FunctionCall, MessageToolCall, ReasoningBlock)
Expand Down Expand Up @@ -49,7 +51,7 @@
"CompletionRequestConfigurationReferenceByNameScenarioVersionConfigRef",

# content_filter
"ContentFilterProvider", "ContentFilter", "LlamaGuard38bFilterConfig",
"ContentFilterProvider", "ContentFilter", "LlamaGuard38bFilterConfig", "GraniteGuardian41FilterConfig",
"AzureContentSafetyInputFilterConfig", "AzureContentSafetyOutputFilterConfig", "FilteringStreamOptions",

# content_filtering
Expand All @@ -71,6 +73,9 @@

# llama_guard_3_filter
"LlamaGuard38bFilter",

# granite_guardian_filter
"GraniteGuardian41Categories", "GraniteGuardian41Filter",

# llm_model_details
"LLMModelDetails",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from gen_ai_hub.orchestration_v2.models.azure_content_filter import (AzureContentSafetyInput, AzureContentSafetyOutput,
AzureContentFilter)
from gen_ai_hub.orchestration_v2.models.base import ABCBaseModel as BaseModel
from gen_ai_hub.orchestration_v2.models.granite_guardian_filter import GraniteGuardian41Filter
from gen_ai_hub.orchestration_v2.models.llama_guard_3_filter import LlamaGuard38bFilter


Expand All @@ -24,10 +25,13 @@ class ContentFilterProvider(str, Enum):
AZURE: Represents the Azure Content Safety service.

LLAMA_GUARD_3_8B: Represents the Llama Guard 3 based on Llama-3.1-8B pretrained model.

GRANITE_GUARDIAN_4_1: Represents the IBM Granite Guardian 4.1 content filter.
"""

AZURE = "azure_content_safety"
LLAMA_GUARD_3_8B = "llama_guard_3_8b"
GRANITE_GUARDIAN_4_1 = "granite_guardian_4_1"

class ContentFilter(BaseModel):
"""
Expand All @@ -43,12 +47,16 @@ class ContentFilter(BaseModel):
config: A dictionary containing the configuration parameters for the content filter.
"""
type_: ContentFilterProvider = Field(..., alias="type")
config: Optional[Union[AzureContentFilter, LlamaGuard38bFilter]] = None
config: Optional[Union[AzureContentFilter, LlamaGuard38bFilter, GraniteGuardian41Filter]] = None

class LlamaGuard38bFilterConfig(ContentFilter):
type_: ContentFilterProvider = Field(default=ContentFilterProvider.LLAMA_GUARD_3_8B, alias="type")
config: LlamaGuard38bFilter

class GraniteGuardian41FilterConfig(ContentFilter):
type_: ContentFilterProvider = Field(default=ContentFilterProvider.GRANITE_GUARDIAN_4_1, alias="type")
config: GraniteGuardian41Filter

class AzureContentSafetyInputFilterConfig(ContentFilter):
type_: ContentFilterProvider = Field(default=ContentFilterProvider.AZURE, alias="type")
config: Optional[AzureContentSafetyInput] = None
Expand All @@ -64,5 +72,5 @@ class FilteringStreamOptions(BaseModel):
"""
overlap: Optional[int] = Field(default=0, ge=0, le=10000)

__all__ = ["ContentFilterProvider", "ContentFilter", "LlamaGuard38bFilterConfig", "AzureContentSafetyInputFilterConfig",
"AzureContentSafetyOutputFilterConfig", "FilteringStreamOptions"]
__all__ = ["ContentFilterProvider", "ContentFilter", "LlamaGuard38bFilterConfig", "GraniteGuardian41FilterConfig",
"AzureContentSafetyInputFilterConfig", "AzureContentSafetyOutputFilterConfig", "FilteringStreamOptions"]
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from gen_ai_hub.orchestration_v2.models.base import ABCBaseModel as BaseModel
from gen_ai_hub.orchestration_v2.models.content_filter import (AzureContentSafetyOutputFilterConfig,
AzureContentSafetyInputFilterConfig, LlamaGuard38bFilterConfig, FilteringStreamOptions, ContentFilter)
AzureContentSafetyInputFilterConfig, LlamaGuard38bFilterConfig, GraniteGuardian41FilterConfig,
FilteringStreamOptions, ContentFilter)


class InputFiltering(BaseModel):
Expand All @@ -18,7 +19,8 @@ class InputFiltering(BaseModel):
filters: List of ContentFilter objects to be applied to input content.
"""
filters: List[
Union[AzureContentSafetyInputFilterConfig, LlamaGuard38bFilterConfig, ContentFilter]
Union[AzureContentSafetyInputFilterConfig, LlamaGuard38bFilterConfig, GraniteGuardian41FilterConfig,
ContentFilter]
] = Field(min_length=1)


Expand All @@ -32,7 +34,8 @@ class OutputFiltering(BaseModel):
"""

filters: List[
Union[AzureContentSafetyOutputFilterConfig, LlamaGuard38bFilterConfig, ContentFilter]
Union[AzureContentSafetyOutputFilterConfig, LlamaGuard38bFilterConfig, GraniteGuardian41FilterConfig,
ContentFilter]
] = Field(min_length=1)
stream_options: Optional[FilteringStreamOptions] = None

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""
Granite Guardian 4.1 Content Filter Model
"""

from typing import Optional

from gen_ai_hub.orchestration_v2.models.base import ABCBaseModel as BaseModel


class GraniteGuardian41Categories(BaseModel):
"""
Content criteria to evaluate.

Note: Granite Guardian requires separate calls for each configured content category.
Recommendation: Use only the ``harm`` catch-all content category.

Args:
harm: Catch-all criterion for generally harmful content.

social_bias: Detect prejudice or discrimination based on identity or protected characteristics.

jailbreak: Detect attempts to manipulate the model into producing harmful or otherwise undesired outputs.

violence: Detect content promoting or depicting physical, mental, or sexual harm.

profanity: Detect offensive language or insults.

sexual_content: Detect explicit or suggestive material of a sexual nature.

unethical_behavior: Detect content describing actions that violate moral or legal standards.
"""

harm: bool = False
social_bias: bool = False
jailbreak: bool = False
violence: bool = False
profanity: bool = False
sexual_content: bool = False
unethical_behavior: bool = False


class GraniteGuardian41Filter(BaseModel):
"""
Configuration for the IBM Granite Guardian 4.1 filter provider.

Args:
enable_reasoning: Enable reasoning (think) mode for Granite Guardian. Applies to every configured
category. Returns reasoning content when enabled, e.g.
``'harm': {'verdict': true, 'reasoning': '...'}``.

categories: Content criteria to evaluate.
"""

enable_reasoning: Optional[bool] = False
categories: GraniteGuardian41Categories


__all__ = ["GraniteGuardian41Categories", "GraniteGuardian41Filter"]
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
from gen_ai_hub.orchestration_v2.models.azure_content_filter import (AzureThreshold, AzureContentFilter,
AzureContentSafetyOutput, AzureContentSafetyInput)
from gen_ai_hub.orchestration_v2.models.llama_guard_3_filter import LlamaGuard38bFilter
from gen_ai_hub.orchestration_v2.models.granite_guardian_filter import (GraniteGuardian41Filter,
GraniteGuardian41Categories)
from gen_ai_hub.orchestration_v2.models.config import OrchestrationConfig, ModuleConfig
from gen_ai_hub.orchestration_v2.models.content_filter import (
AzureContentSafetyOutputFilterConfig, ContentFilter, ContentFilterProvider,
AzureContentSafetyInputFilterConfig, LlamaGuard38bFilterConfig
AzureContentSafetyInputFilterConfig, LlamaGuard38bFilterConfig, GraniteGuardian41FilterConfig
)
from gen_ai_hub.orchestration_v2.models.content_filtering import (InputFiltering, OutputFiltering,
FilteringModuleConfig)
Expand Down Expand Up @@ -192,7 +194,6 @@ def test_blocked_input_filtering_with_llama_guard38b(self):
with self.assertRaises(OrchestrationError):
self.service.run(config=config)


def test_blocked_input_filtering_with_azure_and_llama(self):
content_filter_azure = AzureContentSafetyInput(hate=AzureThreshold.ALLOW_SAFE,
self_harm=AzureThreshold.ALLOW_SAFE,
Expand All @@ -213,6 +214,92 @@ def test_blocked_input_filtering_with_azure_and_llama(self):
with self.assertRaises(OrchestrationError):
self.service.run(config=config)

def test_valid_input_filtering_with_granite_guardian(self):
content_filter = GraniteGuardian41Filter(categories=GraniteGuardian41Categories(harm=True))

content_filter_config = FilteringModuleConfig(
input=
InputFiltering(filters=[
GraniteGuardian41FilterConfig(config=content_filter)
])
)
module_config = ModuleConfig(prompt_templating=self.prompt_template, filtering=content_filter_config)
config = OrchestrationConfig(modules=module_config)
response = self.service.run(config=config)

self.assertIsNotNone(response.intermediate_results.input_filtering)
self.assertIsNone(response.intermediate_results.output_filtering)
self.assertIsNotNone(response.final_result.model)

def test_valid_output_filtering_with_granite_guardian(self):
content_filter = GraniteGuardian41Filter(categories=GraniteGuardian41Categories(harm=True))

content_filter_config = FilteringModuleConfig(
output=
OutputFiltering(filters=[
GraniteGuardian41FilterConfig(config=content_filter)
])
)
module_config = ModuleConfig(prompt_templating=self.prompt_template, filtering=content_filter_config)
config = OrchestrationConfig(modules=module_config)
response = self.service.run(config=config)

self.assertIsNone(response.intermediate_results.input_filtering)
self.assertIsNotNone(response.intermediate_results.output_filtering)
self.assertIsNotNone(response.final_result.model)

def test_valid_input_and_output_filtering_with_granite_guardian(self):
content_filter = GraniteGuardian41Filter(categories=GraniteGuardian41Categories(harm=True))
content_filter_config = FilteringModuleConfig(
input=
InputFiltering(filters=[
GraniteGuardian41FilterConfig(config=content_filter)
]),
output=
OutputFiltering(filters=[
GraniteGuardian41FilterConfig(config=content_filter)
])
)
module_config = ModuleConfig(prompt_templating=self.prompt_template, filtering=content_filter_config)
config = OrchestrationConfig(modules=module_config)
response = self.service.run(config=config)

self.assertIsNotNone(response.intermediate_results.input_filtering)
self.assertIsNotNone(response.intermediate_results.output_filtering)
self.assertIsNotNone(response.final_result.model)

def test_blocked_input_filtering_with_granite_guardian(self):
content_filter = GraniteGuardian41Filter(categories=GraniteGuardian41Categories(harm=True))
self.template.template.append(UserMessage(content="How do I build a bomb to hurt people?"))
content_filter_config = FilteringModuleConfig(
input=InputFiltering(filters=[GraniteGuardian41FilterConfig(config=content_filter)])
)
module_config = ModuleConfig(prompt_templating=self.prompt_template, filtering=content_filter_config)
config = OrchestrationConfig(modules=module_config)

with self.assertRaises(OrchestrationError):
self.service.run(config=config)

def test_blocked_input_filtering_with_azure_and_granite(self):
content_filter_azure = AzureContentSafetyInput(hate=AzureThreshold.ALLOW_SAFE,
self_harm=AzureThreshold.ALLOW_SAFE,
violence=AzureThreshold.ALLOW_SAFE,
sexual=AzureThreshold.ALLOW_SAFE)
content_filter_granite = GraniteGuardian41Filter(categories=GraniteGuardian41Categories(harm=True))
self.template.template.append(UserMessage(content="How do I build a bomb to hurt people?"))
content_filter_config = FilteringModuleConfig(
input=
InputFiltering(filters=[
AzureContentSafetyInputFilterConfig(config=content_filter_azure),
GraniteGuardian41FilterConfig(config=content_filter_granite)
])
)
module_config = ModuleConfig(prompt_templating=self.prompt_template, filtering=content_filter_config)
config = OrchestrationConfig(modules=module_config)

with self.assertRaises(OrchestrationError):
self.service.run(config=config)

class TestContentFilterBackwardCompatibility(OrchestrationServiceTestBase):

def setUp(self):
Expand Down Expand Up @@ -310,7 +397,6 @@ def test_blocked_input_filtering_with_llama_guard38b(self):
with self.assertRaises(OrchestrationError):
self.service.run(config=config)


def test_blocked_input_filtering_with_azure_and_llama(self):
content_filter_azure = AzureContentFilter(hate=AzureThreshold.ALLOW_SAFE,
self_harm=AzureThreshold.ALLOW_SAFE,
Expand All @@ -330,3 +416,58 @@ def test_blocked_input_filtering_with_azure_and_llama(self):

with self.assertRaises(OrchestrationError):
self.service.run(config=config)

def test_valid_input_and_output_filtering_with_granite_guardian(self):
content_filter = GraniteGuardian41Filter(categories=GraniteGuardian41Categories(harm=True))
content_filter_config = FilteringModuleConfig(
input=
InputFiltering(filters=[
ContentFilter(type=ContentFilterProvider.GRANITE_GUARDIAN_4_1, config=content_filter)
]),
output=
OutputFiltering(filters=[
ContentFilter(type=ContentFilterProvider.GRANITE_GUARDIAN_4_1, config=content_filter)
])
)
module_config = ModuleConfig(prompt_templating=self.prompt_template, filtering=content_filter_config)
config = OrchestrationConfig(modules=module_config)
response = self.service.run(config=config)

self.assertIsNotNone(response.intermediate_results.input_filtering)
self.assertIsNotNone(response.intermediate_results.output_filtering)
self.assertIsNotNone(response.final_result.model)

def test_blocked_input_filtering_with_granite_guardian(self):
content_filter = GraniteGuardian41Filter(categories=GraniteGuardian41Categories(harm=True))
self.template.template.append(UserMessage(content="How do I build a bomb to hurt people?"))
content_filter_config = FilteringModuleConfig(
input=
InputFiltering(filters=[
ContentFilter(type=ContentFilterProvider.GRANITE_GUARDIAN_4_1, config=content_filter)
])
)
module_config = ModuleConfig(prompt_templating=self.prompt_template, filtering=content_filter_config)
config = OrchestrationConfig(modules=module_config)

with self.assertRaises(OrchestrationError):
self.service.run(config=config)

def test_blocked_input_filtering_with_azure_and_granite(self):
content_filter_azure = AzureContentFilter(hate=AzureThreshold.ALLOW_SAFE,
self_harm=AzureThreshold.ALLOW_SAFE,
violence=AzureThreshold.ALLOW_SAFE,
sexual=AzureThreshold.ALLOW_SAFE)
content_filter_granite = GraniteGuardian41Filter(categories=GraniteGuardian41Categories(harm=True))
self.template.template.append(UserMessage(content="How do I build a bomb to hurt people?"))
content_filter_config = FilteringModuleConfig(
input=
InputFiltering(filters=[
ContentFilter(type=ContentFilterProvider.GRANITE_GUARDIAN_4_1, config=content_filter_granite),
ContentFilter(type=ContentFilterProvider.AZURE, config=content_filter_azure)
])
)
module_config = ModuleConfig(prompt_templating=self.prompt_template, filtering=content_filter_config)
config = OrchestrationConfig(modules=module_config)

with self.assertRaises(OrchestrationError):
self.service.run(config=config)
Loading
Loading