Migrating from Feedback to Metric¶
The Metric class is the new unified API for evaluation metrics in TruLens. It replaces both Feedback and MetricConfig with a cleaner, more explicit interface.
Why Migrate?¶
- Clearer API: Explicit
selectorsdict instead of chained.on_*()methods - Better OTel integration: Native support for OpenTelemetry span selection
- Unified interface: One class instead of separate
FeedbackandMetricConfig - Same functionality: All existing features are preserved
Quick Comparison¶
Before (Feedback)¶
from trulens.core import Feedback
from trulens.providers.openai import OpenAI
provider = OpenAI()
f_relevance = (
Feedback(provider.relevance, name="Answer Relevance")
.on_input()
.on_output()
)
f_groundedness = (
Feedback(provider.groundedness_measure_with_cot_reasons, name="Groundedness")
.on_context(collect_list=True)
.on_output()
.on_input()
)
f_context_relevance = (
Feedback(provider.context_relevance, name="Context Relevance")
.on_input()
.on_context(collect_list=False)
.aggregate(np.mean)
)
After (Metric)¶
from trulens.core import Metric, Selector
from trulens.providers.openai import OpenAI
import numpy as np
provider = OpenAI()
f_relevance = Metric(
implementation=provider.relevance,
name="Answer Relevance",
selectors={
"prompt": Selector.select_record_input(),
"response": Selector.select_record_output(),
},
)
f_groundedness = Metric(
implementation=provider.groundedness_measure_with_cot_reasons,
name="Groundedness",
selectors={
"source": Selector.select_context(collect_list=True),
"statement": Selector.select_record_output(),
"question": Selector.select_record_input(),
},
)
f_context_relevance = Metric(
implementation=provider.context_relevance,
name="Context Relevance",
selectors={
"question": Selector.select_record_input(),
"context": Selector.select_context(collect_list=False),
},
agg=np.mean,
)
Selector Reference¶
The Selector class provides static methods for common selections:
| Method | Description |
|---|---|
Selector.select_record_input() |
The input to the traced application |
Selector.select_record_output() |
The output from the traced application |
Selector.select_context(collect_list=True) |
Retrieved contexts from RAG |
Custom Selectors¶
For advanced use cases, create custom selectors by matching span attributes:
from trulens.core import Selector
from trulens.otel.semconv.trace import SpanAttributes
# Select by span type
retrieval_query = Selector(
span_type=SpanAttributes.SpanType.RETRIEVAL,
function_attribute="query",
)
# Select by function name
custom_output = Selector(
function_name="my_module.my_function",
function_attribute="return",
)
# Select specific span attribute
generation_output = Selector(
span_type=SpanAttributes.SpanType.GENERATION,
span_attribute=SpanAttributes.GENERATION.OUTPUT,
)
Parameter Mapping¶
| Feedback | Metric | Notes |
|---|---|---|
imp=fn |
implementation=fn |
Renamed for clarity |
.on_input() |
selectors={"param": Selector.select_record_input()} |
Explicit selector |
.on_output() |
selectors={"param": Selector.select_record_output()} |
Explicit selector |
.on_context() |
selectors={"param": Selector.select_context()} |
Explicit selector |
.aggregate(fn) |
agg=fn |
Same functionality |
name="..." |
name="..." |
Unchanged |
examples=[...] |
examples=[...] |
Unchanged |
criteria="..." |
criteria="..." |
Unchanged |
New Fields¶
The Metric class adds optional metadata fields:
Metric(
implementation=my_fn,
name="My Metric",
metric_type="custom", # NEW: Implementation identifier
description="Measures X quality", # NEW: Human-readable description
selectors={...},
)
Migrating from MetricConfig¶
If you were using MetricConfig for custom client-side metrics:
Before (MetricConfig)¶
from trulens.core.feedback.custom_metric import MetricConfig
config = MetricConfig(
metric_name="word_count",
metric_implementation=lambda text: len(text.split()),
selectors={"text": Selector.select_record_output()},
)
feedback = config.create_feedback_definition()
After (Metric)¶
from trulens.core import Metric, Selector
metric = Metric(
name="word_count",
implementation=lambda text: len(text.split()),
selectors={"text": Selector.select_record_output()},
)
Backward Compatibility¶
The old Feedback class still works and will emit a deprecation warning:
# This still works but shows a deprecation warning
from trulens.core import Feedback
f = Feedback(provider.relevance).on_input().on_output()
The chained .on_*() methods also work on Metric for gradual migration, but the selectors={} style is recommended for new code.
Type Checking Notes¶
The Feedback class is implemented as a subclass of Metric:
class Feedback(Metric):
...
This means:
| Check | Result |
|---|---|
isinstance(metric_obj, Metric) |
True |
isinstance(feedback_obj, Metric) |
True |
isinstance(feedback_obj, Feedback) |
True |
isinstance(metric_obj, Feedback) |
False |
For downstream integrators: If your code performs type checks with isinstance(obj, Feedback), you should migrate to isinstance(obj, Metric) before the Feedback alias is removed. After removal:
isinstance(obj, Metric)will continue to work βisinstance(obj, Feedback)will raiseNameErrorβ
# Before (will break when Feedback is removed)
if isinstance(obj, Feedback):
...
# After (recommended)
if isinstance(obj, Metric):
...
Timeline¶
- Future release:
FeedbackandMetricConfigwill be removed
We recommend migrating to Metric for all new code.