Pular para o conteúdo principal

Crie marcadores personalizados baseados em código

Pontuadores personalizados baseados em código oferecem a máxima flexibilidade para definir precisamente como a qualidade do seu aplicativo GenAI é medida. Você pode definir métricas de avaliação adaptadas ao seu caso de uso comercial específico, seja com base em heurísticas simples, lógica avançada ou avaliações programáticas.

Use pontuadores personalizados para os seguintes cenários:

  1. Definir uma métrica de avaliação heurística ou baseada em código personalizada.
  2. Personalizando como os dados do rastreamento do seu aplicativo são mapeados para os juízes do LLM apoiados pela pesquisa do Databricks.
  3. Utilizar seu próprio modelo LLM (em vez de um modelo LLM judge hospedado pela Databricks) para avaliação.
  4. Quaisquer outros casos de uso em que você precise de mais flexibilidade e controle do que os fornecidos pelos pontuadores LLM personalizados.

Para um tutorial com muitos exemplos, consulte Exemplos de pontuação baseados em código.

Como funcionam os marcadores personalizados

Os pontuadores personalizados são escritos em Python e oferecem controle total para avaliar quaisquer dados dos rastros do seu aplicativo. Depois de definir um marcador personalizado, você pode usá-lo exatamente como um marcador predefinido. Assim como outros pontuadores, o mesmo pontuador personalizado pode ser usado para avaliação em desenvolvimento e reutilizado para monitoramento em produção.

Por exemplo, suponha que você queira um avaliador que verifique se o tempo de resposta do LLM está dentro de uma faixa aceitável. A imagem da interface do usuário MLflow abaixo mostra os traços pontuados por essa métrica personalizada.

Exemplo de métricas de um scorer baseado em código

O trecho de código abaixo define esse pontuador personalizado e o usa com mlflow.genai.evaluate():

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

@scorer
def llm_response_time_good(trace: Trace) -> Feedback:
# Search particular span type from the trace
llm_span = trace.search_spans(span_type=SpanType.CHAT_MODEL)[0]

response_time = (llm_span.end_time_ns - llm_span.start_time_ns) / 1e9 # second
max_duration = 5.0
if response_time <= max_duration:
return Feedback(
value="yes",
rationale=f"LLM response time {response_time:.2f}s is within the {max_duration}s limit."
)
else:
return Feedback(
value="no",
rationale=f"LLM response time {response_time:.2f}s exceeds the {max_duration}s limit."
)

# Evaluate the scorer using pre-generated traces
span_check_eval_results = mlflow.genai.evaluate(
data=generated_traces,
scorers=[llm_response_time_good]
)

O exemplo acima ilustra um padrão comum para pontuadores baseados em código:

  • O decorador @scorer é usado para definir o pontuador.
  • A entrada para este marcador é o trace completo, dando-lhe acesso às entradas, intervalos intermediários e saídas do aplicativo de AI .
  • A lógica do marcador pode ser totalmente personalizada. Você pode ligar para LLMs ou outros avaliadores.
  • A saída deste marcador é um objeto Feedback rico com valores e explicações.
  • O nome da métrica é llm_response_time_good, correspondendo ao nome da função de pontuação.

Esse padrão é apenas uma possibilidade para pontuadores baseados em código. O restante deste artigo explica opções para definir pontuadores personalizados.

Defina os marcadores com o decorador @scorer

A maioria dos pontuadores baseados em código deve ser definida usando o decorador@scorer. abaixo está a assinatura para tais marcadores, ilustrando possíveis entradas e saídas.

Python
from mlflow.genai.scorers import scorer
from typing import Optional, Any
from mlflow.entities import Feedback

@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 spans and metadata
) -> Union[int, float, bool, str, Feedback, List[Feedback]]:
# Your evaluation logic here

Para mais flexibilidade do que o decorador @scorer permite, você pode definir pontuadores usando a classeScorer.

Entradas

Os pontuadores recebem o rastreamento completo do MLflow contendo todos os intervalos, atributos e saídas. Para sua conveniência, o MLflow também extrai dados comumente necessários e os passa como argumentos nomeados. Todos os argumentos de entrada são opcionais, então declare apenas o que seu marcador precisa:

  • inputs: A solicitação enviada ao seu aplicativo (por exemplo, consulta do usuário, contexto).
  • outputs: A resposta do seu aplicativo (por exemplo, texto gerado, chamadas de ferramentas)
  • expectations: Verdade fundamental ou rótulo (por exemplo, resposta esperada, diretrizes, etc.)
  • trace: O rastreamento completoMLflow com todos os intervalos, permitindo análise de passos intermediários, latência, uso de ferramentas e muito mais. O rastreamento é passado para o pontuador personalizado como uma classemlflow.entities.trace instanciada.

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

Os pontuadores registrados para monitoramento de produção sempre analisam os parâmetros inputs e outputs do rastreamento. expectations não está disponível.

Saídas

Os pontuadores podem retornar diferentes tipos de valores simples ou objetos de feedback avançados, dependendo das suas necessidades de avaliação.

Tipo de retorno

Exibição da interface do usuário do MLflow

Caso de uso

"yes"/"no"

Aprovado/Reprovado

Avaliação binária

True/False

verdadeiro/falso

Verificações Boolean

int/float

Valor numérico

Pontuações, contagens

Feedback

Valor + justificativa

Avaliação detalhada

List[Feedback]

Múltiplas métricas

Avaliação multiaspecto

Valores simples

Gere valores primitivos para avaliações diretas de aprovação/reprovação ou numéricas. abaixo estão pontuadores simples para um aplicativo AI que retorna uma string como resposta.

Python
@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 um objeto Feedback ou uma lista de objetos Feedback para avaliações detalhadas com pontuações, justificativas e metadados.

Python
from mlflow.entities import Feedback, AssessmentSource

@scorer
def content_quality(outputs):
return Feedback(
value=0.85, # Can be numeric, boolean, string, or other types
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 deve ter o campo name especificado, e esses nomes serão exibidos como métricas separadas 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 nomenclatura de métricas

Ao definir os marcadores, use nomes claros e consistentes que indiquem o propósito do marcador. Esses nomes aparecerão como nomes de métricas nos seus resultados de avaliação e monitoramento e painéis. Siga as convenções de nomenclatura do MLflow, como safety_check ou relevance_monitor.

Quando você define pontuadores usando o decorador @scorer ou a classeScorer, os nomes das métricas na execução de avaliação criada por avaliação e monitoramento seguem regras simples:

  1. Se o marcador retornar um ou mais objetos Feedback , os campos Feedback.name terão precedência, se especificados.
  2. Para valores de retorno primitivos ou Feedbacks sem nome, o nome da função (para o decorador @scorer ) ou o campo Scorer.name (para a classe Scorer ) são usados.

Expandir essas regras para todas as possibilidades resulta na seguinte tabela para o comportamento de nomenclatura de métricas:

Valor de retorno

@scorer comportamento do decorador

Scorer comportamento de classe

Valor primitivo (int, float, str)

Nome da função

name campo

Feedback sem nome

Nome da função

name campo

Feedback com nome

Feedback name

Feedback name

List[Feedback] com nomes

Feedback nomes

Feedback nomes

Para avaliação e monitoramento, é importante que todas as métricas tenham nomes distintos. Se um marcador retornar List[Feedback], cada Feedback no List deverá ter um nome distinto.

Veja exemplos de comportamento de nomenclatura no tutorial.

Tratamento de erros

Quando um scorer encontra um erro em um rastreamento, o MLflow pode capturar detalhes do erro para esse rastreamento e continuar a execução normalmente. Para capturar detalhes de erros, o MLflow fornece duas abordagens:

  • Deixe as exceções se propagarem (recomendado) para que o MLflow possa capturar mensagens de erro para você.
  • Manipule exceções explicitamente.

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

A abordagem mais simples é deixar que as exceções ocorram naturalmente. O MLflow captura automaticamente a exceção e cria um objeto Feedback com os detalhes do erro. No exemplo abaixo, o pontuador espera JSON com campos específicos.

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 de 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

Tratar exceções explicitamente

Para tratamento de erros personalizado ou para fornecer mensagens de erro específicas, capture exceções e retorne um Feedback com valor None e 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 Python : Passe o objeto de exceção diretamente
  • AssessmentError : Para relatórios de erros estruturados com códigos de erro

Defina os marcadores com a classe Scorer

O decorador@scorer descrito acima é simples e geralmente recomendado, mas quando for insuficiente, você pode usar a classe base Scorer . Definições baseadas em classe permitem pontuadores mais complexos, especialmente pontuadores que exigem estado. A classe Scorer é um objeto Pydantic, então você pode definir campos adicionais e usá-los no método __call__ .

Você deve definir o campo name para definir o nome da métrica. Se você retornar uma lista de objetos Feedback , deverá definir o campo name em cada Feedback para evitar conflitos de nomenclatura.

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

# Scorer class is a Pydantic object
class CustomScorer(Scorer):
# The `name` field is mandatory
name: str = "response_quality"
# Define additional fields
my_custom_field_1: int = 50
my_custom_field_2: Optional[list[str]] = None

# Override the __call__ method to implement the scorer logic
def __call__(self, outputs: str) -> Feedback:
# Your logic here
return Feedback(
value=True,
rationale="Response meets all quality criteria"
)

Gestão do Estado

Ao escrever pontuadores usando a classe Scorer , esteja ciente das regras para gerenciar o estado com classes Python. Em particular, certifique-se de usar atributos de instância, não atributos de classe mutáveis. O exemplo abaixo ilustra o compartilhamento equivocado de estado entre instâncias do scorer.

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!

name: str = "bad_scorer"

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

# CORRECT: Use instance attributes
class GoodScorer(Scorer):
results: list[str] = None

name: str = "good_scorer"

def __init__(self):
self.results = [] # Per-instance state

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

Próximas etapas

Referências de API

As APIs do MLflow usadas neste guia incluem: