Amazon Bedrock GuardrailsでDenied topicを試す

# はじめに
Amazon Bedrockを利用したチャットボットを運用する際に、有害なユーザー入力やモデルの出力を防ぎたい場合があります。例えば、チャットボットが個人情報を取り扱う場合、その情報が漏洩しないようにするために、個人情報を含む入力をフィルタリングする必要があります。また、チャットボットが不適切な内容を返答しないようにするために、不適切な内容を含む入力をフィルタリングする必要があります。Amazon Bedrock Guardrailsは、このような問題を解決するためのツールです。この記事では、Amazon Bedrock Guardrailsを使って、Denied topic(拒否されたトピック)を試してみます。

# Amazon Bedrock Guardrailsとは
Amazon Bedrock Guardrailsは、望ましくない有害なコンテンツを回避し、プライバシー保護のために機密情報を削除またはマスクするように設定できる以下のフィルタリングポリシーを提供する仕組みです。グランドチェックは、モデルの出力が情報ソースに基づいて適切であるかどうかやユーザーの入力に関連するものでるかをフィルタリングできるため、ハルシネーションの検出に使用できます。

- コンテンツフィルター
- 拒否されたトピック
- 単語フィルター
- 機密情報フィルター
- コンテキストのグランドチェック

ただし、以下のページに書かれているとおり、Amazon Bedrock Guardrailsは英語のみをサポートしています。そのため、他の言語のテキストコンテンツを評価すると信頼性の低い結果になる可能性があります。

https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html

:::note warn
Important
Amazon Bedrock Guardrails supports English-only. Evaluating text content in other languages can result in unreliable results.
:::

# 参考情報

https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html

https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/guardrails-use-converse-api.html

https://aws.amazon.com/jp/blogs/aws/guardrails-for-amazon-bedrock-can-now-detect-hallucinations-and-safeguard-apps-built-using-custom-or-third-party-fms/

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-runtime/client/converse.html

https://qiita.com/moritalous/items/271b40af3b0d70711679

https://qiita.com/hayao_k/items/45fef3047bf050b7ff34

https://qiita.com/kazuneet/items/753f63c89739660be500

# ガードレールを作成する
## Denied Topicsを作成する
Amazon Bedrock のコンソールメニューから Guardrails を選択し、Create guardrail を選択します。`Step 1: Provide guardrail details` では、以下のように入力します。デフォルトでは、プロンプトとレスポンスに対するブロックメッセージは同じものが使われますが、それぞれ異なるメッセージを指定することもできます。ここでは、どちら側でブロックされたのかが分かるように、
Apply the same blocked message for responses のチェックを外し異なるメッセージを指定しています。

|項目名|入力内容|
|---|---|
|Name(任意の名称) | DeniedTopicTest
|Description(任意の説明) |Denied Topic を英語と日本語でそれぞれ試す。|
|Messaging for blocked prompts (ガードレールがユーザープロンプトをブロックする場合に表示するメッセージ)|その質問には回答できません。|
|Messaging for blocked responses (ガードレールがモデルの応答をブロックする場合に表示するメッセージ)|回答に拒否トピックが含まれるため回答できません。|

![Amazon Bedrock Guardrails: Guardrails作成画面 step 1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/eef0dd18-ca77-9d29-4acd-cf6fbc8690d0.png)

Step 2: Configure content filters は入力をスキップします。

Step 3: Add denied topics では、以下のように Denied Topics を追加します。後述の例のように、いくつかの例を試します。

![Amazon Bedrock Guardrails: Guardrails作成画面 step 3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/41fe2308-e8e0-4e22-1209-894cb029f6b8.png)

以下のステップは入力をスキップします。
Step 4: Add word filters
Step 5: Add sensitive information filters
Step 6: Add contextual grounding check

### 例1: 英語でトピックを定義

`Amazon Bedrock`について回答を拒否するように、このような内容でdenied topicsに設定しました。

<dl>
    <dt>Definition</dt>
    <dd>Amazon Bedrock is a fully managed service that offers a choice of high-performing foundation models from leading AI companies like Anthropic, Cohere, Stability AI, and Amazon through a single API.</dd>
    <dt>Sample phrases</dt>
    <dd>For what chan I use the Amazon Bedrock?</dd>
    <dd>What is Amazon Bedrock?</dd>
</dl>

![Amazon Bedrock Guardrails: Guardrails作成画面 step 3 - 例1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/2a08f6cd-aa77-d670-8e85-be78a73dc4e4.png)



#### 英語で質問する
`What are some ways to build a RAG using AWS resources?` という質問に対し、回答にBedrockが含まれるため回答がブロックされました。

![Amazon Bedrock Guardrails:英語で作成したトピックに英語で質問する例-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/0fe75fae-8f52-75a6-ba38-ae67ef3e7cf1.png)

`What are the different ways to build a RAG using Bedrock?` という質問に対し、プロンプト(質問)にBedrockが含まれるため回答がブロックされました。

![Amazon Bedrock Guardrails:英語で作成したトピックに英語で質問する例-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/64ca7bcd-8c4d-d965-ca5d-526f1acbdf3e.png)



#### 日本語で質問する
日本語で質問してみます。

`AWSのリソースを使ってRAGを構築するには、どのような方法があるか?`という質問に対し、回答にBedrockが含まれるため回答がブロックされました。

![Amazon Bedrock Guardrails:英語で作成したトピックに日本語で質問する例-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/39110ffe-fcb7-a485-05b8-8dc0214c7b55.png)


`Bedrockを使ってRAGを構築するには、どのような方法があるか?`という質問に対し、プロンプト(質問)にBedrockが含まれるため回答がブロックされました。

![Amazon Bedrock Guardrails:英語で作成したトピックに日本語で質問する例-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/e40627c0-bb3e-3170-2a2d-3c93e7437659.png)




### 例2: 日本語でトピックを作成
つづいて、日本語でdenied topicを作成します。

<dl>
    <dt>Definition</dt>
    <dd>Amazon Bedrock は、Anthropic、Cohere、Stability AI、Amazon などの大手 AI 企業の高性能な基盤モデルを単一の API を通じて選択できる、完全に管理されたサービスです。</dd>
    <dt>Sample phrases</dt>
    <dd>Amazon Bedrockは何に使用できますか?</dd>
    <dd>Amazon Bedrockとは何ですか?</dd>
</dl>

![Amazon Bedrock Guardrails: Guardrails作成画面 step 3 - 例2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/714b6c5d-e25b-8df2-69c4-da41bc7a97cf.png)


#### 英語で質問する

`What are some ways to build a RAG using AWS resources?` という質問に対し、回答にBedrockが含まれるため回答がブロックされました。

![Amazon Bedrock Guardrails:日本語で作成したトピックに英語で質問する例-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/d9b8e51c-1b76-7b22-2b87-15b207d79d78.png)


`What are the different ways to build a RAG using Bedrock?` という質問に対し、プロンプト(質問)にBedrockが含まれるため回答がブロックされました。

![Amazon Bedrock Guardrails:日本語で作成したトピックに英語で質問する例-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/8c8279ff-a267-313b-992c-344067f0bb8c.png)



#### 日本語で質問する

`AWSのリソースを使ってRAGを構築するには、どのような方法があるか?`という質問に対し、回答にBedrockが含まれるため回答がブロックされました。

![Amazon Bedrock Guardrails:日本語で作成したトピックに日本語で質問する例-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/b943d733-20d0-7e2a-9202-f2fb3613eb35.png)

`Bedrockを使ってRAGを構築するには、どのような方法があるか?`という質問に対し、プロンプト(質問)にBedrockが含まれるため回答がブロックされました。

![Amazon Bedrock Guardrails:日本語で作成したトピックに日本語で質問する例-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/e646afb1-cef2-1186-6af5-91015181ba8b.png)




### 例3-1: 拒否トピックをすり抜けてしまう(英語のdenied topic)
これまでに挙げた例は、いずれも期待したとおりの動作でした。しかし、以下の例では、拒否トピックをすり抜けてしまうことがありました。
`競馬`について回答を拒否するように、このような内容でdenied topicsに設定しました。Definitionの内容はWikipeidaを参考にしました。

<dl>
    <dt>Definition</dt>
    <dd>Horse racing is a race in which horses ridden by jockeys compete and a gambling game in which people predict the order of finish. Horse racing is held as a set event with the sale of winning tickets.</dd>
    <dt>Sample phrases</dt>
    <dd>What is the Horse racing?</dd>
    <dd>I want to know the history of horse racing.</dd>
</dl>

![Amazon Bedrock Guardrails: Guardrails作成画面 step 3 - 例3-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/0a6136a8-1ed2-d6e2-4a50-e56411fcda77.png)



#### 日本語で質問する

`競馬とはなんですか?`という質問に対し、プロンプトと回答ともに競馬が含まれるにもかかわらず、両者ともブロックされませんでした。

![Amazon Bedrock Guardrails:英語で作成したトピックに日本語で質問する例-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/a67283e5-e7ca-23d7-8fe0-5eaacb1262a5.png)

`騎手が乗った馬により競われる競走競技で、その着順を予想する遊技はなんと呼ばれますか?`という質問に対し、回答に競馬が含まれるにもかかわらず、ブロックされませんでした。

![Amazon Bedrock Guardrails:英語で作成したトピックに日本語で質問する例-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/2b13652b-e052-9af8-3fda-23f2601755fe.png)





### 例3-2: 拒否トピックをすり抜けてしまう(日本語のdenied topic)

競馬について、日本語でdenied topicを作成します。Definitionの内容はWikipeidaを参考にしました。
<dl>
    <dt>Definition</dt>
    <dd>競馬（けいば、英: Horse racing）は、騎手が乗った馬により競われる競走競技、および、その着順を予想する賭博である。イギリスを発祥とする近代競馬は多くの国々で開催されており、その多くは勝馬投票券（馬券）の販売とセットの興行として行われている。</dd>
    <dt>Sample phrases</dt>
    <dd>競馬の歴史を知りたい。</dd>
    <dd>競馬とは何ですか?</dd>
</dl>

![Amazon Bedrock Guardrails: Guardrails作成画面 step 3 - 例3-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/66a15737-53a4-10b9-f48a-d72242ba7048.png)



#### 日本語で質問する
Sample phrasesに含まれる`競馬の歴史を知りたい。`という質問に対し、プロンプトと回答に競馬が含まれるにもかかわらず、ブロックされませんでした。

![Amazon Bedrock Guardrails:日本語で作成したトピックに日本語で質問する例-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/13901c4e-1bb7-2e7c-bd4d-b3e0108eab8b.png)


もう一度同じ質問をしたところ、今度はブロックされました。日本語が正式にサポートされていないためか結果が安定しないようです。

![Amazon Bedrock Guardrails:日本語で作成したトピックに日本語で質問する例-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/481b5736-c634-4c31-6b57-16395f6c27f7.png)


`競馬とは何ですか?`という質問に対し、プロンプトと回答に競馬が含まれるにもかかわらず、ブロックされませんでした。

![Amazon Bedrock Guardrails:日本語で作成したトピックに日本語で質問する例-3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/6964389e-f5b1-3a3b-30db-99176e7d92b5.png)




## コードで書いてみる

以下のコードは、コマンドライン引数で入力されたテキストに対して、Amazon Bedrock Guardrailsを使って回答を生成するものです。
Converse APIであれば、guardrailConfigを指定することでGuardrailを適用できます。

```python:app.py
import json
import logging
import sys

import boto3
from botocore.exceptions import ClientError

logging.basicConfig(format="%(asctime)s [%(levelname)s] %(message)s", level=logging.INFO)
logger = logging.getLogger(__name__)


def get_bedrock_client():
    """Bedrock クライアントを取得する"""
    return boto3.client(service_name="bedrock-runtime", region_name="us-east-1")

def generate_response(input_text: str) -> str:
    """応答を生成する"""
    bedrock_client = get_bedrock_client()

    messages = [{"role": "user", "content": [{"text": f"<text>{input_text}</text>"}]}]

    modelid = "anthropic.claude-3-5-sonnet-20240620-v1:0"

    inference_config = {
        "temperature": 0,
        "maxTokens": 500,
        "topP": 0.99,
    }

    guardrail_id = "xxxxxxxxxxxx" # Guardrail IDを指定する
    guardrail_version = "DRAFT"   # Guardrail Versionを指定する

    guardrail_config = {
        "guardrailIdentifier": guardrail_id,
        "guardrailVersion": guardrail_version,
        "trace": "enabled"
    }

    try:
        response_body = bedrock_client.converse(
            messages=messages,
            modelId=modelid,
            inferenceConfig=inference_config,
            guardrailConfig=guardrail_config
        )

        logger.info("Usage: %s",  json.dumps(response_body['usage'], indent=2, ensure_ascii=False))
        logger.info("Output: %s", json.dumps(response_body['output'], indent=2, ensure_ascii=False))
        logger.info("stopReason: %s", json.dumps(response_body['stopReason'], indent=2, ensure_ascii=False))
        logger.info("Trace: %s", json.dumps(response_body['trace'], indent=2, ensure_ascii=False))

        return response_body['output']['message']['content'][0]['text']

    except Exception as e:
        logger.error("Failed to generate response: %s", e)
        raise


def main():
    # コマンドライン引数を取得する
    if len(sys.argv) < 2:
        print("Usage: python3 ./app.py <input_text>")
        sys.exit(1)

    input_text = sys.argv[1]

    logger.info("Original query: %s", input_text)


    try:
        print("Final response: " f"{generate_response(input_text)}")


    except ClientError  as err:
        message = err.response['Error']['Message']
        logger.error("A client error occurred: %s", message)


if __name__ == "__main__":
    main()
```

実行結果は以下の通りです。

```console
❯ python3 ./app.py "Bedrockを使ってRAGを構築するには、どのような方法があるか?"
2024-09-30 22:45:23,201 [INFO] Original query: Bedrockを使ってRAGを構築するには、どのような方法があるか?
2024-09-30 22:45:23,218 [INFO] Found credentials in shared credentials file: ~/.aws/credentials
2024-09-30 22:45:24,314 [INFO] Usage: {
  "inputTokens": 0,
  "outputTokens": 0,
  "totalTokens": 0
}
2024-09-30 22:45:24,314 [INFO] Output: {
  "message": {
    "role": "assistant",
    "content": [
      {
        "text": "その質問には回答できません。"
      }
    ]
  }
}
2024-09-30 22:45:24,314 [INFO] stopReason: "guardrail_intervened"
2024-09-30 22:45:24,314 [INFO] Trace: {
  "guardrail": {
    "inputAssessment": {
      "50xfas7lh0x7": {
        "topicPolicy": {
          "topics": [
            {
              "name": "About Bedrock",
              "type": "DENY",
              "action": "BLOCKED"
            }
          ]
        }
      }
    }
  }
}
Final response: その質問には回答できません。
```

# まとめ
Amazon Bedrock Guardrailsを使って、コンテンツフィルタを試してみました。英語のテキストに対しては期待通りの結果が得られましたが、日本語のテキストに対しては結果が安定しないようです。日本語のテキストに対しても信頼性の高い結果を得るためには、英語に翻訳してから評価するなどの工夫が必要です。
今後、日本語のテキストに対するサポートが強化されることを期待します。