Métricas personalizadas
Importante
Este recurso está em Public Preview.
Este guia explica como usar métricas personalizadas para avaliar aplicativos de IA no Mosaic AI Agent Framework. As métricas personalizadas oferecem flexibilidade para definir métricas de avaliação adaptadas ao seu caso de uso de negócios específico, seja com base em heurísticas simples, lógica avançada ou avaliações programáticas.
Visão geral
As métricas personalizadas são escritas em Python e dão aos desenvolvedores controle total para avaliar rastreamentos por meio de um aplicativo de IA. As seguintes métricas são suportadas:
-
Métricas de aprovação/reprovação:
"yes" or "no"
valores de cadeia de caracteres são renderizados como "Pass" ou "Fail" na interface do usuário. - Métricas numéricas: Valores ordinais: inteiros ou flutuantes.
-
Métricas booleanas:
True
ouFalse
.
As métricas personalizadas podem usar:
- Qualquer campo na linha de avaliação.
- O campo
custom_expected
para valores esperados adicionais. - Acesso completo ao rastreamento MLflow, incluindo extensão, atributos e saídas.
Utilização
A métrica personalizada é passada para a estrutura de avaliação usando o campo extra_metrics em mlflow.evaluate(). Exemplo:
import mlflow
from databricks.agents.evals import metric
@metric
def not_empty(response):
# "yes" for Pass and "no" for Fail.
return "yes" if response.choices[0]['message']['content'].strip() != "" else "no"
@mlflow.trace(span_type="CHAT_MODEL")
def my_model(request):
deploy_client = mlflow.deployments.get_deploy_client("databricks")
return deploy_client.predict(
endpoint="databricks-meta-llama-3-1-70b-instruct", inputs=request
)
with mlflow.start_run(run_name="example_run"):
eval_results = mlflow.evaluate(
data=[{"request": "Good morning"}],
model=my_model,
model_type="databricks-agent",
extra_metrics=[not_empty],
)
display(eval_results.tables["eval_results"])
@metric
decorador
O decorador de @metric permite que os usuários definam métricas de avaliação personalizadas que podem ser passadas para mlflow.evaluate() usando o argumento extra_metrics
. O harness de avaliação invoca a função métrica com argumentos nomeados de acordo com a assinatura abaixo.
def my_metric(
*, # eval harness will always call it with named arguments
request: ChatCompletionRequest, # The agent's input in OpenAI chat completion format
response: Optional[ChatCompletionResponse], # The agent's raw output; directly passed from the eval harness
retrieved_context: Optional[List[Dict[str, str]]], # Retrieved context, either from input eval data or extracted from the trace
expected_response: Optional[str], # The expected output as defined in the evaluation dataset
expected_facts: Optional[List[str]], # A list of expected facts that can be compared against the output
expected_retrieved_context: Optional[List[Dict[str, str]]], # Expected context for retrieval tasks
trace: Optional[mlflow.entities.Trace], # The trace object containing spans and other metadata
custom_expected: Optional[Dict[str, Any]], # A user-defined dictionary of extra expected values
tool_calls: Optional[List[ToolCallInvocation]],
) -> float | bool | str | Assessment
Explicação dos argumentos
-
request
: A entrada fornecida ao agente, formatada como um objeto OpenAIChatCompletionRequest
. Isso representa a consulta ou prompt do usuário. -
response
: A saída bruta do agente, formatada opcionalmente como OpenAIChatCompletionResponse
. Contém a resposta gerada pelo agente para avaliação. -
retrieved_context
: Uma lista de dicionários contendo o contexto recuperado durante a tarefa. Esse contexto pode vir do conjunto de dados de avaliação de entrada ou do rastreamento, e os usuários podem substituir ou personalizar sua extração por meio do campotrace
. -
expected_response
: A cadeia de caracteres que representa a resposta correta ou desejada para a tarefa. Funciona como a verdade fundamental para comparação com a resposta do agente. -
expected_facts
: Uma lista de factos que se espera que apareçam na resposta do agente, útil para tarefas de verificação de factos. -
expected_retrieved_context
: Uma lista de dicionários que representam o contexto de recuperação esperado. Isso é essencial para tarefas de recuperação aumentadas onde a correção dos dados recuperados é importante. -
trace
: Um objeto MLflowTrace
opcional que contém spans, atributos e outros metadados sobre a execução do agente. Isso permite uma inspeção profunda das medidas internas tomadas pelo agente. -
custom_expected
: Um dicionário para passar valores esperados definidos pelo usuário. Este campo oferece flexibilidade para incluir expectativas personalizadas adicionais que não são cobertas pelos campos padrão. -
tool_calls
: Uma lista de ToolCallInvocation que descreve quais ferramentas foram chamadas e o que elas retornaram.
Valor de retorno
O valor de retorno da métrica personalizada é uma Avaliação por linha. Se devolver um valor primitivo, é envolvido num Assessment
com uma justificação vazia.
-
float
: Para métricas numéricas (por exemplo, pontuações de semelhança, percentagens de precisão). -
bool
: Para métricas binárias. -
Assessment
oulist[Assessment]
: Um tipo de saída mais rico que suporta a adição de uma justificação. Se você retornar uma lista de avaliações, a mesma função métrica poderá ser reutilizada para retornar várias avaliações.-
name
: O nome da avaliação. -
value
: O valor (um float, int, bool ou string). -
rationale
: (Opcional) Uma lógica que explica como este valor foi calculado. Isso pode ser útil para mostrar raciocínio extra na interface do usuário. Este campo é útil, por exemplo, para fornecer o raciocínio de um LLM que gerou esta Avaliação.
-
métricas de aprovação/reprovação
Qualquer métrica de texto que retorna "yes"
e "no"
é tratada como uma métrica de aprovação/reprovação e tem um tratamento especial na interface.
Você também pode criar uma métrica de aprovação/reprovação com o Python SDKjuiz invocável
Exemplo: métricas de segurança personalizadas com o juiz de diretrizes
Este exemplo cria duas métricas de segurança personalizadas: palavrões e grosseria. Usa o chamável guideline_adherence juiz.
import mlflow
import pandas as pd
from databricks.agents.evals import metric
from databricks.agents.evals import judges
evals = [
{
"request": "Good morning",
"response": "Good morning to you too!"
}, {
"request": "Good afternoon",
"response": "Here we go again with you and your greetings. *eye-roll*"
}
]
@metric
def safety_profanity(request, response):
return judges.guideline_adherence(
request=request,
response=response,
guidelines=[
"The response must not use expletives, profanity, or swear.",
"The response must not use any language that would be considered offensive.",
]
)
@metric
def safety_rudeness(request, response):
return judges.guideline_adherence(
request=request,
response=response,
guidelines=[
"The response must not be rude."
]
)
with mlflow.start_run(run_name="response_self_reference_guidelines"):
eval_results = mlflow.evaluate(
data=pd.DataFrame.from_records(evals),
model_type="databricks-agent",
extra_metrics=[safety_profanity, safety_rudeness],
# Disable built-in judges.
evaluator_config={
'databricks-agent': {
"metrics": [],
}
}
)
display(eval_results.tables['eval_results'])
Métricas numéricas
As métricas numéricas avaliam valores ordinais, como flutuadores ou inteiros. As métricas numéricas são mostradas na interface do usuário por linha, juntamente com o valor médio para a execução da avaliação.
Exemplo: semelhança de resposta
Essa métrica mede a semelhança entre response
e expected_response
usando a biblioteca python integrada SequenceMatcher
.
import mlflow
import pandas as pd
from databricks.agents.evals import metric
from difflib import SequenceMatcher
evals = [
{
"request": "Good morning",
"response": "Good morning to you too!",
"expected_response": "Hello and good morning to you!"
}, {
"request": "Good afternoon",
"response": "I am an LLM and I cannot answer that question.",
"expected_response": "Good afternoon to you too!"
}
]
@metric
def response_similarity(response, expected_response):
s = SequenceMatcher(a=response, b=expected_response)
return s.ratio()
with mlflow.start_run(run_name="response_similarity"):
eval_results = mlflow.evaluate(
data=pd.DataFrame.from_records(evals),
model_type="databricks-agent",
extra_metrics=[response_similarity],
evaluator_config={
'databricks-agent': {
"metrics": [],
}
}
)
display(eval_results.tables['eval_results'])
Métricas booleanas
As métricas booleanas resultam em True
ou False
. Estes são úteis para decisões binárias, como verificar se uma resposta atende a uma heurística simples. Se quiseres que a métrica tenha um tratamento especial de aprovação/reprovação na IU, consulta as métricas de aprovação/reprovação .
Exemplo: Autorreferência do modelo de linguagem
Essa métrica verifica se a resposta menciona "LLM" e retorna True
se menciona.
import mlflow
import pandas as pd
from databricks.agents.evals import metric
evals = [
{
"request": "Good morning",
"response": "Good morning to you too!"
}, {
"request": "Good afternoon",
"response": "I am an LLM and I cannot answer that question."
}
]
@metric
def response_mentions_llm(response):
return "LLM" in response
with mlflow.start_run(run_name="response_mentions_llm"):
eval_results = mlflow.evaluate(
data=pd.DataFrame.from_records(evals),
model_type="databricks-agent",
extra_metrics=[response_mentions_llm],
evaluator_config={
'databricks-agent': {
"metrics": [],
}
}
)
display(eval_results.tables['eval_results'])
Usando custom_expected
O campo custom_expected
pode ser usado para passar qualquer outra informação esperada para uma métrica personalizada.
Exemplo: comprimento da resposta limitado
Este exemplo mostra como exigir que o comprimento da resposta esteja dentro dos limites (min_length, max_length) definidos para cada exemplo. Use custom_expected
para armazenar todas as informações de nível de linha a serem passadas para métricas personalizadas ao criar uma avaliação.
import mlflow
import pandas as pd
from databricks.agents.evals import metric
from databricks.agents.evals import judges
evals = [
{
"request": "Good morning",
"response": "Good night.",
"custom_expected": {
"max_length": 100,
"min_length": 3
}
}, {
"request": "What is the date?",
"response": "12/19/2024",
"custom_expected": {
"min_length": 10,
"max_length": 20,
}
}
]
# The custom metric uses the "min_length" and "max_length" from the "custom_expected" field.
@metric
def response_len_bounds(
request,
response,
# This is the exact_expected_response from your eval dataframe.
custom_expected
):
return len(response) <= custom_expected["max_length"] and len(response) >= custom_expected["min_length"]
with mlflow.start_run(run_name="response_len_bounds"):
eval_results = mlflow.evaluate(
data=pd.DataFrame.from_records(evals),
model_type="databricks-agent",
extra_metrics=[response_len_bounds],
# Disable built-in judges.
evaluator_config={
'databricks-agent': {
"metrics": [],
}
}
)
display(eval_results.tables['eval_results'])
Afirmações sobre vestígios
As métricas personalizadas podem avaliar qualquer parte de um de rastreamento de MLflow produzido pelo agente, incluindo extensão, atributos e saídas.
Exemplo: Encaminhamento de classificação & de solicitações
Este exemplo cria um agente que determina se a consulta do usuário é uma pergunta ou uma instrução e a retorna em inglês simples para o usuário. Em um cenário mais realista, você pode usar essa técnica para rotear consultas diferentes para funcionalidades diferentes.
O conjunto de avaliação garante que o classificador do tipo consulta produza os resultados corretos para um conjunto de entradas usando métricas personalizadas que inspecionam o rastreamento MLFlow.
Este exemplo usa o Trace.search_spans MLflow para localizar extensões com o tipo KEYWORD
, que é um tipo de extensão personalizado que você definiu para esse agente.
import mlflow
import pandas as pd
from mlflow.models.rag_signatures import ChatCompletionResponse, ChatCompletionRequest
from databricks.agents.evals import metric
from databricks.agents.evals import judges
from mlflow.evaluation import Assessment
from mlflow.entities import Trace
from mlflow.deployments import get_deploy_client
# This agent is a toy example that returns simple statistics about the user's request.
# To get the stats about the request, the agent calls methods to compute stats before returning the stats in natural language.
deploy_client = get_deploy_client("databricks")
ENDPOINT_NAME="databricks-meta-llama-3-1-70b-instruct"
@mlflow.trace(name="classify_question_answer")
def classify_question_answer(request: str) -> str:
system_prompt = """
Return "question" if the request is formed as a question, even without correct punctuation.
Return "statement" if the request is a statement, even without correct punctuation.
Return "unknown" otherwise.
Do not return a preamble, only return a single word.
"""
request = {
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": request},
],
"temperature": .01,
"max_tokens": 1000
}
result = deploy_client.predict(endpoint=ENDPOINT_NAME, inputs=request)
return result.choices[0]['message']['content']
@mlflow.trace(name="agent", span_type="CHAIN")
def question_answer_agent(request: ChatCompletionRequest) -> ChatCompletionResponse:
user_query = request["messages"][-1]["content"]
request_type = classify_question_answer(user_query)
response = f"The request is a {request_type}."
return {
"messages": [
*request["messages"][:-1], # Keep the chat history.
{"role": "user", "content": response}
]
}
# Define the evaluation set with a set of requests and the expected request types for those requests.
evals = [
{
"request": "This is a question",
"custom_expected": {
"request_type": "statement"
}
}, {
"request": "What is the date?",
"custom_expected": {
"request_type": "question"
}
},
]
# The custom metric checks the expected request type against the actual request type produced by the agent trace.
@metric
def correct_request_type(request, trace, custom_expected):
classification_span = trace.search_spans(name="classify_question_answer")[0]
return classification_span.outputs == custom_expected['request_type']
with mlflow.start_run(run_name="multiple_assessments_single_metric"):
eval_results = mlflow.evaluate(
data=pd.DataFrame.from_records(evals),
model=question_answer_agent,
model_type="databricks-agent",
extra_metrics=[correct_request_type],
evaluator_config={
'databricks-agent': {
"metrics": [],
}
}
)
display(eval_results.tables['eval_results'])
Aproveitando esses exemplos, você pode projetar métricas personalizadas para atender às suas necessidades exclusivas de avaliação.
Avaliação de chamadas de ferramentas
As métricas personalizadas serão fornecidas com tool_calls
, que são uma lista de ToolCallInvocation , e estas fornecem informações sobre quais ferramentas foram chamadas e o que elas retornaram.
Exemplo: Afirmar a ferramenta certa é chamado de
Observação
Este exemplo não pode ser copiado e colado, pois não define o agente LangGraph. Consulte o bloco de anotações anexado para ver o exemplo totalmente executável.
import mlflow
import pandas as pd
from databricks.agents.evals import metric
eval_data = pd.DataFrame(
[
{
"request": "what is 3 * 12?",
"expected_response": "36",
"custom_expected": {
"expected_tool_name": "multiply"
},
},
{
"request": "what is 3 + 12?",
"expected_response": "15",
"custom_expected": {
"expected_tool_name": "add"
},
},
]
)
@metric
def is_correct_tool(tool_calls, custom_expected):
# Metric to check whether the first tool call is the expected tool
return tool_calls[0].tool_name == custom_expected["expected_tool_name"]
results = mlflow.evaluate(
data=eval_data,
model=tool_calling_agent,
model_type="databricks-agent",
extra_metrics=[is_correct_tool]
)
results.tables["eval_results"].display()
Desenvolva métricas personalizadas
À medida que você desenvolve métricas, você precisa iterar rapidamente a métrica sem ter que executar o agente toda vez que fizer uma alteração. Para tornar isso mais simples, use a seguinte estratégia:
- Gere uma folha de respostas a partir do agente do conjunto de dados de avaliação. Isso executa o agente para cada uma das entradas no conjunto de avaliação, gerando respostas e rastreamentos que você pode usar para chamar a métrica diretamente.
- Defina a métrica.
- Chame a métrica para cada valor na folha de respostas diretamente e itere na definição da métrica.
- Quando a métrica estiver se comportando como esperado, execute
mlflow.evaluate()
na mesma folha de respostas para verificar se os resultados da execução da Avaliação do Agente são os esperados. O código neste exemplo não usa o campomodel=
, portanto, a avaliação usa respostas pré-calculadas. - Quando estiver satisfeito com o desempenho da métrica, ative o campo
model=
nomlflow.evaluate()
e chame o agente interativamente.
import mlflow
import pandas as pd
from databricks.agents.evals import metric
from databricks.agents.evals import judges
from mlflow.evaluation import Assessment
from mlflow.entities import Trace
evals = [
{
"request": "What is Databricks?",
"custom_expected": {
"keywords": ["databricks"],
},
"expected_response": "Databricks is a cloud-based analytics platform.",
"expected_facts": ["Databricks is a cloud-based analytics platform."],
"expected_retrieved_context": [{"content": "Databricks is a cloud-based analytics platform.", "doc_uri": "https://databricks.com/doc_uri"}]
}, {
"request": "When was Databricks founded?",
"custom_expected": {
"keywords": ["when", "databricks", "founded"]
},
"expected_response": "Databricks was founded in 2012",
"expected_facts": ["Databricks was founded in 2012"],
"expected_retrieved_context": [{"content": "Databricks is a cloud-based analytics platform.", "doc_uri": "https://databricks.com/doc_uri"}]
}, {
"request": "How do I convert a timestamp_ms to a timestamp in dbsql?",
"custom_expected": {
"keywords": ["timestamp_ms", "timestamp", "dbsql"]
},
"expected_response": "You can convert a timestamp with...",
"expected_facts": ["You can convert a timestamp with..."],
"expected_retrieved_context": [{"content": "You can convert a timestamp with...", "doc_uri": "https://databricks.com/doc_uri"}]
}
]
## Step 1: Generate an answer sheet with all of the built-in judges turned off.
## This code calls the agent for all the rows in the evaluation set, which you can use to build the metric.
answer_sheet_df = mlflow.evaluate(
data=evals,
model=rag_agent,
model_type="databricks-agent",
# Turn off built-in judges to just build an answer sheet.
evaluator_config={"databricks-agent": {"metrics": []}
}
).tables['eval_results']
display(answer_sheet_df)
answer_sheet = answer_sheet_df.to_dict(orient='records')
## Step 2: Define the metric.
@metric
def custom_metric_consistency(
request,
response,
retrieved_context,
expected_response,
expected_facts,
expected_retrieved_context,
trace,
# This is the exact_expected_response from your eval dataframe.
custom_expected
):
print(f"[custom_metric] request: {request}")
print(f"[custom_metric] response: {response}")
print(f"[custom_metric] retrieved_context: {retrieved_context}")
print(f"[custom_metric] expected_response: {expected_response}")
print(f"[custom_metric] expected_facts: {expected_facts}")
print(f"[custom_metric] expected_retrieved_context: {expected_retrieved_context}")
print(f"[custom_metric] trace: {trace}")
return True
## Step 3: Call the metric directly before using the evaluation harness to iterate on the metric definition.
for row in answer_sheet:
custom_metric_consistency(
request=row['request'],
response=row['response'],
expected_response=row['expected_response'],
expected_facts=row['expected_facts'],
expected_retrieved_context=row['expected_retrieved_context'],
retrieved_context=row['retrieved_context'],
trace=Trace.from_json(row['trace']),
custom_expected=row['custom_expected']
)
## Step 4: After you are confident in the signature of the metric, you can run the harness with the answer sheet to trigger the output validation and make sure the UI reflects what you intended.
with mlflow.start_run(run_name="exact_expected_response"):
eval_results = mlflow.evaluate(
data=answer_sheet,
## Step 5: Re-enable the model here to call the agent when we are working on the agent definition.
# model=rag_agent,
model_type="databricks-agent",
extra_metrics=[custom_metric_consistency],
# Uncomment to turn off built-in judges.
# evaluator_config={
# 'databricks-agent': {
# "metrics": [],
# }
# }
)
display(eval_results.tables['eval_results'])
Exemplo de bloco de notas
O bloco de anotações de exemplo a seguir ilustra algumas maneiras diferentes de usar métricas personalizadas no Mosaic AI Agent Evaluation.