datarobot-moderations 11.1.14__py3-none-any.whl → 11.1.16__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.
- datarobot_dome/constants.py +2 -0
- datarobot_dome/drum_integration.py +38 -1
- datarobot_dome/guard.py +90 -8
- datarobot_dome/guard_executor.py +20 -2
- datarobot_dome/guard_helpers.py +16 -17
- datarobot_dome/guards/guard_llm_mixin.py +40 -8
- {datarobot_moderations-11.1.14.dist-info → datarobot_moderations-11.1.16.dist-info}/METADATA +1 -1
- {datarobot_moderations-11.1.14.dist-info → datarobot_moderations-11.1.16.dist-info}/RECORD +9 -9
- {datarobot_moderations-11.1.14.dist-info → datarobot_moderations-11.1.16.dist-info}/WHEEL +0 -0
datarobot_dome/constants.py
CHANGED
|
@@ -69,6 +69,8 @@ LLM_CONTEXT_COLUMN_NAME = "_LLM_CONTEXT"
|
|
|
69
69
|
PROMPT_TOKEN_COUNT_COLUMN_NAME_FROM_USAGE = "prompt_token_count_from_usage"
|
|
70
70
|
RESPONSE_TOKEN_COUNT_COLUMN_NAME_FROM_USAGE = "response_token_count_from_usage"
|
|
71
71
|
|
|
72
|
+
SPAN_PREFIX = "datarobot.guard"
|
|
73
|
+
|
|
72
74
|
|
|
73
75
|
class TargetType(str, Enum):
|
|
74
76
|
"""Target types that may be handed to moderations from DRUM -- casing must align."""
|
|
@@ -26,6 +26,7 @@ from openai.types.chat import ChatCompletionChunk
|
|
|
26
26
|
from openai.types.chat.chat_completion import ChatCompletion
|
|
27
27
|
from openai.types.chat.chat_completion import Choice
|
|
28
28
|
from openai.types.chat.chat_completion_message import ChatCompletionMessage
|
|
29
|
+
from opentelemetry import trace
|
|
29
30
|
|
|
30
31
|
from datarobot_dome.chat_helper import add_citations_to_df
|
|
31
32
|
from datarobot_dome.chat_helper import add_token_count_columns_to_df
|
|
@@ -57,6 +58,9 @@ from datarobot_dome.pipeline.vdb_pipeline import VDBPipeline
|
|
|
57
58
|
from datarobot_dome.streaming import ModerationIterator
|
|
58
59
|
from datarobot_dome.streaming import StreamingContextBuilder
|
|
59
60
|
|
|
61
|
+
tracer = trace.get_tracer(__name__)
|
|
62
|
+
|
|
63
|
+
|
|
60
64
|
_logger = logging.getLogger("drum_integration")
|
|
61
65
|
|
|
62
66
|
|
|
@@ -508,7 +512,7 @@ def build_predictions_df_from_completion(data, pipeline, chat_completion):
|
|
|
508
512
|
if pipeline_interactions:
|
|
509
513
|
predictions_df[AGENTIC_PIPELINE_INTERACTIONS_ATTR] = pipeline_interactions
|
|
510
514
|
else:
|
|
511
|
-
predictions_df[AGENTIC_PIPELINE_INTERACTIONS_ATTR] = [
|
|
515
|
+
predictions_df[AGENTIC_PIPELINE_INTERACTIONS_ATTR] = [None] * len(predictions_df)
|
|
512
516
|
|
|
513
517
|
source_object = chat_completion
|
|
514
518
|
elif isinstance(chat_completion, Iterable):
|
|
@@ -661,6 +665,37 @@ def _is_llm_requesting_user_tool_call(completion):
|
|
|
661
665
|
return False, completion
|
|
662
666
|
|
|
663
667
|
|
|
668
|
+
def __get_otel_values(guards_list, stage, result_df):
|
|
669
|
+
guard_values = {}
|
|
670
|
+
for guard in guards_list:
|
|
671
|
+
if not guard.has_average_score_custom_metric():
|
|
672
|
+
continue
|
|
673
|
+
guard_metric_column_name = guard.get_metric_column_name(stage)
|
|
674
|
+
if guard_metric_column_name not in result_df.columns:
|
|
675
|
+
_logger.warning(f"Missing column: {guard_metric_column_name} in result_df")
|
|
676
|
+
continue
|
|
677
|
+
guard_values[guard.get_span_column_name(stage)] = result_df[
|
|
678
|
+
guard_metric_column_name
|
|
679
|
+
].tolist()[0]
|
|
680
|
+
return guard_values
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
def report_otel_evaluation_set_metric(pipeline, result_df):
|
|
684
|
+
current_span = trace.get_current_span()
|
|
685
|
+
if not current_span:
|
|
686
|
+
_logger.warning("No currently active span found to report evaluation set metric")
|
|
687
|
+
return
|
|
688
|
+
|
|
689
|
+
prompt_values = __get_otel_values(pipeline.get_prescore_guards(), GuardStage.PROMPT, result_df)
|
|
690
|
+
response_values = __get_otel_values(
|
|
691
|
+
pipeline.get_postscore_guards(), GuardStage.RESPONSE, result_df
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
final_value = {"prompt_guards": prompt_values, "response_guards": response_values}
|
|
695
|
+
|
|
696
|
+
current_span.set_attribute("datarobot.moderation.evaluation", json.dumps(final_value))
|
|
697
|
+
|
|
698
|
+
|
|
664
699
|
def guard_chat_wrapper(
|
|
665
700
|
completion_create_params, model, pipeline, drum_chat_fn, association_id=None, **kwargs
|
|
666
701
|
):
|
|
@@ -723,6 +758,7 @@ def guard_chat_wrapper(
|
|
|
723
758
|
completion = _set_moderation_attribute_to_completion(
|
|
724
759
|
pipeline, chat_completion, result_df, association_id=association_id
|
|
725
760
|
)
|
|
761
|
+
report_otel_evaluation_set_metric(pipeline, result_df)
|
|
726
762
|
return completion
|
|
727
763
|
|
|
728
764
|
replaced_prompt_column_name = f"replaced_{prompt_column_name}"
|
|
@@ -802,6 +838,7 @@ def guard_chat_wrapper(
|
|
|
802
838
|
) / result_df.shape[0]
|
|
803
839
|
|
|
804
840
|
response_message, finish_reason = get_response_message_and_finish_reason(pipeline, postscore_df)
|
|
841
|
+
report_otel_evaluation_set_metric(pipeline, result_df)
|
|
805
842
|
|
|
806
843
|
final_completion = build_non_streaming_chat_completion(
|
|
807
844
|
response_message, finish_reason, extra_attributes
|
datarobot_dome/guard.py
CHANGED
|
@@ -35,6 +35,7 @@ from datarobot_dome.constants import FAITHFULLNESS_COLUMN_NAME
|
|
|
35
35
|
from datarobot_dome.constants import NEMO_GUARD_COLUMN_NAME
|
|
36
36
|
from datarobot_dome.constants import NEMO_GUARDRAILS_DIR
|
|
37
37
|
from datarobot_dome.constants import ROUGE_1_COLUMN_NAME
|
|
38
|
+
from datarobot_dome.constants import SPAN_PREFIX
|
|
38
39
|
from datarobot_dome.constants import TASK_ADHERENCE_SCORE_COLUMN_NAME
|
|
39
40
|
from datarobot_dome.constants import TOKEN_COUNT_COLUMN_NAME
|
|
40
41
|
from datarobot_dome.constants import AwsModel
|
|
@@ -48,11 +49,13 @@ from datarobot_dome.constants import GuardStage
|
|
|
48
49
|
from datarobot_dome.constants import GuardTimeoutAction
|
|
49
50
|
from datarobot_dome.constants import GuardType
|
|
50
51
|
from datarobot_dome.constants import OOTBType
|
|
52
|
+
from datarobot_dome.guard_helpers import DEFAULT_OPEN_AI_API_VERSION
|
|
51
53
|
from datarobot_dome.guard_helpers import ModerationDeepEvalLLM
|
|
52
54
|
from datarobot_dome.guard_helpers import get_azure_openai_client
|
|
53
55
|
from datarobot_dome.guard_helpers import get_chat_nvidia_llm
|
|
54
56
|
from datarobot_dome.guard_helpers import get_datarobot_endpoint_and_token
|
|
55
|
-
from datarobot_dome.guard_helpers import
|
|
57
|
+
from datarobot_dome.guard_helpers import get_llm_gateway_client
|
|
58
|
+
from datarobot_dome.guard_helpers import use_llm_gateway_inference
|
|
56
59
|
from datarobot_dome.guards.guard_llm_mixin import GuardLLMMixin
|
|
57
60
|
|
|
58
61
|
MAX_GUARD_NAME_LENGTH = 255
|
|
@@ -141,6 +144,7 @@ guard_intervention_trafaret = t.Dict(
|
|
|
141
144
|
additional_guard_config_trafaret = t.Dict(
|
|
142
145
|
{
|
|
143
146
|
t.Key("cost", to_name="cost", optional=True): t.Or(cost_metric_trafaret, t.Null),
|
|
147
|
+
t.Key("tool_call", to_name="tool_call", optional=True): t.Or(t.Any(), t.Null),
|
|
144
148
|
}
|
|
145
149
|
)
|
|
146
150
|
|
|
@@ -366,6 +370,21 @@ class Guard(ABC):
|
|
|
366
370
|
def get_comparand(self):
|
|
367
371
|
return self.intervention.threshold
|
|
368
372
|
|
|
373
|
+
def get_enforced_span_attribute_name(self, stage):
|
|
374
|
+
intervention_action = self.get_intervention_action()
|
|
375
|
+
if intervention_action in [GuardAction.BLOCK, GuardAction.REPORT]:
|
|
376
|
+
return f"{SPAN_PREFIX}.{stage.lower()}.{intervention_action}ed"
|
|
377
|
+
elif intervention_action == GuardAction.REPLACE:
|
|
378
|
+
return f"{SPAN_PREFIX}.{stage.lower()}.replaced"
|
|
379
|
+
else:
|
|
380
|
+
raise NotImplementedError
|
|
381
|
+
|
|
382
|
+
def get_span_column_name(self, _):
|
|
383
|
+
raise NotImplementedError
|
|
384
|
+
|
|
385
|
+
def get_span_attribute_name(self, _):
|
|
386
|
+
raise NotImplementedError
|
|
387
|
+
|
|
369
388
|
|
|
370
389
|
class GuardModelInfo:
|
|
371
390
|
def __init__(self, model_config: dict):
|
|
@@ -434,6 +453,15 @@ class ModelGuard(Guard):
|
|
|
434
453
|
raise NotImplementedError("Missing model_info for model guard")
|
|
435
454
|
return self.get_stage_str(stage) + "_" + self._model_info.target_name
|
|
436
455
|
|
|
456
|
+
def get_span_column_name(self, _):
|
|
457
|
+
if self.model_info is None:
|
|
458
|
+
raise NotImplementedError("Missing model_info for model guard")
|
|
459
|
+
# Typically 0th index is the target name
|
|
460
|
+
return self._model_info.target_name.split("_")[0]
|
|
461
|
+
|
|
462
|
+
def get_span_attribute_name(self, stage):
|
|
463
|
+
return f"{SPAN_PREFIX}.{stage.lower()}.{self.get_span_column_name(stage)}"
|
|
464
|
+
|
|
437
465
|
def has_average_score_custom_metric(self) -> bool:
|
|
438
466
|
"""A couple ModelGuard types do not have an average score metric"""
|
|
439
467
|
return self.model_info.target_type not in [
|
|
@@ -459,12 +487,18 @@ class NeMoGuard(Guard, GuardLLMMixin):
|
|
|
459
487
|
self.openai_api_base = config.get("openai_api_base")
|
|
460
488
|
self.openai_deployment_id = config.get("openai_deployment_id")
|
|
461
489
|
llm_id = None
|
|
490
|
+
credentials = None
|
|
491
|
+
use_llm_gateway = use_llm_gateway_inference(self._llm_type)
|
|
462
492
|
try:
|
|
463
493
|
self.openai_api_key = self.get_openai_api_key(config, self._llm_type)
|
|
464
494
|
if self._llm_type != GuardLLMType.NIM and self.openai_api_key is None:
|
|
465
495
|
raise ValueError("OpenAI API key is required for NeMo Guardrails")
|
|
466
496
|
|
|
467
497
|
if self.llm_type == GuardLLMType.OPENAI:
|
|
498
|
+
credentials = {
|
|
499
|
+
"credential_type": "openai",
|
|
500
|
+
"api_key": self.openai_api_key,
|
|
501
|
+
}
|
|
468
502
|
os.environ["OPENAI_API_KEY"] = self.openai_api_key
|
|
469
503
|
llm = None
|
|
470
504
|
elif self.llm_type == GuardLLMType.AZURE_OPENAI:
|
|
@@ -472,6 +506,12 @@ class NeMoGuard(Guard, GuardLLMMixin):
|
|
|
472
506
|
raise ValueError("Azure OpenAI API base url is required for LLM Guard")
|
|
473
507
|
if self.openai_deployment_id is None:
|
|
474
508
|
raise ValueError("Azure OpenAI deployment ID is required for LLM Guard")
|
|
509
|
+
credentials = {
|
|
510
|
+
"credential_type": "azure_openai",
|
|
511
|
+
"api_base": self.openai_api_base,
|
|
512
|
+
"api_version": DEFAULT_OPEN_AI_API_VERSION,
|
|
513
|
+
"api_key": self.openai_api_key,
|
|
514
|
+
}
|
|
475
515
|
azure_openai_client = get_azure_openai_client(
|
|
476
516
|
openai_api_key=self.openai_api_key,
|
|
477
517
|
openai_api_base=self.openai_api_base,
|
|
@@ -512,15 +552,20 @@ class NeMoGuard(Guard, GuardLLMMixin):
|
|
|
512
552
|
raise ValueError(f"Invalid LLMType: {self.llm_type}")
|
|
513
553
|
|
|
514
554
|
except Exception as e:
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
555
|
+
# no valid user credentials provided, raise if not using LLM Gateway
|
|
556
|
+
credentials = None
|
|
557
|
+
if not use_llm_gateway:
|
|
558
|
+
raise e
|
|
559
|
+
|
|
560
|
+
if use_llm_gateway:
|
|
561
|
+
# Currently only OPENAI and AZURE_OPENAI are supported by NeMoGuard
|
|
562
|
+
# For Bedrock and Vertex the model in the config is actually the LLM ID
|
|
563
|
+
# For OpenAI we use the default model defined in get_llm_gateway_client
|
|
564
|
+
# For Azure we use the deployment ID
|
|
565
|
+
llm = get_llm_gateway_client(
|
|
520
566
|
llm_id=llm_id,
|
|
521
567
|
openai_deployment_id=self.openai_deployment_id,
|
|
522
|
-
|
|
523
|
-
e=e,
|
|
568
|
+
credentials=credentials,
|
|
524
569
|
)
|
|
525
570
|
|
|
526
571
|
# Use guard stage to determine whether to read from prompt/response subdirectory
|
|
@@ -566,6 +611,19 @@ class OOTBGuard(Guard):
|
|
|
566
611
|
else:
|
|
567
612
|
raise NotImplementedError(f"No metric column name defined for {self._ootb_type} guard")
|
|
568
613
|
|
|
614
|
+
def get_span_column_name(self, _):
|
|
615
|
+
if self._ootb_type == OOTBType.TOKEN_COUNT:
|
|
616
|
+
return TOKEN_COUNT_COLUMN_NAME
|
|
617
|
+
elif self._ootb_type == OOTBType.ROUGE_1:
|
|
618
|
+
return ROUGE_1_COLUMN_NAME
|
|
619
|
+
elif self._ootb_type == OOTBType.CUSTOM_METRIC:
|
|
620
|
+
return self.name
|
|
621
|
+
else:
|
|
622
|
+
raise NotImplementedError(f"No span attribute name defined for {self._ootb_type} guard")
|
|
623
|
+
|
|
624
|
+
def get_span_attribute_name(self, stage):
|
|
625
|
+
return f"{SPAN_PREFIX}.{stage.lower()}.{self.get_span_column_name(stage)}"
|
|
626
|
+
|
|
569
627
|
|
|
570
628
|
class OOTBCostMetric(OOTBGuard):
|
|
571
629
|
def __init__(self, config, stage):
|
|
@@ -603,6 +661,12 @@ class OOTBCostMetric(OOTBGuard):
|
|
|
603
661
|
),
|
|
604
662
|
}
|
|
605
663
|
|
|
664
|
+
def get_span_column_name(self, _):
|
|
665
|
+
return f"{COST_COLUMN_NAME}.{self.currency.lower()}"
|
|
666
|
+
|
|
667
|
+
def get_span_attribute_name(self, _):
|
|
668
|
+
return f"{SPAN_PREFIX}.{self._stage.lower()}.{self.get_span_column_name(_)}"
|
|
669
|
+
|
|
606
670
|
|
|
607
671
|
class FaithfulnessGuard(OOTBGuard, GuardLLMMixin):
|
|
608
672
|
def __init__(self, config: dict, stage=None):
|
|
@@ -624,6 +688,12 @@ class FaithfulnessGuard(OOTBGuard, GuardLLMMixin):
|
|
|
624
688
|
def faithfulness_evaluator(self):
|
|
625
689
|
return self._evaluator
|
|
626
690
|
|
|
691
|
+
def get_span_column_name(self, _):
|
|
692
|
+
return FAITHFULLNESS_COLUMN_NAME
|
|
693
|
+
|
|
694
|
+
def get_span_attribute_name(self, _):
|
|
695
|
+
return f"{SPAN_PREFIX}.{self._stage.lower()}.{self.get_span_column_name(_)}"
|
|
696
|
+
|
|
627
697
|
|
|
628
698
|
class AgentGoalAccuracyGuard(OOTBGuard, GuardLLMMixin):
|
|
629
699
|
def __init__(self, config: dict, stage=None):
|
|
@@ -645,6 +715,12 @@ class AgentGoalAccuracyGuard(OOTBGuard, GuardLLMMixin):
|
|
|
645
715
|
def accuracy_scorer(self):
|
|
646
716
|
return self.scorer
|
|
647
717
|
|
|
718
|
+
def get_span_column_name(self, _):
|
|
719
|
+
return AGENT_GOAL_ACCURACY_COLUMN_NAME
|
|
720
|
+
|
|
721
|
+
def get_span_attribute_name(self, _):
|
|
722
|
+
return f"{SPAN_PREFIX}.{self._stage.lower()}.{self.get_span_column_name(_)}"
|
|
723
|
+
|
|
648
724
|
|
|
649
725
|
class TaskAdherenceGuard(OOTBGuard, GuardLLMMixin):
|
|
650
726
|
def __init__(self, config: dict, stage=None):
|
|
@@ -666,6 +742,12 @@ class TaskAdherenceGuard(OOTBGuard, GuardLLMMixin):
|
|
|
666
742
|
def task_adherence_scorer(self):
|
|
667
743
|
return self.scorer
|
|
668
744
|
|
|
745
|
+
def get_span_column_name(self, _):
|
|
746
|
+
return TASK_ADHERENCE_SCORE_COLUMN_NAME
|
|
747
|
+
|
|
748
|
+
def get_span_attribute_name(self, _):
|
|
749
|
+
return f"{SPAN_PREFIX}.{self._stage.lower()}.{self.get_span_column_name(_)}"
|
|
750
|
+
|
|
669
751
|
|
|
670
752
|
class GuardFactory:
|
|
671
753
|
@classmethod
|
datarobot_dome/guard_executor.py
CHANGED
|
@@ -34,7 +34,6 @@ from datarobot_dome.constants import ModerationEventTypes
|
|
|
34
34
|
from datarobot_dome.constants import OOTBType
|
|
35
35
|
from datarobot_dome.guard import AgentGoalAccuracyGuard
|
|
36
36
|
from datarobot_dome.guard import FaithfulnessGuard
|
|
37
|
-
from datarobot_dome.guard import Guard
|
|
38
37
|
from datarobot_dome.guard import ModelGuard
|
|
39
38
|
from datarobot_dome.guard import NeMoGuard
|
|
40
39
|
from datarobot_dome.guard import OOTBCostMetric
|
|
@@ -113,6 +112,25 @@ class AsyncGuardExecutor:
|
|
|
113
112
|
span.set_attribute("datarobot.moderation.guard.latency", latency)
|
|
114
113
|
if guard.has_latency_custom_metric():
|
|
115
114
|
self.pipeline.report_guard_latency(guard, latency)
|
|
115
|
+
if guard.has_average_score_custom_metric():
|
|
116
|
+
metric_column_name = guard.get_metric_column_name(stage)
|
|
117
|
+
if metric_column_name in df.columns:
|
|
118
|
+
span.set_attribute(
|
|
119
|
+
guard.get_span_attribute_name(stage),
|
|
120
|
+
df[metric_column_name].tolist()[0],
|
|
121
|
+
)
|
|
122
|
+
if guard.get_intervention_action():
|
|
123
|
+
(
|
|
124
|
+
enforced_column_name,
|
|
125
|
+
_,
|
|
126
|
+
_,
|
|
127
|
+
) = self._get_enforced_and_action_column_names(
|
|
128
|
+
guard.get_intervention_action(), self.pipeline.get_input_column(stage)
|
|
129
|
+
)
|
|
130
|
+
span.set_attribute(
|
|
131
|
+
guard.get_enforced_span_attribute_name(stage),
|
|
132
|
+
df[enforced_column_name].tolist()[0],
|
|
133
|
+
)
|
|
116
134
|
|
|
117
135
|
return df, latency
|
|
118
136
|
|
|
@@ -204,7 +222,7 @@ class AsyncGuardExecutor:
|
|
|
204
222
|
# and "Response_toxicity_toxic_PREDICTION", if toxicity is configured for both
|
|
205
223
|
# prompts and responses
|
|
206
224
|
copy_df.rename(
|
|
207
|
-
columns={metric_column:
|
|
225
|
+
columns={metric_column: guard.get_metric_column_name(stage)},
|
|
208
226
|
inplace=True,
|
|
209
227
|
)
|
|
210
228
|
except Exception as ex:
|
datarobot_dome/guard_helpers.py
CHANGED
|
@@ -47,7 +47,7 @@ from datarobot_dome.llm import DataRobotLLM
|
|
|
47
47
|
# but for ROUGE-1 guard, UI allows the user to configure value between
|
|
48
48
|
# 0 and 1, so making scaling factor 1.
|
|
49
49
|
SCALING_FACTOR = 1
|
|
50
|
-
DEFAULT_OPEN_AI_API_VERSION = "
|
|
50
|
+
DEFAULT_OPEN_AI_API_VERSION = "2024-10-21"
|
|
51
51
|
|
|
52
52
|
_logger = logging.getLogger(LOGGER_NAME_PREFIX + ".guard_helpers")
|
|
53
53
|
|
|
@@ -195,8 +195,10 @@ def get_llm_gateway_client(
|
|
|
195
195
|
model: str | None = None,
|
|
196
196
|
llm_id: str | None = None,
|
|
197
197
|
openai_deployment_id: str | None = None,
|
|
198
|
+
credentials: dict | None = None,
|
|
198
199
|
) -> ChatOpenAI:
|
|
199
200
|
"""The LLM gateway client enables chat completions with DR provided credentials and metering.
|
|
201
|
+
User provided credentials are optional and passed to the completion request as json string.
|
|
200
202
|
|
|
201
203
|
Providing model is always required due to openai's chat api.
|
|
202
204
|
llm_id and deployment_id override model if provided.
|
|
@@ -208,7 +210,8 @@ def get_llm_gateway_client(
|
|
|
208
210
|
model=model or "azure/gpt-4o",
|
|
209
211
|
api_key=datarobot_api_token,
|
|
210
212
|
base_url=f"{datarobot_endpoint}/genai/llmgw",
|
|
211
|
-
|
|
213
|
+
# retries are handled by the LLM Gateway
|
|
214
|
+
max_retries=0,
|
|
212
215
|
default_headers={
|
|
213
216
|
# used for metering
|
|
214
217
|
"Client-Id": "moderations",
|
|
@@ -217,28 +220,24 @@ def get_llm_gateway_client(
|
|
|
217
220
|
# optional model overrides
|
|
218
221
|
"deployment_id": openai_deployment_id,
|
|
219
222
|
"llm_id": llm_id,
|
|
223
|
+
# optional user provided credentials
|
|
224
|
+
"credential_json": json.dumps(credentials) if credentials else None,
|
|
220
225
|
},
|
|
221
226
|
)
|
|
222
227
|
return client
|
|
223
228
|
|
|
224
229
|
|
|
225
|
-
def
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
)
|
|
231
|
-
# USE the LLM gateway if its runtime parameter is available and enabled
|
|
232
|
-
# DO NOT USE the gateway if user provided credentials are specified
|
|
233
|
-
# which is the case if no exception was raised trying to create the LLM
|
|
234
|
-
# DATAROBOT and NIM LLM types are not supported by the gateway
|
|
235
|
-
if not json.loads(os.environ.get("ENABLE_LLM_GATEWAY_INFERENCE", "false")) or llm_type in [
|
|
230
|
+
def use_llm_gateway_inference(llm_type: GuardLLMType):
|
|
231
|
+
"""
|
|
232
|
+
USE the LLM gateway if its runtime parameter is available and enabled
|
|
233
|
+
DATAROBOT and NIM LLM types are not supported by the gateway
|
|
234
|
+
"""
|
|
235
|
+
if json.loads(os.environ.get("ENABLE_LLM_GATEWAY_INFERENCE", "false")) and llm_type not in [
|
|
236
236
|
GuardLLMType.DATAROBOT,
|
|
237
237
|
GuardLLMType.NIM,
|
|
238
238
|
]:
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return llm
|
|
239
|
+
return True
|
|
240
|
+
return False
|
|
242
241
|
|
|
243
242
|
|
|
244
243
|
def get_azure_openai_client(
|
|
@@ -400,7 +399,7 @@ def calculate_agent_goal_accuracy(
|
|
|
400
399
|
interactions: str,
|
|
401
400
|
response: str,
|
|
402
401
|
):
|
|
403
|
-
if interactions is None:
|
|
402
|
+
if interactions is None or interactions == "":
|
|
404
403
|
# If interactions are missing - we use prompt and response to gauge the
|
|
405
404
|
# goal accuracy
|
|
406
405
|
sample = MultiTurnSample(
|
|
@@ -22,11 +22,13 @@ from datarobot_dome.constants import SECRET_DEFINITION_PREFIX
|
|
|
22
22
|
from datarobot_dome.constants import GuardLLMType
|
|
23
23
|
from datarobot_dome.constants import GuardType
|
|
24
24
|
from datarobot_dome.constants import OOTBType
|
|
25
|
+
from datarobot_dome.guard_helpers import DEFAULT_OPEN_AI_API_VERSION
|
|
25
26
|
from datarobot_dome.guard_helpers import get_azure_openai_client
|
|
26
27
|
from datarobot_dome.guard_helpers import get_bedrock_client
|
|
27
28
|
from datarobot_dome.guard_helpers import get_datarobot_llm
|
|
29
|
+
from datarobot_dome.guard_helpers import get_llm_gateway_client
|
|
28
30
|
from datarobot_dome.guard_helpers import get_vertex_client
|
|
29
|
-
from datarobot_dome.guard_helpers import
|
|
31
|
+
from datarobot_dome.guard_helpers import use_llm_gateway_inference
|
|
30
32
|
|
|
31
33
|
basic_credential_trafaret = t.Dict(
|
|
32
34
|
{
|
|
@@ -156,6 +158,8 @@ class GuardLLMMixin:
|
|
|
156
158
|
openai_api_base = config.get("openai_api_base")
|
|
157
159
|
openai_deployment_id = config.get("openai_deployment_id")
|
|
158
160
|
llm_id = None
|
|
161
|
+
credentials = None
|
|
162
|
+
use_llm_gateway = use_llm_gateway_inference(llm_type)
|
|
159
163
|
try:
|
|
160
164
|
if llm_type in [GuardLLMType.OPENAI, GuardLLMType.AZURE_OPENAI]:
|
|
161
165
|
openai_api_key = self.get_openai_api_key(config, llm_type)
|
|
@@ -163,6 +167,10 @@ class GuardLLMMixin:
|
|
|
163
167
|
raise ValueError("OpenAI API key is required for Faithfulness guard")
|
|
164
168
|
|
|
165
169
|
if llm_type == GuardLLMType.OPENAI:
|
|
170
|
+
credentials = {
|
|
171
|
+
"credential_type": "openai",
|
|
172
|
+
"api_key": openai_api_key,
|
|
173
|
+
}
|
|
166
174
|
os.environ["OPENAI_API_KEY"] = openai_api_key
|
|
167
175
|
llm = "default"
|
|
168
176
|
elif llm_type == GuardLLMType.AZURE_OPENAI:
|
|
@@ -170,6 +178,12 @@ class GuardLLMMixin:
|
|
|
170
178
|
raise ValueError("OpenAI API base url is required for LLM Guard")
|
|
171
179
|
if openai_deployment_id is None:
|
|
172
180
|
raise ValueError("OpenAI deployment ID is required for LLM Guard")
|
|
181
|
+
credentials = {
|
|
182
|
+
"credential_type": "azure_openai",
|
|
183
|
+
"api_key": openai_api_key,
|
|
184
|
+
"api_base": openai_api_base,
|
|
185
|
+
"api_version": DEFAULT_OPEN_AI_API_VERSION,
|
|
186
|
+
}
|
|
173
187
|
azure_openai_client = get_azure_openai_client(
|
|
174
188
|
openai_api_key=openai_api_key,
|
|
175
189
|
openai_api_base=openai_api_base,
|
|
@@ -182,9 +196,15 @@ class GuardLLMMixin:
|
|
|
182
196
|
raise ValueError("Google model is required for LLM Guard")
|
|
183
197
|
if config.get("google_region") is None:
|
|
184
198
|
raise ValueError("Google region is required for LLM Guard")
|
|
199
|
+
service_account_info = self.get_google_service_account(config)
|
|
200
|
+
credentials = {
|
|
201
|
+
"credential_type": "google_vertex_ai",
|
|
202
|
+
"region": config["google_region"],
|
|
203
|
+
"service_account_info": service_account_info,
|
|
204
|
+
}
|
|
185
205
|
llm = get_vertex_client(
|
|
186
206
|
google_model=llm_id,
|
|
187
|
-
google_service_account=
|
|
207
|
+
google_service_account=service_account_info,
|
|
188
208
|
google_region=config["google_region"],
|
|
189
209
|
)
|
|
190
210
|
elif llm_type == GuardLLMType.AMAZON:
|
|
@@ -194,6 +214,13 @@ class GuardLLMMixin:
|
|
|
194
214
|
if config.get("aws_region") is None:
|
|
195
215
|
raise ValueError("AWS region is required for LLM Guard")
|
|
196
216
|
credential_config = self.get_aws_account(config)
|
|
217
|
+
credentials = {
|
|
218
|
+
"credential_type": "amazon_bedrock",
|
|
219
|
+
"access_key_id": credential_config["aws_access_key_id"],
|
|
220
|
+
"secret_access_key": credential_config["aws_secret_access_key"],
|
|
221
|
+
"session_token": credential_config["aws_session_token"],
|
|
222
|
+
"region": config["aws_region"],
|
|
223
|
+
}
|
|
197
224
|
llm = get_bedrock_client(
|
|
198
225
|
aws_model=llm_id,
|
|
199
226
|
aws_access_key_id=credential_config["aws_access_key_id"],
|
|
@@ -219,14 +246,19 @@ class GuardLLMMixin:
|
|
|
219
246
|
raise ValueError(f"Invalid LLMType: {llm_type}")
|
|
220
247
|
|
|
221
248
|
except Exception as e:
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
249
|
+
# no valid user credentials provided, raise if not using LLM Gateway
|
|
250
|
+
credentials = None
|
|
251
|
+
if not use_llm_gateway:
|
|
252
|
+
raise e
|
|
253
|
+
|
|
254
|
+
if use_llm_gateway:
|
|
255
|
+
# For Bedrock and Vertex the model in the config is actually the LLM ID
|
|
256
|
+
# For OpenAI we use the default model defined in get_llm_gateway_client
|
|
257
|
+
# For Azure we use the deployment ID
|
|
258
|
+
llm = get_llm_gateway_client(
|
|
226
259
|
llm_id=llm_id,
|
|
227
260
|
openai_deployment_id=openai_deployment_id,
|
|
228
|
-
|
|
229
|
-
e=e,
|
|
261
|
+
credentials=credentials,
|
|
230
262
|
)
|
|
231
263
|
|
|
232
264
|
return llm
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
datarobot_dome/__init__.py,sha256=B5Rx8_CNCNsOpxBbRj27XOXCfRZmvmrAR-NzlzIKnDw,583
|
|
2
2
|
datarobot_dome/async_http_client.py,sha256=wkB4irwvnchNGzO1bk2C_HWM-GOSB3AUn5TXKl-X0ZI,9649
|
|
3
3
|
datarobot_dome/chat_helper.py,sha256=BzvtUyZSZxzOqq-5a2wQKhHhr2kMlcP1MFrHaDAeD_o,9671
|
|
4
|
-
datarobot_dome/constants.py,sha256=
|
|
5
|
-
datarobot_dome/drum_integration.py,sha256=
|
|
6
|
-
datarobot_dome/guard.py,sha256=
|
|
7
|
-
datarobot_dome/guard_executor.py,sha256=
|
|
8
|
-
datarobot_dome/guard_helpers.py,sha256=
|
|
4
|
+
datarobot_dome/constants.py,sha256=mnSa8rUAha4XlsS2lwPmFCkH2RzfSL_MMkErsWHqIbA,9040
|
|
5
|
+
datarobot_dome/drum_integration.py,sha256=nULpLYVMiS5vihfNUyuq-nvZpgXrQibQbVu2UMAscu8,42102
|
|
6
|
+
datarobot_dome/guard.py,sha256=1INYx17n9ToiB5bzI-jIReUUuqkK_ucxpOx4jQLts6g,33264
|
|
7
|
+
datarobot_dome/guard_executor.py,sha256=AOI8MZeZETHMoFgBePe0wa2vE9d2975MYQnEDHLZL7s,35462
|
|
8
|
+
datarobot_dome/guard_helpers.py,sha256=Bfdi8gow2_TAVzRHYUDqEfcG5bWx2KR1dnpxt9E850Y,16311
|
|
9
9
|
datarobot_dome/guards/__init__.py,sha256=B5Rx8_CNCNsOpxBbRj27XOXCfRZmvmrAR-NzlzIKnDw,583
|
|
10
|
-
datarobot_dome/guards/guard_llm_mixin.py,sha256=
|
|
10
|
+
datarobot_dome/guards/guard_llm_mixin.py,sha256=VovlpNZjWIGamF4SSvLF5lzOFyApH5IoOiB_qtCmRg0,12216
|
|
11
11
|
datarobot_dome/llm.py,sha256=L02OvTrflmD34-FrfXebfF-zzKTeuin7fpne1Cl5psg,5719
|
|
12
12
|
datarobot_dome/metrics/__init__.py,sha256=B5Rx8_CNCNsOpxBbRj27XOXCfRZmvmrAR-NzlzIKnDw,583
|
|
13
13
|
datarobot_dome/metrics/citation_metrics.py,sha256=q0hTMWuk6wy_jqk2UjFPON3kU94HN3W2vxr9giJ8O8E,3544
|
|
@@ -18,6 +18,6 @@ datarobot_dome/pipeline/llm_pipeline.py,sha256=fOp_OJnQMDUJH-LKv12kEqli-EqfHjAiS
|
|
|
18
18
|
datarobot_dome/pipeline/pipeline.py,sha256=_pZ_4K2LMnfYCYj_ur9EwJzo3T-pbO6lFYz1O-_3uQ4,16491
|
|
19
19
|
datarobot_dome/pipeline/vdb_pipeline.py,sha256=WTOGn1qe_ZvEcdlvHgeXxl2xTqp7GjfL13c6S-FmAfM,5146
|
|
20
20
|
datarobot_dome/streaming.py,sha256=6nYvh6SoxPRLfO6GGdEoHsQuyLP9oX1lDMe8IeGo4lw,17801
|
|
21
|
-
datarobot_moderations-11.1.
|
|
22
|
-
datarobot_moderations-11.1.
|
|
23
|
-
datarobot_moderations-11.1.
|
|
21
|
+
datarobot_moderations-11.1.16.dist-info/METADATA,sha256=WBOhNlF-pwpbJ2PvlkhwqlKbF3vtWkbNdu6vjqvmvaQ,4827
|
|
22
|
+
datarobot_moderations-11.1.16.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
23
|
+
datarobot_moderations-11.1.16.dist-info/RECORD,,
|
|
File without changes
|