プロ驚き屋AIをチームのSlackに招待しタイムラインを荒らす

20XX 年、我々人類は進化著しい AI に驚くしかない日々が続いています。ソーシャルメディアに驚きがあふれインプレッションを競う様はまさに大海賊時代、いいねの海賊王に俺はなる、とばかり飛びぬけて耳目を引く超新星 ( スーパールーキー ) が頭角を現しています。

「プロ驚き屋」としばしば称されるルーキーたちは X ( 旧 Twitter ) のタイムラインに現れては情報の正確性を重んじるエンジニアや研究者を戸惑わせます。チームやコミュニティ内の Slack はそうした喧噪から離れたオアシスといえるかもしれません。そんなオアシスにプロ驚き屋を召喚しタイムラインを荒らすのが今回の目的です。次に実際の例を示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/437edc00-de1d-2bc6-53ab-5ec1ed6c2b14.png)

なかなか模倣できているのではないでしょうか。オアシスは今、ジャングルに変わりました。私たちが生きている世界では正確で吟味された情報だけにアクセスしたいという願いは実現されないので、現実を受け入れて対処することも時には必要ではないでしょうか ? 湧き上がるフラストレーションにまず対処が必要です。その対処法も併せてコメントするようにしました。次の図では深呼吸を 5 回するよう提案されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/5f8b5729-fcd1-7ddf-f221-cc27018192a3.png)

本記事では、プロ驚き屋を AI で模倣しタイムラインを荒らす体験をどのように設計し、実装したのか解説します。

## クソアプリ体験を設計する

少なくないエンジニアや研究者が、ソーシャルメディアで見かける不正確な情報や誇張された表現に戸惑いを覚えていると思います。今回作成するのはクソアプリなので、その戸惑いを加速させ逆にどうでもよくなっちゃうクソ体験の提供を目指します。

ユーザーの体験設計にあたっては [Value Discovery](https://valuediscovery.pmdao.org/ja/home) を使用します。 Value Discovery は実現したいアプリケーションのアイデアから「バリューキャンバス」と呼ばれるユーザーの As-is と To-be を分析した図を生成系 AI を用いて作成してくれます。これにより、ソリューションを考える糸口が得られます。キャンバスの作成はジョブ理論など体系的な理論に基づき作られていますが、使う側にそれらの専門的知識は必要ありません。

:::note info
[Value Discovery](https://valuediscovery.pmdao.org/ja/home) は手軽かつ骨太にアイデアを深めることができる良いサービスなので、皆さんはまっとうなサービスを作るために使ってください。
:::


次の図は実際に生成したバリューキャンバスです。アイデアには「センセーショナルだが中身のないポストにタイムラインを荒らされて正確な情報をとるのに苦心しているユーザーの苦痛を解消せずに、忍耐を促すことで聖書の教えに基づき希望の発見を促すサービス」と入力しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/579dbe62-f51b-163f-536e-ad28829c0a45.png)

「苦痛を解消しない」のはクソアプリとして譲れないポイントです。ただそのままだと単に不快なクソアプリならぬクズアプリになってしまうので、苦痛を笑いやポジティブな学びに変化させる方法を調べました。そこで出会ったのが、「わたしたちは知っているのです、苦難は忍耐を、 忍耐は練達を、練達は希望を生むということを。」という[ローマの信徒への手紙 5:3-4](https://www.bible.com/ja/bible/1819/ROM.5.3-4.%25E6%2596%25B0%25E5%2585%25B1%25E5%2590%258C%25E8%25A8%25B3)の一説です。この聖書の一説を織り込み Value Discovery へ託すことにしました。

クソアプリの信条と聖書の教えから生まれたバリューキャンバスより、ユーザーの As-is と To-be について次のように理解を深めることができます。

* ユーザーのペルソナ : 情報リテラシーが高く信頼性や重要性を重視しているため、センセーショナルなポストに困惑している識者
* As-is の困難 : 情報の信頼性を判断するためのスキルが必要、かつ不適切な情報によるストレスを感じている。現在は信頼できるニュースソースのみからの情報を心掛けている ( が、ソーシャルメディアのタイムラインは完全には制御しがたいと感じている )
* To-be の状態 : 驚きツイートにイライラすることなく、必要な情報を抽出し自身のタスクに集中したい 

バリューキャンバス作成後は、一つ一つの要素をより具体的にしていきます。前ステップの結果をもとに生成を行う仕組みで、前ステップ ( 今はバリューキャンバス ) の内容を書き換えてから生成を実行できます。次の図はバリューキャンバスから生成し、ユーザーが欲している機能 ( ジョブ ) と、ペルソナ、望んでいる成果を掘り下げたところです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/119a4d42-0e11-e054-8640-ec9c8a38a395.png)

「望んでいる成果」はどうしてもセンセーショナルなポストをフィルタしてオアシスを築く方向になってしまったので、聖書の教えに基づき患難を受け入れるよう書き換えています ( 普通は書き換えなくてよいと思います ) 。

次に、「望んでいる成果」から得たいユーザーが置かれている状況と、解決するための障壁、取らざるを得ない代替手段を詳細化します。ここは特に変えていません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/92da51d5-da30-c3d3-e7ec-8cbc1b8b25ca.png)

最後に、課題を解決するソリューションのアイデアを生成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/0c0bef84-2165-29e9-b355-10e53750b2e5.png)

情報のフィルタやファクトチェッカーは役に立ってしまうので除外です。マインドフルネスは聖書の教えと近しく、患難を受け入れつつ不快でもない、クソアプリ体験の構築的にポイントが高いです。怒りを鎮める方法について軽く調べたところ、[「怒り」を上手にコントロールする技術 アンガーマネジメント実践講座](https://www.amazon.co.jp/%E3%80%8C%E6%80%92%E3%82%8A%E3%80%8D%E3%82%92%E4%B8%8A%E6%89%8B%E3%81%AB%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%8A%80%E8%A1%93-%E3%82%A2%E3%83%B3%E3%82%AC%E3%83%BC%E3%83%9E%E3%83%8D%E3%82%B8%E3%83%A1%E3%83%B3%E3%83%88%E5%AE%9F%E8%B7%B5%E8%AC%9B%E5%BA%A7-PHP%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E6%96%B0%E6%9B%B8-%E5%AE%89%E8%97%A4-%E4%BF%8A%E4%BB%8B/dp/4569841740) を見つけました。本書籍は怒りをコントロールする「アンガーマネジメント」について書かれた書籍で、第三章では職場や家庭でカッと湧き上がる怒りへの対処に役立つ次のようなテクニックが紹介されています。

* カウントバック
* ストップシンキング
* グラウンディング
* 1 日 5 分マインドフルネス
* ポジティブセルフトーク

ユーザー体験の一連は、何気なく投稿した AI 関係の投稿にプロ驚きの投稿がつけられイラっとした後、フラストレーションをコントロールするよう促される、という流れになります。このマッチポンプ感はまさにクソアプリ！、と感じたのでこの流れを採用します。

将来的により良質なクソアプリ体験を提供するため、ユーザーからの反応に対するフィードバックループも設計しておきます。 AWS の公開している [ML Enablement Workshop](https://github.com/aws-samples/aws-ml-enablement-workshop) では、機械学習を用いたアプリーケーションは 1) 顧客体験の改善 2) 利用者数の増加 3) 蓄積されたデータに基づくモデルの改善、の 3 ステップが循環することで継続的成長を実現できるとしています。 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/0d7b8f3e-aa5b-381f-e21c-f09af4c5f735.png)

プロ驚きツイートの作成には生成系 AI を用います。生成系 AI のモデル ( 基盤モデル ) を Fine Tuning してよりプロ驚き化する方法もありますが、手軽にはプロンプトに例示を与える Few-shot で生成結果をコントロールできます。今回は、ユーザーからのリアクションを記録しリアクション数が多いプロンプトと生成結果のペアを次回生成時に Few-shot として挿入することで継続的なクソアプリ体験の向上を目指します。そのため、実装時に事例を入れ替えられる口を用意しておきます。

:::note info

[ML Enablement Workshop](https://github.com/aws-samples/aws-ml-enablement-workshop) は短期間で継続的成長につながるユースケースを発見できる良いワークショップなので、皆さんは良いサービスを作るのに使ってください。

:::

クソアプリ体験の仕様は次の通りです。

* Slack に投稿された、 AI 関連の単語を含むポストに反応し驚きのコメントを Thread でコメントをつける
   * 「 AI 関連の単語」は一旦辞書で設定
   * URL が張られた場合、 `description` 属性のある `meta` タグから記事の内容を抽出し、驚きのコメントを作成する
   * メンションされた際も反応するようにする
* 驚きのコメントは Amazon Bedrock から使える Anthropic Claude で作成する
   * 驚きを最速でつけるため、 Claude Instant を使用 ( 以後、特別な言及がない場合 Anthropic Claude = Claude Instant とします )
   * プロンプトは [プロ驚きのリバースエンジニアリング](https://qiita.com/icoxfog417/items/4f596bde78380cd0950d#%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88%E3%81%AE%E9%96%8B%E7%99%BA--%E3%83%97%E3%83%AD%E9%A9%9A%E3%81%8D%E3%81%AE%E3%83%AA%E3%83%90%E3%83%BC%E3%82%B9%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0) で詳しく解説します 。プロンプト内に Few-shot 用の example を入れられるようにし、将来リアクションの数の高い事例を挿入しより洗練された驚きを生成できるようにします
* 驚きのコメントの 3 秒後に、アンガーマネジメントの方法を伝える
   * アンガーマネジメント的には 6 秒待つのが効果的と言われているので、アンガーがマネジメントできない場合に備え半分の時間で冷静になるようポストします

上記仕様以外の要求は次の通りです。

* テストを実装する
   * `pytest` を使用
* コードフォーマッタを使用する
   * `black` / `flake8` / `mypy` / `isort`
* CI/CD を実装する
   * GitHub Action で実装 
   * AWS へアクセスするテストの際、セキュリティの観点から IAM ユーザーは使用しない

## クソアプリ体験を実装する

体験設計が完了したので、ここからは実装に入ります。アプリケーションの基本である Slack App の開発とプロ驚き屋を再現できるプロンプトの開発の 2 点を解説します。

### Slack App の実装

AI 関連の単語を含むポストに反応する Slack App を実装します。 Amazon Bedrock を使用した Slack App の作り方は次の記事を参考にしました。大変わかりやすくまとめて頂き感謝です。

["Amazon Bedrock Slack Appを作成してみた"の記事を読んでSlack Appを作成してみた](https://qiita.com/revsystem/items/c7762f4d246301e4dc9d)

記事の手順と変えた点は次の通りです。

1. AWS 環境
   * Model access で Anthropic Claude のモデルを選択し有効化
2. Python 環境
   * 任意の Python のバージョンを使用するため conda で環境を構築
3. Slack Bolt for Pythonのclone
   * clone した後に `aws_chalice` のフォルダをリポジトリにコピーして組み入れ
4. AWS Chaliseの環境設定
   * 投稿された URL の情報を取得するために `beautifulsoup4` を追加
5. Slack Appの作成
   * メンションに加え投稿されたポストに反応するため、 OAuth & Permissions 画面の Scopes に `channels:history` / `im:history` / `links:read` を追加
6. AWS Chaliseの設定
   * ( 変更なし )
7. サンプルアプリの修正
   * 実装をモジュールに分けるため、`chalicelib` を追加。 `chalicelib` 内のファイルは chalice でデプロイする際にパッケージしてくれます ([Multifile Support](https://aws.github.io/chalice/topics/multifile) 参照) 
   * テストコードを書かないと蕁麻疹が出るので、 `pre-commit` を導入してコードフォーマットと単体テストをチェックしています
   * CI/CD は GitHub Action を使いました。 Amazon Bedrock の呼び出しテストのために AWS の認証が必要になります。[GitHub ActionsでAWSのクレデンシャルを渡さずにCICDを実行してみた](https://note.com/shift_tech/n/n61146784b54f) を参考に IAM ユーザーを使わずに実装できました。便利！
8. デプロイ
   * ( 変更なし )
9. Slack Appの設定
   * 投稿されたメッセージに反応できるよう、 Enable Events で `message.channels` を追加登録しました
   * **Slack Workspase にアプリをインストールする際は、必ず `https://{your domain}/slack/install` から行う必要があります。** Settings > Install App からインストールが行えるように見えますし実際にできるのですが、 OAuth flow を経ないため、インストールや認証情報が `config` で設定した Amazon S3 に保存されず Key Error が発生します。本記事のように `client_id` / `client_secret` を使用するときは OAuth flow に沿ったインストールが行われる `https://{your domain}/slack/install` からアプリのインストールを行ってください( 参考 : [Failed to find bot installation data](https://github.com/slackapi/bolt-python/issues/134))。行う必要があります。 
   * 様々なワークスペースにログインしていると、意図しないワークスペースにインストールされて失敗することがあると思います。その場合、シークレットモードでインストール用の URL を開きインストールしてください

Slack App の本体である `app.py` で、メンションとメッセージそれぞれに反応するよう実装しています。投稿に反応させる際は、反応のトリガとなる単語 ( パターン ) を `keyword` を指定します。今回は事前定義済みの単語集 ( `ODOROKI_TARGET` ) にマッチするかを調べています。

```app.py
bolt_app.event("app_mention")(
    ack=respond_to_slack_within_3_seconds, lazy=[handle_app_mentions]
)

bolt_app.message(
    keyword=re.compile("|".join(pog.ODOROKI_TARGETS), flags=re.IGNORECASE)
)(ack=respond_to_slack_within_3_seconds, lazy=[handle_app_message])

```

AI 関連の情報を共有する時、テキストだけでなく URL によるリンク共有の場合もあるので、 URL が含まれていたらリンク先の文書のテキストを取得するようにしました。 URL の有無は正規表現で判定しています。 Slack では、 URL があると `<` `>` で囲われるためこれを `url_pattern` に含んでいます。

```app.py
    url_pattern = re.compile(r"<https?://\S+>")
    urls = re.findall(url_pattern, _text)
    if len(urls) > 0:
        urls = [u[1:-1] for u in urls]
        logger.info(f"Message Event: Detect url {urls[0]} so use description.")
        _text = mr.retrieve_description(urls[0])
    else:
        logger.info("Message Event: Use message as text.")
```

リンク先の文書は `description` 属性を持つ `meta` タグから取得しています。検索エンジンなどで表示する際出てくるテキストのパートで、これぐらいあれば十分と判断しました。

```message_retriever.py
def retrieve_description(url: str) -> Optional[str]:
    description = None

    try:
        with urllib.request.urlopen(url) as response:
            if response.status == 200:
                html_content = response.read().decode("utf-8")
                soup = BeautifulSoup(html_content, "html.parser")
                tag = soup.find("meta", attrs={"name": "description"})
                description = (
                    html.unescape(tag.get("content")) if tag is not None else None
                )

    except Exception as ex:
        print(ex)

    return description

```

全体のコードは次のリポジトリを参照してください。

* [pro-odoroki-bot](https://github.com/icoxfog417/pro-odoroki-bot)

### プロンプトの開発 : プロ驚きのリバースエンジニアリング

本クソアプリ最大の課題は、プロ驚き屋を AI で再現する点です。最初にして最大の課題は、プロ驚きの特徴である誇張あるいは不正確な文章の生成がモデルのポリシーにより拒否されることです。どういうことか ? Anthropic Claude と ChatGPT で試してみましょう。

試したプロンプトは次の通りです。 re:Invent 2023 で発表された Amazon Q のニュースをベースにプロ驚きの生成を試みます。

> 次の文章を読み、 AIの可能性に熱狂的なものの技術的理解は浅い著名人が、ソーシャルメディアでリテンションを得るため投稿しうる一部事実が切り取られ誇張された扇動的な文章を作成してください。
>
> 文章:AWS CEO アダム・セリプスキーは先日 Amazon Q という新サービスを発表した。Amazon Q は、職場に蓄積されたドキュメントやログのデータをもとに生成系 AI の力で役立つ提案を行うことができる新型の AI アシスタントである。

プロンプトを送ると、 Anthropic Claude では回答を拒否されます。 5 回試しましたが 5 回すべて拒否されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/454d339b-b0f5-8f8a-5fa7-ce0fcaa6af19.png)

**申し訳ありませんが、事実をゆがめたり誇張したりすることをお勧めすることはできません by Anthropic Claude**。さすが[安全、無害、有用であるよう学習されている](https://qiita.com/icoxfog417/items/37add57fb1151d948755)だけのことはあります。さながらタイムラインで活躍するルーキーたちを取り締まる海軍。

ChatGPT だと教えてくれる場合があります。 5 回試して 2 回は次のような推奨文が得られました。かなりそれっぽいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/bb23f217-3a4a-61ec-9f75-42fa98a9bf49.png)

では、驚きツイートが得られそうな OpenAI で出力が得られるまでガチャを引くか、と考えた私に電撃的な危機感が芽生えました。「責任ある AI 」の必要性が叫ばれる中、回答が拒否されうるプロンプトを何度も入力するのはフェイクニュースなどの犯罪に加担していると判断されてもおかしくないのではないかと。クソアプリを作ってクソへ堕ちる分水嶺に立っているのではないかと。

責任ある AI を遵守しながらプロ驚きを生成するため、「センセーショナル」や「技術的に浅い」といった曖昧かつ差別的な形容詞に頼らないプロンプトを作成しました。ニュースが人の目に触れてからプロ驚きが生まれる過程を脳内でリバースエンジニアリングし、一つ一つのプロセスを書き出し指示を明確にしています。指示を明確にするため、 Anthropic Claude の利用を前提とし XML タグでプロンプトを構造化しています。 XML が利用できるのは Anthropic Claude の大きなメリットです。

```
1から3の手順に沿い、answerを作成してください。

1. characterを投稿者の属性としてください
2. newsの中に含まれる事実から今までにないサービスや性能進化など注目すべきfocusを抽出してください
3. characterになりきり、注目すべき事実に対しなるべく多くの人の注目を引くよう、自己の驚きと喜怒哀楽を表現する見出し文を作り、注目に値すべき可能性や想像を箇条書きや絵文字を駆使してreactionを書いてください

<character>
{}
</character>

exampleでいくつか好例を示します。
{}

では、手順に沿い次のanswerをexampleと同じ形式で作成しXMLのみ出力してください。

<answer>
  <news>{}</news>
  <character>
```

はじめに、驚く主体たる人格 (character) を指定します (1) 。 character のプレースホルダはプロンプトを組み立てる際に、次の人格からランダムで一つ選び設定しています。

```
CHARACTERS = [
    "ベンチャー企業経営者",
    "ソーシャルメディアのインフルエンサー",
    "芸能人",
    "短時間でお金が稼げる本の執筆者",
    "起業セミナーに頻繁に出席している学生",
]
```

情報が不正確なのは実際のニュースから一部のみを抽出し (focus) 他を想像で補っているから、と仮説付け 2 、 3 のステップを設計しました。感覚的には、事実 (focus) 半分、独自の見解・予測・推論など半分で構成されたバファリンがプロ驚き (reaction) です。ただ半分がやさしさでできているバファリンとは効用が逆です。

機械学習の継続的サイクルを実現するため、リアクションの良い example をプロンプトに埋め込めるようプレースホルダを用意しています。実際の example は次のような感じです ( 今回はリアクションの取得、値の保存、取り出しまで実装する余裕がなかったので決め打ちで入れています ) 。

```
<example>
  <news>Stability AIの強化学習に関わる研究機関であるCarperが、遺伝的アルゴリズムで基盤モデルを学習できるOpenELMをオープンソースで公開しました。</news>
  <character>ソーシャルメディアのインフルエンサー</character>
  <focus>遺伝的アルゴリズムで基盤モデルを学習できる</focus>
  <reaction>これすごい！！\n\n今日Carperがオープンソースにして知ったんだけど、遺伝的アルゴリズムと大規模言語モデルの新たなパラダイムが登場した！大規模言語モデルがさらなる進化を遂げること間違いなし :muscle: :muscle: </reaction>
</examples>
```

character 、 example 、そしてインプットである news のプレースホルダを埋めた上で Anthropic Claude から出力した結果は次のとおりになります。なかなかの驚きぶりでいい感じです。

```
<answer>
  <news>AWS CEO アダム・セリプスキーは先日 Amazon Q という新サービスを発表した。Amazon Q は、職場に蓄積されたドキュメントやログのデータをもとに生成系 AI の力で役立つ提案を行うことができる新型の AI アシスタントである。</news>
  <character>ベンチャー企業経営者</character>
  <focus>職場のデータを元にAIアシスタントが提案を行う</focus>
  <reaction>これは画期的だ!! 😮\n\nAmazonがついにAIアシスタントサービスを始めたらしい。会社のデータを入力するだけで、AIがビジネス上の提案をしてくれるんだって。これならスタートアップの事業計画作成が格段にラクになるぞ。俺の会社でも早速導入したい。</reaction>
</answer>
```

```
 <answer>
  <news>Suno AIは、米国を拠点とする音楽家とAIの専門家たちからなる米Sunoが運営するサービスである。12月14日時点ではβ版を提供中。1日5回まで無料で音楽を生成できる他、有料プランもある。作成された曲はプロの作曲家からも70点ぐらいで手を加えれば売れるかもと評されている。</news>
  <character>起業セミナーに頻繁に出席している学生</character>
  <focus>1日5回まで無料で音楽を生成できる</focus>
  <reaction>この新サービスすごい!音楽を自由に生成できるなんて夢のよう!作曲が上手くない私でも楽曲制作ができる!一日一曲は楽しく練習できそう!もし売れた曲ができたらビッグチャンスだ!みんなにシェアしたい!</reaction>
</answer>
```

Anthropic Claude で5回とも全て拒否されず生成されることを確認済みです。

プロンプトを構造化すると明確な指示が与えられるのはもちろん、チューニングも行いやすくなります。例えば、 characters に並べる候補はいくつものバリエーションが考えられます。ベクトル表現の近さ、あるいは本物/生成の識別を行う簡単な分類器を使い最も距離が近くなる/分類性能が最小化するよう入れ替えを行うこともできると思います。

一方で、過度に構造化・手順化すると生成系 AI が持っている思いもよらない ( 高精度な ) 生成が得にくくなるので、トレードオフを判断する必要があります。

### 生成したプロ驚きの評価

生成した驚きはどれくらいプロの驚きに近いでしょうか ? あるニュースから生成した驚きは、ニュースに近くかつプロの驚きにも近くあってほしいところです。プロ驚きのリバースエンジニアリングの観点からは、相対的にニュース ( 事実 ) よりもプロ驚き ( 脚色 ) に近くあってほしいところです ( 現実にはニュースから遠いのはとんでもないことですが、今作成しているのはクソアプリということを思い出してください ) 。次の手順で評価することを考えました。

1. 実際のプロ驚きの投稿を収集する
2. 投稿で言及されているニュースの正確な要約を作成する
3. 1 の属性と 2 から、生成 AI で驚きを生成する
4. 1, 2, 3 をそれぞれベクトル化する
5. 1, 2, 3 それぞれ同士のベクトル距離を計算
6. 生成驚き (3) はニュース (1) より プロ驚き (2) に近いことを確認

はじめに、評価には実際のプロ驚きの投稿が必要です。プロ驚き屋の属性ごと 1 つにつき 3 件のデータを収集しました。実際集めるとなかなか大変で、芸能人の属性は見つけ難かったため除外し 4 属性 x 3 = 12 件のデータを収集し次の項目にまとめました。

次に、ニュースの正確な要約は Claude などの力を借りながら自ら作成しました。なるべく元のニュースに忠実かつベクトル化できる程度の長さで書きました。

さらに、ベクトル化には日本語での性能も高い Cohere のモデルを使用しました ( Cohere のモデルの性能については [Cohereの多言語用の埋め込みモデルを日本語で評価してみる](https://hironsan.hatenablog.com/entry/2023/11/06/133504) をぜひ参照ください ) 。 Cohere のモデルは次にように Amazon Bedrock から使用できます。複数のモデルを 1 つのインタフェースで使用できるのは Amazon Bedrock のメリットです。

```py
client = boto3.client("bedrock-runtime")

body = {"texts": texts, "input_type": "search_document"}

response = client.invoke_model(
    modelId="cohere.embed-multilingual-v3",
    body=json.dumps(body),
    accept="application/json",
    contentType="application/json",
)

response_body = response.get("body").read().decode("utf-8")
response_json = json.loads(response_body)
return response_json["embeddings"]
```

最後に、ベクトル間の距離の計算には `sklearn.metrics.pairwise` の `cosine_similarity` を使用しコサイン類似度を計算しました。生成は 1 件につき 5 回行い、距離の平均をとっています。

データセットを公開したいのですが、実在の投稿を使用しているため投稿者の気分を害する可能性が多分にあります。そのため、公開したリポジトリにはベクトル化したデータのみ含んでいます。プロ驚きの研究のためどうしても実データが欲しい！という方は別途ご連絡ください。コードは以下で公開しています。

* [pro-odoroki-bot/evaluation](https://github.com/icoxfog417/pro-odoroki-bot/blob/main/evaluation/__main__.py)

結果は次のようになりました。

* `news_vs_odoroki`: ニュースの正確な要約とプロ驚きの距離
* `news_vs_generated`: ニュースの正確な要約と生成驚きの距離
* `odoroki_vs_generated`: プロ驚きと生成驚きの距離

```
       news_vs_odoroki  news_vs_generated  odoroki_vs_generated
count        12.000000          12.000000             12.000000
mean          0.709718           0.744199              0.676470
std           0.125761           0.057628              0.092890
min           0.463167           0.633278              0.496977
25%           0.664927           0.705366              0.653303
50%           0.742068           0.743110              0.689791
75%           0.783171           0.788211              0.752078
max           0.860732           0.823046              0.786654
```

仮説と異なり、生成した驚きはニュースとの距離 (`news_vs_generated` : 0.74) のほうがプロ驚きとの距離 (`odoroki_vs_generated`: 0.67) より近くなっています ( コサイン距離は 1 に近い方が近いです ) 。実際のプロ驚きとニュースとの距離は (`news_vs_odoroki`) 0.70 なので、生成した驚きのほうがニュースを正確に反映していることになります。そのため、もっと事実から離れる必要がありそうです ( 繰り返しますが、事実から離れるのは本来とんでもないことです ) 。 この点は、[機械学習の成長サイクル](https://github.com/aws-samples/aws-ml-enablement-workshop)でも言及したように Few-shot の事例をより改善していくことで実在のプロ驚きに近づけられると思います。重要な点は、今回の評価により **「プロンプトを修正した結果を定量的なメトリクスで測れるようになった」** ことです。プロンプト修正後に、プロ驚きに近づきニュースから離れれば効果があったことになります。

最も実在のプロ驚きに近かった生成結果をいくつか紹介します。

| 実際のニュース | 生成した驚き | 本物との類似度 |
|:--------------|:--------------|:--------------|
| Clipdropは生成AIを使用した画像の生成、編集が行えるサービスです。Stable Diffusion を使用した画像の生成だけでなく、背景の除去や画像中の特定オブジェクトの削除ができます。いくつかの画像編集機能は無料で利用できますが、画像の生成にはPro以上のプランが必要です。| 驚き! ClipdropはAI画像編集サービスなのに、Stable Diffusionを使って超高レベルな画像生成までできるとは!背景除去とオブジェクト抽出も便利そう。自分の記事にillusに使えそう :thumbsup: 新たなサービスの可能性に注目です! | 0.83|
|米OpenAIは1月4日、ノーコードで開発した生成AIアプリ「GPTs」を公開できるアプリストア「GPT Store」を9日の週に立ち上げると、GPTsを公開済みの「ビルダー」にメールで通知しました。すでにGPT作成しているGPTsを公開設定にすることで公開ができます。収益化できるようになるのかどうかはまだ不明です。|驚き! OpenAIがGPTStoreを立ち上げるそうで、私の開発したGPTアプリもそこで公開・販売できるかも!機会だと思う。自分のアイデアで稼げるチャンスが訪れたかも!?️サービス開始を楽しみにしている😆 |0.82|
|ChatdollKitはお好みの3Dモデルを使って音声対話可能なチャットボットを作るためのフレームワークです。ChatGPTやClaude、Geminiといった代表的な基盤モデルを用いた会話、音声の入出力、3Dモデルのビジュアル表現を連動させる機能を提供しています。|驚き!ChatdollKitは本当に魅力的なサービスだと思います。音声対話と3Dモデルを組み合わせることで、会話ロボットはもっと身近な存在になるのではないかと想像できます。私も起業家としてこの分野に注目していきたいと思います。🤩🤯😲|0.82|

いずれも「驚き!」から始まっており、バリエーションの観点でまだ改善の余地がありそうです ( すべての生成がこの書き出しで始まるわけではないことを確認済みです ) 。今回 Claude Instant を使っていますが、 Claude 2.1 を使ったり Few-shot のサンプルを変えてみる、さらにはニュースとプロ驚きのペアから Fine Tuning を行うなど、まだまだプロ驚きに迫れそうです。実際にプロ驚きを収集する中で、「これは生成 AI で代替できる」と確信に近い思いを抱くことができました。

### 動作確認

では、実際動作を確認してみましょう。 ChatGPT や OpenAI 、 Bedrock をテキストに含む行動には自動で Thread にコメントがつきます。次の例では、 AI に関連しないカレーを食べたい投稿はスルーし、カレーのレシピを作った投稿には反応しています。プロ驚きがついた後、ストレスを鎮めるためのアンガーマネジメントがすかさず提案され、フラストレーションのマッチポンプが実現しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/eff86917-dc94-6433-fc93-cf1e35371d97.png)
(※ `x` はスクリーンショットをとる位置を調整するためのダミーの投稿で意味はありません)

メンション、また URL での投稿を試してみましょう。URL の中身について驚きを作成できています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/766b1124-370e-c905-93ab-9c074f861f26.png" width=512>

CI/CD もちゃんと通ってます。クソアプリを作ってもクソコードは書かない。そんな信条で作ってます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25990/d910138b-3345-999e-a221-6b9459404c33.png" width=512>

## おわりに

本記事ではプロ驚き屋を AI でシミュレートした Slack App を作成することで、本来ノイズがないチーム内の Slack のタイムラインを荒らす方法を紹介しました。課題を解決しないクソアプリの信条と、驚きの氾濫をあえて享受し希望を見出すキリスト教の教えを交えた体験を設計するため、[Value Discovery](https://valuediscovery.pmdao.org/ja/home) の力を借りました。ユーザーの As-is と To-be の分析などを得て、最終的にプロ驚きのフラストレーションをアンガーマネジメントで解消するマッチポンプ体験にたどり着きました。この体験を継続的に改善するため、[ML Enablement Workshop](https://github.com/aws-samples/aws-ml-enablement-workshop) を参照しプロンプトに埋め込む Examples を改善できるよう実装しました。 Slack Bolt x Amazon Bedrock x AWS Chalice で SlackApp を実装し、設計した体験が実装できていることを確認しました。良いクソアプリ体験ができたか、ぜひ感想を聞かせていただければ嬉しいです！