Multiple evaluators

A run can hold any number of evaluators — pass them as a list to evaluators. The SDK runs each one and computes its statistics independently, so every metric shows up separately in Studio.

Multiple scorers in one run

Multiple scorers in one run

import asyncio
import os

from mistralai.evaluations import Evaluation, Evaluator, Mistral, ScorerContext, TaskContext

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

def contains_expected(ctx: ScorerContext) -> int:
    return 1 if ctx.input_record["expected"] in str(ctx.output).lower() else 0

def is_short(ctx: ScorerContext) -> int:
    return 1 if len(str(ctx.output)) < 80 else 0

def starts_capitalized(ctx: ScorerContext) -> int:
    text = str(ctx.output).strip()
    return 1 if text and text[0].isupper() else 0

async def task(ctx: TaskContext) -> str:
    response = await client.chat.complete_async(
        model="mistral-small-latest",
        messages=[{"role": "user", "content": ctx.input_record["prompt"]}],
    )
    return str(response.choices[0].message.content)

async def main():
    run = await client.evaluation.run(
        evaluation=Evaluation(name="Multi-metric eval"),
        dataset=dataset,
        task=task,
        evaluators=[
            Evaluator(name="contains_expected", description="1 if expected substring is in the output.", scorer=contains_expected),
            Evaluator(name="is_short", description="1 if the output is under 80 characters.", scorer=is_short),
            Evaluator(name="starts_capitalized", description="1 if the output starts with an uppercase letter.", scorer=starts_capitalized),
        ],
    )
    run.show(level="run")

asyncio.run(main())
Mix rule-based and LLM judges

Mix rule-based and LLM judges

Scorers are functions, so rule-based checks and LLM judges live side by side in the same run:

evaluators=[
    Evaluator(name="exact_match", description="1 if output matches expected exactly.", scorer=exact_match_scorer),
    Evaluator(name="llm_quality", description="LLM judge quality score (0 to 5).", scorer=llm_judge, num_scores=3),
    Evaluator(name="response_length", description="Character count of the output.", scorer=length_scorer),
]
Per-evaluator goals and statistics

Per-evaluator goals and statistics

Each evaluator carries its own configuration — nothing is shared or merged across them:

  • Goals: set an independent pass/fail gate per evaluator (for example goal=Goal.gte(0.8) on one, goal=Goal.lte(500) on another). See Set goals.
  • Statistics: each evaluator exposes its own run-level statistics, and you can declare exactly which ones. Non-numeric scores get frequency distributions and a mode instead of numeric reductions. See Configure statistics.