大規模言語モデル (LLM) を使用したシステムの構築 (7): 評価 1

今日はDeepLearning.AIのBuilding Systems with LLMのオンラインコースを受講したので、その主な内容の一部を共有したいと思います。私たちはこれまでに次の知識を学びました。

  1. 大規模言語モデル (LLM) を使用したシステムの構築パート 1: 分類
  2. 大規模言語モデル (LLM) を使用したシステム構築 (2): コンテンツのレビュー、プロンプト インジェクションの防止
  3. 大規模言語モデル (LLM) を使用したシステムの構築 (3): 思考連鎖推論
  4. 大規模言語モデル (LLM) を使用したシステムの構築 (4): 連鎖したヒント
  5. 大規模言語モデル(LLM)を使ったシステム構築(5):出力チェック
  6. 大規模言語モデル (LLM) を使用したシステムの構築 (6): エンドツーエンド システムの構築

前回のブログでは、エンドツーエンドのシステムを構築するための大規模言語モデル (LLM) が完成しましたが、システム開発が完了したら、システムの機能を評価する必要があります。システム機能を評価するためのテストケースを設計する必要があり、テスト結果が要件を満たしているかどうかをテストおよび観察します。ここでテストするシステムは、前のブログで開発したエンドツーエンド システムです。以下は LLM モデルにアクセスするためのメイン コードです。ここでバックオフ パッケージを追加しました。その機能は主に API 呼び出し時のレート制限エラーを防ぐことです。エラーの理由は前のブログで説明されているので、ここでは詳細には触れません。:

import openai
import backoff 
 
#您的openai的api key
openai.api_key ='YOUR-OPENAI-API-KEY' 

@backoff.on_exception(backoff.expo, openai.error.RateLimitError) 
def get_completion_from_messages(messages, 
                                 model="gpt-3.5-turbo", 
                                 temperature=0, 
                                 max_tokens=500):
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=temperature, 
        max_tokens=max_tokens,
    )
    return response.choices[0].message["content"]

関連する製品とカテゴリを取得する

前回のブログでは、エンドツーエンド システムを開発しました。システムの主な機能は、関連する電子製品に関するユーザーの質問に答える、パーソナライズされた顧客サービス ロボットを開発することです。ユーザーが質問すると、システムはまず、ユーザーの質問 言及された電子製品がシステム内の電子製品の現在のリストに含まれているかどうか、次のコードは現在のシステム内のすべての電子製品の現在のリストを確認します。

products_and_category = utils.get_products_and_category()
products_and_category

現在の製品リストのすべてのカテゴリを見てみましょう。現在の製品リストには 6 つのカテゴリがあります。

#所有类别
list(products_and_category.keys())

ここでは、電子製品には 6 つの主要カテゴリが含まれており、各主要カテゴリの下にいくつかの特定の電子製品があることがわかります。Python 辞書を使用して製品カタログ リストを保存します。キーはカテゴリに対応し、値は次のとおりです。特定の製品です。

関連する製品とカテゴリ名の検索 (バージョン 1)

次に、関連する製品とカテゴリの名前を検索する関数を定義します。この関数は顧客の質問を受け取り、その質問に関連する製品とカテゴリのカタログ リストを返します。

def find_category_and_product_v1(user_input,products_and_category):

    delimiter = "####"
    system_message = f"""
    You will be provided with customer service queries. \
    The customer service query will be delimited with {delimiter} characters.
    Output a python list of json objects, where each object has the following format:
        'category': <one of Computers and Laptops, Smartphones and Accessories, Televisions and Home Theater Systems, \
    Gaming Consoles and Accessories, Audio Equipment, Cameras and Camcorders>,
    AND
        'products': <a list of products that must be found in the allowed products below>


    Where the categories and products must be found in the customer service query.
    If a product is mentioned, it must be associated with the correct category in the allowed products list below.
    If no products or categories are found, output an empty list.
    

    List out all products that are relevant to the customer service query based on how closely it relates
    to the product name and product category.
    Do not assume, from the name of the product, any features or attributes such as relative quality or price.

    The allowed products are provided in JSON format.
    The keys of each item represent the category.
    The values of each item is a list of products that are within that category.
    Allowed products: {products_and_category}
    

    """
    
    few_shot_user_1 = """I want the most expensive computer."""
    few_shot_assistant_1 = """ 
    [{'category': 'Computers and Laptops', \
'products': ['TechPro Ultrabook', 'BlueWave Gaming Laptop', 'PowerLite Convertible', 'TechPro Desktop', 'BlueWave Chromebook']}]
    """
    
    messages =  [  
    {'role':'system', 'content': system_message},    
    {'role':'user', 'content': f"{delimiter}{few_shot_user_1}{delimiter}"},  
    {'role':'assistant', 'content': few_shot_assistant_1 },
    {'role':'user', 'content': f"{delimiter}{user_input}{delimiter}"},  
    ] 
    return get_completion_from_messages(messages)

ここでは、system_message を誰でも理解しやすい中国語に翻訳します。

System_message = f"""
您将获得客户服务查询。
客户服务查询将用{delimiter}字符分隔。
输出json对象的python列表,其中每个对象具有以下格式:
“category”:<电脑和笔记本电脑,智能手机和配件,电视和家庭影院系统之一,
游戏机及配件、音响设备、照相机及摄像机>、
和
'products': <必须在下面允许的产品中找到的产品列表>


其中类别和产品必须在客户服务查询中找到。
如果提到某个产品,它必须与下面允许的产品列表中的正确类别相关联。
如果没有找到任何产品或类别,则输出一个空列表。


列出与客户服务查询相关的所有产品
到产品名称和产品类别。
不要从产品的名称中假设任何特征或属性,例如相对质量或价格。

允许的产品以JSON格式提供。
每个项目的键代表类别。
每个项目的值是属于该类别的产品列表。
允许的产品:{products_and_category}
"""

ここでは、system_message の提供に加えて、少数の自問学習サンプル some_shot_user_1 および some_shot_assistant_1 も提供しています。この目的は、LLM が指定された形式でクエリ結果を正しく出力する方法を認識できるようにトレーニングすることです。

find_category_and_product_v1 を評価する

find_category_and_product_v1 メソッドを定義した後、find_category_and_product_v1 の実際の効果を評価するためのユーザーの質問をいくつか設計してみましょう。

customer_msg_0 = f"""Which TV can I buy if I'm on a budget?"""

products_by_category_0 = find_category_and_product_v1(customer_msg_0,
                                                      products_and_category)
print(products_by_category_0)

customer_msg_1 = f"""I need a charger for my smartphone"""

products_by_category_1 = find_category_and_product_v1(customer_msg_1,
                                                      products_and_category)
products_by_category_1

customer_msg_2 = f"""What computers do you have?"""
products_by_category_2 = find_category_and_product_v1(customer_msg_2,
                                                      products_and_category)
products_by_category_2

customer_msg_3 = f"""
tell me about the smartx pro phone and the fotosnap camera, the dslr one.
Also, what TVs do you have?"""

products_by_category_3 = find_category_and_product_v1(customer_msg_3,
                                                      products_and_category)
print(products_by_category_3)

 ここでの 4 つのユーザーの質問について、LLM は指定された形式でクエリ結果を出力します。ここでのクエリ結果はすべて文字列形式で出力されることに注意してください。

より複雑なテストケース

 次に、find_category_and_product_v1 が要求どおりに結果を出力できるかどうかを確認するために、より複雑なテスト ケースを設計する必要があります。

customer_msg_4 = f"""
tell me about the CineView TV, the 8K one, Gamesphere console, the X one.
I'm on a budget, what computers do you have?"""

products_by_category_4 = find_category_and_product_v1(customer_msg_4,
                                                      products_and_category)
print(products_by_category_4)

 

 上記の出力結果から、顧客の問題がもう少し複雑な場合、LLM の出力に必要な指定形式の情報に加えて、テキスト情報も含まれることがわかりますが、テキストのこの部分は弊社システムでは出力結果を指定されたPython List形式に変換する必要があるため、出力結果にテキスト情報が混在している場合、形式変換ができません。

より複雑なテスト ケースを処理できるようにプロンプ​​トを変更 (バージョン 2)

次に、以前と同様に複雑なユーザーの問題を処理できるように、system_message を変更する必要があります。主な目的は、LLM が不要なテキスト情報を出力しないようにすることです。

def find_category_and_product_v2(user_input,products_and_category):
    """
    Added: Do not output any additional text that is not in JSON format.
    Added a second example (for few-shot prompting) where user asks for 
    the cheapest computer. In both few-shot examples, the shown response 
    is the full list of products in JSON only.
    """
    delimiter = "####"
    system_message = f"""
    You will be provided with customer service queries. \
    The customer service query will be delimited with {delimiter} characters.
    Output a python list of json objects, where each object has the following format:
        'category': <one of Computers and Laptops, Smartphones and Accessories, Televisions and Home Theater Systems, \
    Gaming Consoles and Accessories, Audio Equipment, Cameras and Camcorders>,
    AND
        'products': <a list of products that must be found in the allowed products below>
    Do not output any additional text that is not in JSON format.
    Do not write any explanatory text after outputting the requested JSON.


    Where the categories and products must be found in the customer service query.
    If a product is mentioned, it must be associated with the correct category in the allowed products list below.
    If no products or categories are found, output an empty list.
    

    List out all products that are relevant to the customer service query based on how closely it relates
    to the product name and product category.
    Do not assume, from the name of the product, any features or attributes such as relative quality or price.

    The allowed products are provided in JSON format.
    The keys of each item represent the category.
    The values of each item is a list of products that are within that category.
    Allowed products: {products_and_category}
    

    """
    
    few_shot_user_1 = """I want the most expensive computer. What do you recommend?"""
    few_shot_assistant_1 = """ 
    [{'category': 'Computers and Laptops', \
'products': ['TechPro Ultrabook', 'BlueWave Gaming Laptop', 'PowerLite Convertible', 'TechPro Desktop', 'BlueWave Chromebook']}]
    """
    
    few_shot_user_2 = """I want the most cheapest computer. What do you recommend?"""
    few_shot_assistant_2 = """ 
    [{'category': 'Computers and Laptops', \
'products': ['TechPro Ultrabook', 'BlueWave Gaming Laptop', 'PowerLite Convertible', 'TechPro Desktop', 'BlueWave Chromebook']}]
    """
    
    messages =  [  
    {'role':'system', 'content': system_message},    
    {'role':'user', 'content': f"{delimiter}{few_shot_user_1}{delimiter}"},  
    {'role':'assistant', 'content': few_shot_assistant_1 },
    {'role':'user', 'content': f"{delimiter}{few_shot_user_2}{delimiter}"},  
    {'role':'assistant', 'content': few_shot_assistant_2 },
    {'role':'user', 'content': f"{delimiter}{user_input}{delimiter}"},  
    ] 
    return get_completion_from_messages(messages)

ここでは、system_message に 2 つのプロンプトを追加しました。

 これら 2 つの文の意味は、追加のテキストを非 JSON 形式で出力しないことです。要求されたJSONを出力した後に説明文を記述しないでください。

さらに、元の学習サンプル ew_shot_user_1 と few_shot_assistant_1 を変更し、学習サンプルのペアである few_shot_user_2 と four_shot_assistant_2 を追加しました。このようにして、LLM が学習するための 2 ペアの学習サンプルが得られます。

複雑な問題に対する変更されたプロンプトの効果を評価する

customer_msg_4 = f"""
tell me about the CineView TV, the 8K one, Gamesphere console, the X one.
I'm on a budget, what computers do you have?"""

products_by_category_4 = find_category_and_product_v2(customer_msg_4,
                                                      products_and_category)
print(products_by_category_4)

上記の結果から、今回 LLM はテキスト情報を付加せずに、該当する商品と分類内容を正しい形式で出力しました。したがって、変更したプロンプトが機能したことがわかります。

 回帰テスト: モデルが以前のテスト ケースでまだ有効であることを確認します。

 以前のテスト ケースを再テストして、変更されたプロンプトが以前のテスト ケースに対して引き続き有効であることを確認する必要があります。ここでは、テストのために以前のテスト ケースをいくつか抽出します。

customer_msg_0 = f"""Which TV can I buy if I'm on a budget?"""

products_by_category_0 = find_category_and_product_v2(customer_msg_0,
                                                      products_and_category)
print(products_by_category_0)

customer_msg_3 = f"""
tell me about the smartx pro phone and the fotosnap camera, the dslr one.
Also, what TVs do you have?"""

products_by_category_3 = find_category_and_product_v2(customer_msg_3,
                                                      products_and_category)
print(products_by_category_3)

 ここでは、出力結果の要件を完全に満たす、前の 2 つのテスト ケースをテストします。

自動テスト用のテスト スイートを構築する

次に、自動テスト用のテスト ケースのセットを作成します。各テスト ケースには、顧客の質問 (customer_msg) と理想的な回答 (ideal_answer) の 2 つの部分が含まれます。私たちの目的は、LLM の回答が理想的な回答と一致しているかどうかを評価することです。そして、これを使用して LLM をスコアリングします。

msg_ideal_pairs_set = [
    
    # eg 0
    {'customer_msg':"""Which TV can I buy if I'm on a budget?""",
     'ideal_answer':{
        'Televisions and Home Theater Systems':set(
            ['CineView 4K TV', 'SoundMax Home Theater', 'CineView 8K TV', 'SoundMax Soundbar', 'CineView OLED TV']
        )}
    },

    # eg 1
    {'customer_msg':"""I need a charger for my smartphone""",
     'ideal_answer':{
        'Smartphones and Accessories':set(
            ['MobiTech PowerCase', 'MobiTech Wireless Charger', 'SmartX EarBuds']
        )}
    },
    # eg 2
    {'customer_msg':f"""What computers do you have?""",
     'ideal_answer':{
           'Computers and Laptops':set(
               ['TechPro Ultrabook', 'BlueWave Gaming Laptop', 'PowerLite Convertible', 'TechPro Desktop', 'BlueWave Chromebook'
               ])
                }
    },

    # eg 3
    {'customer_msg':f"""tell me about the smartx pro phone and \
    the fotosnap camera, the dslr one.\
    Also, what TVs do you have?""",
     'ideal_answer':{
        'Smartphones and Accessories':set(
            ['SmartX ProPhone']),
        'Cameras and Camcorders':set(
            ['FotoSnap DSLR Camera']),
        'Televisions and Home Theater Systems':set(
            ['CineView 4K TV', 'SoundMax Home Theater','CineView 8K TV', 'SoundMax Soundbar', 'CineView OLED TV'])
        }
    }, 
    
    # eg 4
    {'customer_msg':"""tell me about the CineView TV, the 8K one, Gamesphere console, the X one.
I'm on a budget, what computers do you have?""",
     'ideal_answer':{
        'Televisions and Home Theater Systems':set(
            ['CineView 8K TV']),
        'Gaming Consoles and Accessories':set(
            ['GameSphere X']),
        'Computers and Laptops':set(
            ['TechPro Ultrabook', 'BlueWave Gaming Laptop', 'PowerLite Convertible', 'TechPro Desktop', 'BlueWave Chromebook'])
        }
    },
    
    # eg 5
    {'customer_msg':f"""What smartphones do you have?""",
     'ideal_answer':{
           'Smartphones and Accessories':set(
               ['SmartX ProPhone', 'MobiTech PowerCase', 'SmartX MiniPhone', 'MobiTech Wireless Charger', 'SmartX EarBuds'
               ])
                    }
    },
    # eg 6
    {'customer_msg':f"""I'm on a budget.  Can you recommend some smartphones to me?""",
     'ideal_answer':{
        'Smartphones and Accessories':set(
            ['SmartX EarBuds', 'SmartX MiniPhone', 'MobiTech PowerCase', 'SmartX ProPhone', 'MobiTech Wireless Charger']
        )}
    },

    # eg 7 # this will output a subset of the ideal answer
    {'customer_msg':f"""What Gaming consoles would be good for my friend who is into racing games?""",
     'ideal_answer':{
        'Gaming Consoles and Accessories':set([
            'GameSphere X',
            'ProGamer Controller',
            'GameSphere Y',
            'ProGamer Racing Wheel',
            'GameSphere VR Headset'
     ])}
    },
    # eg 8
    {'customer_msg':f"""What could be a good present for my videographer friend?""",
     'ideal_answer': {
        'Cameras and Camcorders':set([
        'FotoSnap DSLR Camera', 'ActionCam 4K', 'FotoSnap Mirrorless Camera', 'ZoomMaster Camcorder', 'FotoSnap Instant Camera'
        ])}
    },
    
    # eg 9
    {'customer_msg':f"""I would like a hot tub time machine.""",
     'ideal_answer': []
    }
    
]

 テスト自動化テストセット

print(f'Customer message: {msg_ideal_pairs_set[7]["customer_msg"]}')
print(f'Ideal answer: {msg_ideal_pairs_set[7]["ideal_answer"]}')

理想的な答えを比較してテスト ケースを評価する

ここでは、評価 LLM の戻り結果と自動テスト ケース セットの理想的な回答を比較し、スコアを計算するための評価関数を定義します。

import json
def eval_response_with_ideal(response,
                              ideal,
                              debug=False):
    
    if debug:
        print("response")
        print(response)
    
    # json.loads() expects double quotes, not single quotes
    json_like_str = response.replace("'",'"')
    
    # parse into a list of dictionaries
    l_of_d = json.loads(json_like_str)
    
    # special case when response is empty list
    if l_of_d == [] and ideal == []:
        return 1
    
    # otherwise, response is empty 
    # or ideal should be empty, there's a mismatch
    elif l_of_d == [] or ideal == []:
        return 0
    
    correct = 0    
    
    if debug:
        print("l_of_d is")
        print(l_of_d)
    for d in l_of_d:

        cat = d.get('category')
        prod_l = d.get('products')
        if cat and prod_l:
            # convert list to set for comparison
            prod_set = set(prod_l)
            # get ideal set of products
            ideal_cat = ideal.get(cat)
            if ideal_cat:
                prod_set_ideal = set(ideal.get(cat))
            else:
                if debug:
                    print(f"did not find category {cat} in ideal")
                    print(f"ideal: {ideal}")
                continue
                
            if debug:
                print("prod_set\n",prod_set)
                print()
                print("prod_set_ideal\n",prod_set_ideal)

            if prod_set == prod_set_ideal:
                if debug:
                    print("correct")
                correct +=1
            else:
                print("incorrect")
                print(f"prod_set: {prod_set}")
                print(f"prod_set_ideal: {prod_set_ideal}")
                if prod_set <= prod_set_ideal:
                    print("response is a subset of the ideal answer")
                elif prod_set >= prod_set_ideal:
                    print("response is a superset of the ideal answer")

    # count correct over total number of items in list
    pc_correct = correct / len(l_of_d)
        
    return pc_correct

 次に、LLM に自動テスト セット内の特定の質問に回答させ、出力結果を自動テスト セット内の理想的な回答と比較してスコアを計算します。

response = find_category_and_product_v2(msg_ideal_pairs_set[7]["customer_msg"],
                                         products_and_category)
print(f'Resonse: {response}')

eval_response_with_ideal(response,
                              msg_ideal_pairs_set[7]["ideal_answer"])

 出力結果を見ると、LLM が返す Resonse の積の数は理想的な答えの積の数より少ないため、Resonse は理想的な結果の部分集合にすぎず、Resonse の結果は完全ではないと思われます。

すべてのテストケースを評価し、正解の割合を計算します。

次に、すべてのテストを評価し、正答率を計算します。

# Note, this will not work if any of the api calls time out
score_accum = 0
for i, pair in enumerate(msg_ideal_pairs_set):
    print(f"example {i}")

    customer_msg = pair['customer_msg']
    ideal = pair['ideal_answer']

    # print("Customer message",customer_msg)
    # print("ideal:",ideal)
    response = find_category_and_product_v2(customer_msg,
                                                      products_and_category)

    # print("products_by_category",products_by_category)
    score = eval_response_with_ideal(response,ideal,debug=False)
    print(f"{i}: {score}")
    score_accum += score


n_examples = len(msg_ideal_pairs_set)
fraction_correct = score_accum / n_examples
print(f"Fraction correct out of {n_examples}: {fraction_correct}")

 すべてのテストをテストしましたが、返された結果のうち、7 番目の質問の返された結果だけが完全に正しくありませんでした。これについては以前にも議論したため、正解が 9 つ、不正解が 1 つあり、最終スコアは 0.9 になります。

要約する

今日は、LLM の応答の正しさを評価する方法と、テスト ケースを作成して LLM の応答をテストする方法を学びました。LLM の応答が要件を満たしていない場合、LLM が正しい結果を出力するようにプロンプ​​トを変更する必要があります。プロンプトを変更するときは、 system_message に、出力結果を制御するステートメントが追加され、少数の学習サンプル (少数ショット プロンプト) が同時に追加されます。これにより、LLM がより適切に微調整され、LLM が確実に結果を出力します。最後に、自動化されたテスト ケースを確立して、LLM の応答を評価します。それが理想的な応答と一致しており、LLM によって評価されているかどうかを確認します。

おすすめ

転載: blog.csdn.net/weixin_42608414/article/details/131258737