azure-ai-evaluation 1.6.0__py3-none-any.whl → 1.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of azure-ai-evaluation might be problematic. Click here for more details.

Files changed (69) hide show
  1. azure/ai/evaluation/__init__.py +1 -0
  2. azure/ai/evaluation/_aoai/aoai_grader.py +1 -1
  3. azure/ai/evaluation/_aoai/label_grader.py +2 -2
  4. azure/ai/evaluation/_aoai/string_check_grader.py +2 -2
  5. azure/ai/evaluation/_aoai/text_similarity_grader.py +2 -2
  6. azure/ai/evaluation/_common/__init__.py +3 -1
  7. azure/ai/evaluation/_common/evaluation_onedp_client.py +50 -5
  8. azure/ai/evaluation/_common/onedp/operations/_operations.py +4 -2
  9. azure/ai/evaluation/_common/rai_service.py +7 -6
  10. azure/ai/evaluation/_converters/_ai_services.py +162 -118
  11. azure/ai/evaluation/_converters/_models.py +76 -6
  12. azure/ai/evaluation/_eval_mapping.py +2 -0
  13. azure/ai/evaluation/_evaluate/_evaluate.py +15 -17
  14. azure/ai/evaluation/_evaluate/_evaluate_aoai.py +24 -5
  15. azure/ai/evaluation/_evaluators/_bleu/_bleu.py +11 -1
  16. azure/ai/evaluation/_evaluators/_code_vulnerability/_code_vulnerability.py +9 -1
  17. azure/ai/evaluation/_evaluators/_coherence/_coherence.py +12 -2
  18. azure/ai/evaluation/_evaluators/_common/_base_eval.py +4 -0
  19. azure/ai/evaluation/_evaluators/_content_safety/_content_safety.py +12 -2
  20. azure/ai/evaluation/_evaluators/_content_safety/_hate_unfairness.py +14 -4
  21. azure/ai/evaluation/_evaluators/_content_safety/_self_harm.py +9 -8
  22. azure/ai/evaluation/_evaluators/_content_safety/_sexual.py +10 -0
  23. azure/ai/evaluation/_evaluators/_content_safety/_violence.py +10 -0
  24. azure/ai/evaluation/_evaluators/_document_retrieval/_document_retrieval.py +31 -29
  25. azure/ai/evaluation/_evaluators/_f1_score/_f1_score.py +10 -0
  26. azure/ai/evaluation/_evaluators/_fluency/_fluency.py +10 -0
  27. azure/ai/evaluation/_evaluators/_gleu/_gleu.py +10 -0
  28. azure/ai/evaluation/_evaluators/_groundedness/_groundedness.py +10 -0
  29. azure/ai/evaluation/_evaluators/_intent_resolution/_intent_resolution.py +10 -0
  30. azure/ai/evaluation/_evaluators/_meteor/_meteor.py +10 -0
  31. azure/ai/evaluation/_evaluators/_protected_material/_protected_material.py +11 -0
  32. azure/ai/evaluation/_evaluators/_qa/_qa.py +10 -0
  33. azure/ai/evaluation/_evaluators/_relevance/_relevance.py +10 -0
  34. azure/ai/evaluation/_evaluators/_response_completeness/_response_completeness.py +13 -0
  35. azure/ai/evaluation/_evaluators/_retrieval/_retrieval.py +10 -0
  36. azure/ai/evaluation/_evaluators/_rouge/_rouge.py +14 -4
  37. azure/ai/evaluation/_evaluators/_service_groundedness/_service_groundedness.py +10 -0
  38. azure/ai/evaluation/_evaluators/_similarity/_similarity.py +10 -0
  39. azure/ai/evaluation/_evaluators/_task_adherence/_task_adherence.py +11 -0
  40. azure/ai/evaluation/_evaluators/_tool_call_accuracy/_tool_call_accuracy.py +80 -10
  41. azure/ai/evaluation/_evaluators/_ungrounded_attributes/_ungrounded_attributes.py +10 -0
  42. azure/ai/evaluation/_evaluators/_xpia/xpia.py +11 -0
  43. azure/ai/evaluation/_safety_evaluation/_safety_evaluation.py +26 -7
  44. azure/ai/evaluation/_version.py +1 -1
  45. azure/ai/evaluation/red_team/_agent/__init__.py +3 -0
  46. azure/ai/evaluation/red_team/_agent/_agent_functions.py +264 -0
  47. azure/ai/evaluation/red_team/_agent/_agent_tools.py +503 -0
  48. azure/ai/evaluation/red_team/_agent/_agent_utils.py +69 -0
  49. azure/ai/evaluation/red_team/_agent/_semantic_kernel_plugin.py +237 -0
  50. azure/ai/evaluation/red_team/_attack_strategy.py +2 -0
  51. azure/ai/evaluation/red_team/_red_team.py +572 -207
  52. azure/ai/evaluation/red_team/_utils/_rai_service_eval_chat_target.py +121 -0
  53. azure/ai/evaluation/red_team/_utils/_rai_service_target.py +570 -0
  54. azure/ai/evaluation/red_team/_utils/_rai_service_true_false_scorer.py +108 -0
  55. azure/ai/evaluation/red_team/_utils/constants.py +5 -1
  56. azure/ai/evaluation/red_team/_utils/metric_mapping.py +2 -2
  57. azure/ai/evaluation/red_team/_utils/strategy_utils.py +2 -0
  58. azure/ai/evaluation/simulator/_adversarial_simulator.py +9 -2
  59. azure/ai/evaluation/simulator/_conversation/constants.py +1 -1
  60. azure/ai/evaluation/simulator/_direct_attack_simulator.py +3 -3
  61. azure/ai/evaluation/simulator/_indirect_attack_simulator.py +3 -3
  62. azure/ai/evaluation/simulator/_model_tools/_generated_rai_client.py +3 -0
  63. azure/ai/evaluation/simulator/_model_tools/_proxy_completion_model.py +15 -7
  64. azure/ai/evaluation/simulator/_model_tools/_template_handler.py +6 -5
  65. {azure_ai_evaluation-1.6.0.dist-info → azure_ai_evaluation-1.8.0.dist-info}/METADATA +35 -3
  66. {azure_ai_evaluation-1.6.0.dist-info → azure_ai_evaluation-1.8.0.dist-info}/RECORD +69 -61
  67. {azure_ai_evaluation-1.6.0.dist-info → azure_ai_evaluation-1.8.0.dist-info}/NOTICE.txt +0 -0
  68. {azure_ai_evaluation-1.6.0.dist-info → azure_ai_evaluation-1.8.0.dist-info}/WHEEL +0 -0
  69. {azure_ai_evaluation-1.6.0.dist-info → azure_ai_evaluation-1.8.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,237 @@
1
+ # ---------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # ---------------------------------------------------------
4
+
5
+ """
6
+ This module provides Semantic Kernel Plugin for Red Team Tools.
7
+ These plugins can be used as functions in a Semantic Kernel agent for red teaming purposes.
8
+ """
9
+
10
+ import asyncio
11
+ import json
12
+ from typing import Annotated, Dict, Any, Optional, Callable
13
+
14
+ from semantic_kernel.functions import kernel_function
15
+
16
+ from azure.ai.evaluation.red_team._agent._agent_tools import RedTeamToolProvider
17
+ from azure.identity import DefaultAzureCredential
18
+
19
+ class RedTeamPlugin:
20
+ """
21
+ A Semantic Kernel plugin that provides red teaming capabilities.
22
+ This plugin wraps around the RedTeamToolProvider to provide red teaming functions
23
+ as Semantic Kernel functions.
24
+
25
+ Example:
26
+ ```python
27
+ # Method 1: Create a plugin with individual environment variables
28
+ plugin = RedTeamPlugin(
29
+ azure_ai_project_endpoint=os.environ.get("AZURE_AI_PROJECT_ENDPOINT"),
30
+ target_func=lambda x: "Target model response"
31
+ )
32
+
33
+ # Create a Semantic Kernel agent with the plugin
34
+ agent = ChatCompletionAgent(
35
+ service=service,
36
+ name="RedTeamAgent",
37
+ instructions="You are a red team agent...",
38
+ plugins=[plugin],
39
+ )
40
+ ```
41
+ """
42
+
43
+ def __init__(self, azure_ai_project_endpoint: str, target_func: Optional[Callable[[str], str]] = None, *,
44
+ application_scenario: str = "", **kwargs):
45
+ """
46
+ Initialize the RedTeamPlugin with the necessary configuration components.
47
+
48
+ :param azure_ai_project_endpoint: The Azure AI project endpoint (e.g., 'https://your-resource-name.services.ai.azure.com/api/projects/your-project-name')
49
+ :param target_func: Optional function to call with prompts
50
+ :param application_scenario: The application scenario for the tool provider
51
+ """
52
+
53
+ # Initialize credential and tool provider
54
+ self.credential = DefaultAzureCredential()
55
+ self.tool_provider = RedTeamToolProvider(
56
+ azure_ai_project_endpoint=azure_ai_project_endpoint,
57
+ credential=self.credential,
58
+ application_scenario=application_scenario
59
+ )
60
+
61
+ # Store the target function
62
+ self.target_function = target_func
63
+
64
+ # Dictionary to store fetched prompts for reference
65
+ self.fetched_prompts = {}
66
+
67
+ @kernel_function(description="Fetch a harmful prompt for a specific risk category to test content filters")
68
+ async def fetch_harmful_prompt(
69
+ self,
70
+ risk_category: Annotated[str, "The risk category (e.g., 'violence', 'hate_unfairness', 'sexual', 'self_harm')"],
71
+ strategy: Annotated[str, "Attack strategy to use (e.g., 'baseline', 'jailbreak')"] = "baseline",
72
+ convert_with_strategy: Annotated[str, "Optional strategy to convert the prompt"] = ""
73
+ ) -> Annotated[str, "A JSON string with the harmful prompt and metadata"]:
74
+ """
75
+ Fetch a harmful prompt for a specific risk category to test content filters.
76
+
77
+ :param risk_category: The risk category (e.g., 'violence', 'hate_unfairness', 'sexual', 'self_harm')
78
+ :param strategy: Attack strategy to use (e.g., 'baseline', 'jailbreak')
79
+ :param convert_with_strategy: Optional strategy to convert the prompt
80
+ :return: A JSON string with the harmful prompt and metadata
81
+ """
82
+ # Convert empty string to None
83
+ if not convert_with_strategy:
84
+ convert_with_strategy = None
85
+
86
+ # Directly await the async method instead of using asyncio.run()
87
+ result = await self.tool_provider.fetch_harmful_prompt(
88
+ risk_category_text=risk_category,
89
+ strategy=strategy,
90
+ convert_with_strategy=convert_with_strategy
91
+ )
92
+
93
+ # Store the prompt for later conversion if successful
94
+ if result["status"] == "success" and "prompt_id" in result:
95
+ prompt_id = result["prompt_id"]
96
+ if "prompt" in result:
97
+ self.fetched_prompts[prompt_id] = result["prompt"]
98
+ # Also update the tool provider's cache
99
+ self.tool_provider._fetched_prompts[prompt_id] = result["prompt"]
100
+
101
+ return json.dumps(result)
102
+
103
+ @kernel_function(description="Convert a prompt using a specified strategy")
104
+ async def convert_prompt(
105
+ self,
106
+ prompt_or_id: Annotated[str, "Either a prompt text or a prompt ID from a previous fetch"],
107
+ strategy: Annotated[str, "The strategy to use for conversion"]
108
+ ) -> Annotated[str, "A JSON string with the original and converted prompt"]:
109
+ """
110
+ Convert a prompt or a previously fetched prompt ID using a specified strategy.
111
+
112
+ :param prompt_or_id: Either a prompt text or a prompt ID from a previous fetch
113
+ :param strategy: The strategy to use for conversion
114
+ :return: A JSON string with the original and converted prompt
115
+ """
116
+ # Check if input is a prompt ID we have stored
117
+ if prompt_or_id in self.fetched_prompts:
118
+ # Update the provider's cache
119
+ self.tool_provider._fetched_prompts[prompt_or_id] = self.fetched_prompts[prompt_or_id]
120
+
121
+ # Directly await the async method instead of using asyncio.run()
122
+ result = await self.tool_provider.convert_prompt(
123
+ prompt_or_id=prompt_or_id,
124
+ strategy=strategy
125
+ )
126
+
127
+ return json.dumps(result)
128
+
129
+ @kernel_function(description="Get a harmful prompt for a specific risk category and optionally convert it")
130
+ async def red_team_unified(
131
+ self,
132
+ category: Annotated[str, "The risk category (e.g., 'violence', 'hate_unfairness', 'sexual', 'self_harm')"],
133
+ strategy: Annotated[str, "Optional strategy to convert the prompt"] = ""
134
+ ) -> Annotated[str, "A JSON string with the harmful prompt and metadata"]:
135
+ """
136
+ Get a harmful prompt for a specific risk category and optionally convert it.
137
+
138
+ :param category: The risk category (e.g., 'violence', 'hate_unfairness', 'sexual', 'self_harm')
139
+ :param strategy: Optional strategy to convert the prompt
140
+ :return: A JSON string with the harmful prompt and metadata
141
+ """
142
+ # Convert empty string to None
143
+ strategy_param = strategy if strategy else None
144
+
145
+ # Directly await the async method instead of using asyncio.run()
146
+ result = await self.tool_provider.red_team(
147
+ category=category,
148
+ strategy=strategy_param
149
+ )
150
+
151
+ # Store the prompt for later conversion if it's a success and we didn't convert it
152
+ if result["status"] == "success":
153
+ if "prompt_id" in result and "prompt" in result:
154
+ prompt_id = result["prompt_id"]
155
+ self.fetched_prompts[prompt_id] = result["prompt"]
156
+ # Also update the tool provider's cache
157
+ self.tool_provider._fetched_prompts[prompt_id] = result["prompt"]
158
+
159
+ return json.dumps(result)
160
+
161
+ @kernel_function(description="Get a list of all available prompt conversion strategies")
162
+ async def get_available_strategies(self) -> Annotated[str, "A JSON string with available conversion strategies"]:
163
+ """
164
+ Get a list of all available prompt conversion strategies.
165
+
166
+ :return: A JSON string with available conversion strategies
167
+ """
168
+ # This method calls a synchronous function, but we make the method itself async
169
+ # for consistency with the rest of the interface
170
+ strategies = self.tool_provider.get_available_strategies()
171
+
172
+ return json.dumps({
173
+ "status": "success",
174
+ "available_strategies": strategies
175
+ })
176
+
177
+ @kernel_function(description="Explain the purpose and responsible use of red teaming tools")
178
+ async def explain_purpose(self) -> Annotated[str, "A JSON string with information about red teaming tools"]:
179
+ """
180
+ Explain the purpose and responsible use of red teaming tools.
181
+
182
+ :return: A JSON string with information about red teaming tools
183
+ """
184
+ # This method doesn't use any async functions, but we make it async
185
+ # for consistency with the rest of the interface
186
+ explanation = {
187
+ "purpose": "Red teaming tools are designed to test AI systems for vulnerabilities and safety issues.",
188
+ "responsible_use": [
189
+ "Only use these tools on systems you have permission to test.",
190
+ "Use the results to improve system safety and robustness.",
191
+ "Do not use these tools to cause harm or bypass legitimate safety measures in production systems."
192
+ ],
193
+ "risk_categories": {
194
+ "violence": "Content related to physical harm, weapons, or dangerous activities",
195
+ "hate_unfairness": "Content related to discrimination, bias, or prejudice",
196
+ "sexual": "Explicit sexual content",
197
+ "self_harm": "Content related to suicide, self-injury, or harmful behaviors"
198
+ },
199
+ "conversion_strategies": "Various encoding and obfuscation methods to test if harmful content can bypass detection"
200
+ }
201
+
202
+ return json.dumps(explanation)
203
+
204
+ @kernel_function(description="Send a prompt to the target function and return the response")
205
+ async def send_to_target(
206
+ self,
207
+ prompt: Annotated[str, "The prompt text to send to the target function"]
208
+ ) -> Annotated[str, "A JSON string with the response from the target"]:
209
+ """
210
+ Send a prompt to the target function and return the response.
211
+
212
+ :param prompt: The prompt text to send to the target function
213
+ :return: A JSON string with the response from the target
214
+ """
215
+ # This method doesn't use any async functions, but we make it async
216
+ # for consistency with the rest of the interface
217
+ if self.target_function is None:
218
+ return json.dumps({
219
+ "status": "error",
220
+ "message": "Target function not initialized. Make sure to pass a target_func when initializing the plugin."
221
+ })
222
+
223
+ try:
224
+ # Call the target function with the prompt
225
+ response = self.target_function(prompt)
226
+
227
+ return json.dumps({
228
+ "status": "success",
229
+ "prompt": prompt,
230
+ "response": response
231
+ })
232
+ except Exception as e:
233
+ return json.dumps({
234
+ "status": "error",
235
+ "message": f"Error calling target function: {str(e)}",
236
+ "prompt": prompt
237
+ })
@@ -34,6 +34,8 @@ class AttackStrategy(Enum):
34
34
  Url = "url"
35
35
  Baseline = "baseline"
36
36
  Jailbreak = "jailbreak"
37
+ MultiTurn = "multi_turn"
38
+ Crescendo = "crescendo"
37
39
 
38
40
  @classmethod
39
41
  def Compose(cls, items: List["AttackStrategy"]) -> List["AttackStrategy"]: