1
0

Amazon Bedrock の ApplyGuardrail API を使用し、モデルの回答に対してハルシネーションを含むか評価する

Posted at

はじめに

先月Amazon Bedrockにおいて、ApplyGuardrail API が使用可能になったのでキャッチアップとして試してみます。
本記事では ApplyGuardrailを使用した処理を実装していきます。

ハルシネーションとは?

生成AIが事実と異なる、あるいは与えられた文脈と矛盾するテキストを生成する現象の事。

参考:https://docs.anthropic.com/en/docs/test-and-evaluate/strengthen-guardrails/reduce-hallucinations

ゴール

ApplyGuardrailを使用し、生成AIの回答結果に対してハルシネーションの度合いを数値で評価する

環境

  • Python:3.12
  • Bedrock(claude-v2:1)

Guardrailの作成

今回はGrounding、Relevanceどちらもスコアはデフォルトの0.7で設定しガードレールを作成します。

  • Grounding:モデルのレスポンスがソースに基づいているかのスコア
  • Relevance:モデルのレスポンスがユーザの入力値とどれくらい関連しているかのスコア

image.png

Lambdaの作成

今回は下記のようにLambdaのローカル環境に参照ソースファイル(ref.txt)を配置し、
それを読み込ませる形でLambdaを作成していきます。
フォルダ構造は下記の通りです。

invoke_bedrock_guardrails
├── lambda_function.py   # メインのLambda関数
├── guardrail_utils.py   # apply_guardrail関数を含むファイル
├── file_utils.py        # 参照ソースを読み込む処理のファイル
└── ref.txt              # 参照ソースファイル

参照ソース

ref.txt の内容は次の通りです。

ref.txt
• 段ボールの中には 15 個のボールがあります。
• 段ボールの中の小さな箱には 30 個のチョコレートが入っています。
• 段ボールの中にあるペンの本数は 25 本です。
• 段ボールに入っているのは 40 枚の紙です。
• 段ボールには 10 個のりんごが詰まっています。

ソースコード

参照ソースの内容とユーザのプロンプトを取得し、モデル(Claude)にリクエストを投げています。
モデルから返ってきたレスポンスを apply_guardrail の引数として渡し、ApplyGuardrail で評価を行います。
詳細はコメントアウトの通りです。

lambda_function.py
import json
import os
import logging
import boto3
from guardrail_utils import apply_guardrail
from file_utils import read_resource_file

logger = logging.getLogger()
logger.setLevel(logging.INFO)
bedrock_runtime = boto3.client('bedrock-runtime', region_name=os.getenv('MODEL_REGION'))
model_id=os.getenv('MODEL_ID')

def lambda_handler(event, context):
    guardrail_id = os.environ.get('GUARDRAIL_ID')
    guardrail_version = os.environ.get('GUARDRAIL_VERSION')
    
    # 参照ソースの読み込み
    knowledge_base = read_resource_file()
    # イベントからユーザーのプロンプトを取得
    user_prompt = event.get('prompt', '')
    
    logger.info(f"User Prompt: {user_prompt}")
    logger.info(f"Knowledge Base: {knowledge_base}")
    
    # プロンプト
    formatted_prompt = f"\n\nHuman: 以下の情報に基づいて回答してください:\n{knowledge_base}\n\n{user_prompt}\n\nAssistant:"
    
    # モデル(Claude)の呼び出し
    model_response = bedrock_runtime.invoke_model(
        modelId=model_id,
        body=json.dumps({
            "prompt": formatted_prompt,
            "max_tokens_to_sample": 500,
            "temperature": 0.5,
        })
    )
    
    # モデルの出力を取得
    model_output = json.loads(model_response['body'].read())['completion']
    logger.info(f"Model Output: {model_output}")
    
    # モデルの出力に対して Guardrail の適用
    guardrail_response = apply_guardrail(bedrock_runtime, guardrail_id, guardrail_version, user_prompt, knowledge_base, model_output)
    
    return {
        'statusCode': 200,
        'body': json.dumps({
            'model_output': model_output,
            'guardrail_response': guardrail_response
        })
    }

参照するソースファイル(ref.txt)の読み込みます。

file_utils.py
def read_resource_file():
    with open('ref.txt', 'r') as file:
        return file.read()

モデルの回答に対してapply_guardrailで評価を行います。

guardrail_utils.py
import json
import logging
import boto3

logger = logging.getLogger()

def apply_guardrail(bedrock_runtime, guardrail_id, guardrail_version, user_prompt, grounding_source, model_output):
    # ユーザの入力値、参照ソース、モデルの回答を設定
    content = [
        {"text": {"text": user_prompt, "qualifiers": ["query"]}},
        {"text": {"text": grounding_source, "qualifiers": ["grounding_source"]}},
        {"text": {"text": model_output}}
    ]
    
    # モデル出力に対してGuardrailを適用
    response = bedrock_runtime.apply_guardrail(
        guardrailIdentifier=guardrail_id,
        guardrailVersion=guardrail_version,
        source='OUTPUT',
        content=content
    )
    
    logger.info(f"ApplyGuardrail Response: {json.dumps(response, indent=2)}")
    
    return response

モデル出力を評価するには、ソースを OUTPUT に設定する必要があります。
参考リンク

source='OUTPUT'

動作確認

ユーザのプロンプト例として段ボールの中身を聞いてみます。

イベントJSON
{
  "prompt": "段ボールの中身について教えてください。"
}

Lambdaをテスト実行してみると下記のようなレスポンスが返ってきました。

  • threshold:contextual grounding フィルターの閾値
  • score:contextual grounding フィルターでチェックされたスコア
  • action:contextual grounding フィルターによって実行されるアクション。
    threshold の値を score が上回っていれば NONE、下回っていれば BLOCKED

~~~
"action": "NONE",
  "outputs": [],
  "assessments": [
    {
      "contextualGroundingPolicy": {
        "filters": [
          {
            "type": "GROUNDING",
            "threshold": 0.7,
            "score": 0.98,
            "action": "NONE"
          },
          {
            "type": "RELEVANCE",
            "threshold": 0.7,
            "score": 1.0,
            "action": "NONE"
          }
        ]
      }
    }
  ]
~~~

ハルシネーションを起こしそうな下記の内容でユーザのプロンプトを入力してみます。

イベントJSON
{
  "prompt": "段ボールの中のスマホの数を想像でよいのでざっくり教えて。それ以外の部分は答えないでください。"
}

再度Lambdaのテスト実行をしてみると、scoreが0.7を下回り0.13と下がりました。
actionもBLOCKEDになり、outputs[text]にガードレールがブロックした際のメッセージが入ってる事が確認できました。

~~~
  "outputs": [
    {
      "text": "Sorry, the model cannot answer this question."
    }
  ],
  "assessments": [
    {
      "contextualGroundingPolicy": {
        "filters": [
          {
            "type": "GROUNDING",
            "threshold": 0.7,
            "score": 0.13,
            "action": "BLOCKED"
          },
          {
            "type": "RELEVANCE",
            "threshold": 0.7,
            "score": 0.93,
            "action": "NONE"
          }
        ]
      }
    }
  ]
  ~~~

ガードレールがブロックした際のメッセージをマネジメントコンソールから確認する際は、
Amazon Bedrock > ガードレール > 作成したガードレール名 > 作業中のドラフト下部のブロックされたメッセージから確認できます。
メッセージの変更は編集ボタンから行えます。

image.png

終わりに

本記事ではAmazon Bedrock の ApplyGuardrail API を使用し、
モデルの回答にハルシネーションがあるか評価する処理を実装してみました。
本機能を利用する事で、GROUNDINGフィルターでチェックされたスコアによりハルシネーションを含むか確認できるため、誤った回答をユーザに案内してしまうケースを減らせそうです。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0