mirror of
https://github.com/dongdongunique/EvoSynth.git
synced 2026-07-17 09:37:29 +02:00
first commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
from . import keyword_evaluator
|
||||
from . import judge_evaluator
|
||||
from . import grouped_evaluator
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,131 @@
|
||||
# jailbreak_toolbox/evaluators/implementations/grouped_evaluator.py
|
||||
from typing import List, Dict, Any, Optional, Callable
|
||||
from collections import defaultdict
|
||||
from ..multi_thread_evaluator import MultiThreadedEvaluator
|
||||
from ...attacks.base_attack import AttackResult
|
||||
from jailbreak_toolbox.evaluators.base_evaluator import EvaluationMetrics
|
||||
from ...core.registry import evaluator_registry
|
||||
from jailbreak_toolbox.judges.base_judge import BaseJudge
|
||||
|
||||
@evaluator_registry.register("grouped")
|
||||
class GroupedEvaluator(MultiThreadedEvaluator):
|
||||
"""
|
||||
Evaluator that groups results by a specified attribute (e.g., attack method).
|
||||
|
||||
This allows comparing the effectiveness of different attack methods.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
group_by: str = "method",
|
||||
judge: BaseJudge = None,
|
||||
max_workers: int = 5,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
Initialize the grouped evaluator.
|
||||
|
||||
Args:
|
||||
group_by: Attack result attribute to group by
|
||||
judge: Judge to evaluate responses
|
||||
max_workers: Maximum number of worker threads
|
||||
"""
|
||||
super().__init__(max_workers=max_workers, **kwargs)
|
||||
self.group_by = group_by
|
||||
self.judge = judge
|
||||
assert self.judge is not None, "Judge must be provided"
|
||||
|
||||
def evaluate(self, results: List[AttackResult]) -> Dict[str, Any]:
|
||||
"""
|
||||
Evaluate attack results grouped by the specified attribute.
|
||||
|
||||
Args:
|
||||
results: List of attack results to evaluate
|
||||
|
||||
Returns:
|
||||
Dictionary containing:
|
||||
- overall: Overall evaluation metrics
|
||||
- by_group: Metrics broken down by group
|
||||
"""
|
||||
if not results:
|
||||
return {
|
||||
"overall": EvaluationMetrics(attack_success_rate=0.0, average_attack_score=0.0),
|
||||
"by_group": {}
|
||||
}
|
||||
|
||||
# Group results
|
||||
grouped_results = defaultdict(list)
|
||||
for result in results:
|
||||
group = self._get_group(result)
|
||||
grouped_results[group].append(result)
|
||||
|
||||
# Evaluate each group
|
||||
group_metrics = {}
|
||||
overall_success_count=0
|
||||
for group, group_results in grouped_results.items():
|
||||
metrics = super().evaluate(group_results)
|
||||
group_metrics[group] = metrics
|
||||
overall_success_count+= metrics.attack_success_rate*len(group_results)
|
||||
|
||||
# Calculate overall metrics
|
||||
# overall_success_count = sum(1 for result in results if result.success)
|
||||
overall_success_rate = overall_success_count / len(results)
|
||||
|
||||
return {
|
||||
"overall": EvaluationMetrics(
|
||||
attack_success_rate=overall_success_rate,
|
||||
average_attack_score=0.0 # We don't calculate this for overall
|
||||
),
|
||||
"by_group": group_metrics
|
||||
}
|
||||
|
||||
def _get_group(self, result: AttackResult) -> str:
|
||||
"""
|
||||
Get the group identifier for a result.
|
||||
|
||||
Args:
|
||||
result: Attack result
|
||||
|
||||
Returns:
|
||||
Group identifier
|
||||
"""
|
||||
# First, check if the method attribute is directly set on the AttackResult
|
||||
if hasattr(result, "method") and result.method:
|
||||
return str(result.method)
|
||||
|
||||
# If not, try to get the group from history
|
||||
if result.history and len(result.history) > 0:
|
||||
history_item = result.history[0]
|
||||
if isinstance(history_item, dict) and self.group_by in history_item:
|
||||
return str(history_item[self.group_by])
|
||||
|
||||
# Try to get from original_record if available
|
||||
if hasattr(result, "original_record") and self.group_by in result.original_record:
|
||||
return str(result.original_record[self.group_by])
|
||||
|
||||
# Default to unknown group
|
||||
return "unknown"
|
||||
|
||||
def _evaluate_single(self, result: AttackResult) -> tuple:
|
||||
"""
|
||||
Evaluate a single attack result.
|
||||
|
||||
Args:
|
||||
result: Attack result to evaluate
|
||||
|
||||
Returns:
|
||||
Tuple of (success, score)
|
||||
"""
|
||||
# success = result.success
|
||||
success = False
|
||||
|
||||
# If we have a judge, use it to evaluate
|
||||
if self.judge and not success:
|
||||
scores, _ = self.judge.judge_prompt([result.target], result.output_text)
|
||||
success = self.judge.is_success(scores)
|
||||
score = scores if scores else 0.0
|
||||
else:
|
||||
score = 5.0 if success else 0.0
|
||||
|
||||
# print(success, score)
|
||||
return (success, score)
|
||||
@@ -0,0 +1,74 @@
|
||||
from ..base_evaluator import BaseEvaluator, EvaluationMetrics
|
||||
from ...attacks.base_attack import AttackResult
|
||||
from ...judges.base_judge import BaseJudge
|
||||
from ...core.registry import evaluator_registry
|
||||
from typing import List
|
||||
|
||||
@evaluator_registry.register("judge")
|
||||
class JudgeEvaluator(BaseEvaluator):
|
||||
"""
|
||||
An evaluator that uses a judge to evaluate attack results.
|
||||
|
||||
This evaluator delegates the evaluation of attack success to a provided judge,
|
||||
which makes the determination based on the content of the model's responses.
|
||||
"""
|
||||
|
||||
def __init__(self, judge: BaseJudge, **kwargs):
|
||||
"""
|
||||
Initialize the JudgeEvaluator.
|
||||
|
||||
Args:
|
||||
judge: The judge to use for evaluating responses
|
||||
**kwargs: Additional keyword arguments
|
||||
"""
|
||||
super().__init__(**kwargs)
|
||||
self.judge = judge
|
||||
self.verbose = kwargs.get("verbose", False)
|
||||
|
||||
def evaluate(self, results: List[AttackResult]) -> EvaluationMetrics:
|
||||
"""
|
||||
Evaluate the success of attacks using the provided judge.
|
||||
|
||||
Args:
|
||||
results: List of attack results to evaluate
|
||||
|
||||
Returns:
|
||||
EvaluationMetrics containing attack success rate and other metrics
|
||||
"""
|
||||
if not results:
|
||||
return EvaluationMetrics(attack_success_rate=0.0)
|
||||
|
||||
total_attacks = len(results)
|
||||
successful_attacks = 0
|
||||
total_scores = 0.0
|
||||
for result in results:
|
||||
# Set success to False initially since we're re-evaluating
|
||||
|
||||
|
||||
# Skip if no final prompt or output
|
||||
if not result.final_prompt or not result.output_text:
|
||||
continue
|
||||
if(result.success== False):
|
||||
# Use the judge to evaluate the response
|
||||
score,_ = self.judge.judge_prompt(result.final_prompt, result.output_text)
|
||||
success = self.judge.is_success(score)
|
||||
# Update the result with the judge's evaluation
|
||||
result.success = success
|
||||
total_scores += score
|
||||
else:
|
||||
success=1
|
||||
total_scores+=self.judge.success_threshold
|
||||
if success:
|
||||
successful_attacks += 1
|
||||
|
||||
if self.verbose:
|
||||
print(f"Attack evaluated as {'successful' if success else 'failed'}")
|
||||
|
||||
# Calculate attack success rate
|
||||
attack_success_rate = successful_attacks / total_attacks if total_attacks > 0 else 0.0
|
||||
attack_average_score = total_scores / total_attacks if total_attacks > 0 else 0.0
|
||||
if self.verbose:
|
||||
print(f"Average score across all attacks: {attack_average_score:.2f}")
|
||||
if self.verbose:
|
||||
print(f"Total attacks: {total_attacks}, Successful attacks: {successful_attacks}, ASR: {attack_success_rate:.2%}")
|
||||
return EvaluationMetrics(attack_success_rate=attack_success_rate,average_attack_score=attack_average_score)
|
||||
Reference in New Issue
Block a user