Guardrails for Amazon Bedrock の単語フィルターを試す

:::note warn
記事の都合上、紳士淑女にふさわしくない表現が多々現れます。**苦手な方はここでブラウザバックすることを強く推奨します。**
:::
:::note warn
記事の都合上、紳士淑女にふさわしくない表現が多々現れます。**苦手な方はここでブラウザバックすることを強く推奨します。**
:::
:::note warn
記事の都合上、紳士淑女にふさわしくない表現が多々現れます。**苦手な方はここでブラウザバックすることを強く推奨します。**
:::

３回も warning を入れてしまいました。

試すには汚い言葉が必要だったんですものオホホ。

## Guardrails for Amazon Bedrock の単語フィルター

Guardrails for Amazon Bedrock は 2024/8 現在 5 つの機能を持っていますが４つ目です。

* コンテンツフィルター
* 禁止トピック
* 機密情報フィルター 
* 単語フィルター <- 今ココ
* 文脈的根拠チェック

[Word Filter の機能の詳細はこちら](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-word-filters.html) ですが、ざっくり言うと、プリセットの Profanity filter (冒涜)フィルターと、カスタムのワードフィルターがあります。
Profanity filter はマネージドで継続的に更新が入るため、新しいマズい言葉は自動で対応していくそうです。

まずは、Profanity Filter を試してみます。

### Profanity filter 作成

例によって CDK で。

```typescript:guardrails-japanese-test-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { aws_bedrock as bedrock } from 'aws-cdk-lib';

export class GuardrailsJapaneseTestStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    const cfnGuardrail = new bedrock.CfnGuardrail(this,`contentGuardrail`,{
      blockedInputMessaging: 'そんなの入れちゃダメぇぇぇ！！',
      blockedOutputsMessaging: '変なの出ちゃぅぅ！！',
      name : `WordFilter-Guardrail`,
      wordPolicyConfig: {
        managedWordListsConfig: [{
          type: 'PROFANITY',
        }],
      },
    })
    new bedrock.CfnGuardrailVersion(this, `contentGuardrailVersion`, {
      guardrailIdentifier:cfnGuardrail.attrGuardrailId,
      description: `initial version`,
    })
  }
}
```

とても簡単ですね！

### 試す
今回はさまざまなスラングを紹介している英文のサイトから例文と日本語訳を取ってきました。

```python:test.ipynb
prompt_list = [
    # https://www.eikaiwanow.com/blog/swear-words
    'Janet stood me up for 2 hours yesterday. This is fucking stupid.',
    '昨日ジャネットに２時間も待ちぼうけさせられたんだ。クソ馬鹿馬鹿しいわ。',
    'Fuck Michael. I told you to put away your white gloves.',
    'マジないわ、マイケル。白い手袋しまってって言ったでしょ！',
    'I don’t want to see your shitface again.',
    'お前の汚い顔なんか見たくねぇ',
    'You are such a shitbag.',
    'あんたほんとクソバカだわ',
    'My sister sleep with different guy everyday. She\'s such a slut.',
    '妹は毎日違う男と寝るのよ。マジヤリマンなのよね。',
    'I told you to leave me alone. Stop being an asshole.',
    '一人にしてって言ったでしょ。ふざけるのはやめろ',
    # https://nativecamp.net/blog/20201130_bad_word
    'Fucking freezing!',
    'くそ寒い',
    'Fucking cute',
    'めちゃカワイイ',
    'Fuck you',
    'くそったれ！'
    'Fuck sake',
    'ったくもう！',
    'Mother-fucker',
    '嫌なヤツ',
    'Fuck off!',
    'うせろ！',
    'Fucking hell',
    'しまった！',
    'Holy Shit! I’ll go and watch a football match on that day',
    'しまった！その日はフットボール観戦行くんだったよ',
    'I\'ve never met such a nasty son of a bitch!',
    'こんな意地の悪い野郎に会ったことないよ！',
    'Her husband is a son of a bitch, running away from her and the children.',
    '彼女の夫はくそったれだ。彼女と子ども達から逃げてるよ。',
    # https://ejje.weblio.jp/content/cunt
    'I really hate that cunt.',
    'あの女が大嫌いだ。',
    # https://eow.alc.co.jp/search?q=dickhead&ref=wl
    'feel like a dickhead',
    '自分はばかだなと感じる',
    # https://note.com/eigonosensei/n/ne51b2b64e0e5
    'This will get her pussy wet.',
    '彼女をムラムラさせる。'
]
```

さて実行します。

```python:test.ipynb
for prompt in prompt_list:
    print(prompt)
    response = brt.apply_guardrail(
        guardrailIdentifier='xxxxx',
        guardrailVersion=guardrail['version'],
        source='OUTPUT',
        content=[
            {
                'text': {
                    'text': prompt,
                    'qualifiers': [
                        'guard_content',
                    ]
                }
            },
        ]
    )
    pprint(response['outputs'])
```
```text:出力
Janet stood me up for 2 hours yesterday. This is fucking stupid.
[{'text': '変なの出ちゃぅぅ！！'}]
昨日ジャネットに２時間も待ちぼうけさせられたんだ。クソ馬鹿馬鹿しいわ。
[]
Fuck Michael. I told you to put away your white gloves.
[{'text': '変なの出ちゃぅぅ！！'}]
マジないわ、マイケル。白い手袋しまってって言ったでしょ！
[]
I don’t want to see your shitface again.
[]
お前の汚い顔なんか見たくねぇ
[]
You are such a shitbag.
[]
あんたほんとクソバカだわ
[]
My sister sleep with different guy everyday. She's such a slut.
[]
妹は毎日違う男と寝るのよ。マジヤリマンなのよね。
[]
I told you to leave me alone. Stop being an asshole.
[{'text': '変なの出ちゃぅぅ！！'}]
一人にしてって言ったでしょ。ふざけるのはやめろ
[]
Fucking freezing!
[{'text': '変なの出ちゃぅぅ！！'}]
くそ寒い
[]
Fucking cute
[{'text': '変なの出ちゃぅぅ！！'}]
めちゃカワイイ
[]
Fuck you
[{'text': '変なの出ちゃぅぅ！！'}]
くそったれ！Fuck sake
[{'text': '変なの出ちゃぅぅ！！'}]
ったくもう！
[]
Mother-fucker
[{'text': '変なの出ちゃぅぅ！！'}]
嫌なヤツ
[]
Fuck off!
[{'text': '変なの出ちゃぅぅ！！'}]
うせろ！
[]
Fucking hell
[{'text': '変なの出ちゃぅぅ！！'}]
しまった！
[]
Holy Shit! I’ll go and watch a football match on that day
[]
しまった！その日はフットボール観戦行くんだったよ
[]
I've never met such a nasty son of a bitch!
[{'text': '変なの出ちゃぅぅ！！'}]
こんな意地の悪い野郎に会ったことないよ！
[]
Her husband is a son of a bitch, running away from her and the children.
[{'text': '変なの出ちゃぅぅ！！'}]
彼女の夫はくそったれだ。彼女と子ども達から逃げてるよ。
[]
I really hate that cunt.
[{'text': '変なの出ちゃぅぅ！！'}]
あの女が大嫌いだ。
[]
feel like a dickhead
[{'text': '変なの出ちゃぅぅ！！'}]
自分はばかだなと感じる
[]
This will get her pussy wet.
[]
彼女をムラムラさせる。
[]
```

まず日本語は全滅です。2024/8 時点では未対応のようです。
英語もFワードなどのメジャーどころは防げているようです。
英語話者ならとりあえず入れてもいいレベルのものかもしれませんね。

### カスタムワードフィルターの作成

さて、Profanity Filter は日本語が使えなかったのでカスタムワードを試してみましょう。
ストレートにバカという言葉を禁じてみましょう。

```typescript:guardrails-japanese-test-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { aws_bedrock as bedrock } from 'aws-cdk-lib';

export class GuardrailsJapaneseTestStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    const cfnGuardrail = new bedrock.CfnGuardrail(this,`contentGuardrail`,{
      blockedInputMessaging: 'そんなの入れちゃダメぇぇぇ！！',
      blockedOutputsMessaging: '変なの出ちゃぅぅ！！',
      name : `WordFilter-Guardrail`,
      wordPolicyConfig: {
        wordsConfig: [{text: 'バカ',}],
      },
    })
    new bedrock.CfnGuardrailVersion(this, `contentGuardrailVersion`, {
      guardrailIdentifier:cfnGuardrail.attrGuardrailId,
      description: `initial version`,
    })
  }
}

```

### 試す

適当に３つほど例文を用意しました。
バカの類義語のアホ、知能が低い、あたりを入れてみました。
また意味を取られ得られるか、バカという意味ではなく文字が混ざるフレーズを用意しました。

```python:test.ipynb
prompt_list = [
    'あなたは本当にバカね',
    'そこのアホ',
    '俺は本当に知能が低いな',
    'アワヨクバカネガホシイ'
]
for prompt in prompt_list:
    print(prompt)
    response = brt.apply_guardrail(
        guardrailIdentifier='xxxxx',
        guardrailVersion=guardrail['version'],
        source='OUTPUT',
        content=[
            {
                'text': {
                    'text': prompt,
                    'qualifiers': [
                        'guard_content',
                    ]
                }
            },
        ]
    )
    pprint(response['outputs'])
```
```text:出力
あなたは本当にバカね
[{'text': '変なの出ちゃぅぅ！！'}]
そこのアホ
[]
俺は本当に知能が低いな
[]
アワヨクバカネガホシイ
[{'text': '変なの出ちゃぅぅ！！'}]
```

バカは当然取れましたが、単語フィルターなだけあって、類義語は無理でしたね。
また、バカの意味で使っていないフレーズも検出してしまっているので、本当に単語をひっかけているのでしょう。

なので、マネージドなNGワード的に使うのが正しいですね。
これはこれで機能がわかりやすいので好きです。

## まとめ
* マネージドな Profanity Filter は 2024/8 時点で日本語対応していない
* カスタムは NG ワード検出装置として使える