COLUMN

Claudeにロールベース形式とチャットマークアップ形式で同じ内容を入力したら結果は変わるのか検証してみた【Amazon Bedrock】

こんにちは。エンジニアの森です。

Amazon Web Services(AWS)上で簡単に生成AIを組み込んだアプリケーションを構築することができるAmazon Bedrockでは日本語対応のLLMとしてAnthropic社のClaudeが提供されています。

Claudeを使用するBedrockを呼び出す際、「ユーザーからの入力」と「AIから返却されるふるまい」というロールの情報を渡すことでより良い出力にしようという以下のようなテクニックがあります。

※ユーザーからの入力をrole:userとして渡し、AIのふるまいをrole:assistantとして渡している

Claude 3 HaikuやClaude 3.5 Sonnetといったバージョンを使用したBedrockをプログラム(Pythonなど)から呼び出す際にロールの情報を渡すには、「ロールベース形式」と「チャットマークアップ形式」の2つの方法が存在します。

※左:ロールベース形式、右:チャットマークアップ形式

AWSのマネジメントコンソールからこの2つの渡し方の違いによって結果が異なるのかClaudeに直接聞いてみると変わらないとの返答とはなりましたが、ご存じの通りLLMは嘘をつくこともあるため、今回いくつかのパターンを作成し、本当に結果は変わらないのか、それとも結果が変わるのか検証していきます。

NTT東日本では、本コラムでのナレッジを使って、電話業務の効率化・行動化を実現する生成AIを活用したIVRソリューションを提供しております。ぜひこちらの特設ページもご覧ください。

1. 検証手順

「ロールベース形式」と「チャットマークアップ形式」の呼び出しに対応しているのはPythonなどのプログラムからBedrockから呼び出した場合です。

そのため、上図のようにLambdaからBedrock(Claude 3.5 Sonnet)を呼び出す構成とし、AWSマネジメントコンソールからテストを実施し、CloudWatchに出力されたデータを検証します。

ちなみにLambdaに作成したコードはこちら。(プロンプトのみテストケースごとに更新)

import json
import boto3
 
def lambda_handler(event, context):
 
    bedrock_runtime = boto3.client('bedrock-runtime', region_name="ap-northeast-1")
    modelId = 'anthropic.claude-3-5-sonnet-20240620-v1:0'
    accept = 'application/json'
    contentType = 'application/json'
 
    # ロールベース形式
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "messages": [
            {"role": "user", "content": "東京の人口は約何人ですか?"},
            {"role": "assistant", "content": "東京の人口は約1,400万人です。23区内の人口は970万人です。"},
            {"role": "user", "content": "ニューヨークと比べてどうですか?"}
        ],
        "max_tokens": 500,
        'temperature': 0,
    })
 
    for i in range(5):
        response = bedrock_runtime.invoke_model(
            modelId=modelId,
            accept=accept,
            contentType=contentType,
            body=body
        )
 
        response_body = json.loads(response.get('body').read())
        response_text = response_body["content"][0]["text"]
        print(f"role base {i + 1} response_text: {response_text.replace('\n', ' ').replace('\r', '')}")
 
 
    # チャットマークアップ形式
    prompt = """\n\nHuman: 東京の人口は約何人ですか?
                \n\nAssistant: 東京の人口は約1,400万人です。23区内の人口は970万人です。
                \n\nHuman: ニューヨークと比べてどうですか?
            """
 
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "messages": [
            {"role": "user", "content": prompt}
        ],
        "max_tokens": 500,
        'temperature': 0,
    })
 
    for i in range(5):
        response = bedrock_runtime.invoke_model(
            modelId=modelId,
            accept=accept,
            contentType=contentType,
            body=body
        )
 
        response_body = json.loads(response.get('body').read())
        response_text = response_body["content"][0]["text"]
        print(f"chat mark up base {i + 1} response_text: {response_text.replace('\n', ' ').replace('\r', '')}")
 
    return True

※LLMは同じプロンプトでも違う内容を出力することもあるので念のため上記コードではそれぞれ5回ループしていますが、今回の検証では結果が変わらなかったため、次章以降では1回の結果のみ掲載します。

NTT東日本では、本コラムでのナレッジを使って、電話業務の効率化・行動化を実現する生成AIを活用したIVRソリューションを提供しております。ぜひこちらの特設ページもご覧ください。

2. 検証

2-1. 東京とニューヨークの人口を比べる

まずは東京都とニューヨークの人口比較の例です。

Claudeに例題を考えてもらいました。

ロールベース形式でプロンプト部分を書くと以下のようになります。

    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "messages": [
            {"role": "user", "content": "東京の人口は約何人ですか?"},
            {"role": "assistant", "content": "東京の人口は約1,400万人です。23区内の人口は970万人です。"},
            {"role": "user", "content": "ニューヨークと比べてどうですか?"}
        ],
        "max_tokens": 500,
        'temperature': 0,
    })

出力結果は以下となりました。

【ロールベース形式】 【チャットマークアップ形式】
ニューヨーク市の人口は約860万人ですので、東京23区の人口(970万人)と比較すると、東京の方がやや多いです。 ただし、ニューヨーク大都市圏(トライステート地域)の人口は約2,000万人ともいわれています。この地域全体で比較すると、ニューヨークの方が人口は多いといえます。 東京という一つの政令指定都市の人口と、ニューヨークを含む大都市圏全体の人口比較は難しい面もありますが、大まかにはこのような関係です。東京は世界でも有数の巨大都市で、ニューヨークと並ぶほどの人口規模を持っています。 東京とニューヨークの人口を比較すると以下のようになります。 - 東京23区の人口は約970万人 - ニューヨーク市の人口は約860万人 つまり、東京23区の方が若干人口が多いです。ただし、郊外も含めた大都市圏全体で比較すると、 - 東京都市圏の人口は約3700万人 - ニューヨーク都市圏の人口は約2000万人 となり、東京の方がかなり人口が多いことがわかります。東京は世界最大の都市圏を形成していると言えます。

「東京のほうが多い」情報はどちらも出力していますが、一方にだけ出力されている情報もあるなど回答から受ける印象は違うことが分かります。

2-2. おすすめを挙げる(考える)

2-1では、事実に基づいて回答を作成する内容でした。

ここでは前提条件を与え、それに基づきおすすめを挙げさせる(考えさせる)内容です。

こちらもClaudeに考えてもらいました。

ロールベース形式でプロンプト部分を書くと以下の内容です。

    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "messages": [
            {"role": "user", "content": "晴れの日と雨の日で異なるおすすめの活動を教えてください。"},
            {"role": "assistant", "content": "晴れの日のおすすめ活動:\n1. ピクニック\n2. ハイキング\n3. 野外スポーツ\n\n雨の日のおすすめ活動:\n1. 美術館巡り\n2. 映画鑑賞\n3. 室内でのボードゲーム"},
            {"role": "user", "content": "今日は曇りです。曇りの日のおすすめ活動を3つ挙げてください。"}
        ],
        "max_tokens": 500,
        'temperature': 0,
    })

出力結果は以下となりました。

【ロールベース形式】 【チャットマークアップ形式】

今日は曇りの日ですね。曇りの日のおすすめ活動を3つ挙げます。

  1. ショッピング 曇りの日は天気の変化があるので、屋内のショッピングモールでゆっくりと買い物を楽しむのがおすすめです。
  2. ボウリング 屋内スポーツのボウリングは曇りの日でも楽しめます。誰でも手軽にできるのでオススメです。
  3. 映画鑑賞 屋内で気分転換できる映画鑑賞は、曇りの日にぴったりです。思い思いに映画を楽しめます。

こうした屋内のアクティビティが曇りの日には向いていると思います。

曇りの日のおすすめ活動3つを挙げます。

  1. ショッピング 曇りの日は天気が安定しているので、のんびりとショッピングを楽しめます。
  2. マッサージやスパ 室内でリラックスできるマッサージやスパは曇りの日にぴったりです。
  3. 美術館や博物館見学 外出しながらも雨にぬれずに済む美術館や博物館は曇りの日のアクティビティとしておすすめです。

どちらも1つめのショッピングは同じですが、その他は違っています。

同じ形式の場合、同じ出力なるため、形式によって回答が変わっていることが分かります。

2-3. 文章から必要な情報を抜き出し、json形式で返答する

これまでは一般的な内容でしたが、業務で活用できそうなケースを試します。

ある文章から必要な情報を抜き出し、指定されたjson形式にして返すというものです。

ロールベース形式でプロンプト部分を書くと以下の内容です。

    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "messages": [
            {"role": "user", "content": """以下の<text></text>タグ内の文章から必要な要件を抜き出してください。
                回答は<example></example>タグ内の例に従ってください。
<text>NTT東日本、営業部の森と申します。2024年11月1日に打ち合わせをお願いします。</text>
<example>
                {
                    "company": $company,
                    "department": $department,
                    "name": $name,
                    "requirement": $requirement
                }
</example>
                """},
            {"role": "assistant", "content": "{"}
        ],
        "max_tokens": 500,
        'temperature': 0,
    })

このassistantロールのcontentに”{“が入っているのはこの続きから書き出してねとClaudeに伝えるものであり、出力形式を指定したい場合によく使われます。

出力結果は以下となりました。

【ロールベース形式】
    "company": "NTT東日本",
    "department": "営業部",
    "name": "森",
    "requirement": "2024年11月1日に打ち合わせをお願いします"
}
【チャットマークアップ形式】
<text>NTT東日本、営業部の森と申します。2024年11月1日に打ち合わせをお願いします。</text>  
{
    "company": "NTT東日本",
    "department": "営業部",
    "name": "森",
    "requirement": "2024年11月1日に打ち合わせを設定"
}

どちらも必要な情報を抜き出すことはできていますが、チャットマークアップ形式の場合、jsonの前にテキストが入ってしまっています。

一方、ロールベース形式では、プロンプトに既に指定してある”{“の続きから出力されており、期待通りの動作となりました。

NTT東日本では、本コラムでのナレッジを使って、電話業務の効率化・行動化を実現する生成AIを活用したIVRソリューションを提供しております。ぜひこちらの特設ページもご覧ください。

3. まとめ:新規構築するならロールベース形式がおすすめだが構築方法によってはチャットマーク形式もあり

これまでの結果を簡単にまとめます。

一般的な内容であればロールベース形式もチャットマークアップ形式も大きな差はない(あくまで表現の違い程度)と言えますが、業務で使うような場面だとロールベース形式のほうがプロンプトに忠実で優れていると感じました。

このことから新規にアプリケーションを構築するのであればロールベース形式を用いることを前提に設計を行うことをおすすめします。

しかし、プロンプトを動的に作るようなシステムの場合、チャットマークアップ形式は1つの文字列を作ればよく工数が少なくなるという利点もあります。

また、Claude 2以前のモデルからClaude 3に移行する場合も工数が少なくなることが予想されます。

これらを考慮し、どちらの形式がいいか検証したうえで構築していくとよいでしょう。

NTT東日本では、今回ご紹介した生成AIなどの最新技術を取り入れたCCaaSプロダクト開発に力を入れています。

コンタクトセンターでお困りのことがある方はぜひお問い合わせください。

コンタクトセンターではないが、クラウド導入でお困りという方ももちろん大歓迎です!

ページ上部へ戻る

相談無料!プロが中立的にアドバイスいたします

クラウド・AWS・Azureでお困りの方はお気軽にご相談ください。