Métricas personalizadas
Importante
Esse recurso está em uma versão prévia.
Este guia explica como usar métricas personalizadas para avaliar aplicativos de IA no Mosaic AI Agent Framework. As métricas personalizadas fornecem flexibilidade para definir métricas de avaliação adaptadas ao seu caso de uso comercial específico, seja com base em heurística 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. Há suporte para as seguintes métricas:
- Métricas de aprovação/reprovação: valores string
"yes" or "no"
renderizados como "Aprovado" ou "Reprovado" na interface do usuário. - Métricas Numéricas: Valores Ordinais: inteiros ou números decimais.
- métricas boolianas:
True
ouFalse
.
As métricas personalizadas podem usar:
- Qualquer campo na linha de avaliação.
- O campo
custom_expected
para valores adicionais esperados. - Conclua o acesso ao rastreamento do MLflow, incluindo intervalos, atributos e saídas.
Uso
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"])
Decorador @metric
O decorador @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 agente de avaliação invoca a função de métrica com argumentos nomeados com base na 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 objetoChatCompletionRequest
OpenAI. Isso representa a consulta ou o prompt do usuário.response
: a saída bruta do agente, formatada opcionalmente como umChatCompletionResponse
OpenAI. Ele contém a resposta gerada pelo agente para avaliação.retrieved_context
: uma lista de dicionários que contêm 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. Ele atua como a verdade básica para comparação com a resposta do agente.expected_facts
: uma lista de fatos esperados para aparecer na resposta do agente, útil para tarefas de verificação de fatos.expected_retrieved_context
: uma lista de dicionários que representam o contexto de recuperação esperado. Isso é essencial para tarefas aumentadas de recuperação em que a correção dos dados recuperados importa.trace
: um objeto MLflowTrace
opcional que contém intervalos, atributos e outros metadados sobre a execução do agente. Isso permite uma inspeção profunda das etapas internas executadas pelo agente.custom_expected
: um dicionário para passar valores esperados definidos pelo usuário. Esse campo fornece 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 seus retornos.
Valor retornado
O valor retornado da métrica personalizada é uma Avaliação por linha. Se você retornar um primitivo, ele será encapsulado em um Assessment
com uma lógica vazia.
float
: para métricas numéricas (por exemplo, pontuações de similaridade, porcentagens de precisão).bool
: para métricas binárias.Assessment
oulist[Assessment]
: um tipo de saída mais rico que dá suporte à adição de uma justificativa. Se você retornar uma lista de avaliações, a mesma função de métrica poderá ser usada novamente para retornar várias avaliações.name
: o nome da avaliação.value
: o valor (um float, int, bool ou cadeia de caracteres).rationale
: (Opcional) Uma lógica que explica como esse valor foi calculado. Isso pode ser útil para mostrar um raciocínio extra na interface do usuário. Esse campo é útil, por exemplo, ao fornecer o raciocínio de uma LLM que gerou essa Avaliação.
Métricas de aprovação ou reprovação do
Qualquer métrica de cadeia de caracteres que retorna "yes"
e "no"
é tratada como uma métrica de aprovação/falha e tem um tratamento especial na interface do usuário.
Você também pode criar uma métrica de aprovação/reprovação com o SDK do Python juiz chamável. Isso oferece mais controle sobre quais partes do rastreamento serão avaliadas e quais campos esperados usar. Você pode usar qualquer um dos juízes integrados da Avaliação de Agentes de IA do Mosaic. Confira Juízes de IA integrados.
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. Ele usa o juiz guideline_adherence chamável.
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 floats ou inteiros. As métricas numéricas são mostradas na interface do usuário por linha, juntamente com o valor médio da execução da avaliação.
Exemplo: similaridade de resposta
Essa métrica mede a similaridade entre response
e expected_response
usando a biblioteca interna do Python 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 boolianas
As métricas boolianas são avaliadas como True
ou False
. Elas são úteis para decisões binárias, como verificar se uma resposta atende a uma heurística simples. Se você quiser que a métrica tenha um tratamento especial de aprovação/falha na interface do usuário, confira métricas de aprovação/falha.
Exemplo: autorreferência de modelo de linguagem
Essa métrica verifica se a resposta menciona "LLM" e retorna True
se o faz.
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 o 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 informações em nível de linha que devem ser 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'])
Declarações sobre rastreamentos
Métricas personalizadas podem avaliar qualquer parte de um rastreamento do MLflow produzido pelo agente, incluindo transposições, atributos e saídas.
Exemplo: classificação da solicitação e roteamento
Este exemplo cria um agente que determina se a consulta de usuário é uma pergunta ou uma instrução e a retorna em inglês sem formatação para o usuário. Em um cenário mais realista, você pode usar essa técnica para rotear consultas diferentes para diferentes funcionalidades.
O conjunto de avaliação garante que o classificador de tipo de consulta produza os resultados certos para um conjunto de entradas usando métricas personalizadas que inspecionam o rastreamento do MLFlow.
Este exemplo usa o Trace.search_spans MLflow para localizar intervalos com o tipo KEYWORD
, que é um tipo de intervalo 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 criar métricas personalizadas para atender às suas necessidades de avaliação exclusivas.
Avaliar chamadas de ferramenta
As métricas personalizadas serão fornecidas com tool_calls
, que inclui uma lista de ToolCallInvocation, fornecendo informações sobre quais ferramentas foram chamadas e o que elas retornaram.
Exemplo: afirmar que a ferramenta certa é chamada
Observação
Este exemplo não pode ser copiado, pois não define o agente do LangGraph. Confira o bloco de anotações anexado para obter 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()
Desenvolver métricas personalizadas
À medida que você desenvolve métricas, precisa fazer ajustes rápidos na métrica sem ter que executar o agente sempre que fizer uma alteração. Para tornar isso mais simples, use a seguinte estratégia:
- Gere uma folha de respostas 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 podem ser usados diretamente para chamar a métrica.
- Defina a métrica.
- Chame diretamente a métrica para cada valor na folha de respostas e itere sobre a definição da métrica.
- Quando a métrica estiver se comportando como você espera, execute
mlflow.evaluate()
na mesma folha de respostas para verificar se os resultados da execução da Avaliação do Agente são o que você espera. O código neste exemplo não usa o campomodel=
, portanto, a avaliação usa respostas pré-computadas. - Quando estiver satisfeito com o desempenho da métrica, habilite o campo
model=
emmlflow.evaluate()
para chamar 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'])
Bloco de anotações de exemplo
O notebook de exemplo a seguir ilustra algumas maneiras diferentes de usar métricas personalizadas na Avaliação do Agente de IA do Mosaico.