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:
- Definir uma métrica de avaliação heurística ou baseada em código personalizada.
- Personalizando como os dados do rastreamento do seu aplicativo são mapeados para os juízes do LLM apoiados pela pesquisa do Databricks.
- Utilizar seu próprio modelo LLM (em vez de um modelo LLM judge hospedado pela Databricks) para avaliação.
- 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.
O trecho de código abaixo define esse pontuador personalizado e o usa com mlflow.genai.evaluate()
:
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.
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 |
---|---|---|
| Aprovado/Reprovado | Avaliação binária |
| verdadeiro/falso | Verificações Boolean |
| Valor numérico | Pontuações, contagens |
Valor + justificativa | Avaliação detalhada | |
| 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.
@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.
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.
@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:
- Se o marcador retornar um ou mais objetos
Feedback
, os camposFeedback.name
terão precedência, se especificados. - Para valores de retorno primitivos ou
Feedback
s sem nome, o nome da função (para o decorador@scorer
) ou o campoScorer.name
(para a classeScorer
) 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 |
|
|
---|---|---|
Valor primitivo ( | Nome da função |
|
Feedback sem nome | Nome da função |
|
Feedback com nome |
|
|
|
|
|
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.
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.
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:
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.
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.
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
- Exemplos de pontuadores baseados em código - Veja muitos exemplos de pontuadores baseados em código
- Desenvolva marcadores baseados em código - ou acompanhe o fluxo de trabalho de desenvolvimento para marcadores personalizados
- Avaliação de desempenho - Entenda como
mlflow.genai.evaluate()
usa seus marcadores - Monitoramento de produção para GenAI - implantei seus pontuadores para monitoramento contínuo
Referências de API
As APIs do MLflow usadas neste guia incluem: