はじめに
先月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:モデルのレスポンスがユーザの入力値とどれくらい関連しているかのスコア
Lambdaの作成
今回は下記のようにLambdaのローカル環境に参照ソースファイル(ref.txt)を配置し、
それを読み込ませる形でLambdaを作成していきます。
フォルダ構造は下記の通りです。
invoke_bedrock_guardrails
├── lambda_function.py # メインのLambda関数
├── guardrail_utils.py # apply_guardrail関数を含むファイル
├── file_utils.py # 参照ソースを読み込む処理のファイル
└── ref.txt # 参照ソースファイル
参照ソース
ref.txt の内容は次の通りです。
• 段ボールの中には 15 個のボールがあります。
• 段ボールの中の小さな箱には 30 個のチョコレートが入っています。
• 段ボールの中にあるペンの本数は 25 本です。
• 段ボールに入っているのは 40 枚の紙です。
• 段ボールには 10 個のりんごが詰まっています。
ソースコード
参照ソースの内容とユーザのプロンプトを取得し、モデル(Claude)にリクエストを投げています。
モデルから返ってきたレスポンスを apply_guardrail の引数として渡し、ApplyGuardrail で評価を行います。
詳細はコメントアウトの通りです。
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)の読み込みます。
def read_resource_file():
with open('ref.txt', 'r') as file:
return file.read()
モデルの回答に対してapply_guardrailで評価を行います。
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'
動作確認
ユーザのプロンプト例として段ボールの中身を聞いてみます。
{
"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"
}
]
}
}
]
~~~
ハルシネーションを起こしそうな下記の内容でユーザのプロンプトを入力してみます。
{
"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 の ApplyGuardrail API を使用し、
モデルの回答にハルシネーションがあるか評価する処理を実装してみました。
本機能を利用する事で、GROUNDINGフィルターでチェックされたスコアによりハルシネーションを含むか確認できるため、誤った回答をユーザに案内してしまうケースを減らせそうです。
参考