[翻訳] MLflow LLM Evaluation

[MLflow LLM Evaluation](https://mlflow.org/docs/latest/llms/llm-evaluate/index.html)の翻訳です。

:::note warn
本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

ChatGPTの出現によって、LLMはQ&A、翻訳、テキスト要約のように様々な領域でのテキスト生成のパワーを示しています。LLMのパフォーマンスの評価は、比較対象となる単一の正解データが存在しないため、従来のMLモデルとは若干異なります。MLflowは、あなたのLLMの評価の助けとなるAPIである[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)を提供します。

MLflowのLLM評価機能は、3つの主要なコンポーネントから構成されます:

1. **評価するモデル:** MLflowの`pyfunc`モデル、登録されているMLflowモデルをポイントするURI、HuggingFaceのテキスト要約パイプラインのように、あなたのモデルを表現する呼び出し可能なPythonであれば大丈夫です。
1. **メトリクス:** 計算するメトリクス、LLM評価ではLLMメトリクスを使用します。
1. **評価データ:** モデルの評価に用いるデータ、pandasデータフレーム、Pythonのリスト、numpyのarray、[mlflow\.data\.dataset\.Dataset\(\)](https://mlflow.org/docs/latest/python_api/mlflow.data.html#mlflow.data.dataset.Dataset)のインスタンスを使うことができます。

# 完全なノートブックガイドと例

LLMに対するMLflowの評価機能のパワーとシンプルさを説明する、包括的なユースケース指向のガイドに興味があるのであれば、以下のノートブックコレクションをご覧ください:

[View the Notebook Guides](https://mlflow.org/docs/latest/llms/llm-evaluate/notebooks/index.html)

# クイックスタート

以下は、MLflowのLLM評価がどのように動作するのかに対するクイックな概要を示すシンプルな例となります。この例では、カスタムプロンプトを用いて「openai/gpt-4」をラッピングすることで、シンプルなQ&Aモデルを構築しています。お使いのIPythonやローカルのエディタにこちらを貼り付けて実行し、求められたら必要な依存関係をインストールします。コードの実行にはOpenAIのAPIキーが必要となりますので、OpenAIキーをお持ちでない場合には、[OpenAIのガイド](https://platform.openai.com/account/api-keys)に沿ってセットアップを行うことができます。

```py
export OPENAI_API_KEY='your-api-key-here'
```
```py
import mlflow
import openai
import os
import pandas as pd
from getpass import getpass

eval_data = pd.DataFrame(
    {
        "inputs": [
            "What is MLflow?",
            "What is Spark?",
        ],
        "ground_truth": [
            "MLflow is an open-source platform for managing the end-to-end machine learning (ML) "
            "lifecycle. It was developed by Databricks, a company that specializes in big data and "
            "machine learning solutions. MLflow is designed to address the challenges that data "
            "scientists and machine learning engineers face when developing, training, and deploying "
            "machine learning models.",
            "Apache Spark is an open-source, distributed computing system designed for big data "
            "processing and analytics. It was developed in response to limitations of the Hadoop "
            "MapReduce computing model, offering improvements in speed and ease of use. Spark "
            "provides libraries for various tasks such as data ingestion, processing, and analysis "
            "through its components like Spark SQL for structured data, Spark Streaming for "
            "real-time data processing, and MLlib for machine learning tasks",
        ],
    }
)

with mlflow.start_run() as run:
    system_prompt = "Answer the following question in two sentences"
    # Wrap "gpt-4" as an MLflow model.
    logged_model_info = mlflow.openai.log_model(
        model="gpt-4",
        task=openai.chat.completions,
        artifact_path="model",
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": "{question}"},
        ],
    )

    # Use predefined question-answering metrics to evaluate our model.
    results = mlflow.evaluate(
        logged_model_info.model_uri,
        eval_data,
        targets="ground_truth",
        model_type="question-answering",
    )
    print(f"See aggregated evaluation results below: \n{results.metrics}")

    # Evaluation result for each data record is available in `results.tables`.
    eval_table = results.tables["eval_results_table"]
    print(f"See evaluation table below: \n{eval_table}")
```

# LLM Evaluationのメトリクス

MLflowのLLM評価メトリクスには2つのタイプがあります:

1. **ヒューリスティック(経験則)ベースのメトリクス:** これらのメトリクスは、Rouge ([rougeL\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.rougeL)), Flesch Kincaid ([flesch\_kincaid\_grade\_level\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.flesch_kincaid_grade_level))やBilingual Evaluation Understudy (BLEU) ([bleu\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.bleu))のような特定の関数を用いてそれぞれのデータレコードのスコアを計算します。これらのメトリクスは、従来の連続値のメトリクスと似ています。ビルトインのヒューリスティックメトリクスのリストや、あなたの関数定義を用いたカスタムのメトリクスの定義方法に関しては、[ヒューリスティックベースのメトリクス](#ヒューリスティックベースのメトリクス)セクションをご覧ください。
1. **LLM-as-a-Judgeメトリクス:** LLM-as-a-Judgeは、モデル出力の品質をスコアリングするためにLLMを活用する新たなタイプのメトリックです。多くの場合で文脈や意味論的な精度のようなニュアンスを見逃してしまう、ヒューリスティックベースのメトリクスの限界を打破します。LLM-as-a-Judgeメトリクスは、人間による評価よりもスケーラブルでコスト効率が高いことに加え、より複雑な言語タスクに対してより人間のような評価を提供します。MLflowでは、さまざまなビルトインのLLM-as-a-Judgeメトリクスを提供し、自身のプロンプト、評点基準、リファレンスの例を用いたカスタムメトリクスの作成をサポートしています。詳細は[LLM-as-a-Judgeメトリクス](#llm-as-a-judgeメトリクス)をご覧ください。

## ヒューリスティックベースのメトリクス

### ビルトインのヒューリスティックメトリクス

ビルトインのヒューリスティックメトリクスの完全なリストに関しては、[こちらのページ](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html)をご覧ください。

### 定義済みモデルタイプによるデフォルトメトリクス

MLflow LLM Evaluationには、「質問-回答」のように事前に選択されたタスクに対するメトリクスのデフォルトコレクションが含まれています。あなたが評価しようとするLLMユースケースに応じて、これらの事前定義のコレクションは、評価実行のプロセスを劇的にシンプルなものにします。選択済みのタスクに対するデフォルトメトリクスを使うには、以下の例に示しているように[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)の`model_type`引数を指定します。

```py
results = mlflow.evaluate(
    model,
    eval_data,
    targets="ground_truth",
    model_type="question-answering",
)
```

サポートされるLLMモデルタイプと関連メトリクスを以下に一覧します:

- **question-answering:** `model_type="question-answering"`:

    - exact-match
    - [toxicity](https://huggingface.co/spaces/evaluate-measurement/toxicity) [^1]
    - [ari\_grade\_level](https://en.wikipedia.org/wiki/Automated_readability_index) [^2]
    - [flesch\_kincaid\_grade\_level](https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests#Flesch%E2%80%93Kincaid_grade_level) [^2]

- **text-summarization:** `model_type="text-summarization"`:

    - [ROUGE](https://huggingface.co/spaces/evaluate-metric/rouge) [^3]
    - [toxicity](https://huggingface.co/spaces/evaluate-measurement/toxicity) [^1]
    - [ari\_grade\_level](https://en.wikipedia.org/wiki/Automated_readability_index) [^2]
    - [flesch\_kincaid\_grade\_level](https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests#Flesch%E2%80%93Kincaid_grade_level) [^2]

- **text models:** `model_type="text"`:

    - [toxicity](https://huggingface.co/spaces/evaluate-measurement/toxicity) [^1]
    - [ari\_grade\_level](https://en.wikipedia.org/wiki/Automated_readability_index) [^2]
    - [flesch\_kincaid\_grade\_level](https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests#Flesch%E2%80%93Kincaid_grade_level) [^2]

- **retrievers:** `model_type="retriever"`:

    - [precision\_at\_k](https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Precision_at_k) [^4]
    - [recall\_at\_k](https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Recall) [^4]
    - [ndcg\_at\_k](https://en.wikipedia.org/wiki/Discounted_cumulative_gain#Normalized_DCG) [^4]


[^1]: [evaluate](https://pypi.org/project/evaluate)、[torch](https://pytorch.org/get-started/locally/)、[transformers](https://huggingface.co/docs/transformers/installation)のパッケージが必要。
[^2]: [textstat](https://pypi.org/project/textstat)のパッケージが必要。
[^3]: [evaluate](https://pypi.org/project/evaluate)、[nltk](https://pypi.org/project/nltk)、[rouge\-score](https://pypi.org/project/rouge-score)のパッケージが必要。
[^4]: すべてのリトリーバメトリクスはデフォルトでは`retriever_k`が`3`だが、`evaluator_config`の`retriever_k`を指定することで上書き可能。

### メトリクスのカスタムリストの活用

特定のモデルタイプに紐づけられた定義済みのメトリクスを用いることが、MLflowにおけるLLM評価のスコアリングを生成する唯一の手段ではありません。`mlflow.evaluate`の`extra_metrics`引数にメトリクスのカスタムリストを指定することができます:

- 事前定義のモデルタイプのデフォルトメトリクスリストにメトリクスを追加するには、`model_type`はそのままで、`extra_metrics`にあなたのメトリクスを追加します:

    ```py
    results = mlflow.evaluate(
        model,
        eval_data,
        targets="ground_truth",
        model_type="question-answering",
        extra_metrics=[mlflow.metrics.latency()],
    )
    ```

    上のコードは、「question-answering」モデルのすべてのメトリクスと[mlflow\.metrics\.latency\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.latency)を用いて、あなたのモデルを評価します。

- デフォルトメトリクスの計算を無効化し、あなたが選択したメトリクスのみを計算するには、`model_type`引数を削除し、必要なメトリクスを定義します。

    ```py
    results = mlflow.evaluate(
        model,
        eval_data,
        targets="ground_truth",
        extra_metrics=[mlflow.metrics.toxicity(), mlflow.metrics.latency()],
    )
    ```

サポートされる評価メトリクスの完全なリファレンスは[こちら](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)で確認できます。

### カスタムのヒューリティックベースのLLM Evaluationメトリクスの作成

これは従来のカスタムメトリクスの作成と非常に似ていますが、[mlflow\.metrics\.MetricValue\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.MetricValue)のインスタンスを返却する点が異なります。

1. あなたのスコアリングロジックを定義する`eval_fn`を実装します。この関数には`predictions`と`targets`の2つの引数が必要です。`eval_fn`は[mlflow\.metrics\.MetricValue\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.MetricValue)を返却しなくてはなりません。
1. メトリックを作成するために、`mlflow.metrics.make_metric` APIに`eval_fn`とその他の引数を渡します。

以下のコードでは`"over_10_chars"`という行単位のダミーメトリックを作成します。モデルの出力が10より多い場合、このスコアは`yes`となり、そうでなければ`no`となります。

```py
def eval_fn(predictions, targets):
    scores = ["yes" if len(pred) > 10 else "no" for pred in predictions]
    return MetricValue(
        scores=scores,
        aggregate_results=standard_aggregations(scores),
    )


# Create an EvaluationMetric object.
passing_code_metric = make_metric(
    eval_fn=eval_fn, greater_is_better=False, name="over_10_chars"
)
```

他のメトリクスに依存するカスタムメトリックを作成するには、`predictions`や`targets`の後の引数としてそれらの他のメトリクス名を含めます。これは、ビルトインメトリックの名前や他のカスタムメトリックにすることができます。メトリクスに間違って循環参照を含めないようにしてください。その場合には評価が失敗します。

以下のコードは、`"toxic_or_over_10_chars"`という行単位のダミーメトリックを作成します: モデルの出力が10以上あるいはtoxityのスコアが0.5より大きい場合にスコアは`yes`、そうでない場合には`no`となります。

```py
def eval_fn(predictions, targets, toxicity, over_10_chars):
    scores = [
        "yes" if toxicity.scores[i] > 0.5 or over_10_chars.scores[i] else "no"
        for i in len(toxicity.scores)
    ]
    return MetricValue(scores=scores)


# Create an EvaluationMetric object.
toxic_and_over_10_chars_metric = make_metric(
    eval_fn=eval_fn, greater_is_better=False, name="toxic_or_over_10_chars"
)
```

## LLM-as-a-Judgeメトリクス

LLM-as-a-Judgeは、モデル出力の品質をスコアリングするためにLLMを活用する新たなタイプのメトリックであり、人間による評価よりもスケーラブルでコスト効率が高いことに加え、より複雑な言語タスクに対してより人間のような評価を提供します。

MLflowでは、ビルトインのLLM-as-a-Judgeメトリクスをサポートすることに加え、カスタムの設定やプロンプトを用いて自身のLLM-as-a-Judgeメトリクスを作成することができます。

### ビルトインのLLM-as-a-Judgeメトリクス

MLflowでビルトインのLLM-as-a-Judgeメトリクスを使うには、[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)関数の`extra_metrics`引数にメトリクス定義のリストを指定します。

以下の例では、評価のためのビルトインの回答の正確性メトリックとレイテンシーメトリック(ヒューリスティック)を用いています:

```py
from mlflow.metrics import latency
from mlflow.metrics.genai import answer_correctness

results = mlflow.evaluate(
    eval_data,
    targets="ground_truth",
    extra_metrics=[
        answer_correctness(),
        latency(),
    ],
)
```

こちらがビルトインのLLM-as-a-Judgeメトリクスのリストです。それぞれのメトリックの完全なドキュメントに関してはリンクをクリックしてください:

- [answer\_similarity\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.answer_similarity): モデルが生成した出力と正解データの情報と比較してどれだけ類似しているかを評価。
- [answer\_correctness\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.answer_correctness): モデルが生成した出力が、正解データの情報に対してどれだけ事実つに基づいて正しいのかを評価。
- [answer\_relevance\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.answer_relevance): 入力に対してモデルが生成した出力がどれだけ適切かを評価(コンテキストは無視)
- [relevance\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.relevance): モデルが生成した出力が、入力とコンテキスト両方の観点でどれだけ適切かを評価。
- [faithfulness\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.faithfulness): モデルが生成した出力は、提供されたコンテキストにどれだけ忠実かを評価。

### Judgeモデルの選択

デフォルトでは、MLflowはメトリクスのスコアリングを行うジャッジモデルとしてOpenAIのGPT-4モデルを使います。メトリック定義の`model`引数にジャッジモデルを指定することで変更することができます。

#### 1. SaaSのLLMプロバイダー

OpenAIやAnthropicのようなSaaSのLLMプロバイダーを使うには、`<provider>:/<model-name>`の形式で、メトリクス定義に`model`パラメータを設定します。現時点では、MLflowはジャッジモデルのための重要なLLMプロバイダーとして`["openai", "anthropic", "bedrock", "mistral", "togetherai"]`をサポートしています。

**OpenAI / Azure OpenAI**

OpenAIモデルは`openai:/<model-name>` URIを通じてアクセスすることができます。

```py
import mlflow
import os

os.environ["OPENAI_API_KEY"] = "<your-openai-api-key>"

answer_correctness = mlflow.metrics.genai.answer_correctness(model="openai:/gpt-4o")

# Test the metric definition
answer_correctness(
    inputs="What is MLflow?",
    predictions="MLflow is an innovative full self-driving airship.",
    targets="MLflow is an open-source platform for managing the end-to-end ML lifecycle.",
)
```

Azure OpenAIエンドポイントは、`OPENAI_API_BASE`や`OPENAI_API_TYPE`などの環境変数を設定することで、同じ`openai:/<model-name>` URIを通じてアクセスすることができます。

```py
os.environ["OPENAI_API_TYPE"] = "azure"
os.environ["OPENAI_API_BASE"] = "https:/my-azure-openai-endpoint.azure.com/"
os.environ["OPENAI_DEPLOYMENT_NAME"] = "gpt-4o-mini"
os.environ["OPENAI_API_VERSION"] = "2024-08-01-preview"
os.environ["OPENAI_API_KEY"] = "<your-api-key-for-azure-openai-endpoint>"
```

:::note info
他のプロバイダーに関しては[原文](https://mlflow.org/docs/latest/llms/llm-evaluate/index.html#selecting-the-judge-model)をご覧ください。
:::

:::note info
**注意**
評価でサードパーティのLLMサービス(OpenAIなど)を使うことで、当該LLMサービスの利用条項の対象となり、管理の対象となる場合があります。
:::

#### 2. 自身でホストするプロキシエンドポイント

(セキュリティコンプライアンスなどの理由で)プロキシエンドポイント経由でSaaSのLLMプロバイダにアクセスする場合、メトリクス定義の`proxy_url`を設定することができます。さらに、エンドポイントの認証のための追加ヘッダーを指定するために`extra_headers`を使います。

```py
answer_similarity = mlflow.metrics.genai.answer_similarity(
    model="openai:/gpt-4o",
    proxy_url="https://my-proxy-endpoint/chat",
    extra_headers={"Group-ID": "my-group-id"},
)
```

#### 3. MLflow AI Gatewayエンドポイント

[MLflow AI Gateway](https://mlflow.org/docs/latest/llms/deployments/index.html)は、統合されたインタフェースでさまざまなLLMプロバイダーへのクエリーを可能とする自己ホストのソリューションです。MLflow AI Gatewayによってホストされているエンドポイントを使うには:

1. [こちらのステップ](https://mlflow.org/docs/latest/llms/deployments/index.html#quickstart)に沿って、ご自身のLLM設定を用いて、MLflow AI Gatewayサーバーを起動する。
1. [set\_deployments\_target\(\)](https://mlflow.org/docs/latest/python_api/mlflow.deployments.html#mlflow.deployments.set_deployments_target)を用いて、サーバーのアドレスを指すように、MLflowデプロイメントクライアントを設定。
1. メトリクス定義の`model`パラメータに`endpoints:/<endpoint-name>`を設定。

```py
from mlflow.deployments import set_deployments_target

# When the MLflow AI Gateway server is running at http://localhost:5000
set_deployments_target("http://localhost:5000")
my_answer_similarity = mlflow.metrics.genai.answer_similarity(
    model="endpoints:/my-endpoint"
)
```

#### 4. Databricksモデルサービング

Databricksにモデルホスティングする場合には、メトリクス定義の`model`パラメータに`endpoints:/<endpoint-name>`を設定することで、ジャッジモデルとして使用できます。以下のコードでは、[基盤モデルAPI](https://docs.databricks.com/ja/machine-learning/model-serving/index.html)を通じて利用できるLlama 3.1 405Bモデルを使っています。

```py
from mlflow.deployments import set_deployments_target

set_deployments_target("databricks")
llama3_answer_similarity = mlflow.metrics.genai.answer_similarity(
    model="endpoints:/databricks-llama-3-1-405b-instruct"
)
```

### デフォルトJudgeパラメータの上書き

デフォルトでは、MLflowは以下のパラメータでジャッジLLMモデルにクエリーします:

```py
temperature: 0.0
max_tokens: 200
top_p: 1.0
```

しかし、これがすべてのLLMプロバイダーに適しているわけではありません。例えば、Amazon Bedrock上のAnthropicのClaudeにアクセスするには、リクエストペイロードで`anthropic_version`を指定する必要があります。メトリクス定義の`parameters`引数を指定することで、デフォルトパラメータを上書きすることができます。

```py
my_answer_similarity = mlflow.metrics.genai.answer_similarity(
    model="bedrock:/anthropic.claude-3-5-sonnet-20241022-v2:0",
    parameters={
        "temperature": 0,
        "max_tokens": 256,
        "anthropic_version": "bedrock-2023-05-31",
    },
)
```

`parameters`引数で指定するパラメータディクショナリーは、マージされるのではなく**すべてのデフォルトパラメータを置き換える**ことに注意してください。例えば、上のコードの例では、`top_p`はモデルに通知されません。


### カスタムLLM-as-a-Judgeメトリクスの作成

また、以下の情報を必要とする[mlflow\.metrics\.genai\.make\_genai\_metric\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.make_genai_metric)で、ご自身のLLM-as-a-judge評価メトリクスを作成することができます。

- `name`: あなたのカスタムメトリックの名前。
- `definition`: メトリックが何をするのかを説明。
- `grading_prompt`: スコアリング基準を説明。
- `examples` (オプション): スコアとその入力/出力のいくつかのサンプル。LLMジャッジの推論に使用される。

設定の完全なリストは[API documentation](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.make_genai_metric)をご覧ください。

内部では、`definition`、`grading_prompt`、`examples`と評価データ、モデルの出力は長いプロンプトにまとめられ、LLMに送信されます。あなたがプロンプトエンジニアリングのコンセプトに慣れているのであれば、SaaSのLLMの評価メトリックは基本的に指示、データ、モデル出力を含む「適切な」プロンプトを構成しようとし、GPT4のようなLLMは必要とする情報を出力することができます。

それでは、我々のモデル出力がどれだけプロフェッショナルかを計測する「professionalism(プロ意識)」と呼ばれるカスタムの生成AIメトリクスを作成しましょう。

はじめに、スコアを伴う幾つかのサンプルを作成しましょう。これらはLLMジャッジが使用する参照サンプルとなります。このようなサンプルを作成するために、4つのフィールドを持つ[mlflow\.metrics\.genai\.EvaluationExample\(\)](https://mlflow.org/docs/latest/python_api/mlflow.metrics.html#mlflow.metrics.genai.EvaluationExample)クラスを使います:

- input: 入力テキスト。
- output: 出力テキスト。
- score: 入力のコンテキストにおける出力のスコア。
- justification: なぜそのデータにその*スコア*を与えるのか。

```py
professionalism_example_score_2 = mlflow.metrics.genai.EvaluationExample(
    input="What is MLflow?",
    output=(
        "MLflow is like your friendly neighborhood toolkit for managing your machine learning projects. It helps "
        "you track experiments, package your code and models, and collaborate with your team, making the whole ML "
        "workflow smoother. It's like your Swiss Army knife for machine learning!"
    ),
    score=2,
    justification=(
        "The response is written in a casual tone. It uses contractions, filler words such as 'like', and "
        "exclamation points, which make it sound less professional. "
    ),
)
professionalism_example_score_4 = mlflow.metrics.genai.EvaluationExample(
    input="What is MLflow?",
    output=(
        "MLflow is an open-source platform for managing the end-to-end machine learning (ML) lifecycle. It was "
        "developed by Databricks, a company that specializes in big data and machine learning solutions. MLflow is "
        "designed to address the challenges that data scientists and machine learning engineers face when "
        "developing, training, and deploying machine learning models.",
    ),
    score=4,
    justification=("The response is written in a formal language and a neutral tone. "),
)
```

それでは、`professionalism`メトリックを定義しましょう。それぞれのフィールドが、どのようにセットアップされるのかを確認することができます。

```py
professionalism = mlflow.metrics.genai.make_genai_metric(
    name="professionalism",
    definition=(
        "Professionalism refers to the use of a formal, respectful, and appropriate style of communication that is "
        "tailored to the context and audience. It often involves avoiding overly casual language, slang, or "
        "colloquialisms, and instead using clear, concise, and respectful language."
    ),
    grading_prompt=(
        "Professionalism: If the answer is written using a professional tone, below are the details for different scores: "
        "- Score 0: Language is extremely casual, informal, and may include slang or colloquialisms. Not suitable for "
        "professional contexts."
        "- Score 1: Language is casual but generally respectful and avoids strong informality or slang. Acceptable in "
        "some informal professional settings."
        "- Score 2: Language is overall formal but still have casual words/phrases. Borderline for professional contexts."
        "- Score 3: Language is balanced and avoids extreme informality or formality. Suitable for most professional contexts. "
        "- Score 4: Language is noticeably formal, respectful, and avoids casual elements. Appropriate for formal "
        "business or academic settings. "
    ),
    examples=[professionalism_example_score_2, professionalism_example_score_4],
    model="openai:/gpt-4o-mini",
    parameters={"temperature": 0.0},
    aggregations=["mean", "variance"],
    greater_is_better=True,
)
```

# ターゲットモデルの準備

`mlflow.evaluate()`であなたのモデルを評価するには、あなたのモデルは以下のタイプのいずれかである必要があります:

1. [mlflow\.pyfunc\.PyFuncModel\(\)](https://mlflow.org/docs/latest/python_api/mlflow.pyfunc.html#mlflow.pyfunc.PyFuncModel)のインスタンス、あるいは記録されている`mlflow.pyfunc.PyFuncModel`モデルをポイントするURI。通常、我々はこれをMLflowモデルと呼びます。
1. 文字列の入力を受け取り、単一の文字列を出力するPython関数。呼び出す関数は、[mlflow\.pyfunc\.PyFuncModel\.predict\(\)](https://mlflow.org/docs/latest/python_api/mlflow.pyfunc.html#mlflow.pyfunc.PyFuncModel.predict)のシグネチャ(`params`引数を除く)にマッチする必要があります。簡単にいうと:

    - `pandas.Dataframe`、`numpy.ndarray`、Pythonのリスト、ディクショナリー、scipyのmatrixのいずれかである単一の引数として`data`を持つこと。
    - `pandas.DataFrame`、`pandas.Series`、`numpy.ndarray`、リストのいずれかを返却すること。

1. ローカルの[MLflow AI Gateway](https://mlflow.org/docs/latest/llms/deployments/index.html)、[Databricks Foundation Models API](https://docs.databricks.com/en/machine-learning/model-serving/score-foundation-models.html)、[External Models in Databricks Model Serving](https://docs.databricks.com/en/generative-ai/external-models/index.html)をポイントするMLflowデプロイメントエンドポイントのURI。
1. `model=None`を設定し、`data`にモデルの出力を配置します。データがPandasデータフレームの場合にのみ適用できます。

## MLflowモデルによる評価

あなたのモデルを`mlflow.pyfunc.PyFuncModel`インスタンスに変換する方法に関する詳細な手順については、[こちらのドキュメント](https://mlflow.org/docs/latest/python_api/mlflow.pyfunc.html#creating-custom-pyfunc-models)をご覧ください。しかし、簡単に言えば、MLflowモデルとしてあなたのモデルを評価するには、以下のステップに従うことをお勧めします:

1. `log_model`であなたのモデルをMLflowサーバーに記録します。それぞれのフレーバーには、[mlflow\.openai\.log\_model\(\)](https://mlflow.org/docs/latest/python_api/openai/index.html#mlflow.openai.log_model)のように自身の`log_model` APIがあります:

    ```py
    with mlflow.start_run():
        system_prompt = "Answer the following question in two sentences"
        # Wrap "gpt-4o-mini" as an MLflow model.
        logged_model_info = mlflow.openai.log_model(
            model="gpt-4o-mini",
            task=openai.chat.completions,
            artifact_path="model",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": "{question}"},
            ],
        )
    ```

1. `mlflow.evaluate()`のモデルインスタンスとして、記録されたモデルのURIを使います:

    ```py
    results = mlflow.evaluate(
        logged_model_info.model_uri,
        eval_data,
        targets="ground_truth",
        model_type="question-answering",
    )
    ```

## カスタム関数による評価

MLflow 2.8.0時点で[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)は、MLflowにモデルを記録することなしに、Python関数の評価をサポートしています。これは、モデルを記録したくなくて評価のみを行いたい場合に有用です。以下の例では、関数の評価に[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)を使用しています。以下のコードを実行するには、OpenAIの認証をセットアップする必要もあります。

```py
import mlflow
import openai
import pandas as pd
from typing import List

eval_data = pd.DataFrame(
    {
        "inputs": [
            "What is MLflow?",
            "What is Spark?",
        ],
        "ground_truth": [
            "MLflow is an open-source platform for managing the end-to-end machine learning (ML) lifecycle. It was developed by Databricks, a company that specializes in big data and machine learning solutions. MLflow is designed to address the challenges that data scientists and machine learning engineers face when developing, training, and deploying machine learning models.",
            "Apache Spark is an open-source, distributed computing system designed for big data processing and analytics. It was developed in response to limitations of the Hadoop MapReduce computing model, offering improvements in speed and ease of use. Spark provides libraries for various tasks such as data ingestion, processing, and analysis through its components like Spark SQL for structured data, Spark Streaming for real-time data processing, and MLlib for machine learning tasks",
        ],
    }
)


def openai_qa(inputs: pd.DataFrame) -> List[str]:
    predictions = []
    system_prompt = "Please answer the following question in formal language."

    for _, row in inputs.iterrows():
        completion = openai.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": row["inputs"]},
            ],
        )
        predictions.append(completion.choices[0].message.content)

    return predictions


with mlflow.start_run():
    results = mlflow.evaluate(
        model=openai_qa,
        data=eval_data,
        targets="ground_truth",
        model_type="question-answering",
    )

print(results.metrics)
```

出力

```py
{
    "flesch_kincaid_grade_level/v1/mean": 14.75,
    "flesch_kincaid_grade_level/v1/variance": 0.5625,
    "flesch_kincaid_grade_level/v1/p90": 15.35,
    "ari_grade_level/v1/mean": 18.15,
    "ari_grade_level/v1/variance": 0.5625,
    "ari_grade_level/v1/p90": 18.75,
    "exact_match/v1": 0.0,
}
```

## MLflowデプロイメントエンドポイントによる評価

MLflow >= 2.11.0では、[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)では、`model`引数にMLflowデプロイメントエンドポイントURIを直接指定することで、モデルエンドポイントを評価できるようになりました。これは、MLflowモデルやPython関数としてラッピングするための実装を行うことなしに、ローカルの[MLflow AI Gateway](https://mlflow.org/docs/latest/llms/deployments/index.html)、[Databricks Foundation Models API](https://docs.databricks.com/ja/machine-learning/model-serving/score-foundation-models.html)、[External Models in Databricks Model Serving](https://docs.databricks.com/ja/generative-ai/external-models/index.html)によってホストされているモデルを評価したい場合に有用です。

以下の例で示しているように、エンドポイントURIで[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)を呼び出す前に、[mlflow\.deployments\.set\_deployments\_target\(\)](https://mlflow.org/docs/latest/python_api/mlflow.deployments.html#mlflow.deployments.set_deployments_target)を用いて、ターゲットのデプロイメントクライアントを設定することを忘れないようにしてください。さもないと、`MlflowException: No deployments target has been set...`のようなエラーメッセージに遭遇することでしょう。

:::note info
**ヒント**
MLflow AI GatewayやDatabricksでホスト**されていない**エンドポイントを使いたい場合、[Evaluating with a Custom Function](https://mlflow.org/docs/latest/llms/llm-evaluate/index.html#llm-eval-custom-function)ガイドに従ってカスタムのPython関数を作成し、`model`引数で使うことができます。
:::

### サポートされる入力データフォーマット

モデルとしてMLflowデプロイメントエンドポイントのURIを用いる際、入力データは以下のフォーマットのいずれかを用いることができます:

[原文](https://mlflow.org/docs/latest/llms/llm-evaluate/index.html#supported-input-data-formats)をご覧ください。

### 推論パラメータの指定

[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)の`inference_params`引数を設定することで、モデルエンドポイントに`max_tokens`、`temperature`、`n`のような追加の推論パラメータを設定することができます。`inference_params`引数は、モデルエンドポイントに渡すパラメータを含むディクショナリーです。指定されたパラメータは評価データセットの入力レコードの全てで使用されます。

:::note info
**注意**
入力がリクエストペイロードを表現するディクショナリー形式の場合、`max_tokens`のようなパラメータを含めることもできます。`inference_params`と入力データの両方でパラメータが重複する場合、`inference_params`の値が優先されます。
:::

### 例

**ローカルの[MLflow AI Gateway](https://mlflow.org/docs/latest/llms/deployments/index.html)によってホストされたチャットエンドポイント**

```py
import mlflow
from mlflow.deployments import set_deployments_target
import pandas as pd

# Point the client to the local MLflow AI Gateway
set_deployments_target("http://localhost:5000")

eval_data = pd.DataFrame(
    {
        # Input data must be a string column and named "inputs".
        "inputs": [
            "What is MLflow?",
            "What is Spark?",
        ],
        # Additional ground truth data for evaluating the answer
        "ground_truth": [
            "MLflow is an open-source platform ....",
            "Apache Spark is an open-source, ...",
        ],
    }
)


with mlflow.start_run() as run:
    results = mlflow.evaluate(
        model="endpoints:/my-chat-endpoint",
        data=eval_data,
        targets="ground_truth",
        inference_params={"max_tokens": 100, "temperature": 0.0},
        model_type="question-answering",
    )
```

**[Databricks Foundation Models API](https://docs.databricks.com/ja/machine-learning/model-serving/score-foundation-models.html)でホストされているコンプリーションエンドポイント**

```py
import mlflow
from mlflow.deployments import set_deployments_target
import pandas as pd

# Point the client to Databricks Foundation Models API
set_deployments_target("databricks")

eval_data = pd.DataFrame(
    {
        # Input data must be a string column and named "inputs".
        "inputs": [
            "Write 3 reasons why you should use MLflow?",
            "Can you explain the difference between classification and regression?",
        ],
    }
)


with mlflow.start_run() as run:
    results = mlflow.evaluate(
        model="endpoints:/databricks-mpt-7b-instruct",
        data=eval_data,
        inference_params={"max_tokens": 100, "temperature": 0.0},
        model_type="text",
    )
```

[External Models in Databricks Model Serving](https://docs.databricks.com/ja/generative-ai/external-models/index.html)の評価は同じ方法で行うことができ、`"endpoints:/your-chat-endpoint"`のように異なるURIを指定するだけです。

## 静的データセットによる評価

MLflow >= 2.8.0では、[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)はモデルを指定することなしに静的なデータセットの評価を行うことができます。モデルの出力をPandasデータフレームやMLflow PandasDatasetに保存しており、モデルを際実行することなしに静的なデータセットを評価したい場合に有用です。

Pandasデータフレームを使っている場合、[mlflow\.evaluate\(\)](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)のトップレベルの`predictions`パラメータを用いて、モデル出力を含むカラム名を指定する必要があります:

```py
import mlflow
import pandas as pd

eval_data = pd.DataFrame(
    {
        "inputs": [
            "What is MLflow?",
            "What is Spark?",
        ],
        "ground_truth": [
            "MLflow is an open-source platform for managing the end-to-end machine learning (ML) lifecycle. "
            "It was developed by Databricks, a company that specializes in big data and machine learning solutions. "
            "MLflow is designed to address the challenges that data scientists and machine learning engineers "
            "face when developing, training, and deploying machine learning models.",
            "Apache Spark is an open-source, distributed computing system designed for big data processing and "
            "analytics. It was developed in response to limitations of the Hadoop MapReduce computing model, "
            "offering improvements in speed and ease of use. Spark provides libraries for various tasks such as "
            "data ingestion, processing, and analysis through its components like Spark SQL for structured data, "
            "Spark Streaming for real-time data processing, and MLlib for machine learning tasks",
        ],
        "predictions": [
            "MLflow is an open-source platform that provides handy tools to manage Machine Learning workflow "
            "lifecycle in a simple way",
            "Spark is a popular open-source distributed computing system designed for big data processing and analytics.",
        ],
    }
)

with mlflow.start_run() as run:
    results = mlflow.evaluate(
        data=eval_data,
        targets="ground_truth",
        predictions="predictions",
        extra_metrics=[mlflow.metrics.genai.answer_similarity()],
        evaluators="default",
    )
    print(f"See aggregated evaluation results below: \n{results.metrics}")

    eval_table = results.tables["eval_results_table"]
    print(f"See evaluation table below: \n{eval_table}")
```

# 評価結果の参照

## コードによる評価結果の参照

`mlflow.evaluate()`は[mlflow\.models\.EvaluationResult\(\)](https://mlflow.org/docs/latest/python_api/mlflow.models.html#mlflow.models.EvaluationResult)インスタンスとして評価結果を返却します。選択したメトリクスのスコアを確認するには以下をチェックします:

- `metrics`: 評価でたセットにおけるaverage/varianceのような集計結果を格納。上のコードさぷるの2番目のパスを取り、集計結果の出力にフォーカスしましょう。

    ```py
    with mlflow.start_run() as run:
        results = mlflow.evaluate(
            data=eval_data,
            targets="ground_truth",
            predictions="predictions",
            extra_metrics=[mlflow.metrics.genai.answer_similarity()],
            evaluators="default",
        )
        print(f"See aggregated evaluation results below: \n{results.metrics}")
    ```
    
- `tables["eval_results_table"]`: 行ごとの評価結果を格納。

    ```py
    with mlflow.start_run() as run:
        results = mlflow.evaluate(
            data=eval_data,
            targets="ground_truth",
            predictions="predictions",
            extra_metrics=[mlflow.metrics.genai.answer_similarity()],
            evaluators="default",
        )
        print(
            f"See per-data evaluation results below: \n{results.tables['eval_results_table']}"
        )
    ```

## MLflow UIによる評価結果の参照

あなたの評価結果はMLflowサーバーに自動で記録されるので、MLflow UIから直接評価結果を確認することができます。MLflow UIで評価結果を参照するには、以下のステップに従ってください:

1. MLflowエクスペリメントのエクスペリメントビューに移動します。
1. 「Evaluation」タブを選択します。
1. 評価結果をチェックしたいランを選択します。
1. 右側のドロップダウンメニューからメトリクスを選択します。

わかりやすくするために、以下のスクリーンショットをご覧ください:

![](https://mlflow.org/docs/latest/_images/llm_evaluate_experiment_view.png)