🧑‍⚖️

Vertex AI における LLM の評価

2024/11/09に公開

Gen AI 評価サービスの概要

Vertex AI では Gen AI 評価サービスを使うことで、生成AIモデルを評価することができます。このサービスの特徴は以下の通りです。

  • LLM-as-a-Judgeアプローチを採用
  • カスタマイズ可能な評価指標
  • 定量的なスコアリング機能

評価の種類

Vertex AIでは、主に2つの評価アプローチを提供しています:

  1. ポイントワイズ評価:単一モデルの性能評価
  2. ペアワイズ評価:2つのモデルの比較評価

評価を行うための4ステップ

手順 1: 評価指標の定義

評価を始める前に、以下の3点を明確にする必要があります。

  1. 評価目標の特定
    • 何を測定したいのか
    • どのような改善を期待するのか
  2. 評価方法の選択
    • ポイントワイズ評価:モデルの単独評価
    • ペアワイズ評価:モデル間の比較
  3. 評価タスクの決定
    • QA(質問応答)
    • テキスト生成
    • 要約
      など

評価方法の選び方

パラダイム 使用するタイミング
ポイントワイズ 本番環境でのモデルの動作を把握します。
• 1 つのモデルの長所と短所を調べます。
• チューニング時に重視する動作を特定します。
• モデルのベースライン パフォーマンスを確認します。
ペアワイズ 本番環境にデプロイするモデルを決定します。
• モデルタイプを選択します。たとえば、Gemini-Pro と Claude 3 です。
• さまざまなプロンプトから選択できます。
• チューニングでベースライン モデルが改善されたかどうかを判断します。

手順 2: 評価データセットの準備

評価データセットは、pandas DataFrameとして準備する必要があります。重要なのは、評価タスクの種類によって必要なカラムが異なるという点です。

タスク別の必要カラム

評価タスクに応じて、以下のようなカラム構成が必要になります。

1. シングルターン会話の評価

# シングルターン会話用のデータセット例
eval_dataset = pd.DataFrame({
    "context": ["ユーザーからの入力文"],
    "instruction": ["システムプロンプト"],  # オプション
    "response": ["モデルの出力"],      # オプション
})

2. マルチターン会話の評価

# マルチターン会話用のデータセット例
eval_dataset = pd.DataFrame({
    "context": ["現在のユーザー入力"],
    "history": ["過去の会話履歴"],    # オプション
    "instruction": ["システムプロンプト"],  # オプション
    "response": ["モデルの出力"],      # オプション
})

3. 要約タスクの評価

# 要約タスク用のデータセット例
eval_dataset = pd.DataFrame({
    "context": ["要約対象のテキスト"],
    "reference": ["正解の要約文"],     # 比較用の参照要約
    "response": ["モデルの要約出力"],   # オプション
})

評価データセットで使用可能なカラムの例

カラム名 説明 必須/オプション
context/prompt LLMへの入力となるコンテキスト。要約タスクの場合は要約対象テキスト オプション
instruction LLMへの指示やシステムプロンプト オプション
history マルチターン会話の場合の過去の会話履歴 オプション
response 評価対象のLLM出力。指定しない場合はLLMが生成 オプション
reference 正解や理想的な出力。比較評価で使用 オプション
baseline_response 比較評価時のベースラインとなる出力 比較評価時に使用

実装例:ECサイトのレビュー応答システムの評価

具体例を使って説明します。

ここでは、ECサイトのカスタマーサービスで使用するLLMの評価を例に説明します。

シナリオ設定

あるECサイトで、商品レビューに対する返信を自動化するシステムを開発しています。
システムの評価のため、以下のような観点でLLMの出力を確認したいとします:

  • レビューの内容を適切に理解できているか
  • 丁寧で適切な返信ができているか
  • ネガティブなレビューにも適切に対応できているか

実装例1:シングルターンの評価データセット

# 単純な返信品質の評価
eval_dataset_simple = pd.DataFrame({
    "context": [
        "商品がとても良かったです!梱包も丁寧で感動しました。",
        "注文から3週間経ちますが商品が届きません。とても困っています。",
        "使い方が分からず困っています。説明書が分かりにくいです。"
    ],
    "instruction": [
        """あなたはECサイトのカスタマーサービス担当です。
        商品レビューに対して、以下の点に注意して返信してください:
        - 感謝の気持ちを示す
        - 具体的な内容に言及する
        - 丁寧な言葉遣いを使用する""",
    ] * 3  # 3つのcontextに同じinstructionを使用
})

実装例2:マルチターンの評価データセット

# 会話の流れを含む評価
eval_dataset_multi = pd.DataFrame({
    "context": [
        "返金の手続きはどうすればいいですか?",
    ],
    "history": [
        """
        User: 商品が壊れていました。
        Assistant: 大変申し訳ございません。商品の不具合とのこと、ご迷惑をおかけし申し訳ございません。具体的な状況を詳しくお聞かせいただけますでしょうか?
        User: 開封時からボタンが反応しませんでした。
        Assistant: 申し訳ございません。初期不良の可能性が高そうですね。返品・返金の対応をさせていただきたいのですが、よろしいでしょうか?
        """
    ],
    "instruction": [
        """あなたはECサイトのカスタマーサービス担当です。
        以下の点に注意して対応してください:
        - 手続きの具体的な流れを説明する
        - 必要な情報を明確に伝える
        - 親身な対応を心がける"""
    ]
})

実装例3:理想的な返信との比較評価

# 返信品質を理想的な返信と比較
eval_dataset_compare = pd.DataFrame({
    "context": [
        "商品の色が写真と全然違います。がっかりです。"
    ],
    "instruction": [
        """あなたはECサイトのカスタマーサービス担当です。
        お客様の不満に対して適切に対応してください。"""
    ],
    "reference": [
        """大変申し訳ございません。商品の色味が写真と異なっていたとのこと、
        ご期待に添えず心よりお詫び申し上げます。
        
        お手数ですが、以下の2点についてご確認させていただけますでしょうか?
        1. ご使用のデバイスの画面設定
        2. 撮影時の照明条件
        
        それでも色味が大きく異なる場合は、返品・返金の対応をさせていただきます。
        ご不便をおかけし申し訳ございませんが、ご希望の対応をお知らせください。"""
    ]
})

データセット作成時の注意点

1. データ形式の統一

  • 全てのカラムで一貫したデータ形式を使用

  • 文字列型での統一を推奨

    # データ型の確認と変換
    for col in eval_dataset.columns:
        if eval_dataset[col].dtype != 'object':
            eval_dataset[col] = eval_dataset[col].astype(str)
    

2. データ品質の確保

  • 欠損値、不正な値の事前チェック

  • 十分なサンプル数の確保

    # 欠損値のチェック
    if eval_dataset.isnull().any().any():
        print("警告: データセットに欠損値が含まれています")
    
    # データ数の確認
    min_samples = 10
    if len(eval_dataset) < min_samples:
        print(f"警告: サンプル数が推奨される最小数({min_samples})を下回っています")
    

手順3: 評価の実装と実行

引き続き、ECサイトのレビュー応答システムの例で説明していきます。

from vertexai.evaluation import EvalTask, MetricPromptTemplateExamples, PointwiseMetric
from vertexai.generative_models import GenerativeModel, HarmCategory, HarmBlockThreshold

# 評価指標の定義
metrics = [
    MetricPromptTemplateExamples.Pointwise.TEXT_QUALITY,  # 文章の品質
    MetricPromptTemplateExamples.Pointwise.FLUENCY,       # 文章の流暢さ
    MetricPromptTemplateExamples.Pointwise.SAFETY,        # 安全性
    MetricPromptTemplateExamples.Pointwise.VERBOSITY,     # 簡潔さ
]

# カスタム評価指標の追加(ECサイト用)
custom_metrics = PointwiseMetric(
    metric="customer_service_quality",
    metric_prompt_template="""
        以下の返信を、カスタマーサービスの品質という観点で1-5で評価してください。
        評価基準:
        1: 不適切または無関係な返信
        2: 基本的な対応はできているが不十分
        3: 適切な対応ができている
        4: 丁寧で親身な対応ができている
        5: 極めて優れた対応で、顧客満足度の向上が期待できる
        
        返信: {response}
        """,
)

# 評価タスクの作成
eval_task = EvalTask(
    dataset=eval_dataset_multi,  # 先ほど作成したデータセット
    metrics=[*metrics, custom_metrics],
    experiment="customer-service-eval"
)

# モデルの設定
generation_config = {
    "max_output_tokens": 1024,    # 十分な長さの返信を許可
    "temperature": 0.4,           # 適度な創造性を維持
    "top_p": 0.8,                # 出力の多様性を確保
    "top_k": 40                  # 選択肢の幅を設定
}

safety_settings = {
    HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
    HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
}

model = GenerativeModel(
    "gemini-1.5-pro",
    generation_config=generation_config,
    safety_settings=safety_settings
)

# 評価の実行
eval_result = eval_task.evaluate(
    model=model,
    prompt_template="""
    {instruction}
    
    顧客レビュー:
    {context}
    
    返信:
    """
)

手順4: 評価結果の解釈

評価結果の例と解釈

以下は、あるレビュー返信の評価結果例です。

EvalResult(
	summary_metrics={
		'row_count': 3,
		'text_quality/mean': 5.0,
		'text_quality/std': 'NaN',
		'fluency/mean': 5.0,
		'fluency/std': 'NaN',
		'safety/mean': 'NaN',
		'safety/std': 'NaN',
		'verbosity/mean': 'NaN',
		'verbosity/std': 'NaN',
		'customer_service_quality/mean':
		'NaN',
		'customer_service_quality/std': 'NaN'
	}, 
	metrics_table=
context  \
0       商品がとても良かったです!梱包も丁寧で感動しました。   
1  注文から3週間経ちますが商品が届きません。とても困っています。   
2     使い方が分からず困っています。説明書が分かりにくいです。   

instruction  \
0  あなたはECサイトのカスタマーサービス担当です。\n        商品レビューに対して、以...   
1  あなたはECサイトのカスタマーサービス担当です。\n        商品レビューに対して、以...   
2  あなたはECサイトのカスタマーサービス担当です。\n        商品レビューに対して、以...   

prompt  \
0  \n    あなたはECサイトのカスタマーサービス担当です。\n        商品レビュー...   
1  \n    あなたはECサイトのカスタマーサービス担当です。\n        商品レビュー...   
2  \n    あなたはECサイトのカスタマーサービス担当です。\n        商品レビュー...   

response  \
0  ## 〇〇様\n\nこの度は、弊社商品をご購入いただき、誠にありがとうございます。\nまた、...   
1  〇〇様\n\nこの度は、ご注文いただいた商品のお届けについて、ご心配をおかけしており、誠に申...   
2  ## 〇〇様\n\nこの度は、弊社商品をご購入いただき、誠にありがとうございます。\nまた、...   

text_quality/explanation  text_quality/score  \
0  Coherence: The response is coherent and easy t...                 5.0   
1                                              Error                 NaN   
2                                              Error                 NaN   

fluency/explanation  fluency/score  \
0  STEP 1: Assess grammar correctness:\nThe AI-ge...            5.0   
1                                              Error            NaN   
2                                              Error            NaN   

safety/explanation safety/score verbosity/explanation verbosity/score  \
0              Error         None                 Error            None   
1              Error         None                 Error            None   
2              Error         None                 Error            None   

customer_service_quality/explanation customer_service_quality/score  
0                                Error                           None  
1                                Error                           None  
2                                Error                           None  ,
metadata={
	'experiment': 'customer-service-eval',
	'experiment_run': '5bf6619b-93cd-4f88-ae64-200e4cfac994'
})

スコアの見方と改善ポイントの特定

  1. テキスト品質(text_quality)のスコア解釈

    • 4.5以上:優れた返信で改善の必要なし
    • 3.5-4.4:良好だが改善の余地あり
    • 2.5-3.4:基本的な改善が必要
    • 2.5未満:大幅な改善が必要
  2. 流暢さ(fluency)の評価ポイント

    # 流暢さスコアの分析
    fluency_issues = eval_result.metrics_table[
        eval_result.metrics_table['fluency/score'] < 3.0
    ][['context', 'response', 'fluency/explanation']]
    
    print("改善が必要な返信例:")
    for _, row in fluency_issues.iterrows():
        print(f"コンテキスト: {row['context']}")
        print(f"返信: {row['response']}")
        print(f"問題点: {row['fluency/explanation']}\n")
    
  3. カスタマーサービス品質の分析

    # サービス品質の平均スコアを計算
    avg_cs_quality = eval_result.metrics_table['customer_service_quality/score'].mean()
    
    # スコア別の返信例を抽出
    best_responses = eval_result.metrics_table[
        eval_result.metrics_table['customer_service_quality/score'] > 4.5
    ]['response'].tolist()
    
    print("優れた返信例:")
    for response in best_responses[:3]:  # 上位3件を表示
        print(f"\n{response}\n---")
    

実践での注意点

  1. トークン数の制限
    • 出力の最大トークン数を適切に設定
    • 文章が途中で切れないよう注意
  2. 計算タスクの評価
    • LLMは計算が苦手
    • 評価プロンプトの特別なチューニングが必要
  3. 評価指標の選択
    • タスクの性質に合わせた指標を選択
    • 必要に応じてカスタム指標を追加

Discussion