MLflowでLLM判定メトリクスを使ってローカルLLMを評価する
はじめに
MLflowでローカルチャットボットを評価する方法を学びます。以前は以下の記事でヒューリスティックベースのメトリクスを使って評価しました。今回はLLM判定メトリクスを使って評価していきます。
また、前回はLLM判定メトリクスを実施する準備として、MLflow AI Gatewayを立ち上げました。
以下の情報を参照して動作確認を進めます。
全コードは以下にあります。
ゴール
MLflowでLLM判定メトリクスによるローカルチャットボットの評価ができている
環境
本記事の動作確認は以下の環境で行いました。
- MacBook Pro
- 14 インチ 2021
- チップ:Apple M1 Pro
- メモリ:32GB
- macOS:15.5(24F74)
LLM判定メトリクスを使ってみる
LLM-as-a-Judge は、モデル出力の品質を評価するためにLLMを使う新しいタイプの指標であり、複雑な言語タスクに対して人間に近い評価を提供しつつ、人手による評価よりもスケーラブルでコスト効率にも優れています。
MLflowでは、様々な組み込み済みのLLM判定によるメトリクスを利用でき、自分自身のプロンプトを使うカスタムメトリクスもサポートしています。
組み込み済みLLM判定メトリクス
mfloww.evaluate
の extra_metrics
引数に、組み込み済みのLLM判定メトリクスを指定して、使用することができます。以下などの指標があります。
- mlflow.metrics.genai.answer_similarity(): モデルが生成した出力が、正解データ内の情報とどの程度類似しているかを評価します。これは、チャットボットが期待される回答を生成しているかを確認する際に特に有用です。
- mlflow.metrics.genai.answer_correctness(): モデルが生成した出力が、正解データ内の情報に基づいてどの程度事実として正しいかを評価します。事実誤認がないかを確認する際に役立ちます。
- mlflow.metrics.genai.answer_relevance(): モデルが生成した出力が、入力に対してどの程度関連しているかを評価します(コンテキストは無視されます)。質問に対する直接的な関連性を測りたい場合に適しています。
- mlflow.metrics.genai.relevance(): モデルが生成した出力が、入力とコンテキストの両方に対してどの程度関連しているかを評価します。RAG(Retrieval Augmented Generation)システムなど、コンテキストを考慮した回答の関連性を評価する際に重要です。
- mlflow.metrics.genai.faithfulness(): モデルが生成した出力が、提供されたコンテキストに基づいてどの程度忠実であるかを評価します。LLMが与えられた情報から逸脱していないかを確認する際に特に有用です。
デフォルトでOpenAI
のGPT-4
を使うので、変更したい場合はmodel
引数を上書きする必要があります。今回はローカルのLLMを評価したいので上書きします。
MLflow AI Gateway エンドポイント
前回 MLflow AI Gateway
を使って、セルフホスト エンドポイントを作成しました。これを使って判定メトリクスを実行してみましょう。 mlflow_evaluate.py
を以下のように書き換えます。
from typing import Any
import mlflow
import mlflow.pyfunc
import pandas as pd # type: ignore
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI
from mlflow.deployments import set_deployments_target
from mlflow.metrics.genai import answer_similarity
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 "
"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",
],
}
)
# MLflowサーバーのURIを設定
mlflow.set_tracking_uri("http://localhost:5001")
mlflow.set_experiment("my-genai-experiment")
# MLflow AI gatewayのターゲットを設定
# ここで設定することで、MLflowがデプロイされたAI Gatewayエンドポイントと通信できるようになります。
set_deployments_target("http://localhost:5002")
# 既存のアクティブなrunがあれば終了
if mlflow.active_run():
mlflow.end_run()
# mlflow.pyfunc.log_model にわたすために必要な関数を実装する
class ChatOpenAIWrapper(mlflow.pyfunc.PythonModel): # type: ignore
def __init__(self):
self.system_prompt = "Answer the following question in two sentences"
def predict(
self,
context: mlflow.pyfunc.PythonModelContext, # type: ignore
model_input: pd.DataFrame,
) -> list[str | list[str | dict[Any, Any]]]:
# contextからモデル設定を取得することも可能(今回は使用しない)
# model_config = context.artifacts if context else {
# ここで使いたいモデルを指定する
llm = ChatOpenAI(
base_url="http://localhost:1234/v1",
api_key=None,
temperature=0.7,
name="google/gemma-3-12b",
)
# 結果はまとめて返却する
predictions = []
for question in model_input["inputs"]:
response = llm.invoke(
[
SystemMessage(content=self.system_prompt),
HumanMessage(content=question),
]
)
predictions.append(response.content)
return predictions
with mlflow.start_run() as run:
# 入力例を作成
input_example = pd.DataFrame({"inputs": ["What is MLflow?"]})
# モデルのsignatureを推論するための予測を実行
model_instance = ChatOpenAIWrapper()
# カスタムモデルをMLflowモデルとしてログ(signatureとinput_exampleを指定)
logged_model_info = mlflow.pyfunc.log_model(
name="model",
python_model=model_instance,
input_example=input_example,
)
# MLflowエンドポイントのデプロイ情報を追加
# ここで再度ターゲットを設定することで、LLM判定メトリクスがこのエンドポイントを参照して評価を実行できるようになります。
set_deployments_target("http://localhost:5002")
# デプロイ済みのエンドポイントを使って結果と正解との類似度を計算する
my_answer_similarity = answer_similarity(model="endpoints:/chat")
# 事前定義された question-answering metrics を使って評価する
results = mlflow.evaluate(
logged_model_info.model_uri,
eval_data,
targets="ground_truth",
model_type="question-answering",
# LLM判定メトリクスを追加
extra_metrics=[
my_answer_similarity,
],
)
print(f"See aggregated evaluation results below: \n{results.metrics}")
# `results.tables` でデータ毎の結果を取得できる
eval_table = results.tables["eval_results_table"]
print(f"See evaluation table below: \n{eval_table}")
実行してみます。
pipenv run python3 ./mlflow_evaluate.py
以下の結果が追加されました。
{
...
"answer_similarity/v1/mean": 4.0,
"answer_similarity/v1/variance": 0.0,
"answer_similarity/v1/p90": 4.0
}
以下の GitHub
のコードによると以下の様に判断できるようです。今回は4.0なので、生成された回答が正解データと非常に近い意味内容を持っていることを示しており、チャットボットの回答品質が高いことを裏付けています。
- Score 1: 全く類似性がないかあるいはわずかに類似しています
- Score 2: いくつかの観点で部分的に類似しています
- Score 3: 適度な類似度です
- Score 4: 多くの観点で類似していてかなり類似しています
- Score 5: 全ての観点でかなり類似しています
LLM判定メトリクスの一つである answer_similarity
を使った評価を行うことができました!
おわりに
今回はローカルLLMと、MLflow AI Gatewayを使って、LLM判定メトリクスを使った評価をしてみました。これらの多様なメトリクスは、LLMの性能改善サイクルにおいて、多角的な評価軸を提供し、より効率的なモデル開発を可能にします。特に、人間による評価が難しい大規模なデータセットや、迅速なフィードバックが必要な開発フェーズにおいて、LLM判定メトリクスは強力なツールとなり得ます。次は、LLM判定メトリクスをカスタマイズしてみたいと思います。
Discussion