[ワークショップ資料] Amazon Bedrock ナレッジベースで商品レコメンド機能を作るため、Amazon AppFlowでStripeの商品データをノーコードで取り込む

:::note
この記事は、[JAWS-UG DEI](https://jawsugkgirls.doorkeeper.jp)にて2024/5/11に開催した、[AWS AppFlow と Amazon Bedrockを使ったオリジナルなAIチャットを作ろう！ワークショップ](https://jawsugkgirls.doorkeeper.jp/events/171050)資料です。

利用するAWSサービスの一部に、課金の発生するものが存在します。ワークショップではAWSクーポンを配布しますが、個人的に挑戦される方は、ご利用予定のAWSアカウントについて、無料枠やトライアルの有無について事前にご確認をお願いします。

また、AWSマネージメントコンソールのスクリーンショットは、**2024/05時点**で撮影されたものを利用しています。今後のAWSアップデートによって、UIやフローが変更される場合もありますので、ご了承ください。
:::

:::note warn
**Q: 前のワークショップは終了しましたか？**

このワークショップは、２つの記事で構成されています。BedrockナレッジベースやS3バケットの作成については、[前のステップ](https://qiita.com/hideokamoto/items/05befdffe6ab17cbe6f8)で紹介していますので、まずはこちらをお試しください。
:::

https://qiita.com/hideokamoto/items/05befdffe6ab17cbe6f8

## ワークショップのゴール

[前回のワークショップ](https://qiita.com/hideokamoto/items/05befdffe6ab17cbe6f8)では、Amazon Bedrockのナレッジベースを使ったAIチャット（RAGアプリ）をノーコードで作成しました。Amazon S3に任意のデータをアップロードすることで、アップロードされたファイルの内容に基づいた回答文章の生成を行うことができます。

こちらのワークショップでは、RAGアプリが参照するデータの追加・更新についても、ノーコードで自動化する方法を体験します。Amazon AppFlowを利用した定期的なデータのインポート方法を、Stripeを例にして学びます。このワークショップを完了することで、AWS外部のサービスで管理しているデータをAmazon Bedrock ナレッジベースが参照できるようにする方法と、そのデータの同期方法を知ることができます。これによってコードを書かずにRAGやAIチャットとよばれるアプリケーションのPoCやデモを、コードを書かずに構築・提供することが可能になります。


## 準備するもの

前回のワークショップで作成したリソース（ Amazon S3バケット / Amazon Bedrock ナレッジベース / Amazon OpenSearch Serverless ）を引き続き利用します。作成がまだという方は、以下の資料を参考に作成しましょう。

https://qiita.com/hideokamoto/items/05befdffe6ab17cbe6f8

## ワークショップの流れ

このワークショップでは、作成済みのS3バケットにデータをインポートし、ナレッジベースが変更を同期する仕組みを構築します。

作業の流れは、おおよそ次のとおりです。

+ Step1: Amazon AppFlow で 外部のデータをインポートするワークフローを作成
+ Step2: Amazon Bedrock ナレッジベースで、データソースを更新する
 
## Step1: Amazon AppFlow で 外部のデータをインポートするワークフローを作成

Amazon AppFlowは、様々なSaaSとAWS間で安全にデータを転送することができるサービスです。今回紹介するStripe以外にも、AsanaやGoogle Ads / Analytics / HubSpotにMarketoなど、非常に多くのサービスとデータを連携することができます。利用しているサービスとも接続できるかは、[サポートしているサービスの一覧](https://docs.aws.amazon.com/appflow/latest/userguide/app-specific.html)をご覧ください。

https://docs.aws.amazon.com/appflow/latest/userguide/app-specific.html

AppFlowを利用するには、検索フォームに **appflow** と入力し、Amazon AppFlowを選択しましょう。

![スクリーンショット 2024-05-10 15.34.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/5bdf6ad8-ce25-2657-eb9a-e7d04d4167b6.png)

Amazon AppFlowのトップページが表示されました。[フローを作成]をクリックすることで、新しいデータ転送ワークフローを作ることができます。

![スクリーンショット 2024-04-22 14.37.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/862f9415-0a21-e494-a900-ef0082405036.png)

AppFlowでのフロー作成手順は、５ステップにわかれています。まずはフローの名前や説明文・データ暗号化の設定と、コスト管理などで利用するためのタグ付けを設定しましょう。今回はワークショップですので、**フロー名** に`workshop-import-stripe-products`と入力して、**[次へ]** ボタンをクリックしてください。


![スクリーンショット 2024-04-22 14.39.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/6e38bfea-880d-ad61-8543-c1b95597323f.png)

手順２では、「どこからどこへデータを転送するか」のフロー設定を行います。ここで設定した内容に基づいて、AppFlowがデータの転送処理を実行するようになります。

### ワークフローで転送するデータの送信元を設定する

まずデータの送信元を設定しましょう。**[送信元の詳細]**セクションにある**送信元名**をクリックします。今回はデータソースに[Stripe](https://stripe.com)を利用しますので、**stripe** と入力しましょう。下の画像のように[Strpie]が表示されますので、これをクリックします。

![スクリーンショット 2024-04-22 14.39.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/588dd998-9a78-30f5-cc80-18509b5b6791.png)

クリックすると、 **[送信元の詳細]** セクション内に`Stripe 接続を選択`が追加で表示されます。ここでStripeなどの外部サービスとAppFlowを接続するための設定を行います。**[新規接続を作成]** をクリックしましょう。

![スクリーンショット 2024-04-22 14.42.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/9e87e275-07e6-566a-4fd0-fd24ebf6a420.png)

外部サービスとの接続設定を行うためのモーダルが表示されました。Stripeと連携する場合は、[**シークレットキー**または**制限付きAPIキー**](https://docs.stripe.com/keys#limit-access)を**API key**に入力します。

![スクリーンショット 2024-04-22 14.42.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d58c562c-2bad-7e6e-6e13-24fd5a63efbe.png)

:::note
**StripeのシークレットAPIキーを取得する方法**
StripeのAPIキーは[Stripeダッシュボード](https://dashboard.stripe.com/)から取得できます。検索フォームに**api**と入力すると、 **[開発者 > APIキー]** ページのリンクが検索結果に表示されます。これをクリックしてページに移動しましょう。
![スクリーンショット 2024-04-22 14.43.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/7f424102-217f-8855-fa23-140578454855.png)

APIキー管理ページでは、３つのAPIキーを管理できます。今回はワークショップですので、**シークレットキー**を取得しましょう。**[トークン]** 行にある **[テストキーを表示]** をクリックして、APIキーを取得しましょう。

![スクリーンショット 2024-04-22 14.44.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/3f693eaa-aa5a-933a-31c0-450bf5115a66.png)
:::

Stripeダッシュボードで取得した`sk_test_xxx`始まるシークレットキーを**API key**に入力しましょう。**[接続名]** には、今回のワークショップで作成したことがわかるように、**stripe-workshop**などの名前をいれましょう。最後に **[接続する]** ボタンをクリックして、変更を保存します。

![スクリーンショット 2024-04-22 14.45.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/74868502-2a40-cd24-c5e5-53d14cf13a6b.png)

モーダルが閉じられて、成功メッセージが出れば作成成功です。`Stripe 接続を選択`に作成した名前が表示されていることを確認しましょう。

![スクリーンショット 2024-04-22 14.46.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/7afd987c-fe74-6ce8-9dbf-a1da541882b9.png)

Stripeへの接続に成功していれば、**[Stripe オブジェクトを選択]** が新しく表示されています。ここでは外部サービスがもつ「**どのデータを転送したいか**」の設定を行います。今回はStripe上に保存されている商品情報をS3に送信しますので、**Product** を選択しましょう。

![スクリーンショット 2024-04-22 14.47.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/285a794b-c0fe-a93a-cde8-037c721b8f19.png)

これで送信元の設定は完了です。続いて送信先のサービスについて設定を行いましょう。

### データの送信先を設定する

続いてデータの転送先を設定しましょう。今回はBedrock ナレッジベースが同期できる場所にファイルを送信する必要がありますので、Amazon S3を転送先にします。**[送信先名]** を選択し、**[Amazon S3]** を選択してください。すると「どのバケットに送信するか」を設定するフィールドが表示されます。

![スクリーンショット 2024-04-22 14.48.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d8fc589a-f7e7-cb1c-9d7e-5d4ef9969a89.png)

**[バケットの詳細]** にある**バケットを選択** をクリックすると、そのAWSアカウントにあるS3バケットを表示・検索できます。**[前のワークショップ](https://qiita.com/hideokamoto/items/05befdffe6ab17cbe6f8#s3%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90%E6%96%B9%E6%B3%95)で作成したS3バケットの名前**　を検索して、選択しましょう。**バケットプレフィックス** やその他の設定項目については、デフォルトの状態のままにしておきます。

![スクリーンショット 2024-04-22 14.57.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/cc32032a-ed13-7076-4b18-9640410e409d.png)

### データの取り込み頻度を設定する

最後に取り込み頻度を設定します。AppFlowは任意のタイミングでデータを取り込むワークフローを実行できます。今回はワークショップですので、**[オンデマンドで実行]** を選択しましょう。

![スクリーンショット 2024-04-22 14.57.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/397e4f4f-7366-451e-7db3-081f7dca675c.png)

:::note
実際のプロジェクトで利用する場合は、**[スケジュール通りにフローを実行]** を選択しましょう。これによって、定期的なデータの取得と更新をAppFlow上の設定だけで定期実行できるようになります。
:::

ここまでの設定が完了したら、**[次へ]** をクリックしましょう。

### どんなデータを送信するかをマッピングする

AppFlowでは、送信元から取得したデータのマッピングも行うことができます。必要なデータだけ送信することによって、S3のストレージコストを削減したり、Bedrock　ナレッジベースが参照するデータのノイズを減らすことができます。

マッピング方法は２種類あり、ワークショップは動作確認であれば **[手動でフィールドをマッピングする]** の選択をお勧めします。マッピング内容が複雑な場合や、複数のワークフローで同じ設定を行いたい場合などでは、CSVファイルを作成して読み込ませる方法がより便利です。

![スクリーンショット 2024-04-22 14.58.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/c3a2ac66-1a55-305e-ce53-506007f92da3.png)

**[手動でフィールドをマッピングする]** を選択した場合、このページでマッピング操作を行います。送信元がどのようなデータを送信するかについては、AppFlow側が認識していますので、チェックボックスのオンオフで利用するフィールドを選択しましょう。今回のワークショップでは、以下のフィールドにチェックをつけましょう。

|name|description|
|:--|:--|
|id|Stripe上の商品ID|
|name|商品の名前|
|active|その商品が利用可能か否か|
|description|商品の説明文|
|metadata|商品に登録されたメタデータ|


![スクリーンショット 2024-04-22 15.04.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/8e21710c-57a0-9a13-1673-d79f78fca290.png)

送信したいフィールドを選択した後、 **[フィールドを直接マッピングする]** をクリックしましょう。

![スクリーンショット 2024-04-22 15.08.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/11dd6a87-3728-7837-ef3b-a96a990ae938.png)

送信元でのフィールド名やデータの簡単な加工を行う式の設定が、マッピング画面では設定できます。今回はデータをそのままS3バケットに送信しますので、 **デフォルトで表示されている設定** をそのまま使いましょう。

![スクリーンショット 2024-04-22 15.09.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/a173e037-cb37-0672-dd11-736d6f3fce58.png)

このページでは、他にパーティションや集約の設定と無効なデータの処理のセクションもあります。「欠損しているデータがある場合に、ワークフローを中断する or そのデータを除外する」のような設定が行えます。今回はワークショップですので、操作はせずに、次に進みましょう。

![スクリーンショット 2024-05-10 17.02.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/ced1d41d-f135-67ad-d419-1f66a1e93ccf.png)

### 除外したいデータのフィルター設定を行う

サービス連携では、「欠損データではないが、取り込みたくないデータではある」ケースも存在します。その場合はこの **[フィルターを追加する]** ステップで設定しましょう。 **[フィルターを追加する]** ボタンをクリックすると、「特定のフィールドが条件を満たした場合に、転送しないようにフィルターする」設定が行えます。

![スクリーンショット 2024-04-22 15.15.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/0d7c4dd4-0d59-a438-3383-b81bffce5c74.png)

Stripeの商品データの場合、`active`フィールドを使って「販売停止している商品データは、除外する」設定が行えます。以下の表とスクリーンショットを参考に設定してみましょう。

|フィールド名|条件|条件1|
|:--|:--|:--|
|active|が次の値と完全に一致する|true|

![スクリーンショット 2024-05-10 23.49.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/dee705fc-473d-f6aa-2c9a-afb6d1490f8d.png)
これでBedrock ナレッジベースによる商品のレコメンドの際に、販売終了している商品をお勧めされないようにできました。**[次へ]** をクリックして、確認画面に進みましょう。

### 設定の確認と作成・データの取り込み

設定内容に問題がないかを確認して、フローを作成します。

![スクリーンショット 2024-04-22 15.17.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/f2c0e686-dbe3-de58-22aa-1c3fb27e1426.png)

作成に成功すると、作成したフローの詳細画面に移動します。これでStripeの情報をS3に取り込む準備ができました。早速 **[フローを実行]** をボタンをクリックして、データの取り込みをはじめましょう。

![スクリーンショット 2024-04-22 15.18.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/81e0d007-c6e1-8fb9-1098-6e52a73e106a.png)

データの取り込みには少し時間がかかります。これはデータの量などで左右されますので、完了メッセージが出るまで気長に待ちましょう。

![スクリーンショット 2024-04-22 15.19.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/505ddf23-fa2b-72c1-4224-f08c9c24debd.png)

完了すると、下のスクリーンショットのように成功メッセージが表示されます。これでStripeからS3にデータを取り込むことができました。

![スクリーンショット 2024-04-22 15.20.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/0ff592dc-5b4a-6948-af36-31caec2ed9d4.png)

:::note
**取り込まれたデータを確認する**
取り込みに成功したかどうかは、S3バケットをみることでも確認できます。AppFlowで送信先に設定したS3バケットに移動すると、新しいフォルダが追加されています。

![スクリーンショット 2024-04-22 15.20.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/c0099c89-1fdd-88fe-2b38-f0521693e6c7.png)

この中にあるファイルをダウンロードして開くと、次のようなデータが保存されていることが確認できます。

```json
{"id":"prod_PuX48cRgmHju58","active":true,"name":"定期サポート","description":null,"metadata":{}}
{"id":"prod_OnWY2V0PY6Nf9H","active":true,"name":"スタンダードプラン","description":null,"metadata":{}}
{"id":"prod_OFnvbuUUnOze0I","active":true,"name":"ファイルストレージ","description":null,"metadata":{}}
{"id":"prod_OFnppeR9bkPzHx","active":true,"name":"エンタープライズプラン","description":null,"metadata":{}}
{"id":"prod_NxtZPS50saFlGM","active":true,"name":"コーヒー豆定期お届け便","description":"厳選したコーヒー豆を、定期的にお届けします。","metadata":{}}
{"id":"prod_Nx9ej4SShtL26Q","active":true,"name":"test","description":null,"metadata":{}}
{"id":"prod_Nuq0TmGran7dKW","active":true,"name":"プレミアムコーヒー豆セット","description":null,"metadata":{}}
{"id":"prod_LXIoekhGy8a6RX","active":true,"name":"コーヒードリッパー（布）","description":"布製のコーヒードリッパーです。","metadata":{}}
{"id":"prod_LXImKA63G85Om5","active":true,"name":"焙煎済みコーヒー豆","description":"焙煎済みのコーヒー豆です。","metadata":{}}
{"id":"prod_LXIlPCBm2Sm9qG","active":true,"name":"あまおう（小粒）","description":"小粒のあまおうを１パックにまとめました","metadata":{}}
{"id":"prod_LXIkjGhz3qmLmO","active":true,"name":"季節の野菜セット","description":"季節に応じた野菜を厳選してお届けします","metadata":{}}
{"id":"prod_LXIfs7eTYBzJwi","active":true,"name":"とうもろこし","description":"産地直送のとうもろこしです。","metadata":{}}
{"id":"prod_LXIVIHcf3KeEBk","active":true,"name":"松坂牛ステーキ２枚セット","description":"松坂牛のステーキ２枚セットを毎月お届けします。＊冷凍","metadata":{}}

```

:::

## Step2: Amazon Bedrock ナレッジベースで、データソースを更新する

StripeのデータをS3に転送することができました。このデータをBedrock ナレッジベースで利用するには、データを同期する必要があります。検索フォームに **[Bedrock]** と入力し、Amazon Bedrockの管理画面に移動しましょう。

![スクリーンショット 2024-04-22 15.23.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/8c3be778-3388-1ecb-4640-528700a039ba.png)

[前のワークショップで作成したBedrock ナレッジベース](https://qiita.com/hideokamoto/items/05befdffe6ab17cbe6f8#step4-amazon-bedrock-%E3%83%8A%E3%83%AC%E3%83%83%E3%82%B8%E3%83%99%E3%83%BC%E3%82%B9%E3%82%92%E4%BD%9C%E6%88%90)の詳細画面に移動しましょう。[前回のワークショップで操作した](https://qiita.com/hideokamoto/items/05befdffe6ab17cbe6f8#step5-%E3%83%8A%E3%83%AC%E3%83%83%E3%82%B8%E3%83%99%E3%83%BC%E3%82%B9%E3%81%B8%E3%81%AEs3%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E3%82%8A%E8%BE%BC%E3%81%BF)際と同様にデータの取り込み操作を行います。

ナレッジベース詳細画面でページをスクロールし、ページ中段にある[データソース]セクションへ移動します。同期したいデータソースを選択し、 [同期]　ボタンをクリックしましょう。

![スクリーンショット 2024-04-22 16.26.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/4b16da22-14bf-d89c-1b73-8317af2e5eb3.png)

ページ上部に同期を開始したメッセージが表示されます。1・2分程度で同期が完了しますので、下のスクリーンショットのように完了画面が出るのを待ちましょう。

![スクリーンショット 2024-04-22 16.27.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/8653e32f-afa4-e0c3-4dd0-afaf5748b814.png)

これでデータの取り込みが完了しました。ナレッジベースのテスト機能を利用して、商品のおすすめができているかを確認しましょう。

![スクリーンショット 2024-05-10 22.51.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/cd066b39-ccc3-1c25-3ea2-f867e83e703e.png)

Stripeに登録している商品情報について紹介する回答文章が生成されていれば、連携成功です。

## おまけ: CloudShell と AWS CLIで、Bedrock ナレッジベースに質問を送信してみる

せっかくですので、実際の組み込みをイメージしてプログラムから質問を送信してみましょう。AWSでは、ブラウザ上でAWS CLIを利用してAWSのAPIを呼び出すことができる、[AWS CloudShell](https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/welcome.html)が提供されています。

![スクリーンショット 2024-05-10 22.54.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/e3c7d4ae-a73d-13a7-c5de-1db89773f9e4.png)

検索フォームに **[Shell]** と入力し、 **CloudShell** の管理画面に移動しましょう。

![スクリーンショット 2024-05-10 22.55.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/0695d54c-31ab-db99-e25a-5cdad261d2d5.png)

CloudShellの紹介モーダルが表示されることもありますが、 **[閉じる]** を押してもらえればOKです。

![スクリーンショット 2024-05-10 22.56.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/c3324883-a34e-80b2-518a-33360cb5ab02.png)

CloudShellでは、文字通りブラウザ上でシェルコマンドを実行できます。

![スクリーンショット 2024-05-10 22.57.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/84b9b5f9-1d29-4a26-a3fc-660e8e0a7c2e.png)

試しに`aws bedrock list-foundation-models --query "modelSummaries[].modelArn"`をコピーアンドペースとして実行してみましょう。実行すると、利用可能なLLMのARNが一覧で表示されます。


![スクリーンショット 2024-05-10 23.04.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/733b9e61-98bb-2c71-dabd-17d0f23e105a.png)

AWS　CLIでナレッジベースに質問を送信する場合、`aws bedrock-agent-runtime retrieve-and-generate`コマンドを実行します。このコマンドは、次のような値を設定して実行します。

```bash
aws bedrock-agent-runtime retrieve-and-generate \
--input text="質問文をここに入れる" \
--retrieve-and-generate-configuration type=KNOWLEDGE_BASE,knowledgeBaseConfiguration="{knowledgeBaseId={Knowledge baseのID},modelArn={利用するモデルのARN}}"
```

`{Knowledge baseのID}`は、作成したナレッジベースの詳細画面から確認できます。**ナレッジベースの概要** セクションに表示されている**ナレッジベースID** をコピーしてコマンドの`{Knowledge baseのID}`部分に設定しましょう。

また、`{利用するモデルのARN}`については、先ほど`aws bedrock list-foundation-models --query "modelSummaries[].modelArn"`を実行して表示された結果から、利用したいモデルのARNをコピーして設定しましょう。例えば`AnthropicのClaude3 Sonnet`を、`us-east-1`リージョンで使うのであれば、`arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0`を設定します。

```bash
aws bedrock-agent-runtime retrieve-and-generate \
--input text="質問文をここに入れる" \
--retrieve-and-generate-configuration type=KNOWLEDGE_BASE,knowledgeBaseConfiguration="{knowledgeBaseId=ABCDEFGH,modelArn=arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0}"
```

あとは質問文を`text`部分に設定すればOKです。例えばコーヒー豆のサブスクリプションがあるかどうかを聞いてみましょう。
```bash
aws bedrock-agent-runtime retrieve-and-generate \
--input text="コーヒー豆のサブスクリプションはありますか？" \
--retrieve-and-generate-configuration type=KNOWLEDGE_BASE,knowledgeBaseConfiguration="{knowledgeBaseId=ABCDEFGH,modelArn=arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0}"
```

このコマンドをCloudShellで実行すると、生成されたテキストがJSON形式で表示されます。

![スクリーンショット 2024-04-22 16.13.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/c6a0a2d3-80ae-2495-e07a-c228d1913951.png)

```bash
$ aws bedrock-agent-runtime retrieve-and-generate \
> --input text="コーヒー豆のサブスクリプションはありますか？" \
> --retrieve-and-generate-configuration type=KNOWLEDGE_BASE,knowledgeBaseConfiguration="{knowledgeBaseId=XXXXX,modelArn=arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2}"
{
    "citations": [
        {
            "generatedResponsePart": {
                "textResponsePart": {
                    "span": {
                        "end": 27,
                        "start": 0
                    },
                    "text": "はい、コーヒー豆のサブスクリプションサービスがあります。"
                }
            },
            "retrievedReferences": [
                {
                    "content": {
                        "text": "{\"id\":\"prod_PuX48cRgmHju58\",\"active\":true,\"name\":\"定期サポート\",\"description\":null,\"metadata\":{}} {\"id\":\"prod_OnWY2V0PY6Nf9H\",\"active\":true,\"name\":\"スタンダードプラン\",\"description\":null,\"metadata\":{}} {\"id\":\"0001\",\"active\":true,\"name\":\"kintoneプラグイン開発\",\"description\":null,\"metadata\":{}} {\"id\":\"prod_OFnvbuUUnOze0I\",\"active\":true,\"name\":\"ファイルストレージ\",\"description\":null,\"metadata\":{}} {\"id\":\"prod_OFnppeR9bkPzHx\",\"active\":true,\"name\":\"エンタープライズプラン\",\"description\":null,\"metadata\":{}} {\"id\":\"prod_NxtZPS50saFlGM\",\"active\":true,\"name\":\"コーヒー豆定期お届け便\",\"description\":\"厳選したコーヒー豆を、定期的にお届けします。\""
                    },
                    "location": {
                        "s3Location": {
                            "uri": "s3://workshop-stripe-appflow-demo-XXXXX/Stripe-products/d2c6935c-a837-497f-af32-bb2341363465/634703275-2024-04-22T06:19:47"
                        },
                        "type": "S3"
                    },
                    "metadata": {
                        "x-amz-bedrock-kb-source-uri": "s3://workshop-stripe-appflow-demo-XXXXX/Stripe-products/d2c6935c-a837-497f-af32-bb2341363465/634703275-2024-04-22T06:19:47"
                    }
                }
            ]
        }
    ],
    "output": {
        "text": "はい、コーヒー豆のサブスクリプションサービスがあります。"
    },
    "sessionId": "2c32e729-df85-46aa-98b2-4fd243cf7ae9"
}
```

実際の開発では、このAWS CLIコマンドをAWS SDKやLangChainなどのフレームワークから利用して実装します。

このようにCloudShellを利用することで、組み込み時のパラメータやレスポンスの確認も、ブラウザ上で完結できます。


## リソースの削除

最後にワークショップで作成した資料を削除しましょう。

### ナレッジベースの削除

ナレッジベースの削除は、ナレッジベース詳細画面で行います。**[削除]** ボタンをクリックしましょう。 

![スクリーンショット 2024-05-09 16.55.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/8383c209-00a7-1f84-6b10-589ad25d1e35.png)

削除操作用のモーダル画面が表示されます。`Delete underlying vector data`のチェックボックスをオンにして、**delete**と入力しましょう。

![スクリーンショット 2024-05-09 16.55.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d737a9c0-c7e4-b64e-10da-a45ac0c52c27.png)

以下のスクリーンショットと同じ状態になっていることを確認して、**削除** ボタンをクリックします。

![スクリーンショット 2024-05-09 16.56.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/cc27f77e-6dca-b001-39b7-267eb55ba24b.png)

削除に成功したメッセージを確認して、削除作業終了です。

![スクリーンショット 2024-05-09 16.57.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/8b369003-98f8-4edc-247d-9c60abc67bd1.png)


### OpenSearch Serviceの削除

つづいてOpenSearch Serviceも削除しましょう。検索フォームに**OpenSearch**と入力して、**Amazon OpenSearch Service**に移動しましょう。

![スクリーンショット 2024-05-09 16.58.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/58104f59-89f0-9e70-dd8a-d6fc16e7f712.png)

ダッシュボードに移動すると、一見リソースが何もないように見えます。しかしBedrockナレッジベースが生成するのは、**サーバーレス**なOpenSearch Serviceです。左側のメニューで**[サーバーレス > ダッシュボード]** をクリックしましょう。

![スクリーンショット 2024-05-09 16.58.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/dea8891b-fe81-a833-9787-001e2297953f.png)

サーバーレスのダッシュボードに移動すると、コレクションセクションにリソースが表示されました。
![スクリーンショット 2024-05-09 16.58.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/3d2e3817-655f-8015-633d-46b8008270e2.png)

削除するコレクションにチェックを入れて、**[削除]**ボタンをクリックしましょう。

![スクリーンショット 2024-05-09 16.58.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/8dec0ccd-7131-f89b-0e0c-22b575178511.png)

削除前の確認画面が開きます。ここでは**確認** とフォームに入力します。

![スクリーンショット 2024-05-09 16.58.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/277211c3-c745-20f8-d2a7-ecd39ec9c623.png)

以下のスクリーンショットと同じ状態になっていることを確認して、**削除** ボタンをクリックします。

![スクリーンショット 2024-05-09 16.58.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/603cdcf4-2ffe-14cb-50d5-918c431dc881.png)

削除に成功したメッセージが表示され、コレクションセクションにリソースがなくなれば、削除成功です。

![スクリーンショット 2024-05-09 17.05.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/91655bed-25f9-22b9-b81d-5c8b10f8796f.png)

### AppFlowワークフローの削除

AppFlowのワークフローを削除する場合、作成したワークフローの詳細画面を開きましょう。**[アクション]** の中に**フローを削除** がありますので、これをクリックします。

![スクリーンショット 2024-05-10 23.23.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/f4f7727b-bb8b-508d-03e9-7c12e3616ef2.png)

削除確認のモーダルが開きますので、**delete** と入力して削除しましょう。

![スクリーンショット 2024-05-10 23.23.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/53525eb4-0352-92ec-f550-e157c65d2070.png)

### Secrets Managerの削除

AppFlowで外部サービスに接続する設定を追加した場合、APIキーなどの情報はSecrets Managerに保存されています。このデータが削除されているかを確認しておきましょう。検索フォームに**Secrets** と入力して、**Secrets Manager**管理画面に移動します。

![スクリーンショット 2024-05-10 23.51.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/53f595d3-a342-e2d3-dc3a-49afaf89f921.png)


AppFlowが作成したシークレットは、`appflow!`から始まる名前で保存されています。検索フォームに`appflow`と入力して、今回のワークショップで追加したワークフロー・接続名と同じものがないか確認してください。

![スクリーンショット 2024-05-10 23.52.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/8349285f-941a-1914-8ed0-43868ef2e547.png)

もしシークレットが残っている場合は、そのシークレットの詳細ページに移動します。 **[アクション]** の中に **シークレットを削除する** がありますので、これで削除します。

![スクリーンショット 2024-05-10 23.54.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/c275a28a-199b-3db4-ef6f-cdad071e2d60.png)


### S3バケットの削除
S3バケットも削除しましょう。管理画面で削除したいバケットを選択し、**[削除]** ボタンをクリックします。

![スクリーンショット 2024-05-10 23.25.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/5bfcbb5f-8ead-c446-c611-24e97215b640.png)

S3バケットを削除するには、バケットの中身が完全に空である必要があります。削除画面に**バケットを空にする** ボタンが表示されている場合は、これをクリックして中身を空にしましょう。

![スクリーンショット 2024-05-10 23.26.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/a679b74e-732c-13ff-cbb7-2b21becd89c1.png)

バケットを空にした状態で、**完全に削除** とフィールドに入力すると、削除ができます。

![スクリーンショット 2024-05-10 23.26.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/af7b057a-3015-b7a4-2072-6d798a247b84.png)



## 終わりに

AppFlowを利用することで、Bedrockナレッジベースを利用したRAG / AIチャットアプリが利用するデータソースを外部からノーコードで取り込むことができます。実際の運用では、ワークフローを定期実行にすることで、情報の更新も自動化することができるでしょう。ただしその場合、S3バケットに転送された新しいデータをナレッジベースに同期させるためのワークフローが必要になります。Amazon EventBridgeでAppFlowのワークフローが完了したイベントを受け取り、Step FunctionsからBedrockナレッジベースの`StartIngestionJob`を実行することで、こちらもコードを書かずに実現できます。具体的な手順については、後日別記事で紹介します。

![スクリーンショット 2024-05-10 23.31.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/7f515bbf-92e7-1156-27e4-c8b8ef0b11a5.png)


このように、AWSのマネージドサービスを組み合わせることで、LLMを利用したRAGについてもほとんどコードを書かずに作ることができます。まずは動くデモをこのような形で作ってみて、回答の精度を高める方法やデータソースの拡充などをどのように実現するかの議論を始めてみましょう。もしノーコードでは厳しくなった場合も問題ありません。Step FunctionsやAWS Lambdaを部分的に活用して、最小限のコードでカスタマイズを目指してみましょう。