Pular para o conteúdo principal

Marcadores

Os pontuadores avaliam a qualidade do aplicativo GenAI analisando os resultados e produzindo feedback estruturado. Escreva uma vez, use em qualquer lugar - no desenvolvimento e na produção.

Referência rápida

Tipo de retorno

Exibição de interface

Caso de uso

"yes"/"no"

Aprovar/falhar

Avaliação binária

True/False

verdadeiro/falso

Boolean cheques

int/float

Valor numérico

Pontuações, contagens

Feedback

Valor + justificativa

Avaliação detalhada

List[Feedback]

Múltiplas métricas

Avaliação multifacetada

Escreva uma vez, use em qualquer lugar

Um key princípio de design dos MLflow scorers é escrever uma vez, usar em qualquer lugar. A mesma função de marcador funciona perfeitamente em:

Essa abordagem unificada significa que o senhor pode desenvolver e testar suas métricas de qualidade localmente e, em seguida, implantar exatamente a mesma lógica na produção sem modificações.

Python
from mlflow.genai.scorers import scorer
from mlflow.entities import Feedback

# Define your scorer once
@scorer
def response_completeness(outputs: str) -> Feedback:
# Outputs is return value of your app. Here we assume it's a string.
if len(outputs.strip()) < 10:
return Feedback(
value=False,
rationale="Response too short to be meaningful"
)

if outputs.lower().endswith(("...", "etc", "and so on")):
return Feedback(
value=False,
rationale="Response appears incomplete"
)

return Feedback(
value=True,
rationale="Response appears complete"
)

# Directly call the scorer function for spot testing
response_completeness(outputs="This is a test response...")

# Use in development evaluation
mlflow.genai.evaluate(
data=test_dataset,
predict_fn=my_app,
scorers=[response_completeness]
)

Como funcionam os marcadores

Os pontuadores analisam traços de seu aplicativo GenAI e produzem avaliações de qualidade. Aqui está o fluxo:

  1. Seu aplicativo é executado e produz um rastreamento que captura sua execução
  2. O MLflow passa o rastreamento para sua função de marcador
  3. Os pontuadores analisam as entradas, saídas e etapas intermediárias de execução do rastreamento usando lógica personalizada
  4. O feedback é produzido com pontuações e explicações
  5. Os feedbacks são anexados ao rastreamento para análise

Entradas

Os avaliadores recebem o rastreamento completo do MLflow contendo todos os intervalos, atributos e saídas. Por conveniência, o MLflow também extrai dados comumente necessários e os passa como argumentos nomeados:

Python
@scorer
def my_custom_scorer(
*, # All arguments are keyword-only
inputs: Optional[dict[str, Any]], # App's raw input, a dictionary of input argument names and values
outputs: Optional[Any], # App's raw output
expectations: Optional[dict[str, Any]], # Ground truth, a dictionary of label names and values
trace: Optional[mlflow.entities.Trace] # Complete trace with all metadata
) -> Union[int, float, bool, str, Feedback, List[Feedback]]:
# Your evaluation logic here

Todos os parâmetros são opcionais — declare somente o que seu marcador precisa:

  • entradas : a solicitação enviada ao seu aplicativo (por exemplo, consulta do usuário, contexto).
  • saídas : a resposta do seu aplicativo (por exemplo, texto gerado, chamadas de ferramentas)
  • expectativas : A verdade básica ou rótulo (por exemplo, resposta esperada, diretrizes etc.)
  • trace : O rastreamento completo da execução com todos os intervalos, permitindo a análise de etapas intermediárias, latência, uso de ferramentas, etc.

Ao executar mlflow.genai.evaluate(), os parâmetros inputs, outputs e expectations podem ser especificados no argumento data ou analisados a partir do rastreamento.

Ao executar mlflow.genai.create_monitor(), os parâmetros inputs e outputs são sempre analisados a partir do rastreamento. expectations não está disponível.

Saídas

Os pontuadores podem retornar tipos diferentes, dependendo de suas necessidades de avaliação:

Valores simples

Retorne valores primitivos para avaliações diretas de aprovação/reprovação ou numéricas.

  • Aprovado/reprovado strings : "yes" ou "no" renderizado como "Aprovado" ou "Reprovado" na UI
  • Boolean Valores : True ou False para avaliações binárias
  • Valores numéricos : números inteiros ou flutuantes para pontuações, contagens ou medidas
Python
# These example assumes your app returns a string as a response.
@scorer
def response_length(outputs: str) -> int:
# Return a numeric metric
return len(outputs.split())

@scorer
def contains_citation(outputs: str) -> str:
# Return pass/fail string
return "yes" if "[source]" in outputs else "no"

Feedback rico

Retorne objetos Feedback para avaliações detalhadas com explicações:

Python
from mlflow.entities import Feedback, AssessmentSource

@scorer
def content_quality(outputs):
return Feedback(
value=0.85, # Can be numeric, boolean, or string
rationale="Clear and accurate, minor grammar issues",
# Optional: source of the assessment. Several source types are supported,
# such as "HUMAN", "CODE", "LLM_JUDGE".
source=AssessmentSource(
source_type="HUMAN",
source_id="grammar_checker_v1"
),
# Optional: additional metadata about the assessment.
metadata={
"annotator": "me@example.com",
}
)

Vários objetos de feedback podem ser retornados como uma lista. Cada feedback será exibido como uma métrica separada nos resultados da avaliação.

Python
@scorer
def comprehensive_check(inputs, outputs):
return [
Feedback(name="relevance", value=True, rationale="Directly addresses query"),
Feedback(name="tone", value="professional", rationale="Appropriate for audience"),
Feedback(name="length", value=150, rationale="Word count within limits")
]

Comportamento de nomeação de métricas

Ao usar o decorador @scorer, os nomes das métricas nos resultados da avaliação seguem estas regras:

  1. Valor primitivo ou feedback único sem nome: o nome da função do marcador se torna o nome do feedback

    Python
    @scorer
    def word_count(outputs: str) -> int:
    # "word_count" will be used as a metric name
    return len(outputs).split()

    @scorer
    def response_quality(outputs: Any) -> Feedback:
    # "response_quality" will be used as a metric name
    return Feedback(value=True, rationale="Good quality")
  2. Feedback único com um nome explícito : o nome especificado no objeto Feedback é usado como o nome métrico

    Python
    @scorer
    def assess_factualness(outputs: Any) -> Feedback:
    # Name "factual_accuracy" is explicitly specfied, it will be used as a metric name
    return Feedback(name="factual_accuracy", value=True, rationale="Factual accuracy is high")
  3. Vários feedbacks: os nomes especificados em cada objeto de feedback são preservados. Você deve especificar um nome exclusivo para cada feedback.

    Python
    @scorer
    def multi_aspect_check(outputs) -> list[Feedback]:
    # These names ARE used since multiple feedbacks are returned
    return [
    Feedback(name="grammar", value=True, rationale="No errors"),
    Feedback(name="clarity", value=0.9, rationale="Very clear"),
    Feedback(name="completeness", value="yes", rationale="All points addressed")
    ]

Esse comportamento de nomenclatura garante nomes de métricas consistentes em seus resultados de avaliação e painéis.

Tratamento de erros

Quando um avaliador encontra um erro, o MLflow oferece duas abordagens:

Permitir que as exceções se propaguem (recomendado)

A abordagem mais simples é permitir que as exceções ocorram naturalmente. O MLflow captura automaticamente a exceção e cria um objeto Feedback com os detalhes do erro:

Python
import mlflow
from mlflow.entities import Feedback
from mlflow.genai.scorers import scorer

@scorer
def is_valid_response(outputs: str) -> Feedback:
import json

# Let json.JSONDecodeError propagate if response isn't valid JSON
data = json.loads(outputs)

# Let KeyError propagate if required fields are missing
summary = data["summary"]
confidence = data["confidence"]

return Feedback(
value=True,
rationale=f"Valid JSON with confidence: {confidence}"
)

# Run the scorer on invalid data that triggers exceptions
invalid_data = [
{
# Valid JSON
"outputs": '{"summary": "this is a summary", "confidence": 0.95}'
},
{
# Invalid JSON
"outputs": "invalid json",
},
{
# Missing required fields
"outputs": '{"summary": "this is a summary"}'
},
]

mlflow.genai.evaluate(
data=invalid_data,
scorers=[is_valid_response],
)

Quando ocorre uma exceção, o MLflow cria um feedback com:

  • value: None
  • error: os detalhes da exceção, como objeto de exceção, mensagem de erro e rastreamento de pilha

As informações sobre o erro serão exibidas nos resultados da avaliação. Abra a linha correspondente para ver os detalhes do erro.

Detalhes do erro nos resultados da avaliação

Lidar com exceções de forma explícita

Para tratamento personalizado de erros ou para fornecer mensagens de erro específicas, detecte exceções e retorne um feedback com o valor None e os detalhes do erro:

Python
from mlflow.entities import AssessmentError, Feedback

@scorer
def is_valid_response(outputs):
import json

try:
data = json.loads(outputs)
required_fields = ["summary", "confidence", "sources"]
missing = [f for f in required_fields if f not in data]

if missing:
return Feedback(
error=AssessmentError(
error_code="MISSING_REQUIRED_FIELDS",
error_message=f"Missing required fields: {missing}",
),
)

return Feedback(
value=True,
rationale="Valid JSON with all required fields"
)

except json.JSONDecodeError as e:
return Feedback(error=e) # Can pass exception object directly to the error parameter

O parâmetro error aceita:

  • Exceção do Python : Passar o objeto de exceção diretamente
  • AssessmentError : para relatórios de erros estruturados com códigos de erro

Quando as expectativas estão disponíveis

As expectativas (verdade básica ou rótulo) são normalmente importantes para a avaliação off-line. Você pode especificá-los de duas maneiras ao executar mlflow.genai.evaluate():

  • Inclua a coluna (ou campo) expectations no argumento de entrada data.
  • Associe Expectation aos Traces e passe-os para o argumento data.
Python
@scorer
def exact_match(outputs: str, expectations: dict[str, Any]) -> Feedback:
expected = expectations.get("expected_response")
is_correct = outputs == expected

return Feedback(
value=is_correct,
rationale=f"Response {'matches' if is_correct else 'differs from'} expected"
)

data = [
{
"inputs": {"question": "What is the capital of France?"},
"outputs": "Paris",
# Specify expected response in the expectations field
"expectations": {
"expected_response": "Paris"
}
},
]

mlflow.genai.evaluate(
data=data,
scorers=[exact_match],
)
nota

Normalmente, o monitoramento da produção não tem expectativas, pois o senhor está avaliando o tráfego ao vivo sem a verdade básica. Se você pretende usar o mesmo marcador para avaliação offline e on-line, projete-o para lidar com as expectativas com elegância.

Usando dados de rastreamento

Os pontuadores podem acessar o rastreamento completo para avaliar o comportamento complexo do aplicativo:

Python
from mlflow.entities import Feedback, Trace
from mlflow.genai.scorers import scorer

@scorer
def tool_call_efficiency(trace: Trace) -> Feedback:
"""Evaluate how effectively the app uses tools"""
# Retrieve all tool call spans from the trace
tool_calls = trace.search_spans(span_type="TOOL")

if not tool_calls:
return Feedback(
value=None,
rationale="No tool usage to evaluate"
)

# Check for redundant calls
tool_names = [span.name for span in tool_calls]
if len(tool_names) != len(set(tool_names)):
return Feedback(
value=False,
rationale=f"Redundant tool calls detected: {tool_names}"
)

# Check for errors
failed_calls = [s for s in tool_calls if s.status.status_code != "OK"]
if failed_calls:
return Feedback(
value=False,
rationale=f"{len(failed_calls)} tool calls failed"
)

return Feedback(
value=True,
rationale=f"Efficient tool usage: {len(tool_calls)} successful calls"
)

Ao executar a avaliação offline com mlflow.genai.evaluate(), os rastreamentos são:

  • especificados no argumento data se eles já estiverem disponíveis.
  • gerado executando predict_fn contra inputs no argumento data.

Ao executar o monitoramento de produção com mlflow.genai.create_monitor(), os traços coletados pelo monitor são passados diretamente para a função de pontuador, com os critérios de amostragem e filtragem especificados.

Abordagens de implementação do Scorer

O MLflow oferece duas maneiras de implementar marcadores:

Abordagem do decorador (recomendada)

Use o decorador @scorer para pontuadores simples e baseados em funções:

Python
from mlflow.genai.scorers import scorer
from mlflow.entities import Feedback

@scorer
def response_tone(outputs: str) -> Feedback:
"""Check if response maintains professional tone"""
informal_phrases = ["hey", "gonna", "wanna", "lol", "btw"]
found = [p for p in informal_phrases if p in outputs.lower()]

if found:
return Feedback(
value=False,
rationale=f"Informal language detected: {', '.join(found)}"
)

return Feedback(
value=True,
rationale="Professional tone maintained"
)

Abordagem baseada em classes

Use a classe base Scorer para pontuadores mais complexos que exigem estado. A classe Scorer é um objeto Pydantic, então você pode definir campos adicionais e usá-los no método __call__.

Python
from mlflow.genai.scorers import Scorer
from mlflow.entities import Feedback
from typing import Optional

# Scorer class is a Pydantic object
class ResponseQualityScorer(Scorer):
# The `name` field is mandatory
name: str = "response_quality"
# Define additiona lfields
min_length: int = 50
required_sections: Optional[list[str]] = None

# Override the __call__ method to implement the scorer logic
def __call__(self, outputs: str) -> Feedback:
issues = []

# Check length
if len(outputs.split()) < self.min_length:
issues.append(f"Too short (minimum {self.min_length} words)")

# Check required sections
missing = [s for s in self.required_sections if s not in outputs]
if missing:
issues.append(f"Missing sections: {', '.join(missing)}")

if issues:
return Feedback(
value=False,
rationale="; ".join(issues)
)

return Feedback(
value=True,
rationale="Response meets all quality criteria"
)

Custom scorer development fluxo de trabalho

Ao desenvolver pontuadores personalizados, você geralmente precisa iterar rapidamente sem executar novamente seu aplicativo a cada vez. O MLflow oferece suporte a um fluxo de trabalho eficiente:

  1. Gere rastreamentos uma vez executando seu aplicativo com mlflow.genai.evaluate()
  2. Armazene os traços usando mlflow.search_traces()
  3. Itere os marcadores passando os rastreamentos armazenados para evaluate() sem executar seu aplicativo novamente

Essa abordagem economiza tempo e recursos durante o desenvolvimento do marcador:

Python
# Step 1: Generate traces with a placeholder scorer
initial_results = mlflow.genai.evaluate(
data=test_dataset,
predict_fn=my_app,
scorers=[lambda **kwargs: 1] # Placeholder scorer
)

# Step 2: Store traces for reuse
traces = mlflow.search_traces(run_id=initial_results.run_id)

# Step 3: Iterate on your scorer without re-running the app
@scorer
def my_custom_scorer(outputs):
# Your evaluation logic here
pass

# Test scorer on stored traces (no predict_fn needed)
results = mlflow.genai.evaluate(
data=traces,
scorers=[my_custom_scorer]
)

Pegadinhas comuns

Nomeação de marcadores com decoradores

Python
from mlflow.genai.scorers import scorer
from mlflow.entities import Feedback

# GOTCHA: Function name becomes feedback name for single returns
@scorer
def quality_check(outputs):
# This 'name' parameter is IGNORED
return Feedback(name="ignored", value=True)
# Feedback will be named "quality_check"

# CORRECT: Use function name meaningfully
@scorer
def response_quality(outputs):
return Feedback(value=True, rationale="Good quality")
# Feedback will be named "response_quality"

# EXCEPTION: Multiple feedbacks preserve their names
@scorer
def multi_check(outputs):
return [
Feedback(name="grammar", value=True), # Name preserved
Feedback(name="spelling", value=True), # Name preserved
Feedback(name="clarity", value=0.9) # Name preserved
]

Gestão estadual em marcadores

Python
from mlflow.genai.scorers import Scorer
from mlflow.entities import Feedback

# WRONG: Don't use mutable class attributes
class BadScorer(Scorer):
results = [] # Shared across all instances!

def __call__(self, outputs, **kwargs):
self.results.append(outputs) # Causes issues
return Feedback(value=True)

# CORRECT: Use instance attributes
class GoodScorer(Scorer):
def __init__(self):
super().__init__(name="good_scorer")
self.results = [] # Per-instance state

def __call__(self, outputs, **kwargs):
self.results.append(outputs) # Safe
return Feedback(value=True)

Próximas etapas