Slack経由でRAGにコードレビューを依頼するBotを作成


## はじめに

プログラミングを書き始めた頃は独りよがりなコードを書いていました。当然「**可読性の高いコード**」とは遥かに遠いコードを書いていました。
ただ、チームプロジェクトに飛び込んだ瞬間、状況は一変し自分のコードが他人の目に触れる現実と、読みづらいコードに悶絶する日々。この経験は誰しもがあるのではないかと思います。

では、可読性の高いコードを書くにはどうすれば良いのか？
を考え始めた時に出会ったのが **リーダブルコード** でした。
リーダブルコードは、コードを読みやすくするための原則を提唱しています。

https://www.oreilly.co.jp/books/9784873115658/

この原則を守り、プロジェクト全体で共有することで、コードの可読性を向上させることができます。

が、現実はそう甘くありません。規約が完璧に反映されているコードレビューが実施されないプロジェクトも多いでしょう。
**政治的な問題** や **納期の関係** もあり、一度実装されたコードの変更が難しいこともあります。

そこで、今回は「リーダブルコード」の原則を準拠したコードレビューをRAGによって自動化するツールを作成してみることにしました。

### 作ってみたもの

Slack経由でRAGにコードレビューをしてもらいます。
`@Reviewer` とメンションすることで、コードレビューを依頼することができます。

![デモ動画.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/7b376189-a62a-998a-526e-93982202bc6d.gif)

### 構成図

<img width="600" alt="構成図" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/bd614ab9-55d7-15f9-73cf-6167a2a2bded.png">

## リーダブルコードとは

RAGの環境構築に入る前に、リーダブルコードについて軽く概要を紹介したいと思います。

**リーダブルコード**、それはまさにその名の通り「読みやすいコード」を意味します。しかし、ここで言う「読みやすい」とは単に面白いわけではなく、基本を守りつつ他の人にも理解しやすいコードを指します。このアプローチの根底にあるのは、「**コードは理解しやすくなければならない**」という原則になります。

では、「理解しやすいコード」とはどんな特徴を持つのでしょうか？

1. **変更が容易**：他の人、または未来のあなたが見たときに、「これは何だったんだろう？」と頭を抱えることなく、簡単に修正や改善ができる。
2. **可読性が高い**：バグが潜んでいても見つけやすい。清潔で整理された部屋で物を探すようなイメージ。

このようなコードを書くことは、チームにとってのみならず、**未来のあなた自身**にとっても大きな恩恵をもたらします。継続的に改善し、磨きをかけることで、コードは時を経てもその価値を保ち続けます。

と、私の解釈を交えつつ説明してみました。

## コードレビューについて

リーダブルコードの原則の数々の中から、今回は「**第Ⅰ部 表面上の改善 第2章 名前に情報を詰め込む**」に焦点を当ててコードレビューをしてもらおうと思います。
この章では、変数名がいかに重要であるか、そしてそれにどのように情報を詰め込むかが解説されています。

以下にこの章の原則をまとめたPDFファイルを作成しましたので、これをデータソースとして使用します。

[[第Ⅰ部][2章]表面上の改善_名前に情報を詰め込む.pdf](https://github.com/sakes9/sam-slack-review-rag/blob/main/data-source/%5B%E7%AC%AC%E2%85%A0%E9%83%A8%5D%5B2%E7%AB%A0%5D%E8%A1%A8%E9%9D%A2%E4%B8%8A%E3%81%AE%E6%94%B9%E5%96%84_%E5%90%8D%E5%89%8D%E3%81%AB%E6%83%85%E5%A0%B1%E3%82%92%E8%A9%B0%E3%82%81%E8%BE%BC%E3%82%80.pdf)

この原則を実践するには、変数名が適切な情報を含んでいるかを確認することが重要です。
そのための方法として、**ペアプログラミング** や **人によるコードレビュー** が挙げられますが、
これらは知識の共有を促し、プロジェクトにおける属人化を防ぎますが、**人の目によるチェックには限界** があります。

そこで登場するのが、静的解析ツールの活用です。
特にJavaScriptで人気のある **ESLint** は、カスタムルールを設定することで、変数名の命名規約や長さをチェックするのに役立ちます。
しかし、**変数名の内容自体の精査には限界** があるため、さらに進んだ技術が求められます。

これらの問題を解決するために、**AIを利用したコードレビュー** が注目されています。
**Code Rabbit** のようなコードレビューAIを導入することで、従来の人力レビューの限界を超え、コーディング規約に基づく自動的なチェックが可能になります。
そして **RAG（Retrieval-Augmented Generation）** を活用すれば、リーダブルコードの原則をデータソースとして取り込み、より精密なレビューを実施することができそうです。

RAGにコーディング規約を読み込ませ、原則に違反があるかどうかをAIがチェックし、その結果をさらにLLM（大規模言語モデル）が分析する。
この一連の流れを 「**Slack経由でRAGにコードレビューを依頼してみよう**」 と思い実装してみました。

## RAG構築

では、実際にRAGを構築していきます。

「AWS SAM」でRAGを構築するために以下のリポジトリを作成しましたが、今回は **AWSマネジメントコンソールから手動で構築** する手順を説明します。

https://github.com/sakes9/sam-slack-review-rag

「AWS SAM」での構築方法については、以下の記事で説明しています。

https://qiita.com/sakes9/items/6655c1de123c6511b25c

全ての手順は「**東京リージョン**」で実施することを前提としているため、AWSのマネジメントコンソールからリージョンを「**東京**」に変更してから手順を進めてください。

<img width="300" alt="alt text" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/7524817b-78dc-f23c-3d9f-a34ff77bc46e.png">

:::note warn
注意
環境構築後は、必ずリソースの削除を行ってください。
リソースが残っていると課金が発生します。
特にKendraは高額な課金が発生するため、削除を忘れないようにしてください。
:::

### S3

Kendraのデータソースとして使用するS3バケットを作成します。

#### S3バケットを作成する

1. S3コンソールに移動して「バケットを作成」をクリックします。

    <img width="600" alt="バケットの作成_01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/9c461b19-da2f-cece-e57f-e11478027615.png">

2. バケット名を入力します。

    バケット名はリージョン内で一意である必要があるため、 `data-source-bucket-{ランダムな文字列}` という形式でバケット名を入力しています。

    <img width="600" alt="バケットの作成_02" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/f69b2c09-d8da-5b08-f904-61de4c7c28ad.png">

3. その他の項目はデフォルトのまま「バケットを作成」をクリックします。

    <img width="600" alt="バケットの作成_03" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/65b5111c-cb34-5bb9-426e-856e884a7dd4.png">

#### S3バケットにファイルをアップロードする

1. 以下のリンクからPDFファイルをダウンロードします。

    [[第Ⅰ部][2章]表面上の改善_名前に情報を詰め込む.pdf](https://github.com/sakes9/sam-slack-review-rag/blob/main/data-source/%5B%E7%AC%AC%E2%85%A0%E9%83%A8%5D%5B2%E7%AB%A0%5D%E8%A1%A8%E9%9D%A2%E4%B8%8A%E3%81%AE%E6%94%B9%E5%96%84_%E5%90%8D%E5%89%8D%E3%81%AB%E6%83%85%E5%A0%B1%E3%82%92%E8%A9%B0%E3%82%81%E8%BE%BC%E3%82%80.pdf)

    ダウンロードアイコンをクリックしてPDFファイルをダウンロードします。

    <img width="300" alt="ファイルのアップロード_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/aa9e6234-2b89-4afb-9123-095fa4dd64f7.png">

2. 作成したバケットを選択します。

    <img width="600" alt="ファイルのアップロード_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/f735e4f0-03d2-c642-4ff3-0e0ca08d2076.png">

3. 「アップロード」をクリックします。

    <img width="600" alt="ファイルのアップロード_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/71e17f71-907c-7f73-d472-a6fa523fb3ee.png">

4. PDFファイルを画面にドラッグ&ドロップして、アップロード対象のファイルに追加します。

    <img width="600" alt="ファイルのアップロード_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/ca1dce08-b44a-d762-e8c7-1e7a6b3edc87.png">

5. 「アップロード」をクリックします。

    <img width="600" alt="ファイルのアップロード_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/5cdd9719-a5ce-1034-dc52-bad5ef8ae551.png">

6. アップロードが完了したら、「閉じる」をクリックします。

    <img width="600" alt="ファイルのアップロード_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/e215d214-0469-93b2-68d9-6a757eb2990c.png">

### Amazon Kendra

RAGの検索エンジンとして使用するKendraを作成します。
Kendraを使用するには「インデックス」と「データソース」を作成する必要があります。

#### インデックスの作成

1. Kendraコンソールに移動します。
2. 「Create an index（インデックスの作成）」をクリックします。

    <img width="600" alt="インデックスの作成_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/5c2e6bb0-3ae9-2864-7e8f-f1c222d25e3a.png">

3. Index name（インデックス名）を入力します。

    インデックス名は `readable-code-index` と入力します。

    <img width="600" alt="インデックスの作成_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/ebb172c4-986b-e1dc-d17f-023550479127.png">

4. IAM role（IAMロール）を選択します。
    IAMロールは推奨設定で新規作成するため「Create a new role（Recommended）」を選択します。
    IAMロール名は `AmazonKendra-ap-northeast-1-readable-code-index-role` と入力し、「Next」をクリックします。

    <img width="600" alt="インデックスの作成_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/51ec52cd-003e-c77a-0e81-7daa8ed13b2c.png">

5. アクセスコントロールの設定はデフォルトのまま「Next」をクリックします。

    <img width="600" alt="インデックスの作成_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/a0d1bf10-d480-88e5-a5cb-8ae8272203f5.png">

6. エディションは「Developer edition」を選択して、「Next」をクリックします。

    <img width="600" alt="インデックスの作成_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/eb1b7fae-c37c-30dc-5cab-771cdaafb24b.png">

7. 確認画面で「Create」をクリックして、インデックスを作成します。

    <img width="600" alt="インデックスの作成_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/278ee3c3-1275-fb99-8ea4-c31c9d167c6d.png">

    30秒後に自動でKendraのホーム画面に戻ります。

    <img width="600" alt="インデックスの作成_7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/e312ced1-66f9-29e7-6235-d96e00425eb6.png">

   インデックスの作成には最大30分かかるため、しばらく待ちます。

    <img width="600" alt="インデックスの作成_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/95ec4e9d-0087-1c51-fa43-c326d3bafdcf.png">

    作成が完了すると、インデックスが Active になります。

    <img width="600" alt="インデックスの作成_9" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/492a2b2b-8ab2-7d32-c350-8a256d4867fc.png">

#### データソースの作成

1. 作成したインデックスを選択し、「Add data source（データソースの追加）」をクリックします。

    <img width="600" alt="データソースの作成_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/871bb7d6-20bb-0fec-5e54-a181f05de2cc.png">

2. Amazon S3 connector の「Add connector」をクリックします。

    <img width="300" alt="データソースの作成_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/5e41f533-97ee-38fd-7879-ab052b81a634.png">

3. Data source name（データソース名）を入力します。

    データソース名には `readable-code-data-source` と入力します。

    <img width="600" alt="データソースの作成_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/cd815f1b-c3a9-39be-c38e-163a2f04e7a4.png">

4. ドキュメントのデフォルト言語は「Japanese（ja）」を選択します。

    <img width="600" alt="データソースの作成_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/cdd88b7d-638a-ed32-2282-72a1b4c50b04.png">

5. IAMロールを選択します。

    IAMロールは推奨設定で新規作成するため「Create a new role（Recommended）」を選択します。
    IAMロール名は `AmazonKendra-readable-code-data-source-role` と入力し、「Next」をクリックします。

    <img width="600" alt="データソースの作成_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/79fadc65-3860-2dda-4f85-1ed1458ca351.png">

6. 同期するデータソースの設定を行います。

    Browse S3 からデータソース用に作成したS3バケットを選択します。

    <img width="600" alt="データソースの作成_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c3760d9d-3ee8-5c81-2bdd-3932272f5ac0.png">

7. 手動でデータソースの同期を行うため、Frequency（頻度）は「On demand」を選択します。

    <img width="600" alt="データソースの作成_7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d866206c-3a4f-42f4-6c30-4b0bdffdce0f.png">

8. Set field mappings - optional はデフォルトのまま「Next」をクリックします。

    <img width="600" alt="データソースの作成_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c8870db0-b5c6-4122-f166-ee4958b71609.png">

    <img width="600" alt="データソースの作成_9" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/66560534-fc1d-38c7-3e29-f227152eb09c.png">

9. Review and create で「Add data source」をクリックします。

    <img width="600" alt="データソースの作成_10" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/01aa15b5-c057-d778-effa-7e3f4d1aff69.png">

    <img width="600" alt="データソースの作成_11" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/50efef9e-0787-7d9e-fa21-d117b4092d77.png">

    30秒後に自動でKendraのホーム画面に戻ります。

    <img width="600" alt="データソースの作成_12" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/50c59386-4c7a-6d09-538a-a0017302987b.png">

    データソースの作成に成功しました。

    <img width="600" alt="データソースの作成_13" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/002e2799-7d1a-9e7c-1522-47a6bc0e3db2.png">

10. データソースを同期するために、「Sync now」をクリックします。

    <img width="600" alt="データソースの作成_14" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/95fd4231-8149-3fc5-7ceb-4fe7ccebc0e6.png">

    同期完了まで時間がかかるため、しばらく待ちます。

    <img width="600" alt="データソースの作成_15" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/5a8ea16a-4abc-e806-669d-364bb35daed3.png">

    同期が完了しました。

    <img width="600" alt="データソースの作成_16" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c70220bd-c4e7-3569-9a1c-b3576e17b9eb.png">

### Bedrock

RAGのLLMとして、東京リージョンのBedrockにあるAnthropic社の **Claude** を使用します。BedrockのLLMを使用するには **モデルアクセスを有効化** する必要があります。
現在、東京リージョンで利用可能なClaudeのバージョンはv2.1となっています。

#### モデルアクセスの有効化

東京リージョンでBedrockを使用するために、モデルアクセスを有効化します。

1. Bedrockコンソールに移動して「モデルアクセス」を選択します。

    <img width="600" alt="モデルアクセスの有効化_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/9141ecc9-f903-a3b6-1c1c-27e6e9561fe1.png">

2. Anthropic社のモデルを使用するには「ユースケースの詳細」を提出する必要があるため、「ユースケースの詳細」をクリックします。

    <img width="300" alt="モデルアクセスの有効化_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/e99a3c73-03f1-d685-e5a6-a9a88ab21181.png">

3. ユースケースの詳細を入力して、「送信」をクリックします

    <img width="400" alt="モデルアクセスの有効化_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/f780cf85-a108-bce4-6479-f782ce418d13.png">

4. 「モデルアクセスを管理」をクリックします

    <img width="600" alt="モデルアクセスの有効化_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d9c1728f-6920-d1ec-ab60-bf7ed633f77e.png">

5. 「Claude」にチェックを入れて、「モデルアクセスをリクエスト」をクリックします。

    <img width="600" alt="モデルアクセスの有効化_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d6d23365-91e1-fc75-0b95-fe079f5aad09.png">

6. アクセスが付与されたことを確認します。

    <img width="600" alt="モデルアクセスの有効化_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/39310fd8-096e-ee78-e59a-fd5a38c8c38c.png">

### Lambda

Slack経由でRAGにコードレビューを依頼するLambda関数を作成します。

#### IAMロールを作成する

1. IAMコンソールに移動して「ロールの作成」をクリックします。

    <img width="600" alt="IAMロールを作成する_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/474d6dc2-71aa-d9bc-bf11-3012cf969c23.png">

2. エンティティは「AWSのサービス」を選択します。

    <img width="600" alt="IAMロールを作成する_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/faf9226e-d911-c53e-7f58-616addc9167c.png">

3. ユースケースは「Lambda」を選択します。

    <img width="600" alt="IAMロールを作成する_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/40a8965c-5419-c6e6-fa0b-4b144a3031f2.png">

4. 許可を追加します。

   追加するポリシーは以下の通りです。

   - **BedrockFullAccess**: Bedrockの全ての機能にアクセスするためのポリシー
   - **AmazonKendraFullAccess**: Amazon Kendraの全ての機能にアクセスするためのポリシー
   - **LambdaBasicExecutionRole**: Lambda関数を実行するためのポリシー

5. ロール名を入力します。

    ロール名は `review-readable-code-function-role` と入力します。

    <img width="600" alt="IAMロールを作成する_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/af71c05a-e397-32c1-ec31-ff81a87f9d76.png">

6. 「ロールの作成」をクリックします。

    <img width="600" alt="IAMロールを作成する_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/58224afa-063d-57b9-e999-4107435517f0.png">

#### Lambda関数を作成する

1. Lambdaコンソールに移動して「関数の作成」をクリックします。

    <img width="600" alt="Lambda関数を作成する_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c6b9d718-b58d-8f90-7140-81efc2680e22.png">

2. 関数の基本的な情報を入力します。

    - **関数名**: `review-readable-code-function`
    - **ランタイム**: Python 3.10
    - **アーキテクチャ**: x86_64

    <img width="600" alt="Lambda関数を作成する_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/eb1a9e29-89da-ce70-f053-f7763c7be3e9.png">

    先ほど作成したIAMロールを選択します。

    <img width="600" alt="Lambda関数を作成する_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/a43538ad-9af3-d6ad-ae75-23a8cbf65ad6.png">

3. 関数URLを有効化します。

    - **関数 URL を有効化**: チェックを入れる
    - **認証タイプ**: NONE

    <img width="600" alt="Lambda関数を作成する_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/f7659934-3d17-8981-a381-05058d10063d.png">

4. 「関数の作成」をクリックします。

    <img width="600" alt="Lambda関数を作成する_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/ebf4c10e-a3ff-4306-6084-0a56dc78a623.png">

5. タイムアウトを変更する

    デフォルトのタイムアウトは「3秒」となっており、処理完了までの時間が足りないため、タイムアウトを「3分」に変更します。

    設定 → 一般設定 の「編集」をクリックします。

    <img width="600" alt="Lambda関数を作成する_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d6c94c03-bcd5-233b-3653-b4a226728817.png">

    タイムアウトを「3分」に変更し、「保存」をクリックします。

    <img width="600" alt="Lambda関数を作成する_7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/a970f9dc-a0b8-2d96-9c25-5d92295a79a6.png">

#### レイヤーを作成する

Lambda関数からLangChainなどのライブラリを使用するには、レイヤーを作成してライブラリを追加する必要があります。

以下の記事を参考にして、使用するライブラリをレイヤー化してLambda関数に追加する手順を説明します。

https://zenn.dev/ndjndj/articles/69a2aabb227530

レイヤーにライブラリをアップロードするには、ライブラリをまとめたZipファイルを「**直接レイヤーにアップロード**」するか、または「**S3バケットを介してアップロード**」する必要があります。

「**直接アップロード**」する場合、ファイルサイズは「50MB以下」でなければなりません。今回のライブラリが50MBを超えているため、「**S3バケットを介してアップロード**」する方法を選択します。

Zipファイルの作成環境によっては、Lambdaでレイヤーを使用する際にエラーが発生することがあるため、環境起因のエラーを防ぐ目的で **Cloud9環境** でZipファイルを作成します。

1. ライブラリをまとめたZipファイルを置くためのS3バケットを作成する

    S3コンソールにアクセスして、「バケットを作成」をクリックします。

    <img width="600" alt="レイヤーを作成する_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/db1de60d-e7b0-8602-7157-ce607fafb938.png">

    バケット名は `lambda-layer-modules-{ランダムな文字列}` と入力します。

    <img width="600" alt="レイヤーを作成する_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/785c7131-0da3-d76f-1517-265eaa5599c3.png">

    その他の項目はデフォルトのまま「バケットを作成」をクリックします。

    <img width="600" alt="レイヤーを作成する_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/8fedb1ec-2aab-cfc6-83ad-9ff0eee8df08.png">

2. Cloud9環境を構築する

    Cloud9コンソールにアクセスして、「環境を作成」をクリックします。

    <img width="600" alt="レイヤーを作成する_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/cd6a28bb-ee84-6305-a292-128d6869e5ba.png">

    名前は `create-layer-modules` として、「新しいEC2インスタンス」を選択します。

    <img width="600" alt="レイヤーを作成する_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/1dcffabe-9769-9b3d-81f5-79054913ad6f.png">

    インスタンスタイプは `t2.micro` を選択し、プラットフォームは「Amazon Linux 2023」を選択します。

    <img width="600" alt="レイヤーを作成する_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/5c1819c6-4a20-78a7-edfa-e9f62f69be6c.png">

    「作成」をクリックします。

    <img width="600" alt="レイヤーを作成する_7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/690a3947-e545-59e1-27ee-ae6872d3bb98.png">

3. Zipファイルを作成する

    作成した環境を選択し、「Cloud9 で開く」を選択します。

    <img width="600" alt="レイヤーを作成する_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/68d93cb2-a71f-1942-af1f-8f72300bbfa7.png">

    Cloud9のターミナルにて、以下のコマンドを実行して pip を使えるようにします。

    ```bash
    # ライブラリを保管するディレクトリを作成
    mkdir tmp-python
    cd tmp-python

    # zip 化に必要なツールをインストール
    sudo yum -y install bzip2-devel xz-devel

    # pyenv を clone
    git clone https://github.com/pyenv/pyenv.git ~/.pyenv

    # pyenv の PATH を通す
    vi ~/.bashrc

    # vi でファイルが開かれるので、 I key で INSERT mode に変更。以下を追記する
    export PATH="$HOME/.pyenv/bin:$PATH"
    eval "$(pyenv init -)"
    # 完了したら、ESC key で INSERT mode を終了
    # :wq! で保存して終了

    # .bashrc の変更を現在のターミナルに適用する
    source ~/.bashrc

    # Python 3.10.14 を Install
    pyenv install 3.10.14

    # pyenv で現環境に設定
    pyenv global 3.10.14
    python -V
    ```

    以下のコマンドを実行して、ライブラリをインストールします。

    ```bash
    pip install --upgrade pip
    mkdir python
    pip install langchain==0.1.16 langchain-community==0.0.36 langchain_aws==0.1.2 slack_bolt==1.18.1 -t ./python
    ```

    以下のコマンドを実行して、Zipファイルを作成します。

    ```bash
    zip -r python.zip python/
    ```

    以下のコマンドを実行して、先ほど作成したS3バケットにZipファイルをアップロードします。

    ```bash
    aws s3 cp python.zip s3://{バケット名}
    ```

    :::note warn
    注意
    アップロードが完了したら、Cloud9は削除します。
    リソースが残っていると課金が発生します。
    :::

4. レイヤーを作成する

    Lambdaコンソールに移動し、レイヤーから「レイヤーの作成」をクリックする。

    <img width="600" alt="レイヤーを作成する_9" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/2010cfc7-2f83-a37a-f4f8-a74ba5ac96fb.png">

    レイヤーの名前は `Layers` を入力する。

    <img width="600" alt="レイヤーを作成する_10" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/e30d53c3-30f6-68c1-e0bd-fe8a46f2bec3.png">

    「Amazon S3 からファイルをアップロードする」を選択します。

    <img width="600" alt="レイヤーを作成する_11_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/ad46ff25-dc77-2454-2374-965490f69bab.png">

    S3バケットからアップロードしたZipファイルを選択し、「URLをコピー」をクリックします。

    <img width="600" alt="レイヤーを作成する_11_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/41309964-2d37-5c1a-6724-8f9261439bfc.png">

    「Amazon S3 からファイルをアップロードする」にコピーしたURLを貼り付けます。

    <img width="600" alt="レイヤーを作成する_11_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/63d8c07d-47ca-278d-70b5-7e9f7456385d.png">

    アーキテクチャは「x86_64」を選択し、ランタイムは「Python 3.10」を選択します。

    <img width="600" alt="レイヤーを作成する_12" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/b815c5fe-45f8-1270-7638-09d4ec53e7e6.png">

    「作成」をクリックすると、レイヤーが作成されます。

    <img width="600" alt="レイヤーを作成する_13" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/2ba84ad7-f6a7-3cc7-4de7-7a775f7ce3d3.png">

    レイヤーが作成されました。

    <img width="600" alt="レイヤーを作成する_14" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/28967040-1c6b-b29c-98f4-89cbab5cff63.png">

#### コードを実装する

1. 関数にレイヤーを関連付けます

    Lambdaコンソールに移動し、作成したLambda関数の「レイヤー」から「レイヤーの追加」をクリックします。

    <img width="600" alt="コードを実装する_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/3f57fb00-c55e-27b7-6de2-575d1ef796c3.png">

    「カスタムレイヤー」を選択し、作成したレイヤーを選択して、「追加」をクリックします。

    <img width="600" alt="コードを実装する_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/218d455e-9cda-dd87-7ea7-9aaf851ad29d.png">

2. 以下のコードをコピペして、Lambda関数に貼り付けて、「Deploy」をクリックします。

    https://github.com/sakes9/sam-slack-review-rag/blob/main/src/app.py

    <img width="600" alt="コードを実装する_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d1a8353c-0d14-61f3-a334-544859e1d394.png">

3. 環境変数を設定します。

    Kendraコンソールに移動し、作成したインデックスのIDをコピーします。

    <img width="600" alt="コードを実装する_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/dd05e3cd-5f6c-deef-714c-6a9e9f3b2504.png">

    Lambdaコンソールに戻り、環境変数の「編集」をクリックします。

    <img width="600" alt="コードを実装する_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/da422f16-4c72-9aae-1290-7487c3ddac60.png">

    「環境変数の追加」をクリックします。

    <img width="600" alt="コードを実装する_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/6df22a0a-7351-ddf9-ae54-39275215566e.png">

    環境変数を追加して、「保存」をクリックします。

    | キー | 値 |
    | --- | --- |
    | KENDRA_INDEX_ID | {KendraのインデックスID} |

    <img width="600" alt="コードを実装する_7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/496ae79f-e7d8-d2f2-54fd-c09d16eb6f85.png">

### Slack

Slack経由でRAGにコードレビューを依頼するために、Slackアプリを作成します。

#### Slackのワークスペースを作成する

既存のワークスペースを使用するか、新規でワークスペースを作成してください。
私は `RAG` というワークスペースを作成しています。

#### アプリを作成する

1. [Slack API](https://api.slack.com/) にアクセスして、「Your apps」をクリックします。

    <img width="600" alt="アプリを作成する_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/9990905d-f249-dac5-2f33-e7763260b1be.png">

2. アプリを作成する

    「Create an App」をクリックします。

    <img width="400" alt="アプリを作成する_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/debe8480-b78f-b911-3aaa-30cbe73cba08.png">

    「From scratch」を選択する

    <img width="400" alt="アプリを作成する_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/429c44e8-a531-a9e4-9bda-c524859be051.png">

    App Name（アプリ名）は `Reviewer` と入力し、作成したワークスペースを選択し、「Create App」をクリックします。

    <img width="400" alt="アプリを作成する_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/59029202-55c1-5cfa-7c0b-a298a3ac7798.png">

3. アプリのBot権限を追加する

    OAuth & Permissions を選択します。

    <img width="600" alt="アプリを作成する_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/7633ef63-2219-565a-3822-09fa617806b0.png">

    Scopes の 「Add an OAuth Scope」をクリックします。

    <img width="600" alt="アプリを作成する_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/7f9ed493-79d3-deb5-c5f8-a56fe176999c.png">

    メンションメッセージを読み取り、レスポンスを返すための権限を追加する

    - app_mentions:read
    - channels:read
    - chat:write

    <img width="600" alt="アプリを作成する_7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/0358076a-dd46-d422-26ea-04e62f67e76f.png">

4. ワークスペースにアプリをインストールする

    OAuth & Permissions の OAuth Tokens for Your Workspace にある Install to Workspace をクリックします。

    <img width="600" alt="アプリを作成する_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/6fd1d472-00b9-a36c-2821-5f01b8b49aa3.png">

    許可するをクリックします。

    <img width="500" alt="アプリを作成する_9" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d070d2f8-435d-276f-8f0b-153a89914f5f.png">

#### Lambda環境変数にSlackアプリの情報を設定

1. OAuth & Permissions にある Bot User OAuth Token をメモしておきます。

    <img width="600" alt="環境変数にSlackのトークンを設定_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/f2b1d11e-c5a8-3b6c-e5cc-c40eb39053a5.png">

2. Basic Information にある Signing Secret をメモしておきます。

    <img width="600" alt="環境変数にSlackのトークンを設定_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/9abc388a-6360-89a8-1797-aca986b74230.png">

    <img width="600" alt="環境変数にSlackのトークンを設定_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/84d8f060-4999-3f04-0af8-eb73b9f0543d.png">

3. Lambdaの環境変数に以下のキーと値を設定します。

    | キー | 値 |
    | --- | --- |
    | SLACK_BOT_TOKEN | {Bot User OAuth Token} |
    | SLACK_SIGNING_SECRET | {Signing Secret} |

    <img width="600" alt="環境変数にSlackのトークンを設定_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/4be9d92e-c460-98fc-7606-3f69530eca3e.png">

#### メンション時のイベントを設定する

1. Slack API から「Event Subscriptions」を選択して、Enable Events を ON にします。

    <img width="600" alt="メンション時のイベントを設定する_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/a42dd784-aab5-a64c-5ae8-0d9051715a8c.png">

2. Lambdaの関数URLをコピーします。

    <img width="600" alt="メンション時のイベントを設定する_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d00d1d2d-e86d-ad95-a8d4-226391382780.png">

3. Request URL にコピーした関数URLを貼り付けます。

    一度目の検証で失敗するが、Retryしたら2回目で成功する（理由はわからない）

    <img width="600" alt="メンション時のイベントを設定する_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/b3ebc5a4-77d6-728b-4621-d093af505b0c.png">

      検証に成功すると Verified にチェックがつきます。

    <img width="600" alt="メンション時のイベントを設定する_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d0dc6c2a-379a-3c5a-280c-0a925424489e.png">

4. 「Subscribe to bot events」の Add Bot User Event をクリックします。

    <img width="600" alt="メンション時のイベントを設定する_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c5db79d2-569b-f2bb-29bd-687bc52b5b52.png">

5. 「app_mention」を追加します。

    <img width="600" alt="メンション時のイベントを設定する_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c75d990f-e4b7-e719-b7cd-06a8870237bd.png">

6. 「Save Changes」をクリックします。
    <img width="600" alt="メンション時のイベントを設定する_7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/de4b46d8-d927-3283-291a-b58d6894ecd7.png">

### 動作検証

1. [Slack](https://slack.com/) にアクセスします
2. Slack App をインストールしたワークスペースを開きます
3. チャンネルを作成します
   私は `review` というプライベートチャンネルを作成しました。

   <img width="600" alt="動作検証_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/8eaa4028-6c48-e9dc-f9ba-c476181b8060.png">

4. Slack Appを招待します

    `@Reviewer` をメンションして、Slack App を招待します。

    <img width="600" alt="動作検証_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/f09b37eb-bd10-ec72-f35e-c5f6c7b20899.png">

    「招待する」をクリックします。

    <img width="600" alt="動作検証_3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/1402441b-45ab-b1ae-96c3-b4aaced47a0a.png">

    Slack App がチャンネルに招待されました。

    <img width="400" alt="動作検証_4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/7ab33d2b-08a8-53e2-922b-7401e41f3a50.png">

    招待時の初回メッセージに対するレスポンスは無視してください。

    <img width="400" alt="動作検証_5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/2640a9b8-6edb-9b91-d75c-23f8f8900ec0.png">

5. レビュー依頼を出します

    `@Reviewer` をメンションして、コードをレビューしてもらうために、以下のメッセージを送信すると、レビューが開始されます。

    ```text
    @Reviewer
    for (var i = 0; i < clubs.length; i++) {
        for (var j = 0; j < clubs[i].members.length; j++) {
            for (var k = 0; k < clubs[i].members[j].users.length; k++) {
                if (clubs[i].members[j].users[k].id === userId) {
                    console.log(`${clubs[i].members[j].users[k].name} が所属しているクラブは ${clubs[i].name}`);
                }
            }
        }
    }
    ```

    <img width="400" alt="動作検証_6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/9ca30f05-3119-6438-6848-7d120bf12c48.png">

6. レビュー結果が返却されます

    <img width="600" alt="動作検証_7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d28fbbbb-461b-a516-541a-92c99785dbfd.png">

    <img width="600" alt="動作検証_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/4dd24e78-b190-5364-a292-4ea2c1f813ce.png">

:::note warn
注意
環境構築後は、必ずリソースの削除を行ってください。
リソースが残っていると課金が発生します。
特にKendraは高額な課金が発生するため、削除を忘れないようにしてください。
:::

## まとめ

RAGを活用してSlack経由でコードレビューを依頼する方法を以前紹介しました。

今回の検証では期待通りの結果が得られたり、期待している結果とは少しズレた回答が得られたり、コードレビューの精度としてはまだまだ改善がありそうな感想です。おそらっく使用しているデータソースの質が十分でないことが原因だと思うので、実用的に使いたい場合は、データソースをさらに充実させることで、より高精度な結果が期待できると思います。

次回は、AWS SAMを使用してRAG環境を構築する手順についてご紹介したいと思います。

https://qiita.com/sakes9/items/6655c1de123c6511b25c

## 参考資料

- RAG構築
  - [LangChainからKendraでRAGする（その1）-Amazon Bedrock APIで始めるLLM超入門⑤ #Python - Qiita](https://qiita.com/cyberBOSE/items/5cdec3580eb22b567d39)
  - [Amazon KendraとAWS Lambdaを使い、RAGのRetrievalフェーズを試してみた | DevelopersIO](https://dev.classmethod.jp/articles/kendra-lambda-retrieval/)
- Kendra作成
  - [Amazon Kendra による機械学習を活用した情報検索を試してみた | cloud.config Tech Blog](https://tech-blog.cloud-config.jp/2023-12-25-amazon-kendra-tutorials)
- Lambda レイヤー
  - [Lambda Layer にアップロードするための zip ファイルを作成するには Cloud9 環境を利用すると結構便利](https://zenn.dev/ndjndj/articles/69a2aabb227530)
- Slack連携
  - [【Bedrock×Lambda】高精度なハイブリッド検索RAGをサーバレスで実装（Slack連携も可） #AWS - Qiita](https://qiita.com/Naoki_Ishihara/items/662d70a9bd0dc3a8c9ce)
  - [【これを読めば誰でも出来るSlackアプリの作り方】SlackAPIを使うための準備 #Slack - Qiita](https://qiita.com/Himeka_Kawaguchi/items/66cce374a88c243c439d)