5959class MetricEvaluatorRegistry :
6060 """A registry for metric Evaluators."""
6161
62- _registry : dict [str , tuple [type [Evaluator ], MetricInfo ]] = {}
62+ def __init__ (self ) -> None :
63+ # Each registry instance owns its mappings, so a custom metric registered
64+ # for one app is not resolvable from another app's registry. The standard
65+ # metrics are seeded into every instance, as they are the same everywhere.
66+ self ._registry : dict [str , tuple [type [Evaluator ], MetricInfo ]] = {}
67+ # Module path of the custom function backing a metric, keyed by metric
68+ # name. Only ever written from an eval config.
69+ self ._custom_function_paths : dict [str , str ] = {}
70+ _register_standard_metrics (self )
6371
6472 def get_evaluator (self , eval_metric : EvalMetric ) -> Evaluator :
6573 """Returns an Evaluator for the given metric.
@@ -75,14 +83,34 @@ def get_evaluator(self, eval_metric: EvalMetric) -> Evaluator:
7583 if eval_metric .metric_name not in self ._registry :
7684 raise NotFoundError (f"{ eval_metric .metric_name } not found in registry." )
7785
78- evaluator_type = self ._registry [eval_metric .metric_name ][ 0 ]
86+ evaluator_type , _ = self ._registry [eval_metric .metric_name ]
7987 if issubclass (evaluator_type , _CustomMetricEvaluator ):
88+ custom_function_path = self ._custom_function_path (eval_metric )
89+ if custom_function_path is None :
90+ raise NotFoundError (
91+ f"No custom function registered for { eval_metric .metric_name } ."
92+ )
8093 return evaluator_type (
8194 eval_metric = eval_metric ,
82- custom_function_path = eval_metric . custom_function_path ,
95+ custom_function_path = custom_function_path ,
8396 )
8497 return evaluator_type (eval_metric = eval_metric )
8598
99+ def _custom_function_path (self , eval_metric : EvalMetric ) -> Optional [str ]:
100+ """Returns the module path to import for a custom metric, if known.
101+
102+ Both sources are eval config entries: one recorded when the metric was
103+ registered from a config, the other carried on a metric built from a
104+ config. The `custom_function_path` field on the incoming metric is not
105+ consulted, as it can be set by whoever built the request.
106+
107+ Args:
108+ eval_metric: The metric whose custom function is being resolved.
109+ """
110+ if path := self ._custom_function_paths .get (eval_metric .metric_name ):
111+ return path
112+ return eval_metric ._config_custom_function_path # pylint: disable=protected-access
113+
86114 def register_evaluator (
87115 self ,
88116 metric_info : MetricInfo ,
@@ -92,6 +120,25 @@ def register_evaluator(
92120
93121 If a mapping already exist, then it is updated.
94122 """
123+ self ._register (metric_info , evaluator , custom_function_path = None )
124+
125+ def _register (
126+ self ,
127+ metric_info : MetricInfo ,
128+ evaluator : type [Evaluator ],
129+ custom_function_path : Optional [str ],
130+ ) -> None :
131+ """Registers an evaluator, along with the function path it may need.
132+
133+ A path already recorded for the metric is kept when this registration does
134+ not carry one, so re-registering an evaluator does not drop it.
135+
136+ Args:
137+ metric_info: Info for the metric the evaluator is registered against.
138+ evaluator: The evaluator class to register.
139+ custom_function_path: Module path of the function backing a custom
140+ metric, taken from an eval config, or None.
141+ """
95142 metric_name = metric_info .metric_name
96143 if metric_name in self ._registry :
97144 logger .info (
@@ -102,6 +149,8 @@ def register_evaluator(
102149 )
103150
104151 self ._registry [str (metric_name )] = (evaluator , metric_info )
152+ if custom_function_path is not None :
153+ self ._custom_function_paths [str (metric_name )] = custom_function_path
105154
106155 def get_registered_metrics (
107156 self ,
@@ -113,10 +162,10 @@ def get_registered_metrics(
113162 ]
114163
115164
116- def _get_default_metric_evaluator_registry () -> MetricEvaluatorRegistry :
117- """Returns an instance of MetricEvaluatorRegistry with standard metrics already registered in it."""
118- metric_evaluator_registry = MetricEvaluatorRegistry ()
119-
165+ def _register_standard_metrics (
166+ metric_evaluator_registry : MetricEvaluatorRegistry ,
167+ ) -> None :
168+ """Registers the metrics that ship with ADK into the given registry."""
120169 metric_evaluator_registry .register_evaluator (
121170 metric_info = TrajectoryEvaluatorMetricInfoProvider ().get_metric_info (),
122171 evaluator = TrajectoryEvaluator ,
@@ -175,7 +224,10 @@ def _get_default_metric_evaluator_registry() -> MetricEvaluatorRegistry:
175224 evaluator = RubricBasedMultiTurnTrajectoryEvaluator ,
176225 )
177226
178- return metric_evaluator_registry
227+
228+ def _get_default_metric_evaluator_registry () -> MetricEvaluatorRegistry :
229+ """Returns an instance of MetricEvaluatorRegistry with standard metrics already registered in it."""
230+ return MetricEvaluatorRegistry ()
179231
180232
181233DEFAULT_METRIC_EVALUATOR_REGISTRY = _get_default_metric_evaluator_registry ()
@@ -223,7 +275,7 @@ def register_custom_metrics_from_config(
223275 metric_info = _get_default_metric_info (
224276 metric_name = metric_name , description = config .description
225277 )
226- metric_evaluator_registry .register_evaluator (
227- metric_info , _CustomMetricEvaluator
278+ metric_evaluator_registry ._register ( # pylint: disable=protected-access
279+ metric_info , _CustomMetricEvaluator , config . code_config . name
228280 )
229281 return metric_evaluator_registry
0 commit comments