trulens.feedback.jury¶
trulens.feedback.jury
¶
LLM Jury β ensemble multiple LLM judges into a single feedback callable.
A single LLM judge is noisy and subject to intra-model bias. Ensembling a panel of diverse judges (a "jury") improves reliability, reduces bias, and can be cheaper when smaller models are used.
A jury can also repeat one judge (see :meth:Jury.repeated). At non-zero
temperature the same judge, given identical inputs, does not always return
the same verdict, so repeating it measures run-to-run variance that a single
draw hides.
Every result carries a reliability summary over the juror scores: their spread, and for a pass/fail view the flip rate and outcome entropy. The reliability metrics follow "The Coin Flip Judge? Reliability and Bias in LLM-as-a-Judge Evaluation" (arXiv:2606.13685), which measured pairwise judge verdicts flipping on average 13.6 percent of the time across repeated identical evaluations.
Classes¶
Jury
¶
Ensemble multiple LLM judges into a single feedback callable.
Jury wraps N provider instances, calls the same named method on each
in parallel, and aggregates their scores using a configurable strategy.
Because Jury.__call__ exposes the same parameter names as the
underlying provider method, it plugs directly into
Metric(implementation=jury) β no changes to Metric, Selector, or
the evaluation pipeline are needed.
__call__ always returns (score, {"reason": ..., "reliability.*":
...}), matching the _with_cot_reasons convention so per-juror
breakdowns flow into FeedbackCall.meta["reason"] and are visible in
OTEL spans and the dashboard without any UI changes. The reliability keys
are flat so each one lands on the eval span as its own typed attribute:
reliability.n_scores: jurors that returned a score.reliability.scores: those scores, in juror order.reliability.score_std: population standard deviation of the scores.reliability.flip_rate: share of scores that disagree with the majority pass/fail verdict at threshold,1 - max(counts) / n. This is the flip rate defined in arXiv:2606.13685, from 0.0 (unanimous) to 0.5 (even split).reliability.outcome_entropy: entropy in bits of the pass/fail split, from 0.0 (unanimous) to 1.0 (even split).reliability.temperature: thetemperaturepassed to the jurors, orNonewhen none was passed.
A juror counts as failed when it raises or when its judge reply carried
no parseable score, which the providers report as
:data:~trulens.feedback.llm_provider.UNPARSABLE_SCORE (-1.0). Either
way it gets no vote. Only a jury with no surviving juror raises.
| PARAMETER | DESCRIPTION |
|---|---|
jurors
|
Non-empty list of |
method
|
Name of the feedback method to call on each juror, e.g.
TYPE:
|
aggregation
|
How to combine individual juror scores. Accepts a
strategy name ( |
weights
|
Per-juror weights for |
threshold
|
Binarisation threshold for
TYPE:
|
max_workers
|
Maximum parallel threads. Defaults to
TYPE:
|
Example::
from trulens.core import Metric
from trulens.feedback.jury import Jury
from trulens.providers.openai import OpenAI
from trulens.providers.litellm import LiteLLM
jury = Jury(
jurors=[
OpenAI(model_engine="gpt-4o-mini"),
OpenAI(model_engine="gpt-4.1-mini"),
LiteLLM(model_engine="anthropic/claude-3-haiku-20240307"),
],
method="relevance",
aggregation="median",
)
m = Metric(implementation=jury, name="Jury Relevance").on_input().on_output()
Functions¶
repeated
classmethod
¶
repeated(
judge: Any,
method: str,
n_trials: int = 5,
aggregation: (
str | Callable[[list[float]], float]
) = "mean",
*,
threshold: float = 0.5,
max_workers: int | None = None
) -> Jury
Run one judge n_trials times and aggregate the scores.
Repeating a single judge measures its run-to-run variance, which a
single draw hides. Judge methods and Metric both default to
temperature=0.0; set a non-zero temperature on the Metric to
sample distinct verdicts, and it is passed to every trial. At
temperature 0 the trials are not sampled, so reliability.* then
reflects only nondeterminism in the serving stack. A nonzero flip
rate is still a real signal, but a zero does not show the judge is
stable, and the jury logs a warning once. reliability.temperature
records the temperature the trials ran at.
With n_trials >= 2 the trials are labeled model[0],
model[1], ... in the reason text. arXiv:2606.13685 found about 11
trials are needed for a majority verdict to match a 50-trial
reference with 95 percent probability, so raise n_trials when the
verdict matters more than the cost.
Example::
from trulens.core import Metric
from trulens.feedback import Jury
from trulens.providers.openai import OpenAI
judge = Jury.repeated(
OpenAI(model_engine="gpt-4o-mini"), method="relevance", n_trials=5
)
metric = Metric(
implementation=judge, name="Relevance (5 trials)", temperature=0.7
).on_input().on_output()
__call__
¶
Evaluate the same arguments in parallel across all jurors.
Always returns (score, {"reason": ..., "reliability.*": ...}),
matching the _with_cot_reasons convention. Per-juror scores and
any CoT explanations are embedded in the reason string so they appear
in OTEL spans and the dashboard automatically. The reliability.*
keys are described on the class.