Udostępnij przez


Metryki niestandardowe (MLflow 2)

Ważne

Usługa Databricks zaleca używanie platformy MLflow 3 do oceniania i monitorowania aplikacji GenAI. Na tej stronie opisano ocenę agenta MLflow 2.

W tym przewodniku wyjaśniono, jak używać niestandardowych metryk do oceny aplikacji sztucznej inteligencji w ramach Mosaic AI Agent Framework. Metryki niestandardowe zapewniają elastyczność definiowania metryk oceny dostosowanych do konkretnego przypadku użycia biznesowego, niezależnie od tego, czy są oparte na prostych heurystyce, zaawansowanej logice czy ocenach programowych.

Przegląd

Wskaźniki niestandardowe są zapisywane w języku Python i dają deweloperom pełną kontrolę do oceny śladów przy użyciu aplikacji AI. Obsługiwane są następujące metryki:

Niestandardowych metryk można używać:

  • Dowolne pole w wierszu oceny.
  • Pole custom_expected dla dodatkowych oczekiwanych wartości.
  • Pełny dostęp do śladu MLflow, w tym spanów, atrybutów i danych wyjściowych.

Użycie

Metryka niestandardowa jest przekazywana do struktury oceny przy użyciu pola extra_metrics w pliku mlflow.evaluate(). Przykład:

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-3-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 dekorator

Dekorator @metric umożliwia użytkownikom definiowanie niestandardowych metryk oceny, które można przekazać do mlflow.evaluate() przy użyciu argumentu extra_metrics. Narzędzie oceny wywołuje funkcję metriczną za pomocą nazwanych argumentów na podstawie poniższej sygnatury.

def my_metric(
  *,  # eval harness will always call it with named arguments
  request: Dict[str, Any],  # The agent's raw input as a serializable object
  response: Optional[Dict[str, Any]],  # 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
  guidelines: Optional[Union[List[str], Dict[str, List[str]]]]  # A list of guidelines or mapping a name of guideline to an array of guidelines for that name
  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

Wyjaśnienie argumentów

  • request: dane wejściowe dostarczone do agenta sformatowane jako dowolny obiekt z możliwością serializacji. Reprezentuje to zapytanie użytkownika lub monit.
  • response: nieprzetworzone dane wyjściowe z agenta sformatowane jako opcjonalny dowolny obiekt z możliwością serializacji. Zawiera on wygenerowaną odpowiedź agenta na potrzeby oceny.
  • retrieved_context: lista słowników zawierających kontekst pobrany podczas zadania. Ten kontekst może pochodzić z zestawu danych oceny wejściowej lub ze śledzenia, a użytkownicy mogą nadpisać lub dostosować jego wyodrębnianie za pomocą pola trace.
  • expected_response: ciąg reprezentujący poprawną lub żądaną odpowiedź dla zadania. Działa jako podstawa prawdy do porównania z odpowiedzią agenta.
  • expected_facts: Lista faktów, które powinny pojawić się w odpowiedzi agenta, przydatne w przypadku zadań sprawdzania faktów.
  • guidelines: lista wytycznych lub mapowanie nazwy wytycznych na tablicę wytycznych powiązanych z tą nazwą. Wytyczne umożliwiają zapewnienie ograniczeń dla dowolnego pola, które można następnie ocenić przez sędziego przestrzegania wytycznych.
  • expected_retrieved_context: lista słowników reprezentujących oczekiwany kontekst pobierania. Jest to niezbędne w przypadku zadań rozszerzonych pobierania, w których istotna jest poprawność pobranych danych.
  • trace: opcjonalny obiekt MLflow Trace zawierający zakresy, atrybuty i inne metadane dotyczące wykonywania agenta. Pozwala to na głęboką inspekcję wewnętrznych kroków podjętych przez agenta.
  • custom_expected: słownik do przekazywania wartości oczekiwanych zdefiniowanych przez użytkownika. To pole zapewnia elastyczność dołączania dodatkowych oczekiwań niestandardowych, które nie są objęte polami standardowymi.
  • tool_calls: Lista ToolCallInvocation, która opisuje, które narzędzia zostały wywołane i co zwróciły.

Wartość zwracana

Wartość zwracana metryki dostosowanej jest dla każdego wiersza określana jako Assessment. Jeśli zwracasz element pierwotny, jest on owinięty w Assessment z pustym uzasadnieniem.

  • float: w przypadku metryk liczbowych (np. wyników podobieństwa, wartości procentowe dokładności).
  • bool: w przypadku metryk binarnych.
  • Assessment lub list[Assessment]: bogatszy typ danych wyjściowych obsługujący dodawanie uzasadnienia. Jeśli zwrócisz listę ocen, ta sama funkcja metryki może zostać ponownie użyta do zwrócenia wielu ocen.
    • name: nazwa oceny.
    • value: wartość (liczba zmiennoprzecinkowa, liczba całkowita, boolean lub ciąg).
    • rationale: (Opcjonalnie) Uzasadnienie objaśniające sposób obliczania tej wartości. Może to być przydatne, aby pokazać dodatkowe rozumowanie w interfejsie użytkownika. To pole jest przydatne, na przykład podczas podawania rozumowania z modelu LLM, który wygenerował tę ocenę.

metryki zaliczone/niezaliczone

Każda metryka ciągu zwracająca "yes" i "no" jest traktowana jako metryka pass/fail i ma specjalne traktowanie w interfejsie użytkownika.

Możesz również utworzyć metrykę zaliczenie/niezaliczenie za pomocą zestawu SDK Python do oceniania. To daje ci większą kontrolę nad tym, które części śladu oceniać i które oczekiwane pola stosować. Możesz użyć dowolnych wbudowanych sędziów oceny agentów AI Mosaic. Zobacz Wbudowane sędziowie sztucznej inteligencji (MLflow 2).

Upewnij się, że pobrany kontekst nie zawiera danych osobowych (DPI).

W tym przykładzie wywoływany jest sędzia guideline_adherence, aby upewnić się, że pobrany kontekst nie zawiera PII.

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!",
    "retrieved_context": [{
      "content": "The email address is noreply@databricks.com",
    }],
  }, {
    "request": "Good afternoon",
    "response": "This is actually the morning!",
    "retrieved_context": [{
      "content": "fake retrieved context",
    }],
  }
]

@metric
def retrieved_context_no_pii(request, response, retrieved_context):
  retrieved_content = '\n'.join([c['content'] for c in retrieved_context])
  return judges.guideline_adherence(
    request=request,
    # You can also pass in per-row guidelines by adding `guidelines` to the signature of your metric
    guidelines=[
      "The retrieved context must not contain personally identifiable information.",
    ],
    # `guidelines_context` requires `databricks-agents>=0.20.0`
    guidelines_context={"retrieved_context": retrieved_content},
  )

with mlflow.start_run(run_name="safety"):
    eval_results = mlflow.evaluate(
        data=pd.DataFrame.from_records(evals),
        model_type="databricks-agent",
        extra_metrics=[retrieved_context_no_pii],
        # Disable built-in judges.
        evaluator_config={
            'databricks-agent': {
                "metrics": [],
            }
        }
    )
    display(eval_results.tables['eval_results'])

metryki liczbowe

Metryki numeryczne oceniają wartości numeryczne, takie jak liczby zmiennoprzecinkowe lub liczby całkowite. Metryki liczbowe są wyświetlane w interfejsie użytkownika na wiersz wraz ze średnią wartością przebiegu oceny.

Przykład: podobieństwo odpowiedzi

Ta metryka mierzy podobieństwo między response a expected_response przy użyciu wbudowanej biblioteki języka 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'])

metryki boolowskie

Metryki logiczne przyjmują wartość True lub False. Są one przydatne w przypadku decyzji binarnych, takich jak sprawdzanie, czy odpowiedź spełnia prostą heurystyczną. Jeśli chcesz, aby metryka miała specjalne podejście "pass/fail" w interfejsie użytkownika, zobacz metryki "pass/fail".

Przykład: Sprawdzanie, czy żądania wejściowe są prawidłowo sformatowane

Ta metryka sprawdza, czy dowolne dane wejściowe są sformatowane zgodnie z oczekiwaniami i zwracają True, jeśli tak jest.

import mlflow
import pandas as pd
from databricks.agents.evals import metric

evals = [
  {
    "request": {"messages": [{"role": "user", "content": "Good morning"}]},
  }, {
    "request": {"inputs": ["Good afternoon"]},
  }, {
    "request": {"inputs": [1, 2, 3, 4]},
  }
]

@metric
def check_valid_format(request):
  # Check that the request contains a top-level key called "inputs" with a value of a list
  return "inputs" in request and isinstance(request.get("inputs"), list)

with mlflow.start_run(run_name="check_format"):
  eval_results = mlflow.evaluate(
      data=pd.DataFrame.from_records(evals),
      model_type="databricks-agent",
      extra_metrics=[check_valid_format],
      # Disable built-in judges.
      evaluator_config={
          'databricks-agent': {
              "metrics": [],
          }
      }
  )
eval_results.tables['eval_results']

Przykład: Samoodniesienie modelu językowego

Ta metryka sprawdza, czy odpowiedź wspomina "LLM" i zwraca True, jeśli tak.

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'])

Korzystanie z custom_expected

Pole custom_expected może być używane do przekazywania dowolnych innych oczekiwanych informacji do dostosowanej metryki.

Przykład: długość odpowiedzi ograniczona

W tym przykładzie pokazano, jak wymagać, aby długość odpowiedzi mieściła się w granicach (min_length, max_length) ustawionych dla każdego przykładu. Użyj custom_expected do przechowywania dowolnych informacji na poziomie wiersza, które mają być przekazywane do metryk niestandardowych podczas tworzenia oceny.

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'])

Potwierdzenia dotyczące śladów

Metryki niestandardowe mogą oceniać dowolną część śladu MLflow generowanego przez agenta, w tym sekcje, atrybuty i dane wyjściowe.

Przykład: klasyfikacja i routing żądań

W tym przykładzie utworzono agenta, który określa, czy zapytanie użytkownika jest pytaniem, czy instrukcją i zwraca je w języku angielskim dla użytkownika. W bardziej realistycznym scenariuszu można użyć tej techniki do kierowania różnych zapytań do różnych funkcji.

Zestaw oceny zapewnia, że klasyfikator typu zapytania generuje odpowiednie wyniki dla zestawu danych wejściowych przy użyciu niestandardowych metryk, które analizują ścieżkę MLFlow.

W tym przykładzie użyto MLflow Trace.search_spans do znalezienia zakresów typu KEYWORD, który jest niestandardowym typem zakresu zdefiniowanym dla tego agenta.


import mlflow
import pandas as pd
from mlflow.types.llm 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-3-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'])

Korzystając z tych przykładów, można zaprojektować metryki niestandardowe w celu spełnienia unikatowych potrzeb oceny.

Ocenianie wywołań narzędzi

Metryki niestandardowe będą dostarczane z tool_calls, które stanowią listę wywołań ToolCallInvocation, dającą informacje o tym, które narzędzia zostały wywołane i co zwróciły.

Przykład: deklarowanie właściwego narzędzia nazywa się

Notatka

Ten przykład nie jest możliwy do skopiowania, ponieważ nie definiuje agenta LangGraph. Zapoznaj się z dołączonym notesem , aby uzyskać w pełni działający przykład.

import mlflow
import pandas as pd
from databricks.agents.evals import metric
from databricks.agents.evals import judges

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"]

@metric
def is_reasonable_tool(request, trace, tool_calls):
  # Metric using the guideline adherence judge to determine whether the chosen tools are reasonable
  # given the set of available tools. Note that `guidelines_context` requires `databricks-agents >= 0.20.0`

  return judges.guideline_adherence(
    request=request["messages"][0]["content"],
    guidelines=[
      "The selected tool must be a reasonable tool call with respect to the request and available tools.",
    ],
    # `guidelines_context` requires `databricks-agents>=0.20.0`
    guidelines_context={
      "available_tools": str(tool_calls[0].available_tools),
      "chosen_tools": str([tool_call.tool_name for tool_call in tool_calls]),
    },
  )

results = mlflow.evaluate(
  data=eval_data,
  model=tool_calling_agent,
  model_type="databricks-agent",
  extra_metrics=[is_correct_tool]
)
results.tables["eval_results"].display()

Opracowywanie metryk niestandardowych

Podczas opracowywania metryk należy dokonywać szybkich iteracji na metrykach bez konieczności wykonywania agenta za każdym razem, gdy dokonujesz zmiany. Aby to ułatwić, użyj następującej strategii:

  1. Wygeneruj arkusz odpowiedzi przy użyciu agenta zestawu danych ewaluacyjnych. Uruchamia agenta dla każdego wpisu w zestawie oceny, generując odpowiedzi i ślady, które umożliwiają bezpośrednie użycie metryki.
  2. Zdefiniuj metryki.
  3. Wywołaj metrykę dla każdej wartości w arkuszu odpowiedzi bezpośrednio i iteruj nad definicją metryki.
  4. Gdy metryka działa zgodnie z oczekiwaniami, uruchom mlflow.evaluate() na tym samym arkuszu odpowiedzi, aby zweryfikować, czy wyniki z procesu Oceny Agenta są zgodne z Twoimi przewidywaniami. Kod w tym przykładzie nie używa pola model=, więc ocena używa wstępnie obliczonych odpowiedzi.
  5. Jeśli wydajność metryki jest satysfakcjonująca, włącz pole model= w mlflow.evaluate(), aby wywołać agenta interaktywnie.
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'])

Przykładowy notatnik

Poniższy przykładowy notes ilustruje kilka różnych sposobów używania metryk niestandardowych w narzędziu Mosaic AI Agent Evaluation.

Przykładowy notatnik do oceniania agenta przy użyciu metryk niestandardowych

Weź notatnik